diff --git a/APRDesign b/APRDesign deleted file mode 100644 index 905f94568bb..00000000000 --- a/APRDesign +++ /dev/null @@ -1,340 +0,0 @@ -Design of APR - -The Apache Portable Run-time libraries have been designed to provide a common -interface to low level routines across any platform. The original goal of APR -was to combine all code in Apache to one common code base. This is not the -correct approach however, so the goal of APR has changed. - -There are places where common code is not a good thing. For example, how to -map requests to either threads or processes should be platform specific. -APR's place is now to combine any code that can be safely combined without -sacrificing performance. - -To this end we have created a set of operations that are required for cross -platfrom development. There may be other types that are desired and those -will be implemented in the future. The first version of APR will focus on -what Apache 2.0 needs. Of course, anything that is submitted will be -considered for inclusion. - -This document will discuss the structure of APR, and how best to contribute -code to the effort. - -APR On Windows - -APR on Windows is different from APR on all other systems, because it -doesn't use autoconf. On Unix, apr_private.h (private to APR) and apr.h -(public, used by applications that use APR) are generated by autoconf -from acconfig.h and apr.h.in respectively. On Windows, apr_private.h -and apr.h are created from apr_private.hw and apr.hw respectively. - -!!!*** If you add code to acconfig.h or tests to configure.in or aclocal.m4, - please give some thought to whether or not Windows needs this addition - as well. A general rule of thumb, is that if it is a feature macro, - such as APR_HAS_THREADS, Windows needs it. If the definition is going - to be used in a public APR header file, such as apr_general.h, Windows - needs it. - - The only time it is safe to add a macro or test without also adding - the macro to apr*.hw, is if the macro tells APR how to build. For - example, a test for a header file does not need to be added to Windows. -***!!! - -APR Features - -One of the goals of APR is to provide a common set of features across all -platforms. This is an admirable goal, it is also not realisitic. We cannot -expect to be able to implement ALL features on ALL platforms. So we are -going to do the next best thing. Provide a common interface to ALL APR -features on MOST platforms. - -APR developers should create FEATURE MACROS for any feature that is not -available on ALL platforms. This should be a simple definition which has -the form: - -APR_HAS_FEATURE - -This macro should evaluate to true if APR has this feature on this platform. -For example, Linux and Windows have mmap'ed files, and APR is providing an -interface for mmapp'ing a file. On both Linux and Windows, APR_HAS_MMAP -should evaluate to one, and the ap_mmap_* functions should map files into -memory and return the appropriate status codes. - -If your OS of choice does not have mmap'ed files, APR_HAS_MMAP should evaluate -to zero, and all ap_mmap_* functions should not be defined. The second step -is a precaution that will allow us to break at compile time if a programmer -tries to use unsupported functions. - -APR types - -The base types in APR -file_io File I/O, including pipes -lib A portable library originally used in Apache. This contains - memory management, tables, and arrays. -locks Mutex and reader/writer locks -misc Any APR type which doesn't have any other place to belong -network_io Network I/O -shmem Shared Memory (Not currently implemented) -signal Asynchronous Signals -threadproc Threads and Processes -time Time - -Directory Structure - -Each type has a base directory. Inside this base directory, are -subdirectories, which contain the actual code. These subdirectories are named -after the platforms the are compiled on. Unix is also used as a common -directory. If the code you are writing is POSIX based, you should look at the -code in the unix directory. A good rule of thumb, is that if more than half -your code needs to be ifdef'ed out, and the structures required for your code -are substantively different from the POSIX code, you should create a new -directory. - -Currently, the APR code is written for Unix, BeOS, Windows, and OS/2. An -example of the directory structure is the file I/O directory: - -apr - | - -> file_io - | - -> unix The Unix and common base code - | - -> win32 The Windows code - | - -> os2 The OS/2 code - -Obviously, BeOS does not have a directory. This is because BeOS is currently -using the Unix directory for it's file_io. In the near future, it will be -possible to use indiviual files from the Unix directory. - -There are a few special top level directories. These are test, inc, include, -and libs. Test is a directory which stores all test programs. It is expected -that if a new type is developed, there will also be a new test program, to -help people port this new type to different platforms. Inc is a directory for -internal header files. This directory is likely to go away soon. Include is -a directory which stores all required APR header files for external use. The -distinction between internal and external header files will be made soon. -Finally, libs is a generated directory. When APR finishes building, it will -store it's library files in the libs directory. - -Creating an APR Type - -The current design of APR requires that APR types be incomplete. It is not -possible to write flexible portable code if programs can access the internals -of APR types. This is because different platforms are likely to define -different native types. - -For this reason, each platform defines a structure in their own directories. -Those structures are then typedef'ed in an external header file. For example -in file_io/unix/fileio.h: - - struct ap_file_t { - ap_context_t *cntxt; - int filedes; - FILE *filehand; - ... - } - -In include/apr_file_io.h: - typedef struct ap_file_t ap_file_t; - -This will cause a compiler error if somebody tries to access the filedes field -in this strcture. Windows does not have a filedes field, so obviously, it is -important that programs not be able to access these. - -The only exception to the incomplete type rule can be found in apr_portable.h. -This file defines the native types for each platform. Using these types, it -is possible to extract native types for any APR type. - -You may notice the ap_context_t field. All APR types have this field. This -type is used to allocate memory within APR. - -New Function - -When creating a new function, please try to adhere to these rules. - -1) Result arguments should be the first arguments. -2) If a function needs a context, it should be the last argument. -3) These rules are flexible, especially if it makes the code easier - to understand because it mimics a standard function. - -Documentation - -Whenever a new function is added to APR, it MUST be documented. New -functions will not be committed unless there are docs to go along with them. -The documentation should be a comment block above the function in the unix -.c file. This does not mean you must implement the function for Unix. But, -it would be nice if you submitted a file with the prototypes and the comments -above the prototypes to be checked into the unix tree. - -The format for the comment block is: - -/* - -=head1 function prototype - -B<Brief description of function> - - arg 1) explanation of arg 1 - arg 2) explanation of arg 2 - arg N) explanation of arg N - -B<NOTE>: Any extra information the programmer needs. - -=cut - */ - -The spacing for the documentation is VERY important, because the docs are -processed with perldoc, and this spacing is required for the perldoc scripts -to work properly. - -For an actual example, look at any function in the fileio/unix directory. - -APR Error reporting - -Most APR functions should return an ap_status_t type. The only time an -APR function does not return an ap_status_t is if it absolutly CAN NOT -fail. Examples of this would be filling out an array when you know you are -not beyond the array's range. If it cannot fail on your platform, but it -could conceivably fail on another platform, it should return an ap_status_t. -Unless you are sure, return an ap_status_t. :-) - -All platform return errno values unchanged. Each platform can also have -one system error type, which can be returned after an offset is added. -There are five types of error values in APR, each with it's own offset. - - Name Purpose -0) This is 0 for all platforms and isn't really defined - anywhere, but it is the offset for errno values. - (This has no name because it isn't actually defined, - but completeness we are discussing it here). -1) APR_OS_START_ERROR This is platform dependant, and is the offset at which - APR errors start to be defined. (Canonical error - values are also defined in this section. [Canonical - error values are discussed later]). -2) APR_OS_START_STATUS This is platform dependant, and is the offset at which - APR status values start. -4) APR_OS_START_USEERR This is platform dependant, and is the offset at which - APR apps can begin to add their own error codes. -3) APR_OS_START_SYSERR This is platform dependant, and is the offset at which - system error values begin. - -All of these definitions can be found in apr_errno.h for all platforms. When -an error occurs in an APR function, the function must return an error code. -If the error occurred in a system call and that system call uses errno to -report an error, then the code is returned unchanged. For example: - - if (open(fname, oflags, 0777) < 0) - return errno; - - -The next place an error can occur is a system call that uses some error value -other than the primary error value on a platform. This can also be handled -by APR applications. For example: - - if (CreateFile(fname, oflags, sharemod, NULL, - createflags, attributes,0) == INVALID_HANDLE_VALUE - return (GetLAstError() + APR_OS_START_SYSERR); - -These two examples implement the same function for two different platforms. -Obviously even if the underlying problem is the same on both platforms, this -will result in two different error codes being returned. This is OKAY, and -is correct for APR. APR relies on the fact that most of the time an error -occurs, the program logs the error and continues, it does not try to -programatically solve the problem. This does not mean we have not provided -support for programmatically solving the problem, it just isn't the default -case. We'll get to how this problem is solved in a little while. - -If the error occurs in an APR function but it is not due to a system call, -but it is actually an APR error or just a status code from APR, then the -appropriate code should be returned. These codes are defined in apr_errno.h -and are self explanatory. - -No APR code should ever return a code between APR_OS_START_USEERR and -APR_OS_START_SYSERR, those codes are reserved for APR applications. - -To programmatically correct an error in a running application, the error codes -need to be consistent across platforms. This should make sense. To get -consistent error codes, APR provides a function ap_canonicalize_error(). -This function will take as input any ap_status_t value, and return a small -subset of canonical APR error codes. These codes will be equivalent to -Unix errno's. Why is it a small subset? Because we don't want to try to -convert everything in the first pass. As more programs require that more -error codes are converted, they will be added to this function. - -Why did APR take this approach? There are two ways to deal with error -codes portably. - -1) return the same error code across all platforms. 2) return platform -specific error codes and convert them when necessary. - -The problem with option number one is that it takes time to convert error -codes to a common code, and most of the time programs want to just output -an error string. If we convert all errors to a common subset, we have four -steps to output an error string: - - make syscall that fails - convert to common error code step 1 - return common error code - check for success - call error output function step 2 - convert back to system error step 3 - output error string step 4 - -By keeping the errors platform specific, we can output error strings in two -steps. - - make syscall that fails - return error code - check for success - call error output function step 1 - output error string step 2 - -Less often, programs change their execution based on what error was returned. -This is no more expensive using option 2 and it is using option 1, but we -put the onus of converting the error code on the programmer themselves. -For example, using option 1: - - make syscall that fails - convert to common error code - return common error code - decide execution basd on common error code - -Using option 2: - - make syscall that fails - return error code - convert to common error code (using ap_canonicalize_error) - decide execution based on common error code - -Finally, there is one more operation on error codes. You can get a string -that explains in human readable form what has happened. To do this using -APR, call ap_strerror(). - -On all platforms ap_strerror takes the form: - -char *ap_strerror(ap_status_t err) -{ - if (err < APR_OS_START_ERRNO2) - return (platform dependant error string generator) - if (err < APR_OS_START_ERROR) - return (platform dependant error string generator for - supplemental error values) - if (err < APR_OS_SYSERR) - return (APR generated error or status string) - if (err == 0) - return "No error was found" - else - return "APR doesn't understand this error value" -} - -Notice, this does not handle canonicalized error values well. Those will -return "APR doesn't understand this error value" on some platforms and -an actual error string on others. To deal with this, just get the -string before canonicalizing your error code. - -The other problem with option 1, is that it is a lossy conversion. For -example, Windows and OS/2 have a couple hundred error codes, but POSIX errno -only defines about 50 errno values. This means that if we convert to a -canonical error value immediately, there is no way for the programmer to -get the actual system error. - diff --git a/CHANGES b/CHANGES new file mode 100644 index 00000000000..2f92d163a9d --- /dev/null +++ b/CHANGES @@ -0,0 +1,194 @@ + -*- coding: utf-8 -*- +Changes for APR 2.0.0 + + *) Add apr_pool_tag_get to retrieve the pool tag name. [Joe Orton] + + *) Add apr_sockaddr_zone_set, apr_sockaddr_zone_set to set and retrieve + the zone for link-local IPv6 addresses. [Joe Orton] + + *) apr_sockaddr_equal: Compare link-local IPv6 addresses with different + zones as not equal. [Joe Orton] + + *) apr_sockaddr_ip_getbuf, apr_sockaddr_ip_get: Append "%zone" for + IPv6 link-local addresses. [Joe Orton] + + *) Don't seek to the end when opening files with APR_FOPEN_APPEND on Windows. + [Evgeny Kotkov <evgeny.kotkov visualsvn.com>] + + *) Fix a deadlock when writing to locked files opened with APR_FOPEN_APPEND + on Windows. PR 50058. + [Evgeny Kotkov <evgeny.kotkov visualsvn.com>] + + *) apr_file_write: Optimize large writes to buffered files on Windows. + [Evgeny Kotkov <evgeny.kotkov visualsvn.com>] + + *) apr_file_trunc: Truncating a buffered file could add unexpected + data after the truncate position. PR 51017. + [Evgeny Kotkov <evgeny.kotkov visualsvn.com>] + + *) apr_file_trunc: Fix an issue where reading from a buffered file + after truncate could return stale data from the buffer. + [Evgeny Kotkov <evgeny.kotkov visualsvn.com>] + + *) apr_allocator, apr_pools: Add apr_allocator_page_size() and + apr_allocator_min_order_set() to respectively get the (system's) page size + in use and set the minimum allocation size for an allocator (expressed in + 2^order pages). [Yann Ylavic] + + *) apr_file_gets: Optimize for buffered files on Windows. + [Evgeny Kotkov <evgeny.kotkov visualsvn.com>] + + *) apr_crypto: avoid excessive iteration in bcrypt hash. + [Hanno Böck <hanno hboeck.de>] + + *) apr_siphash: Implement keyed hash function SipHash. [Yann Ylavic] + + *) apr_atomic: change the API of apr_atomic_casptr() apr_atomic_xchgptr() + functions to take a volatile pointer to void instead of pointer to + volatile void. [Yann Ylavic] + + *) apr_crypto: Add apr_crypto_key() function which supports keys + generated from a passphrase or a raw secret provided by the caller. + Deprecate apr_crypto_passphrase(). [Graham Leggett] + + *) apr_crypto_nss: Ensure the SECItem returned by PK11_ParamFromIV + is properly freed. [Graham Leggett] + + *) apr_crypto: Don't cache the driver if initialisation fails. This + stops the second and subsequent attempt to use the API from failing + claiming the library is not initialised. [Graham Leggett] + + *) apr_xml_to_text: Add style APR_XML_X2T_PARSED to maintain a + consistent namespace prefix. [Jari Urpalainen + <jari.urpalainen nokia.com>] + + *) apr_os_proc_mutex-unix: For consistency with other OS native to APR + types constructors/_put()ers and non-unix mutex mechanisms, always + destroy the underlying native mutex when apr_proc_mutex_destroy() is + called explicitly. [Yann Ylavic] + + *) apr_os_proc_mutex_put_ex: Allow to specify whether the OS native + mutex should or not be cleaned up (destroyed) with the constructed + APR mutex (given pool), and default to not for the simple _put() + function. [Yann Ylavic] + + *) apr_file_io: Add apr_file_pipe_create_pools() allowing a pair of + pipes to be created, each in a different pool. [Graham Leggett] + + *) apr_table_overlap: Add APR_OVERLAP_TABLES_ADD to merge and set when + overlapping tables. [Graham Leggett] + + *) apr_filepath_merge: Fix truename length calculation on Windows + in cases where the "short" name variant is actually longer than + the "long" or "true" name. See: testnames.c:merge_shortname(). + [Bert Huijben <rhuijben a.o>] + + *) apr_file_mktemp: Use mkostemp() where available to save on system + calls. [Joe Orton] + + *) apr_pools: Fix pool debugging output so that creation events are + always emitted before allocation events and subpool destruction + events are emitted on pool clear/destroy for proper accounting. + [Brane Čibej] + + *) apr_atomic: Fix errors when building on Visual Studio 2013 while + maintaining the ability to build on Visual Studio 6 with Windows + Server 2003 R2 SDK. PR 57191. [Gregg Smith] + + *) build: Correctly use AC_(PATH|CHECK)_TOOL to support cross compilation. + PR: 56866. [Timothy Gu <timothygu99 gmail.com>] + + *) apr_queue: Add apr_queue_timedpush() and apr_queue_timedpop() to + support timedout operations. PR 56951. [Anthony Minessale <anthm + freeswitch org>, Travis Cross <tc+asf travislists com>, Yann Ylavic]. + + *) apr_allocator: Be less wasteful and don't return a memnode that is + much larger than what was requested. [Stefan Fuhrmann + <stefan fuhrmann wandisco com>] + + *) Windows platform: Remove support for Windows 9x. + + *) Added signed apr_intptr_t. Changed ODBC dbd driver to use this. + [Tom Donovan] + + *) Changes to apr_pollset_method_e enum value of APR_POLLSET_POLL and + APR_POLLSET_AIO_MSGQ. Restore APR_POLLSET_POLL to its pre-r1308910 + (April 2012) value, and move APR_POLLSET_AIO_MSGQ ahead. This restores + ABI compat with released branches. [Eric Covener] + + *) Add apr_pbase64_encode() and apr_pbase64_decode() to encode to/from + the pool. [Graham Leggett] + + *) Mark apr_dbd_freetds as unsupported, and remove it from all builds + [Nick Kew] + + *) Fix pool integrity checks with threads. Add new apr_pool_owner_set() + function. PR 43375, 52785. [Stefan Fritsch] + + *) Add support code to teach valgrind about APR pools, allocators, and + bucket allocators. [Stefan Fritsch] + + *) apr_socket_accept_filter(): The 2nd and 3rd arguments are now + const char * instead of char *. [Jeff Trawick] + + *) apr_brigades: add a check to prevent infinite while loop in case + of a corrupted brigade. Problem evidenced in PR 51062. Analysis by + Krzysztof Kostałkowicz <KKostalkowicz ivmx.pl>, patch [Nick Kew]. + + *) Support libxml2 as an alternative XML parser to expat [Nick Kew] + + *) Hide apr_wait_for_io_or_timeout() from public view and add instead + apr_socket_wait() and apr_file_pipe_wait(). [Brian Havard] + + *) Support connecttimeout, readtimeout and writetimeout MySQL options + PR 48251 [Marko Kevac <marko kevac.org>] + + *) Transfer the apr-util spec file contents to apr.spec. [Graham + Leggett] + + *) Added Unix domain socket support. [Mladen Turk] + + *) Merge APR-util into APR. [various] + + *) apr_socket_listen: Allow larger listen backlog values on Windows 8+. + [Evgeny Kotkov <evgeny.kotkov visualsvn.com>] + +Changes for APR and APR-util 1.6.x and later: + + *) http://svn.apache.org/viewvc/apr/apr/branches/1.6.x/CHANGES?view=markup + *) http://svn.apache.org/viewvc/apr/apr-util/branches/1.6.x/CHANGES?view=markup + +Changes for APR and APR-util 1.5.x and later: + + *) http://svn.apache.org/viewvc/apr/apr/branches/1.5.x/CHANGES?view=markup + *) http://svn.apache.org/viewvc/apr/apr-util/branches/1.5.x/CHANGES?view=markup + +Changes for APR and APR-util 1.4.x and later: + + *) http://svn.apache.org/viewvc/apr/apr/branches/1.4.x/CHANGES?view=markup + *) http://svn.apache.org/viewvc/apr/apr-util/branches/1.4.x/CHANGES?view=markup + +Changes for APR and APR-util 1.3.x and later: + + *) http://svn.apache.org/viewvc/apr/apr/branches/1.3.x/CHANGES?view=markup + *) http://svn.apache.org/viewvc/apr/apr-util/branches/1.3.x/CHANGES?view=markup + +Changes for APR and APR-util 1.2.x and later: + + *) http://svn.apache.org/viewvc/apr/apr/branches/1.2.x/CHANGES?view=markup + *) http://svn.apache.org/viewvc/apr/apr-util/branches/1.2.x/CHANGES?view=markup + +Changes for APR and APR-util 1.1.x and later: + + *) http://svn.apache.org/viewvc/apr/apr/branches/1.1.x/CHANGES?view=markup + *) http://svn.apache.org/viewvc/apr/apr-util/branches/1.1.x/CHANGES?view=markup + +Changes for APR and APR-util 1.0.x and later: + + *) http://svn.apache.org/viewvc/apr/apr/branches/1.0.x/CHANGES?view=markup + *) http://svn.apache.org/viewvc/apr/apr-util/branches/1.0.x/CHANGES?view=markup + +Changes for APR and APR-util 0.9.x and later/earlier: + + *) http://svn.apache.org/viewvc/apr/apr/branches/0.9.x/CHANGES?view=markup + *) http://svn.apache.org/viewvc/apr/apr-util/branches/0.9.x/CHANGES?view=markup diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 00000000000..9a36de9c26e --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,631 @@ +# 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. +# +# Read README.cmake before using this. + +PROJECT(APR C) + +CMAKE_MINIMUM_REQUIRED(VERSION 2.8) + +# Either Expat or LibXml2 is required; the others are optional +FIND_PACKAGE(Expat) +FIND_PACKAGE(LibXml2) +FIND_PACKAGE(OpenSSL) + +IF(NOT EXPAT_FOUND AND NOT LIBXML2_FOUND) + MESSAGE(FATAL_ERROR "Either Expat or LibXml2 is required, but neither was found") +ENDIF() + +IF(EXPAT_FOUND) + OPTION(APU_USE_EXPAT "Use Expat" ON) + IF(LIBXML2_FOUND) + OPTION(APU_USE_LIBXML2 "Use LibXml2" OFF) + ENDIF() +ELSE() + OPTION(APU_USE_LIBXML2 "Use LibXml2" ON) +ENDIF() + +OPTION(APR_INSTALL_PRIVATE_H "Install selected private .h files (for httpd)" OFF) +OPTION(APU_HAVE_CRYPTO "Crypto support" OFF) +OPTION(APU_HAVE_ODBC "Build ODBC DBD driver" ON) +OPTION(APR_HAVE_IPV6 "IPv6 support" ON) +OPTION(INSTALL_PDB "Install .pdb files (if generated)" ON) +OPTION(APR_BUILD_TESTAPR "Build the test suite" OFF) +OPTION(TEST_STATIC_LIBS "Test programs use APR static libraries instead of shared libraries?" OFF) +SET(MIN_WINDOWS_VER "Vista" + CACHE STRING "Minimum Windows version") +SET(LIBXML2_ICONV_INCLUDE_DIR "" + CACHE STRING "Directory with iconv include files for libxml2") +SET(LIBXML2_ICONV_LIBRARIES "" + CACHE STRING "iconv libraries to link with for libxml2") + +IF(NOT APU_USE_EXPAT AND NOT APU_USE_LIBXML2) + MESSAGE(FATAL_ERROR "Either Expat or LibXml2 must be selected") +ENDIF() +IF(APU_USE_EXPAT AND APU_USE_LIBXML2) + MESSAGE(FATAL_ERROR "Only one of Expat and LibXml2 can be selected") +ENDIF() + +IF(APU_HAVE_CRYPTO) +IF(NOT OPENSSL_FOUND) + MESSAGE(FATAL_ERROR "OpenSSL is the only supported crypto implementation, and it wasn't found!") +ENDIF() +ENDIF() + +# create 1-or-0 representation of feature tests for apr.h + +SET(apr_have_ipv6_10 0) +SET(apu_have_crypto_10 0) +SET(apu_use_libxml2_10 0) +SET(apu_use_expat_10 0) + +IF(APR_HAVE_IPV6) + SET(apr_have_ipv6_10 1) +ENDIF() + +IF(APU_HAVE_CRYPTO) + SET(apu_have_crypto_10 1) +ENDIF() + +IF(APU_USE_EXPAT) + SET(apu_use_expat_10 1) +ELSE() + SET(apu_use_libxml2_10 1) +ENDIF() + +IF("${MIN_WINDOWS_VER}" STREQUAL "") + SET(win32_winnt_str "0x0600") +ELSEIF(${MIN_WINDOWS_VER} STREQUAL "Vista") + SET(win32_winnt_str "0x0600") +ELSEIF(${MIN_WINDOWS_VER} STREQUAL "Windows7") + SET(win32_winnt_str "0x0601") +ELSE() + SET(win32_winnt_str ${MIN_WINDOWS_VER}) +ENDIF() + +CONFIGURE_FILE(include/apr.hwc + ${PROJECT_BINARY_DIR}/apr.h) +# "COPYONLY" just because anything else isn't implemented ;) +CONFIGURE_FILE(include/private/apu_select_dbm.hw + ${PROJECT_BINARY_DIR}/apu_select_dbm.h + COPYONLY) +CONFIGURE_FILE(include/apu_want.hw + ${PROJECT_BINARY_DIR}/apu_want.h + COPYONLY) + +ADD_EXECUTABLE(gen_test_char tools/gen_test_char.c) +GET_TARGET_PROPERTY(GEN_TEST_CHAR_EXE gen_test_char LOCATION) +ADD_CUSTOM_COMMAND( + COMMENT "Generating character tables, apr_escape_test_char.h, for current locale" + DEPENDS gen_test_char + COMMAND ${GEN_TEST_CHAR_EXE} > ${PROJECT_BINARY_DIR}/apr_escape_test_char.h + OUTPUT ${PROJECT_BINARY_DIR}/apr_escape_test_char.h +) +ADD_CUSTOM_TARGET( + test_char_header ALL + DEPENDS ${PROJECT_BINARY_DIR}/apr_escape_test_char.h +) + +IF(APU_USE_EXPAT) + SET(XMLLIB_INCLUDE_DIR ${EXPAT_INCLUDE_DIRS}) + SET(XMLLIB_LIBRARIES ${EXPAT_LIBRARIES}) +ELSE() + SET(XMLLIB_INCLUDE_DIR "${LIBXML2_INCLUDE_DIR};${LIBXML2_ICONV_INCLUDE_DIR}") + SET(XMLLIB_LIBRARIES "${LIBXML2_LIBRARIES};${LIBXML2_ICONV_LIBRARIES}") +ENDIF() + +# Generated .h files are stored in PROJECT_BINARY_DIR, not the +# source tree. +# +# BROKEN: not searching PROJECT_BINARY_DIR first, so you have to +# manually delete apr.h in PROJECT_SOURCE_DIR/include if +# you've generated apr.h before using a different build + +SET(APR_INCLUDE_DIRECTORIES + ${PROJECT_BINARY_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/include + ${CMAKE_CURRENT_SOURCE_DIR}/include/arch/win32 + ${CMAKE_CURRENT_SOURCE_DIR}/include/arch/unix + ${CMAKE_CURRENT_SOURCE_DIR}/include/private +) + +SET(APR_SYSTEM_LIBS + ws2_32 + mswsock + rpcrt4 +) + +INCLUDE_DIRECTORIES(${APR_INCLUDE_DIRECTORIES} ${XMLLIB_INCLUDE_DIR}) + +SET(APR_PUBLIC_HEADERS_STATIC + include/apr_allocator.h + include/apr_anylock.h + include/apr_atomic.h + include/apr_base64.h + include/apr_buckets.h + include/apr_crypto.h + include/apr_cstr.h + include/apr_date.h + include/apr_dbd.h + include/apr_dbm.h + include/apr_dso.h + include/apr_env.h + include/apr_errno.h + include/apr_escape.h + include/apr_file_info.h + include/apr_file_io.h + include/apr_fnmatch.h + include/apr_general.h + include/apr_getopt.h + include/apr_global_mutex.h + include/apr_hash.h + include/apr_hooks.h + include/apr_inherit.h + include/apr_lib.h + include/apr_md4.h + include/apr_md5.h + include/apr_memcache.h + include/apr_mmap.h + include/apr_network_io.h + include/apr_optional.h + include/apr_optional_hooks.h + include/apr_perms_set.h + include/apr_poll.h + include/apr_pools.h + include/apr_portable.h + include/apr_proc_mutex.h + include/apr_queue.h + include/apr_random.h + include/apr_redis.h + include/apr_reslist.h + include/apr_ring.h + include/apr_rmm.h + include/apr_sdbm.h + include/apr_sha1.h + include/apr_shm.h + include/apr_signal.h + include/apr_siphash.h + include/apr_skiplist.h + include/apr_strings.h + include/apr_strmatch.h + include/apr_tables.h + include/apr_thread_cond.h + include/apr_thread_mutex.h + include/apr_thread_pool.h + include/apr_thread_proc.h + include/apr_thread_rwlock.h + include/apr_time.h + include/apr_uri.h + include/apr_user.h + include/apr_uuid.h + include/apr_version.h + include/apr_want.h + include/apr_xlate.h + include/apr_xml.h + include/apu.h + include/apu_errno.h + include/apu_version.h +) +SET(APR_PUBLIC_HEADERS_GENERATED + ${PROJECT_BINARY_DIR}/apr.h + ${PROJECT_BINARY_DIR}/apu_want.h +) + +SET(APR_SOURCES + atomic/win32/apr_atomic.c + buckets/apr_brigade.c + buckets/apr_buckets.c + buckets/apr_buckets_alloc.c + buckets/apr_buckets_eos.c + buckets/apr_buckets_file.c + buckets/apr_buckets_flush.c + buckets/apr_buckets_heap.c + buckets/apr_buckets_mmap.c + buckets/apr_buckets_pipe.c + buckets/apr_buckets_pool.c + buckets/apr_buckets_refcount.c + buckets/apr_buckets_simple.c + buckets/apr_buckets_socket.c + crypto/apr_crypto.c + crypto/apr_md4.c + crypto/apr_md5.c + crypto/apr_passwd.c + crypto/apr_sha1.c + crypto/apr_siphash.c + crypto/crypt_blowfish.c + crypto/getuuid.c + crypto/uuid.c + dbd/apr_dbd.c + dbm/apr_dbm.c + dbm/apr_dbm_sdbm.c + dbm/sdbm/sdbm.c + dbm/sdbm/sdbm_hash.c + dbm/sdbm/sdbm_lock.c + dbm/sdbm/sdbm_pair.c + dso/win32/dso.c + encoding/apr_base64.c + encoding/apr_escape.c + file_io/unix/copy.c + file_io/unix/fileacc.c + file_io/unix/filepath_util.c + file_io/unix/fullrw.c + file_io/unix/mktemp.c + file_io/unix/tempdir.c + file_io/win32/buffer.c + file_io/win32/dir.c + file_io/win32/filedup.c + file_io/win32/filepath.c + file_io/win32/filestat.c + file_io/win32/filesys.c + file_io/win32/flock.c + file_io/win32/open.c + file_io/win32/pipe.c + file_io/win32/readwrite.c + file_io/win32/seek.c + hooks/apr_hooks.c + locks/win32/proc_mutex.c + locks/win32/thread_cond.c + locks/win32/thread_mutex.c + locks/win32/thread_rwlock.c + memcache/apr_memcache.c + memory/unix/apr_pools.c + misc/unix/errorcodes.c + misc/unix/getopt.c + misc/unix/otherchild.c + misc/unix/version.c + misc/win32/charset.c + misc/win32/env.c + misc/win32/internal.c + misc/win32/misc.c + misc/win32/rand.c + misc/win32/start.c + misc/win32/utf8.c + mmap/unix/common.c + mmap/win32/mmap.c + network_io/unix/inet_ntop.c + network_io/unix/inet_pton.c + network_io/unix/multicast.c + network_io/unix/sockaddr.c + network_io/unix/socket_util.c + network_io/win32/sendrecv.c + network_io/win32/sockets.c + network_io/win32/sockopt.c + passwd/apr_getpass.c + poll/unix/poll.c + poll/unix/pollcb.c + poll/unix/pollset.c + poll/unix/select.c + poll/unix/wakeup.c + random/unix/apr_random.c + random/unix/sha2.c + random/unix/sha2_glue.c + redis/apr_redis.c + shmem/win32/shm.c + strings/apr_cpystrn.c + strings/apr_cstr.c + strings/apr_fnmatch.c + strings/apr_snprintf.c + strings/apr_strings.c + strings/apr_strnatcmp.c + strings/apr_strtok.c + strmatch/apr_strmatch.c + tables/apr_hash.c + tables/apr_skiplist.c + tables/apr_tables.c + threadproc/win32/proc.c + threadproc/win32/signals.c + threadproc/win32/thread.c + threadproc/win32/threadpriv.c + time/win32/time.c + time/win32/timestr.c + uri/apr_uri.c + user/win32/groupinfo.c + user/win32/userinfo.c + util-misc/apr_date.c + util-misc/apr_queue.c + util-misc/apr_reslist.c + util-misc/apr_rmm.c + util-misc/apr_thread_pool.c + util-misc/apu_dso.c + xlate/xlate.c + xml/apr_xml.c + xml/apr_xml_expat.c + xml/apr_xml_libxml2.c +) + +SET(APR_TEST_SOURCES + test/abts.c + test/testargs.c + test/testatomic.c + test/testbase64.c + test/testbuckets.c + test/testcond.c + test/testcrypto.c + test/testdate.c + test/testdbd.c + test/testdbm.c + test/testdir.c + test/testdso.c + test/testdup.c + test/testenv.c + test/testescape.c + test/testfile.c + test/testfilecopy.c + test/testfileinfo.c + test/testflock.c + test/testfmt.c + test/testfnmatch.c + test/testglobalmutex.c + test/testhash.c + test/testhooks.c + test/testipsub.c + test/testlfs.c + test/testlfsabi.c + test/testlfsabi32.c + test/testlfsabi64.c + test/testlfsabi_include.c + test/testlock.c + test/testmd4.c + test/testmd5.c + test/testmemcache.c + test/testmmap.c + test/testnames.c + test/testoc.c + test/testpass.c + test/testpath.c + test/testpipe.c + test/testpoll.c + test/testpools.c + test/testproc.c + test/testprocmutex.c + test/testqueue.c + test/testrand.c + test/testredis.c + test/testreslist.c + test/testrmm.c + test/testshm.c + test/testsiphash.c + test/testskiplist.c + test/testsleep.c + test/testsock.c + test/testsockets.c + test/testsockopt.c + test/teststr.c + test/teststrmatch.c + test/teststrnatcmp.c + test/testtable.c + test/testtemp.c + test/testthread.c + test/testtime.c + test/testud.c + test/testuri.c + test/testuser.c + test/testutil.c + test/testuuid.c + test/testvsn.c + test/testxlate.c + test/testxml.c +) + +SET(install_targets) +SET(install_bin_pdb) +SET(dbd_drivers) + +# libapr-2 is shared, apr-2 is static +ADD_LIBRARY(libapr-2 SHARED ${APR_SOURCES} ${APR_PUBLIC_HEADERS_GENERATED} libapr.rc) +SET(install_targets ${install_targets} libapr-2) +SET(install_bin_pdb ${install_bin_pdb} ${PROJECT_BINARY_DIR}/libapr-2.pdb) +TARGET_LINK_LIBRARIES(libapr-2 ${XMLLIB_LIBRARIES} ${APR_SYSTEM_LIBS}) +SET_TARGET_PROPERTIES(libapr-2 PROPERTIES COMPILE_DEFINITIONS "APR_DECLARE_EXPORT;APR_HAVE_MODULAR_DSO") +ADD_DEPENDENCIES(libapr-2 test_char_header) + +ADD_LIBRARY(apr-2 STATIC ${APR_SOURCES} ${APR_PUBLIC_HEADERS_GENERATED}) +SET(install_targets ${install_targets} apr-2) +# no .pdb file generated for static libraries +TARGET_LINK_LIBRARIES(apr-2 ${XMLLIB_LIBRARIES} ${APR_SYSTEM_LIBS}) +SET_TARGET_PROPERTIES(apr-2 PROPERTIES COMPILE_DEFINITIONS "APR_DECLARE_STATIC;APR_HAVE_MODULAR_DSO") +ADD_DEPENDENCIES(apr-2 test_char_header) + +# libaprapp-2 and aprapp-2 are static +ADD_LIBRARY(libaprapp-2 STATIC misc/win32/apr_app.c misc/win32/internal.c ${APR_PUBLIC_HEADERS_GENERATED}) +SET(install_targets ${install_targets} libaprapp-2) +SET_TARGET_PROPERTIES(libaprapp-2 PROPERTIES COMPILE_DEFINITIONS APR_APP) + +ADD_LIBRARY(aprapp-2 STATIC misc/win32/apr_app.c misc/win32/internal.c ${APR_PUBLIC_HEADERS_GENERATED}) +SET(install_targets ${install_targets} aprapp-2) +SET_TARGET_PROPERTIES(aprapp-2 PROPERTIES COMPILE_DEFINITIONS "APR_DECLARE_STATIC;APR_APP") + +IF(APU_HAVE_CRYPTO) + IF(NOT OPENSSL_FOUND) + MESSAGE(FATAL_ERROR "Only OpenSSL-based crypto is currently implemented in the cmake build") + ENDIF() + ADD_LIBRARY(apr_crypto_openssl-2 SHARED crypto/apr_crypto_openssl.c libapr.rc) + SET(install_targets ${install_targets} apr_crypto_openssl-2) + SET(install_bin_pdb ${install_bin_pdb} ${PROJECT_BINARY_DIR}/apr_crypto_openssl-2.pdb) + SET_TARGET_PROPERTIES(apr_crypto_openssl-2 PROPERTIES INCLUDE_DIRECTORIES "${APR_INCLUDE_DIRECTORIES};${OPENSSL_INCLUDE_DIR}") + SET_TARGET_PROPERTIES(apr_crypto_openssl-2 PROPERTIES COMPILE_FLAGS "-DDLL_NAME=apr_crypto_openssl") + TARGET_LINK_LIBRARIES(apr_crypto_openssl-2 libapr-2 ${APR_SYSTEM_LIBS} ${OPENSSL_LIBRARIES}) +ENDIF() + +IF(APU_HAVE_ODBC) + ADD_LIBRARY(apr_dbd_odbc-2 SHARED dbd/apr_dbd_odbc.c libapr.rc) + SET(install_targets ${install_targets} apr_dbd_odbc-2) + SET(install_bin_pdb ${install_bin_pdb} ${PROJECT_BINARY_DIR}/apr_dbd_odbc-2.pdb) + SET(dbd_drivers ${dbd_drivers} odbc) + TARGET_LINK_LIBRARIES(apr_dbd_odbc-2 libapr-2 ${APR_SYSTEM_LIBS} odbc32 odbccp32) + SET_PROPERTY(TARGET apr_dbd_odbc-2 APPEND PROPERTY LINK_FLAGS /export:apr_dbd_odbc_driver) + SET_TARGET_PROPERTIES(apr_dbd_odbc-2 PROPERTIES COMPILE_DEFINITIONS "APU_HAVE_ODBC;HAVE_SQL_H;APR_DECLARE_EXPORT;APU_DSO_MODULE_BUILD") + SET_TARGET_PROPERTIES(apr_dbd_odbc-2 PROPERTIES COMPILE_FLAGS "-DDLL_NAME=apr_dbd_odbc") +ENDIF() + +IF(APR_BUILD_TESTAPR) + ENABLE_TESTING() + # Create a "check" target that displays test program output to the console. + ADD_CUSTOM_TARGET(check COMMAND ${CMAKE_CTEST_COMMAND} --verbose) + + # copy data files to build directory so that we can run programs from there + EXECUTE_PROCESS(COMMAND ${CMAKE_COMMAND} -E make_directory + ${PROJECT_BINARY_DIR}/data) + EXECUTE_PROCESS(COMMAND ${CMAKE_COMMAND} -E copy_if_different + ${PROJECT_SOURCE_DIR}/test/data/billion-laughs.xml + ${PROJECT_BINARY_DIR}/data/billion-laughs.xml) + EXECUTE_PROCESS(COMMAND ${CMAKE_COMMAND} -E copy_if_different + ${PROJECT_SOURCE_DIR}/test/data/file_datafile.txt + ${PROJECT_BINARY_DIR}/data/file_datafile.txt) + EXECUTE_PROCESS(COMMAND ${CMAKE_COMMAND} -E copy_if_different + ${PROJECT_SOURCE_DIR}/test/data/mmap_datafile.txt + ${PROJECT_BINARY_DIR}/data/mmap_datafile.txt) + + IF(TEST_STATIC_LIBS) + SET(whichapr apr-2) + SET(whichaprapp aprapp-2) + SET(apiflag -DAPR_DECLARE_STATIC) + ELSE() + SET(whichapr libapr-2) + SET(whichaprapp libaprapp-2) + SET(apiflag) + ENDIF() + + ADD_EXECUTABLE(testapp test/testapp.c) + TARGET_LINK_LIBRARIES(testapp ${whichapr} ${whichaprapp} ${XMLLIB_LIBRARIES} ${APR_SYSTEM_LIBS}) + SET_TARGET_PROPERTIES(testapp PROPERTIES LINK_FLAGS /entry:wmainCRTStartup) + IF(apiflag) + SET_TARGET_PROPERTIES(testapp PROPERTIES COMPILE_FLAGS ${apiflag}) + ENDIF() + ADD_TEST(NAME testapp COMMAND testapp) + + ADD_EXECUTABLE(testall ${APR_TEST_SOURCES}) + TARGET_LINK_LIBRARIES(testall ${whichapr} ${XMLLIB_LIBRARIES} ${APR_SYSTEM_LIBS}) + IF(apiflag) + SET_TARGET_PROPERTIES(testall PROPERTIES COMPILE_FLAGS ${apiflag}) + ENDIF() + ADD_TEST(NAME testall COMMAND testall) + + ADD_LIBRARY(mod_test MODULE test/mod_test.c) + TARGET_LINK_LIBRARIES(mod_test ${whichapr} ${APR_SYSTEM_LIBS}) + SET_PROPERTY(TARGET mod_test APPEND PROPERTY LINK_FLAGS /export:print_hello) + # nasty work-around for difficulties adding more than one additional flag + # (they get joined in a bad way behind the scenes) + GET_PROPERTY(link_flags TARGET mod_test PROPERTY LINK_FLAGS) + SET(link_flags "${link_flags} /export:count_reps") + SET_TARGET_PROPERTIES(mod_test PROPERTIES LINK_FLAGS ${link_flags}) + IF(apiflag) + SET_TARGET_PROPERTIES(mod_test PROPERTIES COMPILE_FLAGS ${apiflag}) + ENDIF() + + # Build all the single-source executable files with no special build + # requirements. + SET(single_source_programs + test/dbd.c + test/echod.c + test/sendfile.c + test/sockperf.c + test/testlockperf.c + test/testmutexscope.c + test/globalmutexchild.c + test/occhild.c + test/proc_child.c + test/readchild.c + test/sockchild.c + test/testshmproducer.c + test/testshmconsumer.c + test/tryread.c + test/internal/testucs.c + ) + + FOREACH(sourcefile ${single_source_programs}) + STRING(REGEX REPLACE ".*/([^\\]+)\\.c" "\\1" proggie ${sourcefile}) + ADD_EXECUTABLE(${proggie} ${sourcefile}) + TARGET_LINK_LIBRARIES(${proggie} ${whichapr} ${XMLLIB_LIBRARIES} ${APR_SYSTEM_LIBS}) + IF(apiflag) + SET_TARGET_PROPERTIES(${proggie} PROPERTIES COMPILE_FLAGS ${apiflag}) + ENDIF() + ENDFOREACH() + + # Add tests for programs that run by themselves with no arguments. + SET(simple_tests + testmutexscope + testucs + ) + + FOREACH(simple ${simple_tests}) + ADD_TEST(NAME ${simple} COMMAND ${simple}) + ENDFOREACH() + + # testlockperf takes forever on Windows with default counter limit + ADD_TEST(NAME testlockperf COMMAND testlockperf -c 50000) + + # dbd and sendfile are run multiple times with different parameters. + FOREACH(somedbd ${dbd_drivers}) + ADD_TEST(NAME dbd-${somedbd} COMMAND dbd ${somedbd}) + ENDFOREACH() + + FOREACH(sendfile_mode blocking nonblocking timeout) + ADD_TEST(NAME sendfile-${sendfile_mode} COMMAND sendfile client ${sendfile_mode} startserver) + ENDFOREACH() + + # No test is added for echod+sockperf. Those will have to be run manually. + +ENDIF (APR_BUILD_TESTAPR) + +# Installation + +INSTALL(TARGETS ${install_targets} + RUNTIME DESTINATION bin + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib + ) + +IF(INSTALL_PDB) + INSTALL(FILES ${install_bin_pdb} + DESTINATION bin + CONFIGURATIONS RelWithDebInfo Debug) +ENDIF() + +INSTALL(FILES ${APR_PUBLIC_HEADERS_STATIC} ${APR_PUBLIC_HEADERS_GENERATED} DESTINATION include) +IF(APR_INSTALL_PRIVATE_H) + # Kludges for unexpected dependencies of httpd 2.x, not installed by default + SET(APR_PRIVATE_H_FOR_HTTPD + include/arch/win32/apr_arch_file_io.h + include/arch/win32/apr_arch_misc.h + include/arch/win32/apr_arch_utf8.h + include/arch/win32/apr_private.h + ) + INSTALL(FILES ${APR_PRIVATE_H_FOR_HTTPD} DESTINATION include/arch/win32) +ENDIF() + +STRING(TOUPPER "${CMAKE_BUILD_TYPE}" buildtype) +MESSAGE(STATUS "") +MESSAGE(STATUS "") +MESSAGE(STATUS "APR configuration summary:") +MESSAGE(STATUS "") + +MESSAGE(STATUS " Build type ...................... : ${CMAKE_BUILD_TYPE}") +MESSAGE(STATUS " Install .pdb (if available)...... : ${INSTALL_PDB}") +MESSAGE(STATUS " Install prefix .................. : ${CMAKE_INSTALL_PREFIX}") +MESSAGE(STATUS " C compiler ...................... : ${CMAKE_C_COMPILER}") +MESSAGE(STATUS " IPv6 ............................ : ${APR_HAVE_IPV6}") +MESSAGE(STATUS " DBD ODBC driver ................. : ${APU_HAVE_ODBC}") +MESSAGE(STATUS " Use Expat ....................... : ${APU_USE_EXPAT}") +MESSAGE(STATUS " Use LibXml2 ..................... : ${APU_USE_LIBXML2}") +MESSAGE(STATUS " Minimum Windows version ......... : ${MIN_WINDOWS_VER}") +MESSAGE(STATUS " Library files for XML ........... : ${XMLLIB_LIBRARIES}") +MESSAGE(STATUS " Build test suite ................ : ${APR_BUILD_TESTAPR}") +IF(TEST_STATIC_LIBS) +MESSAGE(STATUS " (testing static libraries)") +ELSE() +MESSAGE(STATUS " (testing dynamic libraries)") +ENDIF() +MESSAGE(STATUS " Install private .h for httpd .... : ${APR_INSTALL_PRIVATE_H}") diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000000..f517ea3dc8d --- /dev/null +++ b/LICENSE @@ -0,0 +1,488 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed 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. + + + +APACHE PORTABLE RUNTIME SUBCOMPONENTS: + +The Apache Portable Runtime includes a number of subcomponents with +separate copyright notices and license terms. Your use of the source +code for these subcomponents is subject to the terms and conditions +of the following licenses. + +From strings/apr_fnmatch.c, include/apr_fnmatch.h, misc/unix/getopt.c, +file_io/unix/mktemp.c, strings/apr_strings.c: + +/* + * 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. + +From network_io/unix/inet_ntop.c, network_io/unix/inet_pton.c: + +/* Copyright (c) 1996 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + +From dso/aix/dso.c: + + * Based on libdl (dlfcn.c/dlfcn.h) which is + * Copyright (c) 1992,1993,1995,1996,1997,1988 + * Jens-Uwe Mager, Helios Software GmbH, Hannover, Germany. + * + * Not derived from licensed software. + * + * Permission is granted to freely use, copy, modify, and redistribute + * this software, provided that the author is not construed to be liable + * for any results of using the software, alterations are clearly marked + * as such, and this notice is not modified. + +From strings/apr_strnatcmp.c, include/apr_strings.h: + + strnatcmp.c -- Perform 'natural order' comparisons of strings in C. + Copyright (C) 2000 by Martin Pool <mbp@humbug.org.au> + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + +From strings/apr_snprintf.c: + + * + * cvt - IEEE floating point formatting routines. + * Derived from UNIX V7, Copyright(C) Caldera International Inc. + * + + Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + Redistributions of source code and documentation must retain the above + copyright notice, this list of conditions and the following disclaimer. + + 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. + + All advertising materials mentioning features or use of this software + must display the following acknowledgement: + + This product includes software developed or owned by Caldera + International, Inc. + + Neither the name of Caldera International, Inc. nor the names of other + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA + INTERNATIONAL, INC. 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 CALDERA INTERNATIONAL, INC. 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. + +For the include\apr_md5.h component: + + * This is work is derived from material Copyright RSA Data Security, Inc. + * + * The RSA copyright statement and Licence for that original material is + * included below. This is followed by the Apache copyright statement and + * licence for the modifications made to that material. + + Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All + rights reserved. + + License to copy and use this software is granted provided that it + is identified as the "RSA Data Security, Inc. MD5 Message-Digest + Algorithm" in all material mentioning or referencing this software + or this function. + + License is also granted to make and use derivative works provided + that such works are identified as "derived from the RSA Data + Security, Inc. MD5 Message-Digest Algorithm" in all material + mentioning or referencing the derived work. + + RSA Data Security, Inc. makes no representations concerning either + the merchantability of this software or the suitability of this + software for any particular purpose. It is provided "as is" + without express or implied warranty of any kind. + + These notices must be retained in any copies of any part of this + documentation and/or software. + +For the passwd\apr_md5.c component: + + * This is work is derived from material Copyright RSA Data Security, Inc. + * + * The RSA copyright statement and Licence for that original material is + * included below. This is followed by the Apache copyright statement and + * licence for the modifications made to that material. + + Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All + rights reserved. + + License to copy and use this software is granted provided that it + is identified as the "RSA Data Security, Inc. MD5 Message-Digest + Algorithm" in all material mentioning or referencing this software + or this function. + + License is also granted to make and use derivative works provided + that such works are identified as "derived from the RSA Data + Security, Inc. MD5 Message-Digest Algorithm" in all material + mentioning or referencing the derived work. + + RSA Data Security, Inc. makes no representations concerning either + the merchantability of this software or the suitability of this + software for any particular purpose. It is provided "as is" + without express or implied warranty of any kind. + + These notices must be retained in any copies of any part of this + documentation and/or software. + + * The apr_md5_encode() routine uses much code obtained from the FreeBSD 3.0 + * MD5 crypt() function, which is licenced as follows: + * ---------------------------------------------------------------------------- + * "THE BEER-WARE LICENSE" (Revision 42): + * <phk@login.dknet.dk> wrote this file. As long as you retain this notice you + * can do whatever you want with this stuff. If we meet some day, and you think + * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp + * ---------------------------------------------------------------------------- + +For the crypto\apr_md4.c component: + + * Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All + * rights reserved. + * + * License to copy and use this software is granted provided that it + * is identified as the "RSA Data Security, Inc. MD4 Message-Digest + * Algorithm" in all material mentioning or referencing this software + * or this function. + * + * License is also granted to make and use derivative works provided + * that such works are identified as "derived from the RSA Data + * Security, Inc. MD4 Message-Digest Algorithm" in all material + * mentioning or referencing the derived work. + * + * RSA Data Security, Inc. makes no representations concerning either + * the merchantability of this software or the suitability of this + * software for any particular purpose. It is provided "as is" + * without express or implied warranty of any kind. + * + * These notices must be retained in any copies of any part of this + * documentation and/or software. + +For the crypto\crypt_blowfish.c(.h) component: + + * Written by Solar Designer <solar at openwall.com> in 1998-2011. + * No copyright is claimed, and the software is hereby placed in the public + * domain. In case this attempt to disclaim copyright and place the software + * in the public domain is deemed null and void, then the software is + * Copyright (c) 1998-2011 Solar Designer and it is hereby released to the + * general public under the following terms: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + * There's ABSOLUTELY NO WARRANTY, express or implied. + + See crypto/crypt_blowfish.c for more information. + +For the include\apr_md4.h component: + + * This is derived from material copyright RSA Data Security, Inc. + * Their notice is reproduced below in its entirety. + * + * Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All + * rights reserved. + * + * License to copy and use this software is granted provided that it + * is identified as the "RSA Data Security, Inc. MD4 Message-Digest + * Algorithm" in all material mentioning or referencing this software + * or this function. + * + * License is also granted to make and use derivative works provided + * that such works are identified as "derived from the RSA Data + * Security, Inc. MD4 Message-Digest Algorithm" in all material + * mentioning or referencing the derived work. + * + * RSA Data Security, Inc. makes no representations concerning either + * the merchantability of this software or the suitability of this + * software for any particular purpose. It is provided "as is" + * without express or implied warranty of any kind. + * + * These notices must be retained in any copies of any part of this + * documentation and/or software. + +For the test\testmd4.c component: + + * This is derived from material copyright RSA Data Security, Inc. + * Their notice is reproduced below in its entirety. + * + * Copyright (C) 1990-2, RSA Data Security, Inc. Created 1990. All + * rights reserved. + * + * RSA Data Security, Inc. makes no representations concerning either + * the merchantability of this software or the suitability of this + * software for any particular purpose. It is provided "as is" + * without express or implied warranty of any kind. + * + * These notices must be retained in any copies of any part of this + * documentation and/or software. + diff --git a/Makefile.in b/Makefile.in index b885139d8bc..c3c203bcf42 100644 --- a/Makefile.in +++ b/Makefile.in @@ -1,101 +1,180 @@ + +srcdir=@srcdir@ +VPATH=@srcdir@ +top_srcdir=@apr_srcdir@ +top_blddir=@apr_builddir@ + # # APR (Apache Portable Runtime) library Makefile. # -SHELL=@SH@ +CPP = @CPP@ + +# get substituted into some targets +APR_MAJOR_VERSION=@APR_MAJOR_VERSION@ -# -# Macros for compilation commands -# -@SET_MAKE@ -MFLAGS_STATIC= -RM=@RM@ -CC=@CC@ -CFLAGS=@CFLAGS@ @OPTIM@ -LIBS=@LIBS@ -LDFLAGS=@LDFLAGS@ $(LIBS) -RANLIB=@RANLIB@ # # Macros for supporting directories # INCDIR=./include -INCDIR1=../include -INCLUDES=-I$(INCDIR) -I$(INCDIR1) +OSDIR=$(top_srcdir)/include/arch/@OSDIR@ +DEFOSDIR=$(INCDIR)/arch/@DEFAULT_OSDIR@ +INCLUDES=-I$(INCDIR) -I$(OSDIR) -I$(DEFOSDIR) -I$(top_srcdir)/include/arch/@DEFAULT_OSDIR@ -I$(top_srcdir)/include -I$(top_srcdir)/include/private -I$(top_blddir)/include/private # # Macros for target determination # -MODULES=@MODULES@ -SUBDIRS=@SUBDIRS@ -#shmem/@OSDIR@ +CLEAN_SUBDIRS= test +INSTALL_SUBDIRS=@INSTALL_SUBDIRS@ -LIBAPR = @LIBPREFIX@apr.a +TARGET_LIB = lib@APR_LIBNAME@.la +APR_PCFILE = apr-$(APR_MAJOR_VERSION).pc +APR_CONFIG = apr-$(APR_MAJOR_VERSION)-config +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ -# -# Rules for turning inputs into outputs -# -.c.o: - $(CC) $(CFLAGS) -c $(INCLUDES) $< +EXTRA_OBJECTS = @EXTRA_OBJECTS@ +APR_DSO_MODULES = @APR_DSO_MODULES@ +LINK_MODULE = $(LIBTOOL) $(LTFLAGS) --mode=link $(CC) $(LT_LDFLAGS) $(ALL_CFLAGS) $(ALL_LDFLAGS) $(APRUTIL_LDFLAGS) -release $(APR_MAJOR_VERSION) -module -rpath $(APR_DSO_LIBDIR) +APR_DSO_LIBDIR = @APR_DSO_LIBDIR@ +APRUTIL_EXPORT_LIBS = @APRUTIL_EXPORT_LIBS@ # # Rules for building specific targets, starting with 'all' for # building the entire package. # -all: Makefile $(LIBAPR) - -$(LIBAPR): $(MODULES) subdirs - @rm -rf objs - @mkdir objs - @rm -f $@ - for i in $(SUBDIRS); do cp $$i/*.o objs ; done; - $(AR) cr $@ objs/*.o - $(RANLIB) $@ - -clean: subdirs_clean - $(RM) -f *.o *.a *.so objs/*.o - -depend: subdirs_depend - -distclean: subdirs_distclean - -$(RM) -f include/apr.h include/apr_private.h include/apr_private.h.in - -$(RM) -f *.o *.a *.so - -$(RM) -f config.cache config.status config.log configure - -$(RM) -f Makefile - -$(RM) -rf objs - cd test; make distclean; cd .. - -subdirs: - @for i in $(SUBDIRS); do \ - echo "===> $(SDP)lib/apr/$$i"; \ - ( cd $$i && $(MAKE) $(MFLAGS_STATIC) SDP='$(SDP)' \ - CC='$(CC)' AUX_CFLAGS='$(AUX_CFLAGS)' RANLIB='$(RANLIB)' ) \ - || exit 1; \ - echo "<=== $(SDP)lib/apr/$$i"; \ - done; - -subdirs_depend: - @for i in $(SUBDIRS); do \ - echo "===> $(SDP)lib/apr/$$i"; \ - ( cd $$i && $(MAKE) $(MFLAGS_STATIC) SDP='$(SDP)' depend ) \ - || exit 1; \ - echo "<=== $(SDP)lib/apr/$$i"; \ - done; - -subdirs_clean: - @for i in $(SUBDIRS); do \ - echo "===> $(SDP)lib/apr/$$i"; \ - ( cd $$i && $(MAKE) $(MFLAGS_STATIC) SDP='$(SDP)' clean ) \ - || exit 1; \ - echo "<=== $(SDP)lib/apr/$$i"; \ - done; - -subdirs_distclean: - @for i in $(SUBDIRS); do \ - echo "===> $(SDP)lib/apr/$$i"; \ - ( cd $$i && $(MAKE) $(MFLAGS_STATIC) SDP='$(SDP)' distclean ) \ - || exit 1; \ - echo "<=== $(SDP)lib/apr/$$i"; \ - done; - -install: all - +TARGETS = $(TARGET_LIB) $(APR_DSO_MODULES) \ + include/private/apr_escape_test_char.h apr.exp apr-config.out build/apr_rules.out + +LT_VERSION = @LT_VERSION@ + +# bring in rules.mk for standard functionality +@INCLUDE_RULES@ +@INCLUDE_OUTPUTS@ + +CLEAN_TARGETS = apr-config.out apr.exp exports.c export_vars.c .make.dirs \ + build/apr_rules.out tools/gen_test_char@EXEEXT@ \ + tools/gen_test_char.o tools/gen_test_char.lo \ + include/private/apr_escape_test_char.h +DISTCLEAN_TARGETS = config.cache config.log config.status \ + include/apr.h include/arch/unix/apr_private.h \ + libtool $(APR_CONFIG) build/apr_rules.mk apr.pc \ + build/pkg/pkginfo +EXTRACLEAN_TARGETS = configure aclocal.m4 include/arch/unix/apr_private.h.in \ + build-outputs.mk build/ltcf-c.sh build/aclocal.m4 \ + build/ltconfig build/ltmain.sh \ + build/argz.m4 build/libtool.m4 build/ltoptions.m4 \ + build/ltsugar.m4 build/ltversion.m4 build/lt~obsolete.m4 + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +bindir=@bindir@ +libdir=@libdir@ +includedir=@includedir@ +installbuilddir=@installbuilddir@ + +LDADD_dbd_pgsql = @LDADD_dbd_pgsql@ +LDADD_dbd_oracle = @LDADD_dbd_oracle@ +LDADD_dbd_sqlite2 = @LDADD_dbd_sqlite2@ +LDADD_dbd_sqlite3 = @LDADD_dbd_sqlite3@ +LDADD_dbd_mysql = @LDADD_dbd_mysql@ +LDADD_dbd_odbc = @LDADD_dbd_odbc@ +LDADD_dbm_db = @LDADD_dbm_db@ +LDADD_dbm_gdbm = @LDADD_dbm_gdbm@ +LDADD_dbm_ndbm = @LDADD_dbm_ndbm@ +LDADD_crypto_openssl = @LDADD_crypto_openssl@ +LDADD_crypto_nss = @LDADD_crypto_nss@ +LDADD_crypto_commoncrypto = @LDADD_crypto_commoncrypto@ + +# Create apr-config script suitable for the install tree +apr-config.out: $(APR_CONFIG) + sed 's,^\(location=\).*$$,\1installed,' < $(APR_CONFIG) > $@ + +# Create apr_rules.mk suitable for the install tree +build/apr_rules.out: build/apr_rules.mk + sed -e 's,^\(apr_build.*=\).*$$,\1$(installbuilddir),' -e 's,^\(top_build.*=\).*$$,\1$(installbuilddir),' < build/apr_rules.mk > $@ + +install: install-modules $(TARGETS) + $(APR_MKDIR) $(DESTDIR)$(libdir) $(DESTDIR)$(bindir) $(DESTDIR)$(installbuilddir) \ + $(DESTDIR)$(libdir)/pkgconfig $(DESTDIR)$(includedir) + $(INSTALL_DATA) $(top_blddir)/include/apr.h $(DESTDIR)$(includedir) + $(INSTALL_DATA) $(top_srcdir)/include/apu.h $(DESTDIR)$(includedir) + for f in $(top_srcdir)/include/apr_*.h $(top_srcdir)/include/apu_*.h; do \ + $(INSTALL_DATA) $${f} $(DESTDIR)$(includedir); \ + done + for f in $(top_blddir)/include/apu_*.h; do \ + $(INSTALL_DATA) $${f} $(DESTDIR)$(includedir); \ + done + $(LIBTOOL) --mode=install $(INSTALL) -m 755 $(TARGET_LIB) $(DESTDIR)$(libdir) + $(INSTALL_DATA) apr.exp $(DESTDIR)$(libdir)/apr.exp + $(INSTALL_DATA) apr.pc $(DESTDIR)$(libdir)/pkgconfig/$(APR_PCFILE) + for f in libtool shlibtool; do \ + if test -f $${f}; then $(INSTALL) -m 755 $${f} $(DESTDIR)$(installbuilddir); fi; \ + done + $(INSTALL) -m 755 $(top_srcdir)/build/mkdir.sh $(DESTDIR)$(installbuilddir) + for f in make_exports.awk make_var_export.awk; do \ + $(INSTALL_DATA) $(top_srcdir)/build/$${f} $(DESTDIR)$(installbuilddir); \ + done + $(INSTALL_DATA) build/apr_rules.out $(DESTDIR)$(installbuilddir)/apr_rules.mk + $(INSTALL) -m 755 apr-config.out $(DESTDIR)$(bindir)/$(APR_CONFIG) + @if [ $(INSTALL_SUBDIRS) != "none" ]; then \ + for i in $(INSTALL_SUBDIRS); do \ + ( cd $$i ; $(MAKE) DESTDIR=$(DESTDIR) install ); \ + done \ + fi + +$(TARGET_LIB): $(OBJECTS) $(EXTRA_OBJECTS) + $(LINK) @lib_target@ $(EXTRA_OBJECTS) $(ALL_LIBS) $(APRUTIL_EXPORT_LIBS) + +encoding/apr_escape.lo: include/private/apr_escape_test_char.h + +install-modules: install-modules-@APR_HAVE_MODULES@ + +install-modules-no: + +install-modules-yes: $(APR_DSO_MODULES) + $(APR_MKDIR) $(DESTDIR)$(APR_DSO_LIBDIR) + @for m in $(APR_DSO_MODULES); do $(LIBTOOL) $(LT_LTFLAGS) $(LTFLAGS) --mode=install $(INSTALL) -m 755 $$m $(DESTDIR)$(APR_DSO_LIBDIR); done + +exports.c: $(HEADERS) + $(APR_MKEXPORT) $(HEADERS) > $@ + +export_vars.c: $(HEADERS) + $(APR_MKVAREXPORT) $(HEADERS) > $@ + +apr.exp: exports.c export_vars.c + @echo "#! lib@APR_LIBNAME@.so" > $@ + @echo "* This file was AUTOGENERATED at build time." >> $@ + @echo "* Please do not edit by hand." >> $@ + $(CPP) $(ALL_CPPFLAGS) $(ALL_INCLUDES) exports.c | grep "ap_hack_" | sed -e 's/^.*[)]\(.*\);$$/\1/' >> $@ + $(CPP) $(ALL_CPPFLAGS) $(ALL_INCLUDES) export_vars.c | sed -e 's/^\#[^!]*//' | sed -e '/^$$/d' >> $@ + +dox: + doxygen $(top_srcdir)/docs/doxygen.conf + +gcov: + @build/run-gcov.sh + +test: check +check: $(TARGET_LIB) + cd test && $(MAKE) all check + +etags: + etags `find . -name '*.[ch]'` + +OBJECTS_gen_test_char = tools/gen_test_char.lo $(LOCAL_LIBS) +tools/gen_test_char.lo: tools/gen_test_char.c + $(APR_MKDIR) tools + $(LT_COMPILE) + +tools/gen_test_char@EXEEXT@: $(OBJECTS_gen_test_char) + $(LINK_PROG) $(OBJECTS_gen_test_char) $(ALL_LIBS) + +include/private/apr_escape_test_char.h: tools/gen_test_char@EXEEXT@ + $(APR_MKDIR) include/private + tools/gen_test_char@EXEEXT@ > $@ + +LINK_PROG = $(LIBTOOL) $(LTFLAGS) --mode=link $(COMPILE) $(LT_LDFLAGS) \ + @LT_NO_INSTALL@ $(ALL_LDFLAGS) -o $@ + # DO NOT REMOVE +docs: $(INCDIR)/*.h diff --git a/Makefile.win b/Makefile.win new file mode 100644 index 00000000000..1db5bb2f822 --- /dev/null +++ b/Makefile.win @@ -0,0 +1,171 @@ +# Makefile.win for Win32 APR alone +# +# Targets are: +# +# buildall - compile everything +# checkall - run APR regression tests +# install - compile everything +# clean - mop up everything +# +# You can override the build mechanism, choose only one; +# +# USEMAK=1 - compile from exported make files +# USEDSW=1 - compile from .dsw / .dsp VC6 projects +# USESLN=1 - compile from converted .sln / .vcproj VC7+ files +# +# Define ARCH to your desired preference (your PATH must point +# to the correct compiler tools!) Choose only one; +# +# ARCH="Win32 Release" +# ARCH="Win32 Debug" +# ARCH="x64 Release" +# ARCH="x64 Debug" +# +# For example; +# +# nmake -f Makefile.win PREFIX=C:\APR buildall checkall install clean +# + +!IF EXIST("apr.sln") && ([devenv /help > NUL 2>&1] == 0) \ + && !defined(USEMAK) && !defined(USEDSW) +USESLN=1 +USEMAK=0 +USEDSW=0 +!ELSEIF EXIST("apr.mak") && !defined(USEDSW) +USESLN=0 +USEMAK=1 +USEDSW=0 +!ELSE +USESLN=0 +USEMAK=0 +USEDSW=1 +!ENDIF + +PREFIX=..\apr-dist + +!IF [$(COMSPEC) /c cl /nologo /? \ + | $(SystemRoot)\System32\find.exe "x64" >NUL ] == 0 +ARCH=x64 Release +!ELSE +ARCH=Win32 Release +!ENDIF + +!MESSAGE ARCH = $(ARCH) +!MESSAGE PREFIX = $(PREFIX) (install path) + + +# Utility and Translation things, nothing here for the user +# +!IF "$(ARCH)" == "Win32 Release" +SLNARCH=Release|Win32 +ARCHOSPATH=Release +LIBSOSPATH=LibR +!ELSEIF "$(ARCH)" == "Win32 Debug" +SLNARCH=Debug|Win32 +ARCHOSPATH=Debug +LIBSOSPATH=LibD +!ELSEIF "$(ARCH)" == "x64 Release" +SLNARCH=Release|x64 +ARCHOSPATH=x64\Release +LIBSOSPATH=x64\LibR +!ELSEIF "$(ARCH)" == "x64 Debug" +SLNARCH=Debug|x64 +ARCHOSPATH=x64\Debug +LIBSOSPATH=x64\LibD +!ENDIF + +!IFNDEF MAKEOPT +# Only default the behavior if MAKEOPT= is omitted +!IFDEF _NMAKE_VER +# Microsoft NMake options +MAKEOPT=-nologo +!ELSEIF "$(MAKE)" == "make" +# Borland make options? Not really supported (yet) +MAKEOPT=-s -N +!ENDIF +!ENDIF + + +all: buildall checkall + +!IF $(USEMAK) == 1 + +clean: + $(MAKE) $(MAKEOPT) -f Makefile.win ARCH="$(ARCH)" \ + CTARGET=CLEAN buildall + +buildall: + $(MAKE) $(MAKEOPT) -f apr.mak CFG="apr - $(ARCH)" RECURSE=0 $(CTARGET) + $(MAKE) $(MAKEOPT) -f libapr.mak CFG="libapr - $(ARCH)" RECURSE=0 $(CTARGET) + cd build + $(MAKE) $(MAKEOPT) -f aprapp.mak CFG="aprapp - $(ARCH)" RECURSE=0 $(CTARGET) + $(MAKE) $(MAKEOPT) -f libaprapp.mak CFG="libaprapp - $(ARCH)" RECURSE=0 $(CTARGET) + cd .. + +!ELSEIF $(USESLN) == 1 + +clean: + -devenv apr.sln /useenv /clean "$(SLNARCH)" /project libaprapp + -devenv apr.sln /useenv /clean "$(SLNARCH)" /project libapr + -devenv apr.sln /useenv /clean "$(SLNARCH)" /project aprapp + -devenv apr.sln /useenv /clean "$(SLNARCH)" /project apr + +buildall: + devenv apr.sln /useenv /build "$(SLNARCH)" /project apr + devenv apr.sln /useenv /build "$(SLNARCH)" /project aprapp + devenv apr.sln /useenv /build "$(SLNARCH)" /project libapr + devenv apr.sln /useenv /build "$(SLNARCH)" /project libaprapp + +!ELSE +# $(USEDSP) == 1 + +clean: + -msdev apr.dsw /USEENV /MAKE "libaprapp - $(ARCH)" /CLEAN + -msdev apr.dsw /USEENV /MAKE "libapr - $(ARCH)" /CLEAN + -msdev apr.dsw /USEENV /MAKE "aprapp - $(ARCH)" /CLEAN + -msdev apr.dsw /USEENV /MAKE "apr - $(ARCH)" /CLEAN + +buildall: + @msdev apr.dsw /USEENV /MAKE "apr - $(ARCH)" + @msdev apr.dsw /USEENV /MAKE "aprapp - $(ARCH)" + @msdev apr.dsw /USEENV /MAKE "libapr - $(ARCH)" + @msdev apr.dsw /USEENV /MAKE "libaprapp - $(ARCH)" + +!ENDIF + + +checkapr: + cd test + $(MAKE) $(MAKEOPT) -f Makefile.win MODEL=static \ + OUTDIR=$(LIBSOSPATH) check + $(MAKE) $(MAKEOPT) -f Makefile.win MODEL=dynamic \ + OUTDIR=$(ARCHOSPATH) check + cd .. + +checkall: checkapr + + +install: + echo Y >.y + echo A >.A + @if NOT EXIST "$(PREFIX)\." mkdir "$(PREFIX)" + @if NOT EXIST "$(PREFIX)\bin\." mkdir "$(PREFIX)\bin" + @if NOT EXIST "$(PREFIX)\include\." mkdir "$(PREFIX)\include" + @if NOT EXIST "$(PREFIX)\lib\." mkdir "$(PREFIX)\lib" + copy CHANGES "$(PREFIX)\CHANGES.txt" <.y + copy LICENSE "$(PREFIX)\LICENSE.txt" <.y + copy NOTICE "$(PREFIX)\NOTICE.txt" <.y + xcopy include\*.h "$(PREFIX)\include\" /d < .a + copy $(LIBSOSPATH)\apr-2.lib "$(PREFIX)\lib\" <.y + copy $(LIBSOSPATH)\apr-2.pdb "$(PREFIX)\lib\" <.y + copy $(LIBSOSPATH)\aprapp-2.lib "$(PREFIX)\lib\" <.y + copy $(LIBSOSPATH)\aprapp-2.pdb "$(PREFIX)\lib\" <.y + copy $(ARCHOSPATH)\libaprapp-2.lib "$(PREFIX)\lib\" <.y + copy $(ARCHOSPATH)\libaprapp-2.pdb "$(PREFIX)\lib\" <.y + copy $(ARCHOSPATH)\libapr-2.lib "$(PREFIX)\lib\" <.y + copy $(ARCHOSPATH)\libapr-2.exp "$(PREFIX)\lib\" <.y + copy $(ARCHOSPATH)\libapr-2.dll "$(PREFIX)\bin\" <.y + copy $(ARCHOSPATH)\libapr-2.pdb "$(PREFIX)\bin\" <.y + del .y + del .a + diff --git a/NOTICE b/NOTICE new file mode 100644 index 00000000000..e8117bf13a5 --- /dev/null +++ b/NOTICE @@ -0,0 +1,15 @@ +Apache Portable Runtime +Copyright (c) 2000-2018 The Apache Software Foundation. + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). + +Portions of this software were developed at the National Center +for Supercomputing Applications (NCSA) at the University of +Illinois at Urbana-Champaign. + +This software contains code derived from the RSA Data Security +Inc. MD5 Message-Digest Algorithm. + +This software contains code derived from UNIX V7, Copyright(C) +Caldera International Inc. diff --git a/NWGNUmakefile b/NWGNUmakefile new file mode 100644 index 00000000000..9b472007760 --- /dev/null +++ b/NWGNUmakefile @@ -0,0 +1,465 @@ +# +# Declare the sub-directories to be built here +# + +SUBDIRS = \ + build \ + xml \ + $(EOLIST) + +ifdef WITH_APR_DBD +SUBDIRS += \ + dbd \ + $(EOLIST) +endif + +ifdef WITH_APR_DBM +SUBDIRS += \ + dbm \ + $(EOLIST) +endif + +# +# Get the 'head' of the build environment. This includes default targets and +# paths to tools +# +ifndef APR_WORK +export APR_WORK = $(CURDIR) +endif +include $(APR_WORK)/build/NWGNUhead.inc + +# +# build this level's files + +# +# Make sure all needed macro's are defined +# + +# +# These directories will be at the beginning of the include list, followed by +# INCDIRS +# +XINCDIRS += \ + $(APR)/include \ + $(APR)/include/private \ + $(APR)/include/arch/netware \ + $(APR)/include/arch/unix \ + $(APR)/dbm/sdbm \ + $(APR)/random/unix \ + $(EOLIST) + +# +# These flags will come after CFLAGS +# +XCFLAGS += \ + $(EOLIST) + +# +# These defines will come after DEFINES +# +XDEFINES += \ + $(EOLIST) + +# +# These flags will be added to the link.opt file +# +XLFLAGS += \ + $(EOLIST) + +# +# These values will be appended to the correct variables based on the value of +# RELEASE +# +ifeq "$(RELEASE)" "debug" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +ifeq "$(RELEASE)" "noopt" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +ifeq "$(RELEASE)" "release" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +# +# These are used by the link target if an NLM is being generated +# This is used by the link 'name' directive to name the nlm. If left blank +# TARGET_nlm (see below) will be used. +# +NLM_NAME = aprlib + +# +# This is used by the link '-desc ' directive. +# If left blank, NLM_NAME will be used. +# +NLM_DESCRIPTION = Apache Portability Runtime Library $(VERSION_STR) $(VERSION_SKT) + +# +# This is used by the '-threadname' directive. If left blank, +# NLM_NAME Thread will be used. +# +NLM_THREAD_NAME = +# +# If this is specified, it will override VERSION value in +# $(APR_WORK)/build/NWGNUenvironment.inc +# +NLM_VERSION = + +# +# If this is specified, it will override the default of 64K +# +NLM_STACK_SIZE = + +# +# If this is specified it will be used by the link '-entry' directive +# +NLM_ENTRY_SYM = + +# +# If this is specified it will be used by the link '-exit' directive +# +NLM_EXIT_SYM = + +# +# If this is specified it will be used by the link '-check' directive +# +NLM_CHECK_SYM = + +# +# If this is specified it will be used by the link '-flags' directive +# +NLM_FLAGS = + +# +# If this is specified it will be linked in with the XDCData option in the def +# file instead of the default of $(APR)/misc/netware/apache.xdc. XDCData can +# be disabled by setting APACHE_UNIPROC in the environment +# +XDCDATA = + +# +# Declare all target files (you must add your files here) +# + +# +# If there is an NLM target, put it here +# +TARGET_nlm = \ + $(OBJDIR)/$(NLM_NAME).nlm \ + $(EOLIST) + +# +# If there is an LIB target, put it here +# +TARGET_lib = \ + $(OBJDIR)/aprlib.lib \ + $(EOLIST) + +# +# These are the OBJ files needed to create the NLM target above. +# Paths must all use the '/' character +# +FILES_nlm_objs = \ + $(OBJDIR)/libprews.o \ + $(EOLIST) + +# +# These are the LIB files needed to create the NLM target above. +# These will be added as a library command in the link.opt file. +# +FILES_nlm_libs = \ + $(PRELUDE) \ + $(APRLIB) \ + $(APRXMLLIB) \ + $(EOLIST) + +ifdef EXPATSDK +ifdef EXPAT_LINK_STATIC +FILES_nlm_libs += \ + $(EXPAT_LIB) \ + $(EOLIST) +endif +endif + +# +# These are the modules that the above NLM target depends on to load. +# These will be added as a module command in the link.opt file. +# +FILES_nlm_modules = \ + libc \ + $(EOLIST) + +# Include the Winsock libraries if Winsock is being used +ifndef USE_STDSOCKETS +FILES_nlm_modules += ws2_32 \ + $(EOLIST) +endif + +ifdef EXPATSDK +ifndef EXPAT_LINK_STATIC +FILES_nlm_modules += \ + $(EXPAT_NLM) \ + $(EOLIST) +endif +endif + +# +# If the nlm has a msg file, put it's path here +# +FILE_nlm_msg = + +# +# If the nlm has a hlp file put it's path here +# +FILE_nlm_hlp = + +# +# If this is specified, it will override $(NWOS)\copyright.txt. +# +FILE_nlm_copyright = + +# +# Any additional imports go here +# +FILES_nlm_Ximports = \ + @$(NOVI)/libc.imp \ + @$(NOVI)/netware.imp \ + $(EOLIST) + +# Include the Winsock imports if Winsock is being used +ifndef USE_STDSOCKETS +FILES_nlm_Ximports += \ + @$(NOVI)/ws2nlm.imp \ + $(EOLIST) +FILES_nlm_imports += \ + WSAStartupRTags \ + WSACleanupRTag \ + $(EOLIST) +endif + +ifdef EXPATSDK +ifndef EXPAT_LINK_STATIC +FILES_nlm_Ximports += \ + @$(EXPAT_IMP) \ + $(EOLIST) +endif +endif + +# +# Any symbols exported to here +# +FILES_nlm_exports = \ + @aprlib.imp \ + $(EOLIST) + +# +# These are the OBJ files needed to create the LIB target above. +# Paths must all use the '/' character +# +FILES_lib_objs = \ + $(OBJDIR)/apr_atomic.o \ + $(OBJDIR)/apr_base64.o \ + $(OBJDIR)/apr_brigade.o \ + $(OBJDIR)/apr_buckets.o \ + $(OBJDIR)/apr_buckets_alloc.o \ + $(OBJDIR)/apr_buckets_eos.o \ + $(OBJDIR)/apr_buckets_file.o \ + $(OBJDIR)/apr_buckets_flush.o \ + $(OBJDIR)/apr_buckets_heap.o \ + $(OBJDIR)/apr_buckets_mmap.o \ + $(OBJDIR)/apr_buckets_pipe.o \ + $(OBJDIR)/apr_buckets_pool.o \ + $(OBJDIR)/apr_buckets_refcount.o \ + $(OBJDIR)/apr_buckets_simple.o \ + $(OBJDIR)/apr_buckets_socket.o \ + $(OBJDIR)/apr_cpystrn.o \ + $(OBJDIR)/apr_date.o \ + $(OBJDIR)/apr_dbd.o \ + $(OBJDIR)/apr_dbm.o \ + $(OBJDIR)/apr_dbm_berkeleydb.o \ + $(OBJDIR)/apr_dbm_sdbm.o \ + $(OBJDIR)/apr_escape.o \ + $(OBJDIR)/apr_fnmatch.o \ + $(OBJDIR)/apr_getpass.o \ + $(OBJDIR)/apr_hash.o \ + $(OBJDIR)/apr_hooks.o \ + $(OBJDIR)/apr_md4.o \ + $(OBJDIR)/apr_md5.o \ + $(OBJDIR)/apr_memcache.o \ + $(OBJDIR)/apr_passwd.o \ + $(OBJDIR)/apr_pools.o \ + $(OBJDIR)/apr_queue.o \ + $(OBJDIR)/apr_random.o \ + $(OBJDIR)/apr_redis.o \ + $(OBJDIR)/apr_reslist.o \ + $(OBJDIR)/apr_rmm.o \ + $(OBJDIR)/apr_sha1.o \ + $(OBJDIR)/apr_siphash.o \ + $(OBJDIR)/apr_skiplist.o \ + $(OBJDIR)/apr_snprintf.o \ + $(OBJDIR)/apr_strings.o \ + $(OBJDIR)/apr_strmatch.o \ + $(OBJDIR)/apr_strnatcmp.o \ + $(OBJDIR)/apr_strtok.o \ + $(OBJDIR)/apr_tables.o \ + $(OBJDIR)/apr_thread_pool.o \ + $(OBJDIR)/apr_uri.o \ + $(OBJDIR)/apu_dso.o \ + $(OBJDIR)/buffer.o \ + $(OBJDIR)/charset.o \ + $(OBJDIR)/crypt_blowfish.o \ + $(OBJDIR)/common.o \ + $(OBJDIR)/copy.o \ + $(OBJDIR)/dir.o \ + $(OBJDIR)/dso.o \ + $(OBJDIR)/env.o \ + $(OBJDIR)/errorcodes.o \ + $(OBJDIR)/fileacc.o \ + $(OBJDIR)/filedup.o \ + $(OBJDIR)/filepath.o \ + $(OBJDIR)/filepath_util.o \ + $(OBJDIR)/filestat.o \ + $(OBJDIR)/filesys.o \ + $(OBJDIR)/flock.o \ + $(OBJDIR)/fullrw.o \ + $(OBJDIR)/getopt.o \ + $(OBJDIR)/getuuid.o \ + $(OBJDIR)/groupinfo.o \ + $(OBJDIR)/inet_ntop.o \ + $(OBJDIR)/inet_pton.o \ + $(OBJDIR)/mktemp.o \ + $(OBJDIR)/mmap.o \ + $(OBJDIR)/multicast.o \ + $(OBJDIR)/open.o \ + $(OBJDIR)/otherchild.o \ + $(OBJDIR)/pipe.o \ + $(OBJDIR)/pollcb.o \ + $(OBJDIR)/pollset.o \ + $(OBJDIR)/printf.o \ + $(OBJDIR)/proc.o \ + $(OBJDIR)/proc_mutex.o \ + $(OBJDIR)/procsup.o \ + $(OBJDIR)/rand.o \ + $(OBJDIR)/readwrite.o \ + $(OBJDIR)/sdbm.o \ + $(OBJDIR)/sdbm_hash.o \ + $(OBJDIR)/sdbm_lock.o \ + $(OBJDIR)/sdbm_pair.o \ + $(OBJDIR)/seek.o \ + $(OBJDIR)/select.o \ + $(OBJDIR)/sendrecv.o \ + $(OBJDIR)/sha2.o \ + $(OBJDIR)/sha2_glue.o \ + $(OBJDIR)/shm.o \ + $(OBJDIR)/signals.o \ + $(OBJDIR)/sockaddr.o \ + $(OBJDIR)/socket_util.o \ + $(OBJDIR)/sockets.o \ + $(OBJDIR)/sockopt.o \ + $(OBJDIR)/start.o \ + $(OBJDIR)/tempdir.o \ + $(OBJDIR)/thread.o \ + $(OBJDIR)/thread_cond.o \ + $(OBJDIR)/thread_mutex.o \ + $(OBJDIR)/thread_rwlock.o \ + $(OBJDIR)/threadpriv.o \ + $(OBJDIR)/time.o \ + $(OBJDIR)/timestr.o \ + $(OBJDIR)/userinfo.o \ + $(OBJDIR)/uuid.o \ + $(OBJDIR)/version.o \ + $(OBJDIR)/waitio.o \ + $(OBJDIR)/wakeup.o \ + $(OBJDIR)/xlate.o \ + $(EOLIST) + +# +# implement targets and dependancies (leave this section alone) +# + +libs :: $(OBJDIR) $(TARGET_lib) + +nlms :: libs $(TARGET_nlm) + +# +# Updated this target to create necessary directories and copy files to the +# correct place. (See $(APR_WORK)/build/NWGNUhead.inc for examples) +# + +install :: nlms $(INSTDIRS) FORCE + $(call COPY,$(APR)/$(TARGET_nlm),$(INSTALLBASE)/) +ifndef DEST + -$(call COPY,$(APR)/STATUS,$(INSTALLBASE)/STATUS.apr) + -$(call COPY,$(APR)/LICENSE,$(INSTALLBASE)/) + -$(call COPY,$(APR)/CHANGES,$(INSTALLBASE)/CHANGES.apr) + @-$(call COPYR,$(APR)/docs,$(INSTALLBASE)/docs/) +endif + +ifndef DEST +installdev :: $(INSTDEVDIRS) FORCE + $(call COPY,$(APR)/include/*.h,$(INSTALLBASE)/include/) + $(call COPY,$(APR)/*.imp,$(INSTALLBASE)/lib/) + $(call COPY,$(APR)/misc/netware/*.xdc,$(INSTALLBASE)/lib/) + $(call COPY,$(APR)/$(TARGET_lib),$(INSTALLBASE)/lib/) + $(call COPY,$(APR)/$(TARGET_nlm),$(INSTALLBASE)/bin/) + +$(INSTDEVDIRS) :: + $(call MKDIR,$@) +endif + +# +# Any specialized rules here +# + +vpath filepath.c file_io/win32 +vpath %.c atomic/netware:strings:tables:passwd:time/unix +vpath %.c file_io/netware:file_io/unix:locks/netware:misc/netware:misc/unix +vpath %.c threadproc/netware:poll/unix:shmem/unix:support/unix:random/unix +vpath %.c dso/netware:memory/unix:mmap/unix:user/netware:util-misc +vpath %.c buckets:crypto:dbd:dbm:dbm/sdbm:encoding:hooks:memcache:redis:misc:strmatch:uri:xlate + +# Use the win32 network_io if Winsock is being used +ifndef USE_STDSOCKETS +vpath %.c network_io/win32 +endif +vpath %.c network_io/unix + +# +# Include the 'tail' makefile that has targets that depend on variables defined +# in this makefile +# + +include $(APRBUILD)/NWGNUtail.inc + + diff --git a/README b/README new file mode 100644 index 00000000000..c97cd704601 --- /dev/null +++ b/README @@ -0,0 +1,235 @@ +Apache Portable Runtime Library (APR) +===================================== + + The Apache Portable Runtime Library provides a predictable and + consistent interface to underlying platform-specific + implementations, with an API to which software developers may code + and be assured of predictable if not identical behavior regardless + of the platform on which their software is built, relieving them of + the need to code special-case conditions to work around or take + advantage of platform-specific deficiencies or features. + + APR and its companion libraries are implemented entirely in C + and provide a common programming interface across a wide variety + of operating system platforms without sacrificing performance. + Currently supported platforms include: + + UNIX variants + Windows + Netware + Mac OS X + OS/2 + + To give a brief overview, the primary core + subsystems of APR 1.3 include the following: + + Atomic operations + Dynamic Shared Object loading + File I/O + Locks (mutexes, condition variables, etc) + Memory management (high performance allocators) + Memory-mapped files + Multicast Sockets + Network I/O + Shared memory + Thread and Process management + Various data structures (tables, hashes, priority queues, etc) + + APR 2.0 also provides a number of utility functions and library + compatibility interfaces. These were formerly part of APR-util, + a seperate utility library in version 1 releases. These include; + + Hashing and UUID services + Multiple SQL DBD client interfaces + Multiple flat-database DBM client interfaces + Typesafe function Hooks abstraction + MemCache interface + Date parsing rourtines + Resource Lists + Thread Pools + Queues + Relocatable Memory Management functions + String filename-style pattern matching + URI Parsing + Charset translation (iconv based) + XML parsing (expat based) + + For a more complete list, please refer to the following URLs: + + http://apr.apache.org/docs/apr/modules.html + + Users of APR 0.9 should be aware that migrating to the APR 1.x + programming interfaces may require some adjustments; APR 1.x is + neither source nor binary compatible with earlier APR 0.9 releases. + Users of APR 1.x can expect consistent interfaces and binary backwards + compatibility throughout the entire APR 1.x release cycle, as defined + in our versioning rules: + + http://apr.apache.org/versioning.html + + APR is already used extensively by the Apache HTTP Server + version 2 and the Subversion revision control system, to + name but a few. We list all known projects using APR at + http://apr.apache.org/projects.html -- so please let us know + if you find our libraries useful in your own projects! + + +Database Providers +================== +Interfaces for copy-left licensed MySQL and gdbm DBD drivers, and +Berkeley DB DBM all ship as part of the distribution. To avoid licensing +incompatibilities, these are not built by default. To enable support, +the corresponding use the --with-{provider} option, but be aware that +these licenses may introduce licensing implications for your compiled code. +Similarly, the bindings for propritary drivers such as Oracle must also be +explicitly enabled. + +Whenever distributing apr-util in combination with database client +drivers, always review the license requirements of all components. + + +Using a Subversion Checkout on Unix +=================================== + +If you are building APR from SVN, you need to perform a prerequisite +step. You must have autoconf, libtool and python installed for this +to work. The prerequisite is simply; + + ./buildconf + +If you are building APR from a distribution tarball, buildconf is +already run for you, and you do not need autoconf, libtool or python +installed or to run buildconf unless you have patched APR's buildconf +inputs (such as configure.in, build.conf, virtually any file within +the build/ tree, or you add or remove source files). + +Remember when updating from svn that you must rerun ./buildconf again +to effect any changes made to the build schema in your fresh update. + + +Configuring and Building APR on Unix +==================================== + +Simply; + + ./configure --prefix=/desired/path/of/apr + make + make test + make install + +Configure has additional options, ./configure --help will offer you +those choices. You may also add CC=compiler CFLAGS="compiler flags" +etc. prior to the ./configure statement (on the same line). Please +be warned, some flags must be passed as part of the CC command, +itself, in order for autoconf to make the right determinations. Eg.; + + CC="gcc -m64" ./configure --prefix=/desired/path/of/apr + +will inform APR that you are compiling to a 64 bit CPU, and autoconf +must consider that when setting up all of APR's internal and external +type declarations. + +For more verbose output from testall, you may wish to invoke testall +with the flag; + + cd test + ./testall -v + + +Building APR RPM files on Linux +=============================== + +Run the following to create SRPMs: + +rpmbuild -ts apr-<version>.tar.bz2 +rpmbuild -ts apr-util-<version>.tar.bz2 + +Run the following to create RPMs (or build from the SRPMs): + +rpmbuild -tb apr-<version>.tar.bz2 +rpmbuild -tb apr-util-<version>.tar.bz2 + +Resolve dependencies as appropriate. + + +Configuring and Building APR on Windows +======================================= + +Using Visual Studio, you can build and run the test validation of APR. +The Makefile.win make file has a bunch of documentation about it's +options, but a trivial build is simply; + + nmake -f Makefile.win + nmake -f Makefile.win PREFIX=c:\desired\path\of\apr install + +Note you must manually modify the include\apr.hw file before you +build to change default options, see the #define APR_HAS_... or the +#define APR_HAVE_... statements. Be careful, many of these aren't +appropriate to be modified. The most common change is + +#define APR_HAVE_IPV6 1 + +rather than 0 if this build of APR will be used strictly on machines +with the IPv6 adapter support installed. + +It's trivial to include the apr.dsp (for a static library) or the +libapr.dsp (for a dynamic library) in your own build project, or you +can load apr.dsw in Visual Studio 2002 (.NET) or later, which will +convert these for you into apr.sln and associated .vcproj files. + +When using APR as a dynamic library, nothing special is required, +simply link to libapr-2.lib. To use it as a static library, simply +define APR_DECLARE_STATIC before you include any apr header files +in your source, and link to apr-2.lib instead. + +On windows, selection of database drivers is via the environment values +DBD_LIST (for mysql, oracle, pgsql, sqlite2 and/or sqlite3) +and DBM_LIST (db and/or gdbm). DBD odbc and DBM sdbm are unconditionally +compiled and installed, do not include these in the list. + + +Generating Test Coverage information with gcc +============================================= + +If you want to generate test coverage data, use the following steps: + + ./buildconf + CFLAGS="-fprofile-arcs -ftest-coverage" ./configure + make + cd test + make + ./testall + cd .. + make gcov + + +Cryptographic Software Notice +============================= +This distribution includes cryptographic software. The country in +which you currently reside may have restrictions on the import, +possession, use, and/or re-export to another country, of +encryption software. BEFORE using any encryption software, please +check your country's laws, regulations and policies concerning the +import, possession, or use, and re-export of encryption software, to +see if this is permitted. See http://www.wassenaar.org/ for more +information. + +The U.S. Government Department of Commerce, Bureau of Industry and +Security (BIS), has classified this software as Export Commodity +Control Number (ECCN) 5D002.C.1, which includes information security +software using or performing cryptographic functions with asymmetric +algorithms. The form and manner of this Apache Software Foundation +distribution makes it eligible for export under the License Exception +ENC Technology Software Unrestricted (TSU) exception (see the BIS +Export Administration Regulations, Section 740.13) for both object +code and source code. + +The following provides more details on the included cryptographic +software: + + APR provides an abstract interface for symmetrical cryptographic + functions that make use of a general-purpose encryption library, + such as OpenSSL, NSS, or the operating system's platform-specific + facilities. This interface is known as the apr_crypto interface, + with implementation beneath the /crypto directory. + diff --git a/README.FREETDS b/README.FREETDS new file mode 100644 index 00000000000..15eeeaf39a9 --- /dev/null +++ b/README.FREETDS @@ -0,0 +1,11 @@ +The APR DBD Driver for FreeTDS has been removed from the build. +It is known to have problems, and we are not able to maintain it. + +The source code is still available. If you want it and are able +to manage maintenance for yourself, you can patch the build and +work through issues that affect you, but you're on your own. + +We expect that for most users, the ODBC driver will serve as +an alternative. + +Sorry. diff --git a/README.cmake b/README.cmake new file mode 100644 index 00000000000..380f97bce55 --- /dev/null +++ b/README.cmake @@ -0,0 +1,171 @@ +Experimental cmake-based build support for APR on Microsoft Windows + +Status +------ + +This build support is currently intended only for Microsoft Windows. + +This build support is experimental. Specifically, + +* It does not support all features of APR. +* Some components may not be built correctly and/or in a manner + compatible with the previous Windows build support. +* Build interfaces, such as the mechanisms which are used to enable + optional functionality or specify prerequisites, may change from + release to release as feedback is received from users and bugs and + limitations are resolved. + +Important: Refer to the "Known Bugs and Limitations" section for further + information. + + It is beyond the scope of this document to document or explain + how to utilize the various cmake features, such as different + build backends or provisions for finding support libraries. + + Please refer to the cmake documentation for additional information + that applies to building any project with cmake. + +Prerequisites +------------- + +The following tools must be in PATH: + +* cmake, version 2.8 or later + cmake version 3.1.3 or later is required to work with current OpenSSL + releases. (OpenSSL is an optional prerequisite of APR.) +* If using a command-line compiler: compiler and linker and related tools + (Refer to the cmake documentation for more information.) + +The following support libraries are mandatory: + +* Either expat or libxml2 + +Additional support libraries allow optional features of APR to be enabled: + +* OpenSSL +* many others potentially, though the build support isn't currently + implemented + +How to build +------------ + +1. cd to a clean directory for building (i.e., don't build in your + source tree) + +2. Some cmake backends may want your compile tools in PATH. (Hint: "Visual + Studio Command Prompt") + +3. set CMAKE_LIBRARY_PATH=d:\path\to\prereq1\lib;d:\path\to\prereq2\lib;... + +4. set CMAKE_INCLUDE_PATH=d:\path\to\prereq1\include;d:\path\to\prereq2\include;... + +5. cmake -G "some backend, like 'NMake Makefiles'" + -DCMAKE_INSTALL_PREFIX=d:/path/to/aprinst + -DAPR-specific-flags + d:/path/to/aprsource + + Alternately, use cmake-gui and update settings in the GUI. + + APR feature flags: + + Exactly one of APU_USE_EXPAT and APU_USE_LIBXML2 must be specified. + + APU_USE_EXPAT Use Expat as the underlying XML implementation + Default: ON + APU_USE_LIBXML2 Use libxml2 as the underlying XML + implementation + Default: OFF + APR_INSTALL_PRIVATE_H Install extra .h files which are required when + building httpd and Subversion but which aren't + intended for use by applications. + Default: OFF + APU_HAVE_CRYPTO Build crypt support (only the OpenSSL + implementation is currently supported) + Default: OFF + APU_HAVE_ODBC Build ODBC DBD driver + Default: ON + APR_HAVE_IPV6 Enable IPv6 support + Default: ON + APR_BUILD_TESTAPR Build APR test suite + Default: OFF + TEST_STATIC_LIBS Build the test suite to test the APR static + library instead of the APR dynamic library. + Default: OFF + In order to build the test suite against both + static and dynamic libraries, separate builds + will be required, one with TEST_STATIC_LIBS + set to ON. + MIN_WINDOWS_VER Minimum Windows version supported by this build + (This controls the setting of _WIN32_WINNT.) + "Vista" or "Windows7" or a numeric value like + "0x0601" + Default: "Vista" + For desktop/server equivalence or other values, + refer to + http://msdn.microsoft.com/en-us/library/windows/ + desktop/aa383745(v=vs.85).aspx + INSTALL_PDB Install .pdb files if generated. + Default: ON + + LIBXML2_ICONV_INCLUDE_DIR, LIBXML2_ICONV_LIBRARIES + + If using libxml2 for the XML implementation and the build of libxml2 + requires iconv, set these variables to allow iconv includes + and libraries to be found. + + CMAKE_C_FLAGS_RELEASE, _DEBUG, _RELWITHDEBINFO, _MINSIZEREL + + CMAKE_BUILD_TYPE + + For NMake Makefiles the choices are at least DEBUG, RELEASE, + RELWITHDEBINFO, and MINSIZEREL + Other backends make have other selections. + +6. build using chosen backend (e.g., "nmake install") + +Tested generators +----------------- + +1. NMake Makefiles + +This has been tested successfully with the following: + +* Visual Studio 2008 64-bit (requires KB948127 hot fix) +* Visual Studio 2012 64-bit + +2. Visual Studio 11 (Visual Studio 2012 project files) + +Known Bugs and Limitations +-------------------------- + +* If include/apr.h or other generated files have been created in the source + directory by another build system, they will be used unexpectedly and + cause the build to fail. +* Options should be provided for remaining features, along with finding any + necessary libraries + + APR_POOL_DEBUG + + DBM: + . APU_HAVE_GDBM + . APU_HAVE_NDBM + . APU_HAVE_DB + + DBD: + . APU_HAVE_PGSQL + . APU_HAVE_MYSQL + . APU_HAVE_SQLITE3 + . APU_HAVE_SQLITE2 + . APU_HAVE_ORACLE + + CRYPTO: + . APU_HAVE_NSS + + APU_HAVE_ICONV +* Static builds of APR modules are not supported. +* XML implementation (i.e., Expat or libxml2) could support static XML impl + with apr-2.lib. + +Generally: + +* Many APR features have not been tested with this build. +* Developers need to examine the existing Windows build in great detail and see + what is missing from the cmake-based build, whether a feature or some build + nuance. +* Any feedback you can provide on your experiences with this build will be + helpful. diff --git a/SConscript b/SConscript new file mode 100644 index 00000000000..b2c60a8a991 --- /dev/null +++ b/SConscript @@ -0,0 +1,33 @@ + +Import("env") + +files = env.core_lib_files() + +(major, minor, patch) = env.APRVersion() + +libapr = env.SharedLibrary('apr-%d' % (major), files) +tests = Split(""" + abts.c testutil.c + testtime.c teststr.c testvsn.c testipsub.c testshm.c + testmmap.c testud.c testtable.c testsleep.c testpools.c + testfmt.c testfile.c testdir.c testfileinfo.c testrand.c + testdso.c testoc.c testdup.c testsockets.c testproc.c + testpoll.c testlock.c testsockopt.c testpipe.c + testthread.c testhash.c testargs.c testnames.c testuser.c + testpath.c testenv.c testprocmutex.c testfnmatch.c + testatomic.c testflock.c testsock.c testglobalmutex.c + teststrnatcmp.c testfilecopy.c testtemp.c testlfs.c + testcond.c testuri.c testmemcache.c testdate.c + testxlate.c testdbd.c testrmm.c testmd4.c + teststrmatch.c testpass.c testcrypto.c testqueue.c + testbuckets.c testxml.c testdbm.c testuuid.c testmd5.c + testreslist.c dbd.c +""") + +tenv = env.Clone() +tenv.AppendUnique(LIBS = libapr) +testall = tenv.Program('testall', source = ["test/"+t for t in tests]) + +targets = [libapr, testall] + +Return("targets") diff --git a/SConstruct b/SConstruct new file mode 100644 index 00000000000..cdeb8b7ce39 --- /dev/null +++ b/SConstruct @@ -0,0 +1,49 @@ +#!/usr/bin/env scons +# + +from build import APREnv + +EnsureSConsVersion(1, 1, 0) + +vars = Variables('build.py') + +vars.Add('prefix', 'Installation Prefix', '/usr/local') +vars.Add('maintainer_mode', 'Turn on debugging and compile time warnings', 0) +vars.Add('profile', 'Turn on profiling for the build (GCC)', 0) +vars.Add('lfs', 'Large file support on 32-bit platforms', 1) +vars.Add('ipv6', 'IPv6 support', 1) +vars.Add(EnumVariable('pool_debug', 'Turn on pools debugging', 'no', + allowed_values=('yes', 'no', 'verbose', 'verbose-alloc', 'lifetime', 'owner', 'all'))) + +env = APREnv(args=ARGUMENTS, variables=vars) + + +Help(vars.GenerateHelpText(env)) + +env.APRHints() + +env = env.APRAutoconf() + +if env['maintainer_mode']: + if env.is_gcc(): + env.AppendUnique(CPPFLAGS = ['-g', '-Wall', '-Wmissing-prototypes', '-Wstrict-prototypes', '-Wmissing-declarations']) + +if env['profile']: + env.Filter(CPPFLAGS = '-g') + env.AppendUnique(CPPFLAGS = ['-pg']) + +if env['pool_debug'] != 'no': + flags = {'yes': 1, + 'verbose': 2, + 'lifetime': 4, + 'owner': 8, + 'verbose-alloc': 16, + 'all': 31} + env.AppendUnique(CPPFLAGS = "-DAPR_POOL_DEBUG=%d" % flags[env['pool_debug']]) + +Export("env") + +# TODO: Support debug/release builds +targets = SConscript("SConscript", variant_dir='builds/default', duplicate=0) + +env.Default(targets) diff --git a/STATUS b/STATUS new file mode 100644 index 00000000000..50a9e98c935 --- /dev/null +++ b/STATUS @@ -0,0 +1,558 @@ +APACHE PORTABLE RUNTIME (APR) LIBRARY STATUS: -*- coding: utf-8 -*- +Last modified at [$Date$] + +The current version of this file can be found at: + + * http://svn.apache.org/repos/asf/apr/apr/trunk/STATUS + + +NOTICE: + +Effective with version 2.0 , apr-util ceases to exist. For reference, +the final standalone apr-util can be found in subversion at: + + * http://svn.apache.org/repos/asf/apr/apr-util/branches -r784519 + + +Patches considered for backport are noted in their branches' STATUS: + + * http://svn.apache.org/repos/asf/apr/apr/branches/0.9.x/STATUS + * http://svn.apache.org/repos/asf/apr/apr/branches/1.3.x/STATUS + * http://svn.apache.org/repos/asf/apr/apr/branches/1.4.x/STATUS + * http://svn.apache.org/repos/asf/apr/apr/branches/1.5.x/STATUS + * http://svn.apache.org/repos/asf/apr/apr-util/branches/0.9.x/STATUS + * http://svn.apache.org/repos/asf/apr/apr-util/branches/1.3.x/STATUS + * http://svn.apache.org/repos/asf/apr/apr-util/branches/1.4.x/STATUS + * http://svn.apache.org/repos/asf/apr/apr-util/branches/1.5.x/STATUS + +Releases: + 2.0.0 : in development on trunk/ + 1.7.0 : in development on branches/1.7.x + 1.6.4 : in maintenance + 1.6.3 : released October 22, 2017 + 1.6.2 : released June 14, 2017 + 1.6.1 : not released + 1.6.0 : not released + 1.5.2 : released April 29, 2015 + 1.5.1 : released April 20, 2014 + 1.5.0 : released November 18, 2013 + 1.4.8 : released June 21, 2013 + 1.4.7 : not released + 1.4.6 : released Feb 14, 2012 + 1.4.5 : released May 22, 2011 + 1.4.4 : released May 9, 2011 + 1.4.3 : not released + 1.4.2 : released April 3, 2010 + 1.4.1 : not released + 1.4.0 : not released + 1.3.9 : released September 23, 2009 + 1.3.8 : released August 6, 2009 + 1.3.7 : released July 23, 2009 + 1.3.6 : released July 4, 2009 + 1.3.5 : released June 5, 2009 + 1.3.4 : not released + 1.3.3 : released August 14, 2008 + 1.3.2 : released June 23, 2008 + 1.3.1 : not released + 1.3.0 : released June 3, 2008 + 1.2.12 : released November 25, 2007 + 1.2.11 : released September 6, 2007 + 1.2.10 : not released + 1.2.9 : released June 7, 2007 + 1.2.8 : released December 4, 2006 + 1.2.7 : released April 14, 2006 + 1.2.6 : released March 25, 2006 + 1.2.5 : not released + 1.2.4 : not released + 1.2.3 : not released + 1.2.2 : released October 11, 2005 + 1.2.1 : released August 18, 2005 + 1.2.0 : not released + 1.1.2 : no such version + 1.1.1 : released March 17, 2005 + 1.1.0 : released January 25, 2005 + 1.0.1 : released November 19, 2004 + 1.0.0 : released September 1, 2004 + 0.9.18 : in maintenance + 0.9.17 : released November 25, 2007 + 0.9.16 : released September 6, 2007 + 0.9.15 : not released + 0.9.14 : released June 7, 2007 + 0.9.13 : released December 4, 2006 + 0.9.12 : released April 13, 2006 + 0.9.11 : released March 30, 2006 + 0.9.10 : tagged March 22, 2006, not released + 0.9.9 : tagged January 30, 2006, not released + 0.9.8 : tagged January 27, 2006, not released + 0.9.7 : released October 11, 2005 + 0.9.6 : released February 4, 2005 + 0.9.5 : released November 19, 2004 + 0.9.4 : released September 25, 2003 + 0.9.3 : released April 3, 2003 + 0.9.2 : released March 22, 2003 + 0.9.1 : released September 11, 2002 + 0.9.0 : released August 28, 2002 + +Bundled with httpd: + 2.0a9 : released December 12, 2000 + 2.0a8 : released November 20, 2000 + 2.0a7 : released October 8, 2000 + 2.0a6 : released August 18, 2000 + 2.0a5 : released August 4, 2000 + 2.0a4 : released June 7, 2000 + 2.0a3 : released April 28, 2000 + 2.0a2 : released March 31, 2000 + 2.0a1 : released March 10, 2000 + +Contributors looking for a mission: + + * Just do an egrep on "TODO" or "XXX" in the source. + + * Review the bug database at: http://issues.apache.org/bugzilla/ + + * Review the "PatchAvailable" bugs in the bug database: + + https://issues.apache.org/bugzilla/buglist.cgi?bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&product=APR&keywords=PatchAvailable + + After testing, you can append a comment saying "Reviewed and tested". + + * Open bugs in the bug database. + + +RELEASE SHOWSTOPPERS: + + * apr_file_rotating_* on most platforms + +CURRENT VOTES: + + +CURRENT test/testall -v EXCEPTIONS: + + Please add any platform anomilies to the following exception list. + + * 'testipsub' will tickle an Solaris 8 getaddrinfo() IPv6 bug, + causing the test to hang. Configure with --disable-ipv6 if + using an unpatched Solaris 8 installation. + + * The 'testdso' tests will not work if configured with + --disable-shared since the loadable modules cannot be built. + + * 'testdso' fails on older versions of OpenBSD due to dlsym(NULL, + ...) segfaulting. + + * Win32 Not Implemented tests + poll: pollcb not implemented + procmutex: lacks fork() support + sock : Sync behavior causes us to skip one test + sockets: tcp6_socket/udp6_socket skipped for no IPv6 adapter + sockopt: TCP isn't corkable + users: username: Groups from apr_uid_get not implemented + + * Win32 tests are known to fail when APR_HAVE_IPV6, but there is no + ipv6 adapter is loaded (even loopback is sufficient). There are + obnoxious getaddrinfo() missing results from looking up a fixed + IPv4-IPv6 mixed notation address, which reflect a Win32 bug. + ipsub: One test fails for IPv6 with no IPv6 adapter configured + sock : One test fails for IPv6 with no IPv6 adapter configured + + +ONGOING REMINDERS FOR STYLE/SUBSTANCE OF CONTRIBUTING TO APR: + + * Flush out the test suite and make sure it passes on all platforms. + We currently have about 450 functions in APR and 147 tests. That + means we have a large number of functions that we can't verify are + actually portable. This TODO includes finishing the migration to the + unified test suite, and adding more tests to make the suite + comprehensive. + + * Eliminate the TODO's and XXX's by using the doxygen @bug feature + to allow us to better track the open issues, and provide historical + bug lists that help porters understand what was wrong in the old + versions of APR that they would be upgrading from. + + * Continue to review, deprecate and eliminate from 2.0 all namespace + un-protected names throughout include/apr_foo.h headers. + + +RELEASE NON-SHOWSTOPPERS BUT WOULD BE REAL NICE TO WRAP THESE UP: + + * Implement TOS for linux and solaris and bsd network API's. + The patches below implement only one of these API's, see the + pointer to mod_ftp in this bugzilla incident for hints to offer + all the necessary implementations, for starters. + http://qaix.com/apache-http-server/569-729-patch-add-ip-tos-support-read.shtml + https://issues.apache.org/bugzilla/show_bug.cgi?id=42848 + + * Need a proper fragmentation control API for clearing apr_pool's, + where the block alloc/clear/realloc sequence introduces more and + more unusable spaces in the physical blocks. APR must provide + a mechanism to recognize such fragmented conditions, free the + physical pages, and allocate a new single pool block. See also + http://svn.haxx.se/dev/archive-2008-10/0070.shtml + + * Implement apr_pool_realloc for consumers such as apr_vformatter, + where the possibility to extend an allocation exists. Given that + an apr function does this, external consumers should be allowed to. + + * Need some architecture/OS specific versions of the atomic operations. + progress: generic, solaris Sparc, FreeBSD5, linux, and OS/390 done + need: AIX, AS400, HPUX + + * The new lock API is a full replacement for the old API, but is + not yet complete on all platforms. Components that are incomplete + or missing include: + Netware: apr_proc_mutex_*() (Is proc_mutex unnecessary on Netware?) + * proc_mutex is not necessary on NetWare since the OS does + not support processes. The proc_mutex APIs actually + redirect to the thread_mutex APIs. (bnicholes) + OS/2: apr_thread_cond_*(), apr_proc_mutex_*() + + Less critical components that we may wish to add at some point: + Beos: apr_thread_rwlock_try*lock() + apr_proc_mutex_trylock() + Unix: apr_thread_rwlock_*() for platforms w/o rwlocks in pthread + + * Need to contemplate apr_strftime... platforms vary. OtherBill + suggested this solution (but has no time to implement): + Document our list of 'supported' escapes. + Run some autoconf/m4 magic against the complete list we support. + Move the strftime re-implementation from time/win32 to time/unix. + Add some APR_HAVE_STRFTIME magic to use the system fn, or fail + over to time/unix/strftime.c. + Message-ID: <025e01c1a891$bf41f660$94c0b0d0@v505> + + * Using reentrant libraries with non-threaded APR + - Anecdotal evidence exists that suggests it is bad to + mix reentrant and non-reentrant libraries and therefore + we should always use the reentrant versions. + - Unfortunately, on some platforms (AIX 4.2.1) defining + the reentrant flag (-D_THREAD_SAFE) causes builds to fail, + and so one would expect --disable-threads to fix this. + Although this has been fixed for that particular version + of AIX, it may be useful to only enable the reentrant + versions when threads are enabled. + How will we deal with this issue once APR becomes a standalone + library? It is perfectly legitimate to have apps needing + both versions (threaded/reentrant and non-threaded/non-reentrant) + on the same machine. + Wrowe chuckles, uhm, it already is. And seems most have shifted + to shipping threaded builds, of at least apr itself. + + * Pools debugging + - Find a way to do check if a pool is used in multiple + threads, while the creation flags say it isn't. IOW, + when the pool was created with APR_POOL_FNEWALLOCATOR, + but without APR_POOL_FLOCK. + Currently, no matter what the creation flags say, we always + create a lock. Without it integrity_check() and + apr_pool_num_bytes() blow up (because they traverse pools + child lists that possibly belong to another thread, in + combination with the pool having no lock). However, + this might actually hide problems like creating a child pool + of a pool belonging to another thread. + Maybe a debug function apr_pool_set_owner(apr_thread_t *) in + combination with extra checks in integrity_check() will point + out these problems. apr_pool_set_owner() would need to be called + everytime the owner(the thread the pool is being used in) of + the pool changes. + + - Implement apr_pool_join and apr_pool_lock. Those functions + are noops at the moment. + + - Add stats to the pools code. We already have basic stats + in debug mode. Stats that tell us about wasted memory + in the production code require more thought. + Status: Sander Striker is looking into this (low priority) + + David says this is a 1.1 issue. + + * Get OTHER_CHILD support into Win32 + Status: Bill S. is looking into this + + * SysV semaphore support isn't usable by Apache when started as + root because we don't have a way to allow the semaphore to be + used by the configured User and Group. Current work-around: + change the initial permissions to 0666. Needed code: See + 1.3's http_main.c, SysV sem flavor of accept_mutex_init(). + Status: Jim will look into this + Update: Apache deals with this itself, though it might be nice + if APR could do something. + + * Build scripts do not recognise AIX 4.2.1 pthreads + Justin says: "Is this still true?" + + * FirstBill says we need a new procattr, APR_CREATE_SUSPENDED (or + something similar) to direct ap_create_process to create the + process suspended. We also need a call to wake up the suspended + process. This may not be able to be implemented everywhere though. + Status: OtherBill asks, why? What is the benefit, how is it + portably implemented? Unless this creates some tangible that + mirrors another platform, then I'm -1. + + * Replace tables with a proper opaque ADT that has pluggable + implementations (including something like the existing data type, + plus hash tables for speed, with options for more later). + Status: fanf is working on this. + + * add a version number to apr_initialize() as an extra failsafe against + (APR) library version skew. + MsgID: <Pine.LNX.4.10.10005231712380.31927-100000@nebula.lyra.org> + Status: Greg -1, Jeff +1, Ryan +1, Tony -0(?), david +1 + + * add apr_crypt() and APR_HAS_CRYPT for apps to determine whether the + crypt() function is available, and a way to call it (whether it is + located in libc, libcrypt, or libufc) + Justin says: Should apr_crypt() be in apr-util? + Wrowe answers: of course! It's called openssl DES_fcrypt ;-) + + * use os_(un)cork in network_io/unix/sendrecv.c for FreeBSD's + sendfile implementation. + + david: The socket options stuff is now in and using it should + reduce the number of syscalls that are required for + os_cork and uncork, so the code should be reviewed to + make use of the new calls. If no-one beats me to it I'll + get around to it soonish... + + * toss the per-Makefile setup of INCLUDES; shift to rules.mk.in + rbb: This is a bad thing IMHO. If we do this, then we + can't use these makefiles for anything else. For example, + apr-util + + * add the rest of the pool accessor declare/impl macros. + Justin says: Both thread and file have the accessors now. Any others? + Status: Greg volunteers + + * I think apr_open_stderr() and friends *should* dup() the + descriptor. That would allow the new/returned file to be closed + (via pool cleanup or manually) without accidentally closing + stderr/out. + wrowe: votes -1, reasons directly manipulate this through APR + + * need to export (in code, not just build scripts) the shared + library extension (e.g. ".so") for the platform. clients need to + use this to construct filenames to pass to apr_dso_load() + -- note on Win32 we distinguish 'apache module' names from other + 'loadable module' names, so be careful with Apache's directive. + AIX, HPUX may use similar (.so for a 'module's name while the + defaults .a or .sl are used for libs.) + + * Possible gmtime_r replacement in explode_time + On Solaris (and possibly others), the gmtime_r libc function obtains + a mutex. We have seen 21/25 threads being blocked in this mutex on + a threaded httpd MPM when requesting static pages. It may be worth + it to hand optimize this since there is no real need for a mutex at + the system level (straight arithmetic from what I can tell). If you + have access to the Solaris source code: + osnet_volume/usr/src/lib/libc/port/gen/time_comm.c. + + * Add a way to query APR for what features it has at runtime (i.e. + threads). + Justin says: I'm not completely sold on this, but it has been mentioned + before and at least added to STATUS. + + * apr_xlate.h generates a bunch of compiler warnings. + Jeff asks: which platform? + Justin says: Solaris with Forte 6.1. + + * fcntl() oddness on Solaris. Under high loads, fcntl() decides to + return error code 46 (ENOLCK). + + httpd (prefork MPM) error log says (predictably): + + (46)No record locks available: couldn't grab the accept mutex + + All of the children report this and subsequently exits. httpd is now + hosed. AFAICT, this does not look to be an out-of-fds error. + + Solaris's man page says: + ENOLCK + The cmd argument is F_SETLK, F_SETLK64, F_SETLKW, or + F_SETLKW64 and satisfying the lock or unlock request + would result in the number of locked regions in the + system exceeding a system-imposed limit. + + Justin says: What is this system-imposed limit and how do we change it? + This gives me more rationale for switching the default + interprocess lock mechanism to pthread (if available). + + Explanation (from Kristofer Spinka <kspinka@style.net>): + ============ + The system imposed default limit of outstanding lock requests is + 512. + You can verify this by, in a contemporary version of Solaris: + + # mdb -k + > tune_t_flckrec/D + tune_t_flckrec: + tune_t_flckrec: 512 + + This can be increased by adding the following to /etc/system: + + set tune_t_flckrec=1024 + + and rebooting. + + Of course "1024" can be any reasonable limit, although we do not know + what "reasonable" should be, so be conservative, only increase this as + necessary. + + * There are some optimizations that can be done to the new + apr_proc_*() functions (on UNIX). One that may reduce pointer + indirection would be to make the apr_proc_mutex_unix_lock_methods_t + first-class members of the apr_proc_mutex_t structure. + + * Condition variables are tricky enough to use, and even trickier + to implement properly. We could really use a better test case + for those subtle quirks that sometimes creep into CV implementations. + + * Once we are fully satisfied with the new lock API, we can + begin to migrate the old API to be implemented on top of the + new one, or just decide to get rid of it altogether. + + * FreeBSD returns 45 (EOPNOTSUPP) when the lockfile is on a NFS + partition when you call fcntl(F_SETLKW). It may be good if we + can somehow detect this and error out when creating the lock + rather than waiting for the error to occur when acquiring lock. + + * Fix autoconf tests for strerror_r on BeOS and remove the hack in + misc/unix/errorcodes.c to get error reporting working. Committed as + the solution is elusive at present. + + * implement APR_PROGRAM_ENV and APR_PROGRAM_PATH on BeOS, OS/2, Netware + + * stat() on a few platforms (notably Solaris and AIX) succeeds for + a non-directory even if a trailing '/' was specified in the + name. APR should perhaps simulate the normal -1/ENOTDIR + behavior in APR routines which retrieve information about the + file. Note: Win2K fails GetFileAttributesEx in this scenario. + See OtherBill's comments in this message to dev@httpd.apache.org: + Message-Id: <5.1.0.14.2.20020315080852.00bce168@localhost> + + * Identify and implement those protection bits that have general + usefulness, perhaps hidden, generic read-only [immutable], + effective current user permissions, etc. + + * dso getsym implementation are becoming very strict about returning + a fn pointer v.s. a data pointer, this should be split in apr_dso. + +Interface Changes Postponed for APR 2.0: + + * apr_proc_other_child_register()'s write_fd argument should be removed + or made used. The comment in the API previously said: + + write_fd duplicates the proc->out stream, it's really + redundant and should be replaced in the APR 1.0 API with a + bitflag of which proc->in/out/err handles should be health + checked. no platform currently tests the pipes health. + + * apr_atomic_casptr() has the volatile qualifier in the wrong + place: should take "pointer to volatile pointer to void", not + "pointer to pointer to volatile void". + + * apr_socket_sendfile(): the offset parameter should not be + pass-by-reference, or it should be updated to do something + useful. + + * apr_password_get(): the bufsize parameter should not be + pass-by-reference. + + * apr_allocator.h: apr_memnode_t's use of uint32_t's doesn't match + well with allocation sizes being apr_size_t, possibly this can + be improved by using apr_size_t throughout. + + * apr_hash_count() should take a const apr_hash_t * argument. + + * apr_ino_t should be an ino64_t in LFS builds. + + * possible type renames: + + apr_file_info_t from apr_finfo_t + apr_file_attrs_t from apr_fileattrs_t + apr_file_seek_where_t from apr_seek_where_t + apr_lock_mech_e from apr_lockmech_e + apr_time_interval_t from apr_interval_time_t + apr_time_interval_short_t from apr_short_interval_time_t + + * wrowe writes: + Looking at bug 32520, it occurs to me that exploding times using the + apr_time_exp_* functions; it would make more sense to split ->tm_usec into + + ->tm_msec thousandths (milleseconds) + ->tm_usec millionths (microseconds) + + for most display purposes. It's trivial to roll them together with the + format string %03d%03d if that's what's desired, or display simply + %02d.%03d if millisecond resolution is desired. It would also shrink + the fields to int's so unpacking would be slightly slower, using them + would be slightly faster, for what's likely to be little impact on + performance. + + * The other-child API doesn't allow the apr_exit_why_e to be passed to the + application's maintenance function. The expected usage is that the + application calls apr_proc_wait[_all_procs]() and is given back + apr_exit_why_e and exit_code_or_signal_num, thus losing the original + (on Unix, at least) representation which held both pieces of information + in an int. Both pieces of data should be available to the maintenance + function so that it has the opportunity to take different actions. An + example would be to issue messages about probable misconfiguration when + receiving a certain exit code and trying to restart otherwise. Thus, + apr_proc_other_child_alert() should take an additional apr_exit_why_e + parameter, as should the application-provided maintenance function. The + exit-why value would be ignored in the same circumstances as the existing + status parameter: reason != APR_OC_REASON_DEATH. + + * apr_file_gets() should take an apr_size_t size parameter? + + * apr_table_vdo should not continue iterating through the keys + list once the callback function returns non-zero; see JCW's + comment in apr_tables.c. + + * The library SONAME should vary for the different library ABIs - + i.e. LFS support, IPv6 support or not. + + * remove APR_POLL_LASTDESC from apr_datatype_e. + + * Almost every API in APR depends on pools, but pool semantics + aren't a good match for a lot of applications. We need to find + a way to support alternate allocators polymorphically without + a significant performance penalty. + + * apr_global_mutex_child_init and apr_proc_mutex_child_init aren't + portable. There are a variety of problems with the locking API when it + is used with apr_create_proc instead of apr_fork. First, _child_init + doesn't take a lockmech_e parameter so it causes a segfault after the + apr_proc_create, because the proc_mutex field hasn't been initialized. + When the lockmech_e parameter is added, it _still_ doesn't work, because + some lock mechanisms expect to inherit from the parent process. For + example, sys V semaphores don't have a file to open, so the child process + can't reaquire the lock. + + jerenkrantz says: This is not a showstopper and I believe the above + analysis is slightly confusing. The real problem here is that + apr_*_mutex_child_init assumes a shared memory space - that is, the + children processes have access to the parent apr_*_mutex_t pointer. The + children just call child_init on the original, inherited apr_*_mutex_t. + Unlike globalmutexchild in test, apr_*_mutex_create is *not* intended to + be called from the child and subsequently call child_init. Instead, + apr_create_proc is intended to exec separate processes with disjoint + memory addresses. Currently, APR does not provide a cross-platform + mechanism for joining an already existing lock. A simple + 'apr_*_mutex_join' which is intended to be called from separate + processes to an already-existing lock would solve this problem. + child_init is not intended to be used this way. Even with SysV + semaphores, using IPC_PRIVATE should still work due to the parent-child + relationship. A strawman has been posted to dev@apr: + Message-Id: <213031CF0406DE1AC426A411@[10.0.1.137]> + + * The return type of a thread function (void *) is inconsistent with + the type used in apr_thread_exit()/apr_thread_join() (apr_status_t). + The thread function's return type should be changed to apr_status_t + so that a return from the thread main function has the same effect + as apr_thread_exit(). + See Message-Id: <E16JjZA-0007hg-00@zakath.apana.org.au> for thread + discussing this. + +1: BrianH, Aaron, david, jerenkrantz + Status: Deferred to 2.0.0 (API change) + + diff --git a/acconfig.h b/acconfig.h deleted file mode 100644 index 5ad3008c6a7..00000000000 --- a/acconfig.h +++ /dev/null @@ -1,71 +0,0 @@ -#ifndef APR_PRIVATE_H -#define APR_PRIVATE_H - -/* So that we can use inline on some critical functions, and use - * GNUC attributes (such as to get -Wall warnings for printf-like - * functions). Only do this in gcc 2.7 or later ... it may work - * on earlier stuff, but why chance it. - * - * We've since discovered that the gcc shipped with NeXT systems - * as "cc" is completely broken. It claims to be __GNUC__ and so - * on, but it doesn't implement half of the things that __GNUC__ - * means. In particular it's missing inline and the __attribute__ - * stuff. So we hack around it. PR#1613. -djg - */ -#if !defined(__GNUC__) || __GNUC__ < 2 || \ - (__GNUC__ == 2 && __GNUC_MINOR__ < 7) ||\ - defined(NEXT) -#define ap_inline -#define __attribute__(__x) -#define ENUM_BITFIELD(e,n,w) signed int n : w -#else -#define ap_inline __inline__ -#define USE_GNU_INLINE -#define ENUM_BITFIELD(e,n,w) e n : w -#endif - -@TOP@ - -/* Various #defines we need to know about */ -#undef HAVE_LOCK_EX -#undef HAVE_F_SETLK -#undef HAVE_PTHREAD_PROCESS_SHARED -#undef DEV_RANDOM -#undef HAVE_TRUERAND - -/* Cross process serialization techniques */ -#undef USE_FLOCK_SERIALIZE -#undef USE_SYSVSEM_SERIALIZE -#undef USE_FCNTL_SERIALIZE -#undef USE_PROC_PTHREAD_SERIALIZE -#undef USE_PTHREAD_SERIALIZE - -#undef READDIR_IS_THREAD_SAFE - -#undef NEED_RLIM_T -#undef USEBCOPY - -#undef HAVE_GMTOFF -#undef USE_THREADS - -#undef SIZEOF_SSIZE_T -#undef SIZEOF_OFF_T - -@BOTTOM@ - -/* Make sure we have ssize_t defined to be somethine */ -#undef ssize_t - -#if !defined(HAVE_PTHREAD_SIGMASK) && defined(_AIX) -#define pthread_sigmask sigprocmask -#endif - -#if !defined(HAVE_STRCASECMP) && defined(HAVE_STRICMP) -#define strcasecmp(s1,s2) stricmp(s1,s2) -#endif - -#if !defined(HAVE_SOCKLEN_T) -typedef int socklen_t; -#endif - -#endif /* APR_PRIVATE_H */ diff --git a/aclocal.m4 b/aclocal.m4 deleted file mode 100644 index ce2128a4a88..00000000000 --- a/aclocal.m4 +++ /dev/null @@ -1,199 +0,0 @@ -dnl ## -dnl ## -dnl ## -define(AC_USE_FUNCTION,[dnl -AC_CHECK_FUNCS($1) -if test ".$ac_func_$1" = .yes; then -AC_DEFINE(USE_$2) -fi -])dnl -dnl ## -dnl ## -dnl ## -define(AC_CHECK_DEFINE,[dnl -AC_CACHE_CHECK(for $1 in $2, ac_cv_define_$1, -AC_EGREP_CPP([YES_IS_DEFINED], [ -#include <$2> -#ifdef $1 -YES_IS_DEFINED -#endif -], ac_cv_define_$1=yes; AC_DEFINE(HAVE_$1), ac_cv_define_$1=no) -)])dnl -dnl ## -dnl ## -dnl ## -define(AC_IFALLYES,[dnl -ac_rc=yes -for ac_spec in $1; do - ac_type=`echo "$ac_spec" | sed -e 's/:.*$//'` - ac_item=`echo "$ac_spec" | sed -e 's/^.*://'` - case $ac_type in - header ) - ac_item=`echo "$ac_item" | sed 'y%./+-%__p_%'` - ac_var="ac_cv_header_$ac_item" - ;; - file ) - ac_item=`echo "$ac_item" | sed 'y%./+-%__p_%'` - ac_var="ac_cv_file_$ac_item" - ;; - func ) ac_var="ac_cv_func_$ac_item" ;; - define ) ac_var="ac_cv_define_$ac_item" ;; - custom ) ac_var="$ac_item" ;; - esac - eval "ac_val=\$$ac_var" - if test ".$ac_val" != .yes; then - ac_rc=no - break - fi -done -if test ".$ac_rc" = .yes; then - : - $2 -else - : - $3 -fi -])dnl -dnl ## -dnl ## -dnl ## -define(AC_BEGIN_DECISION,[dnl -ac_decision_item='$1' -ac_decision_msg='FAILED' -ac_decision='' -])dnl -define(AC_DECIDE,[dnl -ac_decision='$1' -ac_decision_msg='$2' -ac_decision_$1=yes -ac_decision_$1_msg='$2' -])dnl -define(AC_DECISION_OVERRIDE,[dnl - ac_decision='' - for ac_item in $1; do - eval "ac_decision_this=\$ac_decision_${ac_item}" - if test ".$ac_decision_this" = .yes; then - ac_decision=$ac_item - eval "ac_decision_msg=\$ac_decision_${ac_item}_msg" - fi - done -])dnl -define(AC_DECISION_FORCE,[dnl -ac_decision="$1" -eval "ac_decision_msg=\"\$ac_decision_${ac_decision}_msg\"" -])dnl -define(AC_END_DECISION,[dnl -if test ".$ac_decision" = .; then - echo "[$]0:Error: decision on $ac_decision_item failed" 1>&2 - exit 1 -else - if test ".$ac_decision_msg" = .; then - ac_decision_msg="$ac_decision" - fi - AC_DEFINE_UNQUOTED(${ac_decision_item}) - AC_MSG_RESULT([decision on $ac_decision_item... $ac_decision_msg]) -fi -])dnl - -dnl ### AC_TRY_RUN had some problems actually using a programs return code, -dnl ### so I am re-working it here to be used in APR's configure script. -dnl MY_TRY_RUN(PROGRAM, [ACTION-IF-TRUE [, ACTION-IF-FALSE -dnl [, ACTION-IF-CROSS-COMPILING]]]) -AC_DEFUN(MY_TRY_RUN, -[if test "$cross_compiling" = yes; then - ifelse([$4], , - [errprint(__file__:__line__: warning: [AC_TRY_RUN] called without default to allow cross compiling -)dnl - AC_MSG_ERROR(can not run test program while cross compiling)], - [$4]) -else - MY_TRY_RUN_NATIVE([$1], [$2], [$3]) -fi -]) - -dnl Like AC_TRY_RUN but assumes a native-environment (non-cross) compiler. -dnl MY_TRY_RUN_NATIVE(PROGRAM, [ACTION-IF-TRUE [, ACTION-IF-FALSE]]) -AC_DEFUN(MY_TRY_RUN_NATIVE, -[cat > conftest.$ac_ext <<EOF -[#]line __oline__ "configure" -#include "confdefs.h" -ifelse(AC_LANG, CPLUSPLUS, [#ifdef __cplusplus -extern "C" void exit(int); -#endif -])dnl -[$1] -EOF -if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null -then -dnl Don't remove the temporary files here, so they can be examined. - ifelse([$2], , :, [$2]) -else -ifelse([$3], , , [ $3 - rm -fr conftest* -])dnl -fi -rm -fr conftest*]) -dnl A variant of AC_CHECK_SIZEOF which allows the checking of -dnl sizes of non-builtin types -dnl AC_CHECK_SIZEOF_EXTENDED(INCLUDES, TYPE [, CROSS_SIZE]) -AC_DEFUN(AC_CHECK_SIZEOF_EXTENDED, -[changequote(<<,>>)dnl -dnl The name to #define -define(<<AC_TYPE_NAME>>, translit(sizeof_$2, [a-z *], [A-Z_P]))dnl -dnl The cache variable -define(<<AC_CV_NAME>>, translit(ac_cv_sizeof_$2, [ *],[<p>]))dnl -changequote([, ])dnl -AC_MSG_CHECKING(size of $2) -AC_CACHE_VAL(AC_CV_NAME, -[AC_TRY_RUN([#include <stdio.h> -$1 -main() -{ - FILE *f=fopen("conftestval","w"); - if (!f) exit(1); - fprintf(f, "%d\n", sizeof($2)); - exit(0); -}], AC_CV_NAME=`cat conftestval`, AC_CV_NAME=0, ifelse([$3],,, -AC_CV_NAME=$3))])dnl -AC_MSG_RESULT($AC_CV_NAME) -AC_DEFINE_UNQUOTED(AC_TYPE_NAME, $AC_CV_NAME) -undefine([AC_TYPE_NAME])dnl -undefine([AC_CV_NAME])dnl -]) - -dnl -dnl check for socklen_t, fall back to unsigned int -dnl - -AC_DEFUN(APR_CHECK_SOCKLEN_T,[ -AC_CACHE_CHECK(for socklen_t, ac_cv_socklen_t,[ -AC_TRY_COMPILE([ -#ifdef HAVE_SYS_TYPES_H -#include <sys/types.h> -#endif -#ifdef HAVE_SYS_SOCKET_H -#include <sys/socket.h> -#endif -],[ -socklen_t foo = (socklen_t) 0; -],[ - ac_cv_socklen_t=yes -],[ - ac_cv_socklen_t=no -]) -]) - -if test "$ac_cv_socklen_t" = "yes"; then - AC_DEFINE(HAVE_SOCKLEN_T, 1, [Whether you have socklen_t]) -fi -]) - -dnl Check for ranlib but, unlike the check provided with autoconf, set -dnl RANLIB to "true" if there is no ranlib instead of setting it to ":". -dnl OS/390 doesn't have ranlib and the make utility doesn't parse "RANLIB=:" -dnl the way we might want it to. - -AC_DEFUN(AC_PROG_RANLIB_NC, -[AC_CHECK_PROG(RANLIB, ranlib, ranlib, true)]) - -sinclude(threads.m4) diff --git a/apr-config.in b/apr-config.in new file mode 100644 index 00000000000..84b407356b6 --- /dev/null +++ b/apr-config.in @@ -0,0 +1,251 @@ +#!/bin/sh +# 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. +# + +# APR script designed to allow easy command line access to APR configuration +# parameters. + +APR_MAJOR_VERSION="@APR_MAJOR_VERSION@" +APR_DOTTED_VERSION="@APR_DOTTED_VERSION@" + +prefix="@prefix@" +exec_prefix="@exec_prefix@" +bindir="@bindir@" +libdir="@libdir@" +datarootdir="@datadir@" +datadir="@datadir@" +installbuilddir="@installbuilddir@" +includedir="@includedir@" + +CC="@CC@" +CPP="@CPP@" +SHELL="@SHELL@" +CPPFLAGS="@EXTRA_CPPFLAGS@" +CFLAGS="@EXTRA_CFLAGS@" +LDFLAGS="@EXTRA_LDFLAGS@" +LIBS="@EXTRA_LIBS@" +EXTRA_INCLUDES="@EXTRA_INCLUDES@" +SHLIBPATH_VAR="@shlibpath_var@" +APR_SOURCE_DIR="@apr_srcdir@" +APR_BUILD_DIR="@apr_builddir@" +APR_SO_EXT="@so_ext@" +APR_LIB_TARGET="@export_lib_target@" +APR_LIBNAME="@APR_LIBNAME@" + +# NOTE: the following line is modified during 'make install': alter with care! +location=@APR_CONFIG_LOCATION@ + +show_usage() +{ + cat << EOF +Usage: apr-$APR_MAJOR_VERSION-config [OPTION] + +Known values for OPTION are: + --prefix[=DIR] change prefix to DIR + --bindir print location where binaries are installed + --includedir print location where headers are installed + --cc print C compiler name + --cpp print C preprocessor name and any required options + --cflags print C compiler flags + --cppflags print C preprocessor flags + --includes print include information + --ldflags print linker flags + --libs print additional libraries to link against + --srcdir print APR source directory + --installbuilddir print APR build helper directory + --link-ld print link switch(es) for linking to APR + --link-libtool print the libtool inputs for linking to APR + --shlib-path-var print the name of the shared library path env var + --apr-la-file print the path to the .la file, if available + --apr-so-ext print the extensions of shared objects on this platform + --apr-lib-target print the libtool target information + --apr-libtool print the path to APR's libtool + --version print the APR's version as a dotted triple + --help print this help + +When linking with libtool, an application should do something like: + APR_LIBS="\`apr-$APR_MAJOR_VERSION-config --link-libtool --libs\`" +or when linking directly: + APR_LIBS="\`apr-$APR_MAJOR_VERSION-config --link-ld --libs\`" + +An application should use the results of --cflags, --cppflags, --includes, +and --ldflags in their build process. +EOF +} + +if test $# -eq 0; then + show_usage + exit 1 +fi + +if test "$location" = "installed"; then + LA_FILE="$libdir/lib${APR_LIBNAME}.la" +else + LA_FILE="$APR_BUILD_DIR/lib${APR_LIBNAME}.la" +fi + +flags="" + +while test $# -gt 0; do + # Normalize the prefix. + case "$1" in + -*=*) optarg=`echo "$1" | sed 's/[-_a-zA-Z0-9]*=//'` ;; + *) optarg= ;; + esac + + case "$1" in + # It is possible for the user to override our prefix. + --prefix=*) + prefix=$optarg + ;; + --prefix) + echo $prefix + exit 0 + ;; + --bindir) + echo $bindir + exit 0 + ;; + --includedir) + if test "$location" = "installed"; then + flags="$includedir" + elif test "$location" = "source"; then + flags="$APR_SOURCE_DIR/include" + else + # this is for VPATH builds + flags="$APR_BUILD_DIR/include $APR_SOURCE_DIR/include" + fi + echo $flags + exit 0 + ;; + --cc) + echo $CC + exit 0 + ;; + --cpp) + echo $CPP + exit 0 + ;; + --cflags) + flags="$flags $CFLAGS" + ;; + --cppflags) + flags="$flags $CPPFLAGS" + ;; + --libs) + flags="$flags $LIBS" + ;; + --ldflags) + flags="$flags $LDFLAGS" + ;; + --includes) + if test "$location" = "installed"; then + flags="$flags -I$includedir $EXTRA_INCLUDES" + elif test "$location" = "source"; then + flags="$flags -I$APR_SOURCE_DIR/include $EXTRA_INCLUDES" + else + # this is for VPATH builds + flags="$flags -I$APR_BUILD_DIR/include -I$APR_SOURCE_DIR/include $EXTRA_INCLUDES" + fi + ;; + --srcdir) + echo $APR_SOURCE_DIR + exit 0 + ;; + --installbuilddir) + if test "$location" = "installed"; then + echo "${installbuilddir}" + elif test "$location" = "source"; then + echo "$APR_SOURCE_DIR/build" + else + # this is for VPATH builds + echo "$APR_BUILD_DIR/build" + fi + exit 0 + ;; + --version) + echo $APR_DOTTED_VERSION + exit 0 + ;; + --link-ld) + if test "$location" = "installed"; then + ### avoid using -L if libdir is a "standard" location like /usr/lib + flags="$flags -L$libdir -l${APR_LIBNAME}" + else + ### this surely can't work since the library is in .libs? + flags="$flags -L$APR_BUILD_DIR -l${APR_LIBNAME}" + fi + ;; + --link-libtool) + # If the LA_FILE exists where we think it should be, use it. If we're + # installed and the LA_FILE does not exist, assume to use -L/-l + # (the LA_FILE may not have been installed). If we're building ourselves, + # we'll assume that at some point the .la file be created. + if test -f "$LA_FILE"; then + flags="$flags $LA_FILE" + elif test "$location" = "installed"; then + ### avoid using -L if libdir is a "standard" location like /usr/lib + # Since the user is specifying they are linking with libtool, we + # *know* that -R will be recognized by libtool. + flags="$flags -L$libdir -R$libdir -l${APR_LIBNAME}" + else + flags="$flags $LA_FILE" + fi + ;; + --shlib-path-var) + echo "$SHLIBPATH_VAR" + exit 0 + ;; + --apr-la-file) + if test -f "$LA_FILE"; then + flags="$flags $LA_FILE" + fi + ;; + --apr-so-ext) + echo "$APR_SO_EXT" + exit 0 + ;; + --apr-lib-target) + echo "$APR_LIB_TARGET" + exit 0 + ;; + --apr-libtool) + if test "$location" = "installed"; then + echo "${installbuilddir}/libtool" + else + echo "$APR_BUILD_DIR/libtool" + fi + exit 0 + ;; + --help) + show_usage + exit 0 + ;; + *) + show_usage + exit 1 + ;; + esac + + # Next please. + shift +done + +if test -n "$flags"; then + echo "$flags" +fi + +exit 0 diff --git a/apr.dsp b/apr.dsp index c30f9ecc16b..c5b3f480d3f 100644 --- a/apr.dsp +++ b/apr.dsp @@ -1,32 +1,36 @@ -# Microsoft Developer Studio Project File - Name="aprlib" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 5.00 +# Microsoft Developer Studio Project File - Name="apr" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 # ** DO NOT EDIT ** # TARGTYPE "Win32 (x86) Static Library" 0x0104 -CFG=aprlib - Win32 Debug +CFG=apr - Win32 Release !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run !MESSAGE -!MESSAGE NMAKE /f "aprlib.mak". +!MESSAGE NMAKE /f "apr.mak". !MESSAGE !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE -!MESSAGE NMAKE /f "aprlib.mak" CFG="aprlib - Win32 Debug" +!MESSAGE NMAKE /f "apr.mak" CFG="apr - Win32 Release" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE -!MESSAGE "aprlib - Win32 Release" (based on "Win32 (x86) Static Library") -!MESSAGE "aprlib - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "apr - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "apr - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "apr - x64 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "apr - x64 Debug" (based on "Win32 (x86) Static Library") !MESSAGE # Begin Project +# PROP AllowPerConfigDependencies 0 # PROP Scc_ProjName "" # PROP Scc_LocalPath "" CPP=cl.exe +RSC=rc.exe -!IF "$(CFG)" == "aprlib - Win32 Release" +!IF "$(CFG)" == "apr - Win32 Release" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 0 @@ -38,17 +42,18 @@ CPP=cl.exe # PROP Output_Dir "LibR" # PROP Intermediate_Dir "LibR" # PROP Target_Dir "" -# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c -# ADD CPP /nologo /MD /W3 /GX /O2 /I "./include" /I "./inc" /I "./misc/win32" /I "./file_io/win32" /I "./time/win32" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c -# SUBTRACT CPP /YX +# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c +# ADD CPP /nologo /MD /W3 /Zi /O2 /Oy- /I "./include" /I "./include/private" /I "./include/arch/win32" /I "./include/arch/unix" /I "../expat/lib" /D "NDEBUG" /D "APR_DECLARE_STATIC" /D "XML_STATIC" /D "WIN32" /D "WINNT" /D "_WINDOWS" /Fo"$(INTDIR)\" /Fd"$(OUTDIR)\apr-2" /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LIB32=link.exe -lib -# ADD BASE LIB32 /nologo /out:".\LibR\apr.lib" -# ADD LIB32 /nologo /out:".\LibR\apr.lib" +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"LibR\apr-2.lib" -!ELSEIF "$(CFG)" == "aprlib - Win32 Debug" +!ELSEIF "$(CFG)" == "apr - Win32 Debug" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 1 @@ -61,191 +66,919 @@ LIB32=link.exe -lib # PROP Intermediate_Dir "LibD" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" -# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c -# ADD CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /I "./include" /I "./inc" /I "./misc/win32" /I "./file_io/win32" /I "./time/win32" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /c -# SUBTRACT CPP /YX +# ADD BASE CPP /nologo /MDd /W3 /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /EHsc /c +# ADD CPP /nologo /MDd /W3 /Zi /Od /I "./include" /I "./include/private" /I "./include/arch/win32" /I "./include/arch/unix" /I "../expat/lib" /D "_DEBUG" /D "APR_DECLARE_STATIC" /D "XML_STATIC" /D "WIN32" /D "WINNT" /D "_WINDOWS" /Fo"$(INTDIR)\" /Fd"$(OUTDIR)\apr-2" /FD /EHsc /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LIB32=link.exe -lib -# ADD BASE LIB32 /nologo /out:".\LibD\apr.lib" -# ADD LIB32 /nologo /out:".\LibD\apr.lib" +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"LibD\apr-2.lib" + +!ELSEIF "$(CFG)" == "apr - x64 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "x64\LibR" +# PROP BASE Intermediate_Dir "x64\LibR" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "x64\LibR" +# PROP Intermediate_Dir "x64\LibR" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c +# ADD CPP /nologo /MD /W3 /Zi /O2 /Oy- /I "./include" /I "./include/private" /I "./include/arch/win32" /I "./include/arch/unix" /I "../expat/lib" /D "NDEBUG" /D "APR_DECLARE_STATIC" /D "XML_STATIC" /D "WIN32" /D "WINNT" /D "_WINDOWS" /Fo"$(INTDIR)\" /Fd"$(OUTDIR)\apr-2" /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"x64\LibR\apr-2.lib" + +!ELSEIF "$(CFG)" == "apr - x64 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "x64\LibD" +# PROP BASE Intermediate_Dir "x64\LibD" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "x64\LibD" +# PROP Intermediate_Dir "x64\LibD" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /EHsc /c +# ADD CPP /nologo /MDd /W3 /Zi /Od /I "./include" /I "./include/private" /I "./include/arch/win32" /I "./include/arch/unix" /I "../expat/lib" /D "_DEBUG" /D "APR_DECLARE_STATIC" /D "XML_STATIC" /D "WIN32" /D "WINNT" /D "_WINDOWS" /Fo"$(INTDIR)\" /Fd"$(OUTDIR)\apr-2" /FD /EHsc /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"x64\LibD\apr-2.lib" !ENDIF -# Begin Target +# Begin Target + +# Name "apr - Win32 Release" +# Name "apr - Win32 Debug" +# Name "apr - x64 Release" +# Name "apr - x64 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter ".c" +# Begin Group "atomic" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\atomic\win32\apr_atomic.c +# End Source File +# End Group +# Begin Group "buckets" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\buckets\apr_brigade.c +# End Source File +# Begin Source File + +SOURCE=.\buckets\apr_buckets.c +# End Source File +# Begin Source File + +SOURCE=.\buckets\apr_buckets_alloc.c +# End Source File +# Begin Source File + +SOURCE=.\buckets\apr_buckets_eos.c +# End Source File +# Begin Source File + +SOURCE=.\buckets\apr_buckets_file.c +# End Source File +# Begin Source File + +SOURCE=.\buckets\apr_buckets_flush.c +# End Source File +# Begin Source File + +SOURCE=.\buckets\apr_buckets_heap.c +# End Source File +# Begin Source File + +SOURCE=.\buckets\apr_buckets_mmap.c +# End Source File +# Begin Source File + +SOURCE=.\buckets\apr_buckets_pipe.c +# End Source File +# Begin Source File + +SOURCE=.\buckets\apr_buckets_pool.c +# End Source File +# Begin Source File + +SOURCE=.\buckets\apr_buckets_refcount.c +# End Source File +# Begin Source File + +SOURCE=.\buckets\apr_buckets_simple.c +# End Source File +# Begin Source File + +SOURCE=.\buckets\apr_buckets_socket.c +# End Source File +# End Group +# Begin Group "crypto" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\crypto\apr_crypto.c +# End Source File +# Begin Source File + +SOURCE=.\crypto\apr_md4.c +# End Source File +# Begin Source File + +SOURCE=.\crypto\apr_md5.c +# End Source File +# Begin Source File + +SOURCE=.\crypto\apr_passwd.c +# End Source File +# Begin Source File + +SOURCE=.\crypto\apr_sha1.c +# End Source File +# Begin Source File + +SOURCE=.\crypto\apr_siphash.c +# End Source File +# Begin Source File + +SOURCE=.\crypto\crypt_blowfish.c +# End Source File +# Begin Source File + +SOURCE=.\crypto\crypt_blowfish.h +# End Source File +# Begin Source File + +SOURCE=.\crypto\getuuid.c +# End Source File +# Begin Source File + +SOURCE=.\crypto\uuid.c +# End Source File +# End Group +# Begin Group "dbd" +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\dbd\apr_dbd.c +# End Source File +# Begin Source File + +SOURCE=.\dbd\apr_dbd_mysql.c +# End Source File +# Begin Source File + +SOURCE=.\dbd\apr_dbd_odbc.c +# End Source File +# Begin Source File + +SOURCE=.\dbd\apr_dbd_oracle.c +# End Source File +# Begin Source File + +SOURCE=.\dbd\apr_dbd_pgsql.c +# End Source File +# Begin Source File + +SOURCE=.\dbd\apr_dbd_sqlite2.c +# End Source File +# Begin Source File + +SOURCE=.\dbd\apr_dbd_sqlite3.c +# End Source File +# End Group +# Begin Group "dbm" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\dbm\apr_dbm.c +# End Source File +# Begin Source File + +SOURCE=.\dbm\apr_dbm_berkeleydb.c +# End Source File +# Begin Source File + +SOURCE=.\dbm\apr_dbm_gdbm.c +# End Source File +# Begin Source File + +SOURCE=.\dbm\apr_dbm_sdbm.c +# End Source File +# End Group +# Begin Group "dso" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\dso\win32\dso.c +# End Source File +# End Group +# Begin Group "encoding" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\encoding\apr_base64.c +# End Source File +# Begin Source File + +SOURCE=.\encoding\apr_escape.c +# End Source File +# End Group +# Begin Group "file_io" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\file_io\win32\buffer.c +# End Source File +# Begin Source File + +SOURCE=.\file_io\unix\copy.c +# End Source File +# Begin Source File + +SOURCE=.\file_io\win32\dir.c +# End Source File +# Begin Source File + +SOURCE=.\file_io\unix\fileacc.c +# End Source File +# Begin Source File + +SOURCE=.\file_io\win32\filedup.c +# End Source File +# Begin Source File + +SOURCE=.\file_io\win32\filepath.c +# End Source File +# Begin Source File + +SOURCE=.\file_io\unix\filepath_util.c +# End Source File +# Begin Source File + +SOURCE=.\file_io\win32\filestat.c +# End Source File +# Begin Source File + +SOURCE=.\file_io\win32\filesys.c +# End Source File +# Begin Source File + +SOURCE=.\file_io\win32\flock.c +# End Source File +# Begin Source File + +SOURCE=.\file_io\unix\fullrw.c +# End Source File +# Begin Source File + +SOURCE=.\file_io\unix\mktemp.c +# End Source File +# Begin Source File + +SOURCE=.\file_io\win32\open.c +# End Source File +# Begin Source File + +SOURCE=.\file_io\win32\pipe.c +# End Source File +# Begin Source File + +SOURCE=.\file_io\win32\readwrite.c +# End Source File +# Begin Source File + +SOURCE=.\file_io\win32\seek.c +# End Source File +# Begin Source File + +SOURCE=.\file_io\unix\tempdir.c +# End Source File +# End Group +# Begin Group "hooks" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\hooks\apr_hooks.c +# End Source File +# End Group +# Begin Group "locks" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\locks\win32\proc_mutex.c +# End Source File +# Begin Source File + +SOURCE=.\locks\win32\thread_cond.c +# End Source File +# Begin Source File + +SOURCE=.\locks\win32\thread_mutex.c +# End Source File +# Begin Source File + +SOURCE=.\locks\win32\thread_rwlock.c +# End Source File +# End Group +# Begin Group "memcache" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\memcache\apr_memcache.c +# End Source File +# End Group +# Begin Group "memory" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\memory\unix\apr_pools.c +# End Source File +# End Group +# Begin Group "misc" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\misc\win32\apr_app.c +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=.\misc\win32\charset.c +# End Source File +# Begin Source File + +SOURCE=.\misc\win32\env.c +# End Source File +# Begin Source File + +SOURCE=.\misc\unix\errorcodes.c +# End Source File +# Begin Source File + +SOURCE=.\misc\unix\getopt.c +# End Source File +# Begin Source File + +SOURCE=.\misc\win32\internal.c +# End Source File +# Begin Source File + +SOURCE=.\misc\win32\misc.c +# End Source File +# Begin Source File + +SOURCE=.\misc\unix\otherchild.c +# End Source File +# Begin Source File + +SOURCE=.\misc\win32\rand.c +# End Source File +# Begin Source File + +SOURCE=.\misc\win32\start.c +# End Source File +# Begin Source File + +SOURCE=.\misc\win32\utf8.c +# End Source File +# Begin Source File + +SOURCE=.\misc\unix\version.c +# End Source File +# End Group +# Begin Group "mmap" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\mmap\unix\common.c +# End Source File +# Begin Source File + +SOURCE=.\mmap\win32\mmap.c +# End Source File +# End Group +# Begin Group "network_io" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\network_io\unix\inet_ntop.c +# End Source File +# Begin Source File + +SOURCE=.\network_io\unix\inet_pton.c +# End Source File +# Begin Source File + +SOURCE=.\network_io\unix\multicast.c +# End Source File +# Begin Source File + +SOURCE=.\network_io\win32\sendrecv.c +# End Source File +# Begin Source File + +SOURCE=.\network_io\unix\sockaddr.c +# End Source File +# Begin Source File + +SOURCE=.\network_io\win32\sockets.c +# End Source File +# Begin Source File + +SOURCE=.\network_io\unix\socket_util.c +# End Source File +# Begin Source File + +SOURCE=.\network_io\win32\sockopt.c +# End Source File +# End Group +# Begin Group "passwd" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\passwd\apr_getpass.c +# End Source File +# End Group +# Begin Group "poll" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\poll\unix\pollcb.c +# End Source File +# Begin Source File + +SOURCE=.\poll\unix\pollset.c +# End Source File +# Begin Source File + +SOURCE=.\poll\unix\poll.c +# End Source File +# Begin Source File + +SOURCE=.\poll\unix\select.c +# End Source File +# Begin Source File + +SOURCE=.\poll\unix\wakeup.c +# End Source File +# End Group +# Begin Group "random" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\random\unix\apr_random.c +# End Source File +# Begin Source File -# Name "aprlib - Win32 Release" -# Name "aprlib - Win32 Debug" -# Begin Group "Source Files" +SOURCE=.\random\unix\sha2.c +# End Source File +# Begin Source File -# PROP Default_Filter ".c" +SOURCE=.\random\unix\sha2_glue.c +# End Source File +# End Group +# Begin Group "sdbm" + +# PROP Default_Filter "" # Begin Source File -SOURCE=.\time\win32\access.c +SOURCE=.\dbm\sdbm\sdbm.c # End Source File # Begin Source File -SOURCE=.\lib\apr_cpystrn.c +SOURCE=.\dbm\sdbm\sdbm_hash.c # End Source File # Begin Source File -SOURCE=.\lib\apr_execve.c +SOURCE=.\dbm\sdbm\sdbm_lock.c # End Source File # Begin Source File -SOURCE=.\lib\apr_fnmatch.c +SOURCE=.\dbm\sdbm\sdbm_pair.c # End Source File # Begin Source File -SOURCE=.\lib\apr_getpass.c +SOURCE=.\dbm\sdbm\sdbm_pair.h # End Source File # Begin Source File -SOURCE=.\lib\apr_md5.c +SOURCE=.\dbm\sdbm\sdbm_private.h # End Source File # Begin Source File -SOURCE=.\lib\apr_pools.c +SOURCE=.\dbm\sdbm\sdbm_tune.h # End Source File +# End Group +# Begin Group "shmem" + +# PROP Default_Filter "" # Begin Source File -SOURCE=.\lib\apr_snprintf.c +SOURCE=.\shmem\win32\shm.c # End Source File +# End Group +# Begin Group "strings" + +# PROP Default_Filter "" # Begin Source File -SOURCE=.\lib\apr_strnatcmp.c +SOURCE=.\strings\apr_cpystrn.c # End Source File # Begin Source File -SOURCE=.\lib\apr_tables.c +SOURCE=.\strings\apr_fnmatch.c # End Source File # Begin Source File -SOURCE=.\aprlib.def +SOURCE=.\strings\apr_snprintf.c # End Source File # Begin Source File -SOURCE=.\misc\win32\canonerr.c +SOURCE=.\strings\apr_strings.c # End Source File # Begin Source File -SOURCE=.\file_io\win32\dir.c +SOURCE=.\strings\apr_strnatcmp.c # End Source File # Begin Source File -SOURCE=.\dso\win32\dso.c +SOURCE=.\strings\apr_strtok.c # End Source File +# End Group +# Begin Group "strmatch" + +# PROP Default_Filter "" # Begin Source File -SOURCE=.\misc\win32\errorcodes.c +SOURCE=.\strmatch\apr_strmatch.c # End Source File +# End Group +# Begin Group "tables" + +# PROP Default_Filter "" # Begin Source File -SOURCE=.\file_io\win32\fileacc.c +SOURCE=.\tables\apr_hash.c # End Source File # Begin Source File -SOURCE=.\file_io\win32\filedup.c +SOURCE=.\tables\apr_tables.c # End Source File # Begin Source File -SOURCE=.\file_io\win32\filestat.c +SOURCE=.\tables\apr_skiplist.c # End Source File +# End Group +# Begin Group "threadproc" + +# PROP Default_Filter "" # Begin Source File -SOURCE=.\misc\win32\getopt.c +SOURCE=.\threadproc\win32\proc.c # End Source File # Begin Source File -SOURCE=.\locks\win32\locks.c +SOURCE=.\threadproc\win32\signals.c # End Source File # Begin Source File -SOURCE=.\misc\win32\names.c +SOURCE=.\threadproc\win32\thread.c # End Source File # Begin Source File -SOURCE=.\file_io\win32\open.c +SOURCE=.\threadproc\win32\threadpriv.c # End Source File +# End Group +# Begin Group "time" + +# PROP Default_Filter "" # Begin Source File -SOURCE=.\file_io\win32\pipe.c +SOURCE=.\time\win32\time.c # End Source File # Begin Source File -SOURCE=.\network_io\win32\poll.c +SOURCE=.\time\win32\timestr.c # End Source File +# End Group +# Begin Group "uri" + +# PROP Default_Filter "" # Begin Source File -SOURCE=.\threadproc\win32\proc.c +SOURCE=.\uri\apr_uri.c # End Source File +# End Group +# Begin Group "user" + +# PROP Default_Filter "" # Begin Source File -SOURCE=.\misc\win32\rand.c +SOURCE=.\user\win32\groupinfo.c # End Source File # Begin Source File -SOURCE=.\file_io\win32\readwrite.c +SOURCE=.\user\win32\userinfo.c # End Source File +# End Group +# Begin Group "util-misc" + +# PROP Default_Filter "" # Begin Source File -SOURCE=.\file_io\win32\seek.c +SOURCE=.\util-misc\apr_date.c # End Source File # Begin Source File -SOURCE=.\network_io\win32\sendrecv.c +SOURCE=.\util-misc\apu_dso.c # End Source File # Begin Source File -SOURCE=.\threadproc\win32\signals.c +SOURCE=.\util-misc\apr_queue.c # End Source File # Begin Source File -SOURCE=.\network_io\win32\sockaddr.c +SOURCE=.\util-misc\apr_reslist.c # End Source File # Begin Source File -SOURCE=.\network_io\win32\sockets.c +SOURCE=.\util-misc\apr_rmm.c # End Source File # Begin Source File -SOURCE=.\network_io\win32\sockopt.c +SOURCE=.\util-misc\apr_thread_pool.c # End Source File +# End Group +# Begin Group "xlate" + +# PROP Default_Filter "" # Begin Source File -SOURCE=.\misc\win32\start.c +SOURCE=.\xlate\xlate.c +# End Source File +# End Group +# Begin Group "xml" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\xml\apr_xml.c # End Source File # Begin Source File -SOURCE=.\threadproc\win32\thread.c +SOURCE=.\xml\apr_xml_expat.c +# End Source File +# End Group +# End Group +# Begin Group "Private Header Files" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\include\arch\win32\apr_arch_atime.h # End Source File # Begin Source File -SOURCE=.\threadproc\win32\threadpriv.c +SOURCE=.\include\arch\win32\apr_arch_dso.h # End Source File # Begin Source File -SOURCE=.\time\win32\time.c +SOURCE=.\include\arch\win32\apr_arch_file_io.h # End Source File # Begin Source File -SOURCE=.\time\win32\timestr.c +SOURCE=.\include\arch\win32\apr_arch_inherit.h +# End Source File +# Begin Source File + +SOURCE=.\include\arch\win32\apr_arch_misc.h +# End Source File +# Begin Source File + +SOURCE=.\include\arch\win32\apr_arch_networkio.h +# End Source File +# Begin Source File + +SOURCE=.\include\arch\win32\apr_arch_thread_mutex.h +# End Source File +# Begin Source File + +SOURCE=.\include\arch\win32\apr_arch_thread_rwlock.h +# End Source File +# Begin Source File + +SOURCE=.\include\arch\win32\apr_arch_threadproc.h +# End Source File +# Begin Source File + +SOURCE=.\include\arch\win32\apr_arch_utf8.h +# End Source File +# Begin Source File + +SOURCE=.\include\arch\win32\apr_private.h # End Source File # End Group -# Begin Group "Header Files" +# Begin Group "Public Header Files" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\include\apr.h.in +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=.\include\apr.hnw +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=.\include\apr.hw + +!IF "$(CFG)" == "apr - Win32 Release" + +# Begin Custom Build - Creating apr.h from apr.hw, apr_escape_test_char.h from gen_test_char.exe +InputPath=.\include\apr.hw + +".\include\apr.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + type .\include\apr.hw > .\include\apr.h + +# End Custom Build + +!ELSEIF "$(CFG)" == "apr - Win32 Debug" + +# Begin Custom Build - Creating apr.h from apr.hw, apr_escape_test_char.h from gen_test_char.exe +InputPath=.\include\apr.hw + +".\include\apr.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + type .\include\apr.hw > .\include\apr.h + +# End Custom Build + +!ELSEIF "$(CFG)" == "apr - Win32 Release9x" + +# Begin Custom Build - Creating apr.h from apr.hw, apr_escape_test_char.h from gen_test_char.exe +InputPath=.\include\apr.hw + +".\include\apr.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + type .\include\apr.hw > .\include\apr.h + +# End Custom Build + +!ELSEIF "$(CFG)" == "apr - x64 Debug" + +# Begin Custom Build - Creating apr.h from apr.hw, apr_escape_test_char.h from gen_test_char.exe +InputPath=.\include\apr.hw + +".\include\apr.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + type .\include\apr.hw > .\include\apr.h + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\include\apr_allocator.h +# End Source File +# Begin Source File -# PROP Default_Filter ".h" +SOURCE=.\include\apr_atomic.h +# End Source File # Begin Source File SOURCE=.\include\apr_dso.h # End Source File # Begin Source File +SOURCE=.\include\apr_env.h +# End Source File +# Begin Source File + SOURCE=.\include\apr_errno.h # End Source File # Begin Source File +SOURCE=.\include\apr_escape.h + +!IF "$(CFG)" == "libapr - Win32 Release" + +# Begin Custom Build - Creating gen_test_char.exe and apr_escape_test_char.h +InputPath=.\include\apr_escape.h + +".\include\apr_escape_test_char.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cl.exe /nologo /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FD /I ".\include" /Fo.\Release\gen_test_char /Fe.\Release\gen_test_char.exe .\tools\gen_test_char.c + .\Release\gen_test_char.exe > .\include\apr_escape_test_char.h + +# End Custom Build + +!ELSEIF "$(CFG)" == "libapr - Win32 Debug" + +# Begin Custom Build - Creating gen_test_char.exe and apr_escape_test_char.h +InputPath=.\include\apr_escape.h + +".\include\apr_escape_test_char.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cl.exe /nologo /W3 /EHsc /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FD /I ".\include" /Fo.\Debug\gen_test_char /Fe.\Debug\gen_test_char.exe .\tools\gen_test_char.c + .\Debug\gen_test_char.exe > .\include\apr_escape_test_char.h + +# End Custom Build + +!ELSEIF "$(CFG)" == "libapr - Win32 Release9x" + +# Begin Custom Build - Creating gen_test_char.exe and apr_escape_test_char.h +InputPath=.\include\apr_escape.h + +".\include\apr_escape_test_char.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cl.exe /nologo /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FD /I ".\include" /Fo.\9x\Release\gen_test_char /Fe.\9x\Release\gen_test_char.exe .\tools\gen_test_char.c + .\9x\Release\gen_test_char.exe > .\include\apr_escape_test_char.h + +# End Custom Build + +!ELSEIF "$(CFG)" == "libapr - Win32 Debug9x" + +# Begin Custom Build - Creating gen_test_char.exe and apr_escape_test_char.h +InputPath=.\include\apr_escape.h + +".\include\apr_escape_test_char.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cl.exe /nologo /W3 /EHsc /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FD /I ".\include" /Fo.\9x\Debug\gen_test_char /Fe.\9x\Debug\gen_test_char.exe .\tools\gen_test_char.c + .\9x\Debug\gen_test_char.exe > .\include\apr_escape_test_char.h + +# End Custom Build + +!ELSEIF "$(CFG)" == "libapr - x64 Release" + +# Begin Custom Build - Creating gen_test_char.exe and apr_escape_test_char.h +InputPath=.\include\apr_escape.h + +".\include\apr_escape_test_char.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cl.exe /nologo /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FD /I ".\include" /Fo.\x64\Release\gen_test_char /Fe.\x64\Release\gen_test_char.exe .\tools\gen_test_char.c + .\x64\Release\gen_test_char.exe > .\include\apr_escape_test_char.h + +# End Custom Build + +!ELSEIF "$(CFG)" == "libapr - x64 Debug" + +# Begin Custom Build - Creating gen_test_char.exe and apr_escape_test_char.h +InputPath=.\include\apr_escape.h + +".\include\apr_escape_test_char.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cl.exe /nologo /W3 /EHsc /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FD /I ".\include" /Fo.\x64\Debug\gen_test_char /Fe.\x64\Debug\gen_test_char.exe .\tools\gen_test_char.c + .\x64\Debug\gen_test_char.exe > .\include\apr_escape_test_char.h + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\include\apr_file_info.h +# End Source File +# Begin Source File + SOURCE=.\include\apr_file_io.h # End Source File # Begin Source File @@ -262,15 +995,23 @@ SOURCE=.\include\apr_getopt.h # End Source File # Begin Source File -SOURCE=.\include\apr_lib.h +SOURCE=.\include\apr_global_mutex.h # End Source File # Begin Source File -SOURCE=.\include\apr_lock.h +SOURCE=.\include\apr_hash.h # End Source File # Begin Source File -SOURCE=.\include\apr_md5.h +SOURCE=.\include\apr_inherit.h +# End Source File +# Begin Source File + +SOURCE=.\include\apr_lib.h +# End Source File +# Begin Source File + +SOURCE=.\include\apr_mmap.h # End Source File # Begin Source File @@ -278,7 +1019,7 @@ SOURCE=.\include\apr_network_io.h # End Source File # Begin Source File -SOURCE=.\inc\apr_pools.h +SOURCE=.\include\apr_poll.h # End Source File # Begin Source File @@ -290,7 +1031,19 @@ SOURCE=.\include\apr_portable.h # End Source File # Begin Source File -SOURCE=.\include\apr_shmem.h +SOURCE=.\include\apr_proc_mutex.h +# End Source File +# Begin Source File + +SOURCE=.\include\apr_random.h +# End Source File +# Begin Source File + +SOURCE=.\include\apr_ring.h +# End Source File +# Begin Source File + +SOURCE=.\include\apr_shm.h # End Source File # Begin Source File @@ -298,117 +1051,157 @@ SOURCE=.\include\apr_signal.h # End Source File # Begin Source File -SOURCE=.\include\apr_strnatcmp.h +SOURCE=.\include\apr_skiplist.h # End Source File # Begin Source File -SOURCE=.\include\apr_thread_proc.h +SOURCE=.\include\apr_strings.h # End Source File # Begin Source File -SOURCE=.\include\apr_time.h +SOURCE=.\include\apr_support.h # End Source File # Begin Source File -SOURCE=.\time\win32\atime.h +SOURCE=.\include\apr_tables.h # End Source File # Begin Source File -SOURCE=.\dso\win32\dso.h +SOURCE=.\include\apr_thread_cond.h # End Source File # Begin Source File -SOURCE=.\file_io\win32\fileio.h +SOURCE=.\include\apr_thread_mutex.h # End Source File # Begin Source File -SOURCE=.\locks\win32\locks.h +SOURCE=.\include\apr_thread_proc.h # End Source File # Begin Source File -SOURCE=.\misc\win32\misc.h +SOURCE=.\include\apr_thread_rwlock.h # End Source File # Begin Source File -SOURCE=.\network_io\win32\networkio.h +SOURCE=.\include\apr_time.h # End Source File # Begin Source File -SOURCE=.\threadproc\win32\threadproc.h +SOURCE=.\include\apr_user.h # End Source File -# End Group -# Begin Group "Generated Header Files" +# Begin Source File -# PROP Default_Filter "" +SOURCE=.\include\apr_version.h +# End Source File # Begin Source File -SOURCE=.\include\apr.h +SOURCE=.\include\apr_want.h # End Source File # Begin Source File -SOURCE=.\include\apr_private.h +SOURCE=.\include\apu.h # End Source File -# End Group -# Begin Group "Internal Header Files" +# Begin Source File -# PROP Default_Filter "" +SOURCE=.\include\private\apu_select_dbm.h.in +# End Source File # Begin Source File -SOURCE=.\include\apr_private.hw +SOURCE=.\include\private\apu_select_dbm.hw + +!IF "$(CFG)" == "apr - Win32 Release" + +# Begin Custom Build - Creating apu_select_dbm.h from apu_select_dbm.hw +InputPath=.\include\private\apu_select_dbm.hw + +".\include\private\apu_select_dbm.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + type .\include\private\apu_select_dbm.hw > .\include\private\apu_select_dbm.h + +# End Custom Build + +!ELSEIF "$(CFG)" == "apr - Win32 Debug" + +# Begin Custom Build - Creating apu_select_dbm.h from apu_select_dbm.hw +InputPath=.\include\private\apu_select_dbm.hw + +".\include\private\apu_select_dbm.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + type .\include\private\apu_select_dbm.hw > .\include\private\apu_select_dbm.h -!IF "$(CFG)" == "aprlib - Win32 Release" +# End Custom Build + +!ELSEIF "$(CFG)" == "apr - x64 Release" -# Begin Custom Build -InputPath=.\include\apr_private.hw +# Begin Custom Build - Creating apu_select_dbm.h from apu_select_dbm.hw +InputPath=.\include\private\apu_select_dbm.hw + +".\include\private\apu_select_dbm.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + type .\include\private\apu_select_dbm.hw > .\include\private\apu_select_dbm.h -".\include\apr_private.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - copy .\include\apr_private.hw .\include\apr_private.h > nul - echo Created apr_private.h from apr_private.hw - # End Custom Build -!ELSEIF "$(CFG)" == "aprlib - Win32 Debug" +!ELSEIF "$(CFG)" == "apr - x64 Debug" + +# Begin Custom Build - Creating apu_select_dbm.h from apu_select_dbm.hw +InputPath=.\include\private\apu_select_dbm.hw -# Begin Custom Build -InputPath=.\include\apr_private.hw +".\include\private\apu_select_dbm.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + type .\include\private\apu_select_dbm.hw > .\include\private\apu_select_dbm.h -".\include\apr_private.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - copy .\include\apr_private.hw .\include\apr_private.h > nul - echo Created apr_private.h from apr_private.hw - # End Custom Build !ENDIF # End Source File -# End Group -# Begin Group "External Header Files" +# Begin Source File -# PROP Default_Filter "" +SOURCE=.\include\apu_want.h.in +# End Source File # Begin Source File -SOURCE=.\include\apr.hw +SOURCE=.\include\apu_want.hnw +# End Source File +# Begin Source File -!IF "$(CFG)" == "aprlib - Win32 Release" +SOURCE=.\include\apu_want.hw -# Begin Custom Build -InputPath=.\include\apr.hw +!IF "$(CFG)" == "apr - Win32 Release" + +# Begin Custom Build - Creating apu_want.h from apu_want.hw +InputPath=.\include\apu_want.hw + +".\include\apu_want.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + type .\include\apu_want.hw > .\include\apu_want.h -".\include\apr.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - copy .\include\apr.hw .\include\apr.h > nul - echo Created apr.h from apr.hw - # End Custom Build -!ELSEIF "$(CFG)" == "aprlib - Win32 Debug" +!ELSEIF "$(CFG)" == "apr - Win32 Debug" -# Begin Custom Build -InputPath=.\include\apr.hw +# Begin Custom Build - Creating apu_want.h from apu_want.hw +InputPath=.\include\apu_want.hw + +".\include\apu_want.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + type .\include\apu_want.hw > .\include\apu_want.h + +# End Custom Build + +!ELSEIF "$(CFG)" == "apr - x64 Release" + +# Begin Custom Build - Creating apu_want.h from apu_want.hw +InputPath=.\include\apu_want.hw + +".\include\apu_want.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + type .\include\apu_want.hw > .\include\apu_want.h + +# End Custom Build + +!ELSEIF "$(CFG)" == "apr - x64 Debug" + +# Begin Custom Build - Creating apu_want.h from apu_want.hw +InputPath=.\include\apu_want.hw + +".\include\apu_want.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + type .\include\apu_want.hw > .\include\apu_want.h -".\include\apr.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - copy .\include\apr.hw .\include\apr.h > nul - echo Created apr.h from apr.hw - # End Custom Build !ENDIF diff --git a/test/test.dsw b/apr.dsw similarity index 58% rename from test/test.dsw rename to apr.dsw index af6f6901c60..ff7dadd8cb3 100644 --- a/test/test.dsw +++ b/apr.dsw @@ -1,9 +1,9 @@ -Microsoft Developer Studio Workspace File, Format Version 5.00 +Microsoft Developer Studio Workspace File, Format Version 6.00 # WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! ############################################################################### -Project: "ab_apr"=.\ab_apr.dsp - Package Owner=<4> +Project: "apr"=".\apr.dsp" - Package Owner=<4> Package=<5> {{{ @@ -15,19 +15,7 @@ Package=<4> ############################################################################### -Project: "client"=.\client.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Project: "server"=.\server.dsp - Package Owner=<4> +Project: "aprapp"=".\build\aprapp.dsp" - Package Owner=<4> Package=<5> {{{ @@ -35,11 +23,14 @@ Package=<5> Package=<4> {{{ + Begin Project Dependency + Project_Dep_Name preaprapp + End Project Dependency }}} ############################################################################### -Project: "testarg"=.\testarg.dsp - Package Owner=<4> +Project: "libapr"=".\libapr.dsp" - Package Owner=<4> Package=<5> {{{ @@ -51,7 +42,7 @@ Package=<4> ############################################################################### -Project: "testfile"=.\testfile.dsp - Package Owner=<4> +Project: "libaprapp"=".\build\libaprapp.dsp" - Package Owner=<4> Package=<5> {{{ @@ -59,11 +50,14 @@ Package=<5> Package=<4> {{{ + Begin Project Dependency + Project_Dep_Name prelibaprapp + End Project Dependency }}} ############################################################################### -Project: "testproc"=.\testproc.dsp - Package Owner=<4> +Project: "preaprapp"=".\build\preaprapp.dsp" - Package Owner=<4> Package=<5> {{{ @@ -71,11 +65,14 @@ Package=<5> Package=<4> {{{ + Begin Project Dependency + Project_Dep_Name apr + End Project Dependency }}} ############################################################################### -Project: "testsock"=.\testsock.dsp - Package Owner=<4> +Project: "prelibaprapp"=".\build\prelibaprapp.dsp" - Package Owner=<4> Package=<5> {{{ @@ -84,16 +81,13 @@ Package=<5> Package=<4> {{{ Begin Project Dependency - Project_Dep_Name client - End Project Dependency - Begin Project Dependency - Project_Dep_Name server + Project_Dep_Name libapr End Project Dependency }}} ############################################################################### -Project: "testthread"=.\testthread.dsp - Package Owner=<4> +Project: "apr_crypto_nss"=".\crypto\apr_crypto_nss.dsp" - Package Owner=<4> Package=<5> {{{ @@ -101,11 +95,14 @@ Package=<5> Package=<4> {{{ + Begin Project Dependency + Project_Dep_Name libapr + End Project Dependency }}} ############################################################################### -Project: "timetest"=.\timetest.dsp - Package Owner=<4> +Project: "apr_crypto_openssl"=".\crypto\apr_crypto_openssl.dsp" - Package Owner=<4> Package=<5> {{{ @@ -113,6 +110,9 @@ Package=<5> Package=<4> {{{ + Begin Project Dependency + Project_Dep_Name libapr + End Project Dependency }}} ############################################################################### diff --git a/apr.pc.in b/apr.pc.in new file mode 100644 index 00000000000..318a81e26b7 --- /dev/null +++ b/apr.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +APR_MAJOR_VERSION=@APR_MAJOR_VERSION@ +includedir=@includedir@ + +Name: APR +Description: The Apache Portable Runtime library +Version: @APR_DOTTED_VERSION@ +Libs: -L${libdir} -l@APR_LIBNAME@ @EXTRA_LIBS@ +Cflags: @EXTRA_CPPFLAGS@ @EXTRA_CFLAGS@ -I${includedir} diff --git a/aprlib.def b/aprlib.def deleted file mode 100644 index b9fe301fef7..00000000000 --- a/aprlib.def +++ /dev/null @@ -1,251 +0,0 @@ -; aprlib.def : - -LIBRARY aprlib -DESCRIPTION '' - -EXPORTS - ; Add new API calls to the end of this list. - ap_opendir @1 - ap_closedir @2 - ap_readdir @3 - ap_rewinddir @4 - ap_make_dir @5 - ap_remove_dir @6 - ap_dir_entry_size @7 - ap_dir_entry_mtime @8 - ap_dir_entry_ftype @9 - ap_get_dir_filename @10 -; ap_get_filename @11 - ap_stat @11 -; ap_get_filesize @12 -; ap_get_fileatime @13 -; ap_get_filectime @14 -; ap_make_iov @15 - ap_dupfile @16 - ap_getfileinfo @17 - ap_open @18 - ap_close @19 - ap_remove_file @20 - ap_create_pipe @21 - ap_read @22 - ap_write @23 - ap_seek @24 - ap_get_filedata @25 - ap_set_filedata @26 - ap_get_os_file @27 - ap_put_os_file @28 - ap_get_os_dir @29 - ap_putc @30 - ap_getc @31 - ap_puts @32 - ap_fgets @33 - ap_flush @34 - ap_fprintf @35 - ap_eof @36 -; ap_get_filetype @37 - ap_writev @38 - ; locks - ap_create_lock @39 - ap_lock @40 - ap_unlock @41 - ap_destroy_lock @42 - ap_child_init_lock @43 - ap_get_lockdata @44 - ap_set_lockdata @45 - ap_get_os_lock @46 - ap_create_tcp_socket @47 - ap_shutdown @48 - ap_close_socket @49 - ap_bind @50 - ap_listen @51 - ap_accept @52 - ap_connect @53 - ap_get_remote_hostname @54 - ap_gethostname @55 - ap_send @56 - ap_recv @57 - ap_setsocketopt @58 - ap_sendv @59 - ap_sendfile @60 - ap_setup_poll @61 - ap_poll @62 - ap_add_poll_socket @63 - ap_get_revents @64 - ap_get_socketdata @65 - ap_set_socketdata @66 - ap_get_polldata @67 - ap_set_polldata @68 - ap_put_os_sock @69 - ap_get_os_sock @70 - ap_remove_poll_socket @71 - ap_clear_poll_sockets @72 -; ap_setipaddr @73 -; ap_getipaddr @74 -; ap_create_signal @75 -; ap_setup_signal @76 -; SignalHandling @77 -; ap_send_signal @78 -; thread_ready @79 - ap_createprocattr_init @80 - ap_setprocattr_io @81 - ap_setprocattr_dir @82 - ap_setprocattr_cmdtype @83 - ap_setprocattr_detach @84 - ap_create_process @85 - ap_get_childin @86 - ap_get_childout @87 - ap_get_childerr @88 - ap_wait_proc @89 - ap_kill @90 - ap_create_threadattr @91 - ap_setthreadattr_detach @92 - ap_getthreadattr_detach @93 - ap_create_thread @94 - ap_thread_exit @95 - ap_thread_join @96 - ap_thread_detach @97 -; ap_cancel_thread @98 - ap_create_thread_private @99 - ap_get_thread_private @100 - ap_set_thread_private @101 - ap_delete_thread_private @102 - ap_get_threaddata @103 - ap_set_threaddata @104 - ap_get_threadkeydata @105 - ap_set_threadkeydata @106 - ap_get_procdata @107 -; ap_set_procdata @108 - ap_get_os_proc @109 - ap_get_os_thread @110 - ap_get_os_threadkey @111 - ap_os_systemcase_filename @112 - canonical_filename @113 - ap_create_pool @114 - ap_destroy_context @115 -; WinTimeToUnixTime @116 -; ap_get_oslevel @117 - ap_get_userdata @118 - ap_set_userdata @119 - ap_initialize @120 - ap_getopt @121 - ap_opterr @122 DATA - ap_optind @123 DATA - ap_optopt @124 DATA - ap_optreset @125 DATA - ap_optarg @126 DATA -; ap_make_time @127 - ap_ansi_time_to_ap_time @127 -; ap_current_time @128 - ap_now @128 -; ap_explode_time @129 - ap_explode_gmt @129 -; ap_implode_time @130 - ap_explode_localtime @130 -; ap_get_curtime @131 - ap_implode_time @131 -; ap_get_sec @132 - ap_get_os_imp_time @132 -; ap_get_min @133 - ap_get_os_exp_time @133 -; ap_get_hour @134 - ap_put_os_imp_time @134 -; ap_get_mday @135 - ap_put_os_exp_time @135 -; ap_get_mon @136 - ap_ctime @136 -; ap_get_year @137 - ap_rfc822_date @137 -; ap_get_wday @138 - ap_strftime @138 -; ap_set_sec @139 -; ap_set_min @140 -; ap_set_hour @141 -; ap_set_mday @142 -; ap_set_mon @143 -; ap_set_year @144 -; ap_set_wday @145 -; ap_get_timedata @146 -; ap_set_timedata @147 -; ap_get_os_time @148 -; ap_timediff @149 - ap_MD5Final @150 - ap_MD5Init @151 - ap_MD5Update @152 - ap_cpystrn @153 - ap_register_cleanup @154 - ap_kill_cleanup @155 - ap_fnmatch @156 - ap_is_fnmatch @157 - ap_MD5Encode @158 - ap_validate_password @159 - ap_make_sub_pool @160 - ap_init_alloc @161 - ap_clear_pool @162 - ap_destroy_pool @163 - ap_bytes_in_pool @164 - ap_bytes_in_free_blocks @165 - ap_palloc @166 - ap_pcalloc @167 - ap_pstrdup @168 - ap_pstrndup @169 - ap_pstrcat @170 - ap_pvsprintf @171 - ap_psprintf @172 - ap_make_array @173 - ap_push_array @174 - ap_array_cat @175 - ap_copy_array @176 - ap_copy_array_hdr @177 - ap_append_arrays @178 - ap_array_pstrcat @179 - ap_make_table @180 - ap_copy_table @181 - ap_clear_table @182 - ap_table_get @183 - ap_table_set @184 - ap_table_setn @185 - ap_table_unset @186 - ap_table_merge @187 - ap_table_mergen @188 - ap_table_add @189 - ap_table_addn @190 - ap_overlay_tables @191 - ap_table_do @192 - ap_overlap_tables @193 - ap_run_cleanup @194 - ap_cleanup_for_exec @195 - ap_null_cleanup @196 - ap_note_subprocess @197 -; ap_slack @198 - ap_vformatter @199 - ap_snprintf @200 - ap_vsnprintf @201 - ap_getpass @202 - ap_ungetc @203 - ap_tokenize_to_argv @204 - ap_filename_of_pathname @205 - ap_get_remote_name @206 - ap_get_local_name @207 - ap_get_local_ipaddr @208 - ap_set_local_ipaddr @209 - ap_get_remote_ipaddr @210 - ap_set_remote_ipaddr @211 - ap_get_local_port @212 - ap_set_local_port @213 - ap_get_remote_port @214 - ap_set_remote_port @215 - ap_open_stderr @216 - ap_set_pipe_timeout @217 - ap_terminate @218 - ap_dso_load @219 - ap_dso_unload @220 - ap_dso_sym @221 - ap_dso_init @222 - ap_collapse_spaces @223 - ap_month_snames @224 - ap_day_snames @225 - ap_canonical_error @226 - ap_strerror @227 - ap_generate_random_bytes @228 - ap_strnatcmp @229 - ap_strnatcasecmp @230 diff --git a/aprlib.dsp b/aprlib.dsp deleted file mode 100644 index c30f9ecc16b..00000000000 --- a/aprlib.dsp +++ /dev/null @@ -1,419 +0,0 @@ -# Microsoft Developer Studio Project File - Name="aprlib" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 5.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Static Library" 0x0104 - -CFG=aprlib - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "aprlib.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "aprlib.mak" CFG="aprlib - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "aprlib - Win32 Release" (based on "Win32 (x86) Static Library") -!MESSAGE "aprlib - Win32 Debug" (based on "Win32 (x86) Static Library") -!MESSAGE - -# Begin Project -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe - -!IF "$(CFG)" == "aprlib - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "LibR" -# PROP BASE Intermediate_Dir "LibR" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "LibR" -# PROP Intermediate_Dir "LibR" -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c -# ADD CPP /nologo /MD /W3 /GX /O2 /I "./include" /I "./inc" /I "./misc/win32" /I "./file_io/win32" /I "./time/win32" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c -# SUBTRACT CPP /YX -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LIB32=link.exe -lib -# ADD BASE LIB32 /nologo /out:".\LibR\apr.lib" -# ADD LIB32 /nologo /out:".\LibR\apr.lib" - -!ELSEIF "$(CFG)" == "aprlib - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "LibD" -# PROP BASE Intermediate_Dir "LibD" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "LibD" -# PROP Intermediate_Dir "LibD" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c -# ADD CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /I "./include" /I "./inc" /I "./misc/win32" /I "./file_io/win32" /I "./time/win32" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /c -# SUBTRACT CPP /YX -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LIB32=link.exe -lib -# ADD BASE LIB32 /nologo /out:".\LibD\apr.lib" -# ADD LIB32 /nologo /out:".\LibD\apr.lib" - -!ENDIF - -# Begin Target - -# Name "aprlib - Win32 Release" -# Name "aprlib - Win32 Debug" -# Begin Group "Source Files" - -# PROP Default_Filter ".c" -# Begin Source File - -SOURCE=.\time\win32\access.c -# End Source File -# Begin Source File - -SOURCE=.\lib\apr_cpystrn.c -# End Source File -# Begin Source File - -SOURCE=.\lib\apr_execve.c -# End Source File -# Begin Source File - -SOURCE=.\lib\apr_fnmatch.c -# End Source File -# Begin Source File - -SOURCE=.\lib\apr_getpass.c -# End Source File -# Begin Source File - -SOURCE=.\lib\apr_md5.c -# End Source File -# Begin Source File - -SOURCE=.\lib\apr_pools.c -# End Source File -# Begin Source File - -SOURCE=.\lib\apr_snprintf.c -# End Source File -# Begin Source File - -SOURCE=.\lib\apr_strnatcmp.c -# End Source File -# Begin Source File - -SOURCE=.\lib\apr_tables.c -# End Source File -# Begin Source File - -SOURCE=.\aprlib.def -# End Source File -# Begin Source File - -SOURCE=.\misc\win32\canonerr.c -# End Source File -# Begin Source File - -SOURCE=.\file_io\win32\dir.c -# End Source File -# Begin Source File - -SOURCE=.\dso\win32\dso.c -# End Source File -# Begin Source File - -SOURCE=.\misc\win32\errorcodes.c -# End Source File -# Begin Source File - -SOURCE=.\file_io\win32\fileacc.c -# End Source File -# Begin Source File - -SOURCE=.\file_io\win32\filedup.c -# End Source File -# Begin Source File - -SOURCE=.\file_io\win32\filestat.c -# End Source File -# Begin Source File - -SOURCE=.\misc\win32\getopt.c -# End Source File -# Begin Source File - -SOURCE=.\locks\win32\locks.c -# End Source File -# Begin Source File - -SOURCE=.\misc\win32\names.c -# End Source File -# Begin Source File - -SOURCE=.\file_io\win32\open.c -# End Source File -# Begin Source File - -SOURCE=.\file_io\win32\pipe.c -# End Source File -# Begin Source File - -SOURCE=.\network_io\win32\poll.c -# End Source File -# Begin Source File - -SOURCE=.\threadproc\win32\proc.c -# End Source File -# Begin Source File - -SOURCE=.\misc\win32\rand.c -# End Source File -# Begin Source File - -SOURCE=.\file_io\win32\readwrite.c -# End Source File -# Begin Source File - -SOURCE=.\file_io\win32\seek.c -# End Source File -# Begin Source File - -SOURCE=.\network_io\win32\sendrecv.c -# End Source File -# Begin Source File - -SOURCE=.\threadproc\win32\signals.c -# End Source File -# Begin Source File - -SOURCE=.\network_io\win32\sockaddr.c -# End Source File -# Begin Source File - -SOURCE=.\network_io\win32\sockets.c -# End Source File -# Begin Source File - -SOURCE=.\network_io\win32\sockopt.c -# End Source File -# Begin Source File - -SOURCE=.\misc\win32\start.c -# End Source File -# Begin Source File - -SOURCE=.\threadproc\win32\thread.c -# End Source File -# Begin Source File - -SOURCE=.\threadproc\win32\threadpriv.c -# End Source File -# Begin Source File - -SOURCE=.\time\win32\time.c -# End Source File -# Begin Source File - -SOURCE=.\time\win32\timestr.c -# End Source File -# End Group -# Begin Group "Header Files" - -# PROP Default_Filter ".h" -# Begin Source File - -SOURCE=.\include\apr_dso.h -# End Source File -# Begin Source File - -SOURCE=.\include\apr_errno.h -# End Source File -# Begin Source File - -SOURCE=.\include\apr_file_io.h -# End Source File -# Begin Source File - -SOURCE=.\include\apr_fnmatch.h -# End Source File -# Begin Source File - -SOURCE=.\include\apr_general.h -# End Source File -# Begin Source File - -SOURCE=.\include\apr_getopt.h -# End Source File -# Begin Source File - -SOURCE=.\include\apr_lib.h -# End Source File -# Begin Source File - -SOURCE=.\include\apr_lock.h -# End Source File -# Begin Source File - -SOURCE=.\include\apr_md5.h -# End Source File -# Begin Source File - -SOURCE=.\include\apr_network_io.h -# End Source File -# Begin Source File - -SOURCE=.\inc\apr_pools.h -# End Source File -# Begin Source File - -SOURCE=.\include\apr_pools.h -# End Source File -# Begin Source File - -SOURCE=.\include\apr_portable.h -# End Source File -# Begin Source File - -SOURCE=.\include\apr_shmem.h -# End Source File -# Begin Source File - -SOURCE=.\include\apr_signal.h -# End Source File -# Begin Source File - -SOURCE=.\include\apr_strnatcmp.h -# End Source File -# Begin Source File - -SOURCE=.\include\apr_thread_proc.h -# End Source File -# Begin Source File - -SOURCE=.\include\apr_time.h -# End Source File -# Begin Source File - -SOURCE=.\time\win32\atime.h -# End Source File -# Begin Source File - -SOURCE=.\dso\win32\dso.h -# End Source File -# Begin Source File - -SOURCE=.\file_io\win32\fileio.h -# End Source File -# Begin Source File - -SOURCE=.\locks\win32\locks.h -# End Source File -# Begin Source File - -SOURCE=.\misc\win32\misc.h -# End Source File -# Begin Source File - -SOURCE=.\network_io\win32\networkio.h -# End Source File -# Begin Source File - -SOURCE=.\threadproc\win32\threadproc.h -# End Source File -# End Group -# Begin Group "Generated Header Files" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=.\include\apr.h -# End Source File -# Begin Source File - -SOURCE=.\include\apr_private.h -# End Source File -# End Group -# Begin Group "Internal Header Files" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=.\include\apr_private.hw - -!IF "$(CFG)" == "aprlib - Win32 Release" - -# Begin Custom Build -InputPath=.\include\apr_private.hw - -".\include\apr_private.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - copy .\include\apr_private.hw .\include\apr_private.h > nul - echo Created apr_private.h from apr_private.hw - -# End Custom Build - -!ELSEIF "$(CFG)" == "aprlib - Win32 Debug" - -# Begin Custom Build -InputPath=.\include\apr_private.hw - -".\include\apr_private.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - copy .\include\apr_private.hw .\include\apr_private.h > nul - echo Created apr_private.h from apr_private.hw - -# End Custom Build - -!ENDIF - -# End Source File -# End Group -# Begin Group "External Header Files" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=.\include\apr.hw - -!IF "$(CFG)" == "aprlib - Win32 Release" - -# Begin Custom Build -InputPath=.\include\apr.hw - -".\include\apr.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - copy .\include\apr.hw .\include\apr.h > nul - echo Created apr.h from apr.hw - -# End Custom Build - -!ELSEIF "$(CFG)" == "aprlib - Win32 Debug" - -# Begin Custom Build -InputPath=.\include\apr.hw - -".\include\apr.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - copy .\include\apr.hw .\include\apr.h > nul - echo Created apr.h from apr.hw - -# End Custom Build - -!ENDIF - -# End Source File -# End Group -# End Target -# End Project diff --git a/aprlibdll.dsp b/aprlibdll.dsp deleted file mode 100644 index 05f5831e2a3..00000000000 --- a/aprlibdll.dsp +++ /dev/null @@ -1,103 +0,0 @@ -# Microsoft Developer Studio Project File - Name="aprlibdll" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 5.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 - -CFG=aprlibdll - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "aprlibdll.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "aprlibdll.mak" CFG="aprlibdll - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "aprlibdll - Win32 Release" (based on\ - "Win32 (x86) Dynamic-Link Library") -!MESSAGE "aprlibdll - Win32 Debug" (based on\ - "Win32 (x86) Dynamic-Link Library") -!MESSAGE - -# Begin Project -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -MTL=midl.exe -RSC=rc.exe - -!IF "$(CFG)" == "aprlibdll - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c -# ADD CPP /nologo /MD /W3 /GX /O2 /I "./include" /I "./inc" /I "./misc/win32" /I "./file_io/win32" /I "./time/win32" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c -# SUBTRACT CPP /YX -# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o NUL /win32 -# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o NUL /win32 -# ADD BASE RSC /l 0x409 /d "NDEBUG" -# ADD RSC /l 0x409 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 apr.lib kernel32.lib advapi32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /map /machine:I386 /def:".\aprlib.def" /out:"Release/aprlib.dll" /libpath:"LibR" /base:@"..\..\os\win32\BaseAddr.ref",aprlib -# ADD LINK32 apr.lib kernel32.lib advapi32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /map /machine:I386 /def:".\aprlib.def" /out:"Release/aprlib.dll" /libpath:"LibR" /base:@"..\..\os\win32\BaseAddr.ref",aprlib - -!ELSEIF "$(CFG)" == "aprlibdll - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c -# ADD CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /I "./include" /I "./inc" /I "./misc/win32" /I "./file_io/win32" /I "./time/win32" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /c -# SUBTRACT CPP /YX -# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o NUL /win32 -# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o NUL /win32 -# ADD BASE RSC /l 0x409 /d "_DEBUG" -# ADD RSC /l 0x409 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 aprlib.lib kernel32.lib advapi32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /map /debug /machine:I386 /def:".\aprlib.def" /out:"Debug/aprlib.dll" /libpath:"LibD" /base:@"..\..\os\win32\BaseAddr.ref",aprlib -# ADD LINK32 apr.lib kernel32.lib advapi32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /map /debug /machine:I386 /def:".\aprlib.def" /out:"Debug/aprlib.dll" /libpath:"LibD" /base:@"..\..\os\win32\BaseAddr.ref",aprlib - -!ENDIF - -# Begin Target - -# Name "aprlibdll - Win32 Release" -# Name "aprlibdll - Win32 Debug" -# Begin Source File - -SOURCE=.\misc\win32\aprlib.c -# End Source File -# Begin Source File - -SOURCE=.\aprlib.def -# PROP Exclude_From_Build 1 -# End Source File -# End Target -# End Project diff --git a/atomic/netware/apr_atomic.c b/atomic/netware/apr_atomic.c new file mode 100644 index 00000000000..d7e00cd4e8f --- /dev/null +++ b/atomic/netware/apr_atomic.c @@ -0,0 +1,75 @@ +/* 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_atomic.h" + +#include <stdlib.h> + +APR_DECLARE(apr_status_t) apr_atomic_init(apr_pool_t *pool) +{ + return APR_SUCCESS; +} + +APR_DECLARE(apr_uint32_t) apr_atomic_add32(volatile apr_uint32_t *mem, apr_uint32_t val) +{ + return atomic_xchgadd((unsigned long *)mem,(unsigned long)val); +} + +APR_DECLARE(void) apr_atomic_sub32(volatile apr_uint32_t *mem, apr_uint32_t val) +{ + atomic_sub((unsigned long *)mem,(unsigned long)val); +} + +APR_DECLARE(apr_uint32_t) apr_atomic_inc32(volatile apr_uint32_t *mem) +{ + return atomic_xchgadd((unsigned long *)mem, 1); +} + +APR_DECLARE(void) apr_atomic_set32(volatile apr_uint32_t *mem, apr_uint32_t val) +{ + *mem = val; +} + +APR_DECLARE(apr_uint32_t) apr_atomic_read32(volatile apr_uint32_t *mem) +{ + return *mem; +} + +APR_DECLARE(apr_uint32_t) apr_atomic_cas32(volatile apr_uint32_t *mem, apr_uint32_t with,apr_uint32_t cmp) +{ + return atomic_cmpxchg((unsigned long *)mem,(unsigned long)cmp,(unsigned long)with); +} + +APR_DECLARE(apr_uint32_t) apr_atomic_xchg32(volatile apr_uint32_t *mem, apr_uint32_t val) +{ + return atomic_xchg((unsigned long *)mem,(unsigned long)val); +} + +APR_DECLARE(int) apr_atomic_dec32(volatile apr_uint32_t *mem) +{ + return (atomic_xchgadd((unsigned long *)mem, 0xFFFFFFFF) - 1); +} + +APR_DECLARE(void *) apr_atomic_casptr(void *volatile *mem, void *with, const void *cmp) +{ + return (void*)atomic_cmpxchg((unsigned long *)mem,(unsigned long)cmp,(unsigned long)with); +} + +APR_DECLARE(void*) apr_atomic_xchgptr(void *volatile *mem, void *with) +{ + return (void*)atomic_xchg((unsigned long *)mem,(unsigned long)with); +} diff --git a/atomic/os390/atomic.c b/atomic/os390/atomic.c new file mode 100644 index 00000000000..8fd1586022c --- /dev/null +++ b/atomic/os390/atomic.c @@ -0,0 +1,137 @@ +/* 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_atomic.h" + +#include <stdlib.h> + +apr_status_t apr_atomic_init(apr_pool_t *p) +{ + return APR_SUCCESS; +} + +apr_uint32_t apr_atomic_add32(volatile apr_uint32_t *mem, apr_uint32_t val) +{ + apr_uint32_t old, new_val; + + old = *mem; /* old is automatically updated on cs failure */ + do { + new_val = old + val; + } while (__cs(&old, (cs_t *)mem, new_val)); + return old; +} + +void apr_atomic_sub32(volatile apr_uint32_t *mem, apr_uint32_t val) +{ + apr_uint32_t old, new_val; + + old = *mem; /* old is automatically updated on cs failure */ + do { + new_val = old - val; + } while (__cs(&old, (cs_t *)mem, new_val)); +} + +apr_uint32_t apr_atomic_inc32(volatile apr_uint32_t *mem) +{ + return apr_atomic_add32(mem, 1); +} + +int apr_atomic_dec32(volatile apr_uint32_t *mem) +{ + apr_uint32_t old, new_val; + + old = *mem; /* old is automatically updated on cs failure */ + do { + new_val = old - 1; + } while (__cs(&old, (cs_t *)mem, new_val)); + + return new_val != 0; +} + +apr_uint32_t apr_atomic_read32(volatile apr_uint32_t *mem) +{ + return *mem; +} + +void apr_atomic_set32(volatile apr_uint32_t *mem, apr_uint32_t val) +{ + *mem = val; +} + +apr_uint32_t apr_atomic_cas32(volatile apr_uint32_t *mem, apr_uint32_t swap, + apr_uint32_t cmp) +{ + apr_uint32_t old = cmp; + + __cs(&old, (cs_t *)mem, swap); + return old; /* old is automatically updated from mem on cs failure */ +} + +#if APR_SIZEOF_VOIDP == 4 +void *apr_atomic_casptr(void *volatile *mem_ptr, + void *swap_ptr, + const void *cmp_ptr) +{ + __cs1(&cmp_ptr, /* automatically updated from mem on __cs1 failure */ + mem_ptr, /* set from swap when __cs1 succeeds */ + &swap_ptr); + return (void *)cmp_ptr; +} +#elif APR_SIZEOF_VOIDP == 8 +void *apr_atomic_casptr(void *volatile *mem_ptr, + void *swap_ptr, + const void *cmp_ptr) +{ + __csg(&cmp_ptr, /* automatically updated from mem on __csg failure */ + mem_ptr, /* set from swap when __csg succeeds */ + &swap_ptr); + return (void *)cmp_ptr; +} +#else +#error APR_SIZEOF_VOIDP value not supported +#endif /* APR_SIZEOF_VOIDP */ + +apr_uint32_t apr_atomic_xchg32(volatile apr_uint32_t *mem, apr_uint32_t val) +{ + apr_uint32_t old, new_val; + + old = *mem; /* old is automatically updated on cs failure */ + do { + new_val = val; + } while (__cs(&old, (cs_t *)mem, new_val)); + + return old; +} + +APR_DECLARE(void*) apr_atomic_xchgptr(void *volatile *mem_ptr, void *new_ptr) +{ + void *old_ptr; + + old_ptr = *(void **)mem_ptr; /* old is automatically updated on cs failure */ +#if APR_SIZEOF_VOIDP == 4 + do { + } while (__cs1(&old_ptr, mem_ptr, &new_ptr)); +#elif APR_SIZEOF_VOIDP == 8 + do { + } while (__csg(&old_ptr, mem_ptr, &new_ptr)); +#else +#error APR_SIZEOF_VOIDP value not supported +#endif /* APR_SIZEOF_VOIDP */ + + return old_ptr; +} diff --git a/atomic/unix/builtins.c b/atomic/unix/builtins.c new file mode 100644 index 00000000000..ebf8833d193 --- /dev/null +++ b/atomic/unix/builtins.c @@ -0,0 +1,81 @@ +/* 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_atomic.h" + +#ifdef USE_ATOMICS_BUILTINS + +APR_DECLARE(apr_status_t) apr_atomic_init(apr_pool_t *p) +{ + return APR_SUCCESS; +} + +APR_DECLARE(apr_uint32_t) apr_atomic_read32(volatile apr_uint32_t *mem) +{ + return *mem; +} + +APR_DECLARE(void) apr_atomic_set32(volatile apr_uint32_t *mem, apr_uint32_t val) +{ + *mem = val; +} + +APR_DECLARE(apr_uint32_t) apr_atomic_add32(volatile apr_uint32_t *mem, apr_uint32_t val) +{ + return __sync_fetch_and_add(mem, val); +} + +APR_DECLARE(void) apr_atomic_sub32(volatile apr_uint32_t *mem, apr_uint32_t val) +{ + __sync_fetch_and_sub(mem, val); +} + +APR_DECLARE(apr_uint32_t) apr_atomic_inc32(volatile apr_uint32_t *mem) +{ + return __sync_fetch_and_add(mem, 1); +} + +APR_DECLARE(int) apr_atomic_dec32(volatile apr_uint32_t *mem) +{ + return __sync_sub_and_fetch(mem, 1); +} + +APR_DECLARE(apr_uint32_t) apr_atomic_cas32(volatile apr_uint32_t *mem, apr_uint32_t with, + apr_uint32_t cmp) +{ + return __sync_val_compare_and_swap(mem, cmp, with); +} + +APR_DECLARE(apr_uint32_t) apr_atomic_xchg32(volatile apr_uint32_t *mem, apr_uint32_t val) +{ + __sync_synchronize(); + + return __sync_lock_test_and_set(mem, val); +} + +APR_DECLARE(void*) apr_atomic_casptr(void *volatile *mem, void *with, const void *cmp) +{ + return (void*) __sync_val_compare_and_swap(mem, cmp, with); +} + +APR_DECLARE(void*) apr_atomic_xchgptr(void *volatile *mem, void *with) +{ + __sync_synchronize(); + + return (void*) __sync_lock_test_and_set(mem, with); +} + +#endif /* USE_ATOMICS_BUILTINS */ diff --git a/atomic/unix/ia32.c b/atomic/unix/ia32.c new file mode 100644 index 00000000000..9941af5f5f3 --- /dev/null +++ b/atomic/unix/ia32.c @@ -0,0 +1,127 @@ +/* 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_atomic.h" + +#ifdef USE_ATOMICS_IA32 + +APR_DECLARE(apr_status_t) apr_atomic_init(apr_pool_t *p) +{ + return APR_SUCCESS; +} + +APR_DECLARE(apr_uint32_t) apr_atomic_read32(volatile apr_uint32_t *mem) +{ + return *mem; +} + +APR_DECLARE(void) apr_atomic_set32(volatile apr_uint32_t *mem, apr_uint32_t val) +{ + *mem = val; +} + +APR_DECLARE(apr_uint32_t) apr_atomic_add32(volatile apr_uint32_t *mem, apr_uint32_t val) +{ + asm volatile ("lock; xaddl %0,%1" + : "=r" (val), "=m" (*mem) + : "0" (val), "m" (*mem) + : "memory", "cc"); + return val; +} + +APR_DECLARE(void) apr_atomic_sub32(volatile apr_uint32_t *mem, apr_uint32_t val) +{ + asm volatile ("lock; subl %1, %0" + : /* no output */ + : "m" (*(mem)), "r" (val) + : "memory", "cc"); +} + +APR_DECLARE(apr_uint32_t) apr_atomic_inc32(volatile apr_uint32_t *mem) +{ + return apr_atomic_add32(mem, 1); +} + +APR_DECLARE(int) apr_atomic_dec32(volatile apr_uint32_t *mem) +{ + unsigned char prev; + + asm volatile ("lock; decl %0; setnz %1" + : "=m" (*mem), "=qm" (prev) + : "m" (*mem) + : "memory"); + + return prev; +} + +APR_DECLARE(apr_uint32_t) apr_atomic_cas32(volatile apr_uint32_t *mem, apr_uint32_t with, + apr_uint32_t cmp) +{ + apr_uint32_t prev; + + asm volatile ("lock; cmpxchgl %1, %2" + : "=a" (prev) + : "r" (with), "m" (*(mem)), "0"(cmp) + : "memory", "cc"); + return prev; +} + +APR_DECLARE(apr_uint32_t) apr_atomic_xchg32(volatile apr_uint32_t *mem, apr_uint32_t val) +{ + apr_uint32_t prev = val; + + asm volatile ("xchgl %0, %1" + : "=r" (prev), "+m" (*mem) + : "0" (prev)); + return prev; +} + +APR_DECLARE(void*) apr_atomic_casptr(void *volatile *mem, void *with, const void *cmp) +{ + void *prev; +#if APR_SIZEOF_VOIDP == 4 + asm volatile ("lock; cmpxchgl %2, %1" + : "=a" (prev), "=m" (*mem) + : "r" (with), "m" (*mem), "0" (cmp)); +#elif APR_SIZEOF_VOIDP == 8 + asm volatile ("lock; cmpxchgq %q2, %1" + : "=a" (prev), "=m" (*mem) + : "r" ((unsigned long)with), "m" (*mem), + "0" ((unsigned long)cmp)); +#else +#error APR_SIZEOF_VOIDP value not supported +#endif + return prev; +} + +APR_DECLARE(void*) apr_atomic_xchgptr(void *volatile *mem, void *with) +{ + void *prev; +#if APR_SIZEOF_VOIDP == 4 + asm volatile ("xchgl %2, %1" + : "=a" (prev), "+m" (*mem) + : "0" (with)); +#elif APR_SIZEOF_VOIDP == 8 + asm volatile ("xchgq %q2, %1" + : "=a" (prev), "+m" (*mem) + : "0" (with)); +#else +#error APR_SIZEOF_VOIDP value not supported +#endif + return prev; +} + +#endif /* USE_ATOMICS_IA32 */ diff --git a/atomic/unix/mutex.c b/atomic/unix/mutex.c new file mode 100644 index 00000000000..4ec5451e144 --- /dev/null +++ b/atomic/unix/mutex.c @@ -0,0 +1,205 @@ +/* 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_atomic.h" + +#ifdef USE_ATOMICS_GENERIC + +#include <stdlib.h> + +#if APR_HAS_THREADS +# define DECLARE_MUTEX_LOCKED(name, mem) \ + apr_thread_mutex_t *name = mutex_hash(mem) +# define MUTEX_UNLOCK(name) \ + do { \ + if (apr_thread_mutex_unlock(name) != APR_SUCCESS) \ + abort(); \ + } while (0) +#else +# define DECLARE_MUTEX_LOCKED(name, mem) +# define MUTEX_UNLOCK(name) +# warning Be warned: using stubs for all atomic operations +#endif + +#if APR_HAS_THREADS + +static apr_thread_mutex_t **hash_mutex; + +#define NUM_ATOMIC_HASH 7 +/* shift by 2 to get rid of alignment issues */ +#define ATOMIC_HASH(x) (unsigned int)(((unsigned long)(x)>>2)%(unsigned int)NUM_ATOMIC_HASH) + +static apr_status_t atomic_cleanup(void *data) +{ + if (hash_mutex == data) + hash_mutex = NULL; + + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_atomic_init(apr_pool_t *p) +{ + int i; + apr_status_t rv; + + if (hash_mutex != NULL) + return APR_SUCCESS; + + hash_mutex = apr_palloc(p, sizeof(apr_thread_mutex_t*) * NUM_ATOMIC_HASH); + apr_pool_cleanup_register(p, hash_mutex, atomic_cleanup, + apr_pool_cleanup_null); + + for (i = 0; i < NUM_ATOMIC_HASH; i++) { + rv = apr_thread_mutex_create(&(hash_mutex[i]), + APR_THREAD_MUTEX_DEFAULT, p); + if (rv != APR_SUCCESS) { + return rv; + } + } + + return APR_SUCCESS; +} + +static APR_INLINE apr_thread_mutex_t *mutex_hash(volatile apr_uint32_t *mem) +{ + apr_thread_mutex_t *mutex = hash_mutex[ATOMIC_HASH(mem)]; + + if (apr_thread_mutex_lock(mutex) != APR_SUCCESS) { + abort(); + } + + return mutex; +} + +#else + +APR_DECLARE(apr_status_t) apr_atomic_init(apr_pool_t *p) +{ + return APR_SUCCESS; +} + +#endif /* APR_HAS_THREADS */ + +APR_DECLARE(apr_uint32_t) apr_atomic_read32(volatile apr_uint32_t *mem) +{ + return *mem; +} + +APR_DECLARE(void) apr_atomic_set32(volatile apr_uint32_t *mem, apr_uint32_t val) +{ + DECLARE_MUTEX_LOCKED(mutex, mem); + + *mem = val; + + MUTEX_UNLOCK(mutex); +} + +APR_DECLARE(apr_uint32_t) apr_atomic_add32(volatile apr_uint32_t *mem, apr_uint32_t val) +{ + apr_uint32_t old_value; + DECLARE_MUTEX_LOCKED(mutex, mem); + + old_value = *mem; + *mem += val; + + MUTEX_UNLOCK(mutex); + + return old_value; +} + +APR_DECLARE(void) apr_atomic_sub32(volatile apr_uint32_t *mem, apr_uint32_t val) +{ + DECLARE_MUTEX_LOCKED(mutex, mem); + *mem -= val; + MUTEX_UNLOCK(mutex); +} + +APR_DECLARE(apr_uint32_t) apr_atomic_inc32(volatile apr_uint32_t *mem) +{ + return apr_atomic_add32(mem, 1); +} + +APR_DECLARE(int) apr_atomic_dec32(volatile apr_uint32_t *mem) +{ + apr_uint32_t new; + DECLARE_MUTEX_LOCKED(mutex, mem); + + (*mem)--; + new = *mem; + + MUTEX_UNLOCK(mutex); + + return new; +} + +APR_DECLARE(apr_uint32_t) apr_atomic_cas32(volatile apr_uint32_t *mem, apr_uint32_t with, + apr_uint32_t cmp) +{ + apr_uint32_t prev; + DECLARE_MUTEX_LOCKED(mutex, mem); + + prev = *mem; + if (prev == cmp) { + *mem = with; + } + + MUTEX_UNLOCK(mutex); + + return prev; +} + +APR_DECLARE(apr_uint32_t) apr_atomic_xchg32(volatile apr_uint32_t *mem, apr_uint32_t val) +{ + apr_uint32_t prev; + DECLARE_MUTEX_LOCKED(mutex, mem); + + prev = *mem; + *mem = val; + + MUTEX_UNLOCK(mutex); + + return prev; +} + +APR_DECLARE(void*) apr_atomic_casptr(void *volatile *mem, void *with, const void *cmp) +{ + void *prev; + DECLARE_MUTEX_LOCKED(mutex, *mem); + + prev = *(void **)mem; + if (prev == cmp) { + *mem = with; + } + + MUTEX_UNLOCK(mutex); + + return prev; +} + +APR_DECLARE(void*) apr_atomic_xchgptr(void *volatile *mem, void *with) +{ + void *prev; + DECLARE_MUTEX_LOCKED(mutex, *mem); + + prev = *(void **)mem; + *mem = with; + + MUTEX_UNLOCK(mutex); + + return prev; +} + +#endif /* USE_ATOMICS_GENERIC */ diff --git a/atomic/unix/ppc.c b/atomic/unix/ppc.c new file mode 100644 index 00000000000..87c6900d384 --- /dev/null +++ b/atomic/unix/ppc.c @@ -0,0 +1,207 @@ +/* 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_atomic.h" + +#ifdef USE_ATOMICS_PPC + +#ifdef PPC405_ERRATA +# define PPC405_ERR77_SYNC " sync\n" +#else +# define PPC405_ERR77_SYNC +#endif + +APR_DECLARE(apr_status_t) apr_atomic_init(apr_pool_t *p) +{ + return APR_SUCCESS; +} + +APR_DECLARE(apr_uint32_t) apr_atomic_read32(volatile apr_uint32_t *mem) +{ + return *mem; +} + +APR_DECLARE(void) apr_atomic_set32(volatile apr_uint32_t *mem, apr_uint32_t val) +{ + *mem = val; +} + +APR_DECLARE(apr_uint32_t) apr_atomic_add32(volatile apr_uint32_t *mem, apr_uint32_t val) +{ + apr_uint32_t prev, temp; + + asm volatile ("1:\n" /* lost reservation */ + " lwarx %0,0,%3\n" /* load and reserve */ + " add %1,%0,%4\n" /* add val and prev */ + PPC405_ERR77_SYNC /* ppc405 Erratum 77 */ + " stwcx. %1,0,%3\n" /* store new value */ + " bne- 1b\n" /* loop if lost */ + : "=&r" (prev), "=&r" (temp), "=m" (*mem) + : "b" (mem), "r" (val) + : "cc", "memory"); + + return prev; +} + +APR_DECLARE(void) apr_atomic_sub32(volatile apr_uint32_t *mem, apr_uint32_t val) +{ + apr_uint32_t temp; + + asm volatile ("1:\n" /* lost reservation */ + " lwarx %0,0,%2\n" /* load and reserve */ + " subf %0,%3,%0\n" /* subtract val */ + PPC405_ERR77_SYNC /* ppc405 Erratum 77 */ + " stwcx. %0,0,%2\n" /* store new value */ + " bne- 1b\n" /* loop if lost */ + : "=&r" (temp), "=m" (*mem) + : "b" (mem), "r" (val) + : "cc", "memory"); +} + +APR_DECLARE(apr_uint32_t) apr_atomic_inc32(volatile apr_uint32_t *mem) +{ + apr_uint32_t prev; + + asm volatile ("1:\n" /* lost reservation */ + " lwarx %0,0,%2\n" /* load and reserve */ + " addi %0,%0,1\n" /* add immediate */ + PPC405_ERR77_SYNC /* ppc405 Erratum 77 */ + " stwcx. %0,0,%2\n" /* store new value */ + " bne- 1b\n" /* loop if lost */ + " subi %0,%0,1\n" /* return old value */ + : "=&b" (prev), "=m" (*mem) + : "b" (mem), "m" (*mem) + : "cc", "memory"); + + return prev; +} + +APR_DECLARE(int) apr_atomic_dec32(volatile apr_uint32_t *mem) +{ + apr_uint32_t prev; + + asm volatile ("1:\n" /* lost reservation */ + " lwarx %0,0,%2\n" /* load and reserve */ + " subi %0,%0,1\n" /* subtract immediate */ + PPC405_ERR77_SYNC /* ppc405 Erratum 77 */ + " stwcx. %0,0,%2\n" /* store new value */ + " bne- 1b\n" /* loop if lost */ + : "=&b" (prev), "=m" (*mem) + : "b" (mem), "m" (*mem) + : "cc", "memory"); + + return prev; +} + +APR_DECLARE(apr_uint32_t) apr_atomic_cas32(volatile apr_uint32_t *mem, apr_uint32_t with, + apr_uint32_t cmp) +{ + apr_uint32_t prev; + + asm volatile ("1:\n" /* lost reservation */ + " lwarx %0,0,%1\n" /* load and reserve */ + " cmpw %0,%3\n" /* compare operands */ + " bne- exit_%=\n" /* skip if not equal */ + PPC405_ERR77_SYNC /* ppc405 Erratum 77 */ + " stwcx. %2,0,%1\n" /* store new value */ + " bne- 1b\n" /* loop if lost */ + "exit_%=:\n" /* not equal */ + : "=&r" (prev) + : "b" (mem), "r" (with), "r" (cmp) + : "cc", "memory"); + + return prev; +} + +APR_DECLARE(apr_uint32_t) apr_atomic_xchg32(volatile apr_uint32_t *mem, apr_uint32_t val) +{ + apr_uint32_t prev; + + asm volatile ("1:\n" /* lost reservation */ + " lwarx %0,0,%1\n" /* load and reserve */ + PPC405_ERR77_SYNC /* ppc405 Erratum 77 */ + " stwcx. %2,0,%1\n" /* store new value */ + " bne- 1b" /* loop if lost */ + : "=&r" (prev) + : "b" (mem), "r" (val) + : "cc", "memory"); + + return prev; +} + +APR_DECLARE(void*) apr_atomic_casptr(void *volatile *mem, void *with, const void *cmp) +{ + void *prev; +#if APR_SIZEOF_VOIDP == 4 + asm volatile ("1:\n" /* lost reservation */ + " lwarx %0,0,%1\n" /* load and reserve */ + " cmpw %0,%3\n" /* compare operands */ + " bne- 2f\n" /* skip if not equal */ + PPC405_ERR77_SYNC /* ppc405 Erratum 77 */ + " stwcx. %2,0,%1\n" /* store new value */ + " bne- 1b\n" /* loop if lost */ + "2:\n" /* not equal */ + : "=&r" (prev) + : "b" (mem), "r" (with), "r" (cmp) + : "cc", "memory"); +#elif APR_SIZEOF_VOIDP == 8 + asm volatile ("1:\n" /* lost reservation */ + " ldarx %0,0,%1\n" /* load and reserve */ + " cmpd %0,%3\n" /* compare operands */ + " bne- 2f\n" /* skip if not equal */ + PPC405_ERR77_SYNC /* ppc405 Erratum 77 */ + " stdcx. %2,0,%1\n" /* store new value */ + " bne- 1b\n" /* loop if lost */ + "2:\n" /* not equal */ + : "=&r" (prev) + : "b" (mem), "r" (with), "r" (cmp) + : "cc", "memory"); +#else +#error APR_SIZEOF_VOIDP value not supported +#endif + return prev; +} + +APR_DECLARE(void*) apr_atomic_xchgptr(void *volatile *mem, void *with) +{ + void *prev; +#if APR_SIZEOF_VOIDP == 4 + asm volatile ("1:\n" /* lost reservation */ + " lwarx %0,0,%1\n" /* load and reserve */ + PPC405_ERR77_SYNC /* ppc405 Erratum 77 */ + " stwcx. %2,0,%1\n" /* store new value */ + " bne- 1b\n" /* loop if lost */ + " isync\n" /* memory barrier */ + : "=&r" (prev) + : "b" (mem), "r" (with) + : "cc", "memory"); +#elif APR_SIZEOF_VOIDP == 8 + asm volatile ("1:\n" /* lost reservation */ + " ldarx %0,0,%1\n" /* load and reserve */ + PPC405_ERR77_SYNC /* ppc405 Erratum 77 */ + " stdcx. %2,0,%1\n" /* store new value */ + " bne- 1b\n" /* loop if lost */ + " isync\n" /* memory barrier */ + : "=&r" (prev) + : "b" (mem), "r" (with) + : "cc", "memory"); +#else +#error APR_SIZEOF_VOIDP value not supported +#endif + return prev; +} + +#endif /* USE_ATOMICS_PPC */ diff --git a/atomic/unix/s390.c b/atomic/unix/s390.c new file mode 100644 index 00000000000..cc139b83795 --- /dev/null +++ b/atomic/unix/s390.c @@ -0,0 +1,155 @@ +/* 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_atomic.h" + +#ifdef USE_ATOMICS_S390 + +APR_DECLARE(apr_status_t) apr_atomic_init(apr_pool_t *p) +{ + return APR_SUCCESS; +} + +APR_DECLARE(apr_uint32_t) apr_atomic_read32(volatile apr_uint32_t *mem) +{ + return *mem; +} + +APR_DECLARE(void) apr_atomic_set32(volatile apr_uint32_t *mem, apr_uint32_t val) +{ + *mem = val; +} + +static APR_INLINE apr_uint32_t atomic_add(volatile apr_uint32_t *mem, apr_uint32_t val) +{ + apr_uint32_t prev = *mem, temp; + + asm volatile ("loop_%=:\n" + " lr %1,%0\n" + " alr %1,%3\n" + " cs %0,%1,%2\n" + " jl loop_%=\n" + : "+d" (prev), "+d" (temp), "=Q" (*mem) + : "d" (val), "m" (*mem) + : "cc", "memory"); + + return prev; +} + +APR_DECLARE(apr_uint32_t) apr_atomic_add32(volatile apr_uint32_t *mem, apr_uint32_t val) +{ + return atomic_add(mem, val); +} + +APR_DECLARE(apr_uint32_t) apr_atomic_inc32(volatile apr_uint32_t *mem) +{ + return atomic_add(mem, 1); +} + +static APR_INLINE apr_uint32_t atomic_sub(volatile apr_uint32_t *mem, apr_uint32_t val) +{ + apr_uint32_t prev = *mem, temp; + + asm volatile ("loop_%=:\n" + " lr %1,%0\n" + " slr %1,%3\n" + " cs %0,%1,%2\n" + " jl loop_%=\n" + : "+d" (prev), "+d" (temp), "=Q" (*mem) + : "d" (val), "m" (*mem) + : "cc", "memory"); + + return temp; +} + +APR_DECLARE(void) apr_atomic_sub32(volatile apr_uint32_t *mem, apr_uint32_t val) +{ + atomic_sub(mem, val); +} + +APR_DECLARE(int) apr_atomic_dec32(volatile apr_uint32_t *mem) +{ + return atomic_sub(mem, 1); +} + +APR_DECLARE(apr_uint32_t) apr_atomic_cas32(volatile apr_uint32_t *mem, apr_uint32_t with, + apr_uint32_t cmp) +{ + asm volatile (" cs %0,%2,%1\n" + : "+d" (cmp), "=Q" (*mem) + : "d" (with), "m" (*mem) + : "cc", "memory"); + + return cmp; +} + +APR_DECLARE(apr_uint32_t) apr_atomic_xchg32(volatile apr_uint32_t *mem, apr_uint32_t val) +{ + apr_uint32_t prev = *mem; + + asm volatile ("loop_%=:\n" + " cs %0,%2,%1\n" + " jl loop_%=\n" + : "+d" (prev), "=Q" (*mem) + : "d" (val), "m" (*mem) + : "cc", "memory"); + + return prev; +} + +APR_DECLARE(void*) apr_atomic_casptr(void *volatile *mem, void *with, const void *cmp) +{ + void *prev = (void *) cmp; +#if APR_SIZEOF_VOIDP == 4 + asm volatile (" cs %0,%2,%1\n" + : "+d" (prev), "=Q" (*mem) + : "d" (with), "m" (*mem) + : "cc", "memory"); +#elif APR_SIZEOF_VOIDP == 8 + asm volatile (" csg %0,%2,%1\n" + : "+d" (prev), "=Q" (*mem) + : "d" (with), "m" (*mem) + : "cc", "memory"); +#else +#error APR_SIZEOF_VOIDP value not supported +#endif + return prev; +} + +APR_DECLARE(void*) apr_atomic_xchgptr(void *volatile *mem, void *with) +{ + void *prev = (void *) *mem; +#if APR_SIZEOF_VOIDP == 4 + asm volatile ("loop_%=:\n" + " cs %0,%2,%1\n" + " jl loop_%=\n" + : "+d" (prev), "=Q" (*mem) + : "d" (with), "m" (*mem) + : "cc", "memory"); +#elif APR_SIZEOF_VOIDP == 8 + asm volatile ("loop_%=:\n" + " csg %0,%2,%1\n" + " jl loop_%=\n" + : "+d" (prev), "=Q" (*mem) + : "d" (with), "m" (*mem) + : "cc", "memory"); +#else +#error APR_SIZEOF_VOIDP value not supported +#endif + return prev; +} + +#endif /* USE_ATOMICS_S390 */ diff --git a/atomic/unix/solaris.c b/atomic/unix/solaris.c new file mode 100644 index 00000000000..a160f6808cd --- /dev/null +++ b/atomic/unix/solaris.c @@ -0,0 +1,79 @@ +/* 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_atomic.h" + +#ifdef USE_ATOMICS_SOLARIS + +#include <atomic.h> + +APR_DECLARE(apr_status_t) apr_atomic_init(apr_pool_t *p) +{ + return APR_SUCCESS; +} + +APR_DECLARE(apr_uint32_t) apr_atomic_read32(volatile apr_uint32_t *mem) +{ + return *mem; +} + +APR_DECLARE(void) apr_atomic_set32(volatile apr_uint32_t *mem, apr_uint32_t val) +{ + *mem = val; +} + +APR_DECLARE(apr_uint32_t) apr_atomic_add32(volatile apr_uint32_t *mem, apr_uint32_t val) +{ + return atomic_add_32_nv(mem, val) - val; +} + +APR_DECLARE(void) apr_atomic_sub32(volatile apr_uint32_t *mem, apr_uint32_t val) +{ + atomic_add_32(mem, -val); +} + +APR_DECLARE(apr_uint32_t) apr_atomic_inc32(volatile apr_uint32_t *mem) +{ + return atomic_inc_32_nv(mem) - 1; +} + +APR_DECLARE(int) apr_atomic_dec32(volatile apr_uint32_t *mem) +{ + return atomic_dec_32_nv(mem); +} + +APR_DECLARE(apr_uint32_t) apr_atomic_cas32(volatile apr_uint32_t *mem, apr_uint32_t with, + apr_uint32_t cmp) +{ + return atomic_cas_32(mem, cmp, with); +} + +APR_DECLARE(apr_uint32_t) apr_atomic_xchg32(volatile apr_uint32_t *mem, apr_uint32_t val) +{ + return atomic_swap_32(mem, val); +} + +APR_DECLARE(void*) apr_atomic_casptr(void *volatile *mem, void *with, const void *cmp) +{ + return atomic_cas_ptr(mem, (void*) cmp, with); +} + +APR_DECLARE(void*) apr_atomic_xchgptr(void *volatile *mem, void *with) +{ + return atomic_swap_ptr(mem, with); +} + +#endif /* USE_ATOMICS_SOLARIS */ diff --git a/atomic/win32/apr_atomic.c b/atomic/win32/apr_atomic.c new file mode 100644 index 00000000000..9228d0a3da2 --- /dev/null +++ b/atomic/win32/apr_atomic.c @@ -0,0 +1,113 @@ +/* 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_atomic.h" +#include "apr_thread_mutex.h" + +APR_DECLARE(apr_status_t) apr_atomic_init(apr_pool_t *p) +{ + return APR_SUCCESS; +} + +APR_DECLARE(apr_uint32_t) apr_atomic_add32(volatile apr_uint32_t *mem, apr_uint32_t val) +{ +#if (defined(_M_IA64) || defined(_M_AMD64)) + return InterlockedExchangeAdd(mem, val); +#else + return InterlockedExchangeAdd((long *)mem, val); +#endif +} + +/* Of course we want the 2's compliment of the unsigned value, val */ +#ifdef _MSC_VER +#pragma warning(disable: 4146) +#endif + +APR_DECLARE(void) apr_atomic_sub32(volatile apr_uint32_t *mem, apr_uint32_t val) +{ +#if (defined(_M_IA64) || defined(_M_AMD64)) + InterlockedExchangeAdd(mem, -val); +#else + InterlockedExchangeAdd((long *)mem, -val); +#endif +} + +APR_DECLARE(apr_uint32_t) apr_atomic_inc32(volatile apr_uint32_t *mem) +{ + /* we return old value, win32 returns new value :( */ +#if (defined(_M_IA64) || defined(_M_AMD64)) && !defined(RC_INVOKED) + return InterlockedIncrement(mem) - 1; +#else + return InterlockedIncrement((long *)mem) - 1; +#endif +} + +APR_DECLARE(int) apr_atomic_dec32(volatile apr_uint32_t *mem) +{ +#if (defined(_M_IA64) || defined(_M_AMD64)) && !defined(RC_INVOKED) + return InterlockedDecrement(mem); +#else + return InterlockedDecrement((long *)mem); +#endif +} + +APR_DECLARE(void) apr_atomic_set32(volatile apr_uint32_t *mem, apr_uint32_t val) +{ +#if (defined(_M_IA64) || defined(_M_AMD64)) && !defined(RC_INVOKED) + InterlockedExchange(mem, val); +#else + InterlockedExchange((long*)mem, val); +#endif +} + +APR_DECLARE(apr_uint32_t) apr_atomic_read32(volatile apr_uint32_t *mem) +{ + return *mem; +} + +APR_DECLARE(apr_uint32_t) apr_atomic_cas32(volatile apr_uint32_t *mem, apr_uint32_t with, + apr_uint32_t cmp) +{ +#if (defined(_M_IA64) || defined(_M_AMD64)) && !defined(RC_INVOKED) + return InterlockedCompareExchange(mem, with, cmp); +#else + return InterlockedCompareExchange((long*)mem, with, cmp); +#endif +} + +APR_DECLARE(void *) apr_atomic_casptr(void *volatile *mem, void *with, const void *cmp) +{ +#if (defined(_M_IA64) || defined(_M_AMD64)) && !defined(RC_INVOKED) + return InterlockedCompareExchangePointer(mem, with, (void*)cmp); +#else + return InterlockedCompareExchangePointer((void**)mem, with, (void*)cmp); +#endif +} + +APR_DECLARE(apr_uint32_t) apr_atomic_xchg32(volatile apr_uint32_t *mem, apr_uint32_t val) +{ +#if (defined(_M_IA64) || defined(_M_AMD64)) && !defined(RC_INVOKED) + return InterlockedExchange(mem, val); +#else + return InterlockedExchange((long *)mem, val); +#endif +} + +APR_DECLARE(void*) apr_atomic_xchgptr(void *volatile *mem, void *with) +{ + return InterlockedExchangePointer((void**)mem, with); +} diff --git a/buckets/apr_brigade.c b/buckets/apr_brigade.c new file mode 100644 index 00000000000..42403f4a113 --- /dev/null +++ b/buckets/apr_brigade.c @@ -0,0 +1,762 @@ +/* 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_lib.h" +#include "apr_strings.h" +#include "apr_pools.h" +#include "apr_tables.h" +#include "apr_buckets.h" +#include "apr_errno.h" +#define APR_WANT_MEMFUNC +#define APR_WANT_STRFUNC +#include "apr_want.h" + +#if APR_HAVE_SYS_UIO_H +#include <sys/uio.h> +#endif + +static apr_status_t brigade_cleanup(void *data) +{ + return apr_brigade_cleanup(data); +} + +APR_DECLARE(apr_status_t) apr_brigade_cleanup(void *data) +{ + apr_bucket_brigade *b = data; + apr_bucket *e; + apr_bucket *prev = NULL; + + APR_BRIGADE_CHECK_CONSISTENCY(b); + + while (!APR_BRIGADE_EMPTY(b)) { + e = APR_BRIGADE_FIRST(b); + if (e == prev) { /* PR#51062: prevent infinite loop on a corrupt brigade */ + return APR_EGENERAL; /* FIXME: this should definitely be a "can't happen"! */ + } + prev = e; + apr_bucket_delete(e); + } + /* We don't need to free(bb) because it's allocated from a pool. */ + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_brigade_destroy(apr_bucket_brigade *b) +{ +#ifndef APR_BUCKET_DEBUG + return apr_pool_cleanup_run(b->p, b, brigade_cleanup); +#else + apr_status_t rv; + + APR_BRIGADE_CHECK_CONSISTENCY(b); + + rv = apr_pool_cleanup_run(b->p, b, brigade_cleanup); + + /* Trigger consistency check failures if the brigade is + * re-used. */ + b->p = NULL; + b->bucket_alloc = NULL; + + return rv; +#endif +} + +APR_DECLARE(apr_bucket_brigade *) apr_brigade_create(apr_pool_t *p, + apr_bucket_alloc_t *list) +{ + apr_bucket_brigade *b; + + b = apr_palloc(p, sizeof(*b)); + b->p = p; + b->bucket_alloc = list; + + APR_RING_INIT(&b->list, apr_bucket, link); + + apr_pool_cleanup_register(b->p, b, brigade_cleanup, apr_pool_cleanup_null); + return b; +} + +APR_DECLARE(apr_bucket_brigade *) apr_brigade_split_ex(apr_bucket_brigade *b, + apr_bucket *e, + apr_bucket_brigade *a) +{ + apr_bucket *f; + + if (!a) { + a = apr_brigade_create(b->p, b->bucket_alloc); + } + else if (!APR_BRIGADE_EMPTY(a)) { + apr_brigade_cleanup(a); + } + /* Return an empty brigade if there is nothing left in + * the first brigade to split off + */ + if (e != APR_BRIGADE_SENTINEL(b)) { + f = APR_RING_LAST(&b->list); + APR_RING_UNSPLICE(e, f, link); + APR_RING_SPLICE_HEAD(&a->list, e, f, apr_bucket, link); + } + + APR_BRIGADE_CHECK_CONSISTENCY(a); + APR_BRIGADE_CHECK_CONSISTENCY(b); + + return a; +} + +APR_DECLARE(apr_bucket_brigade *) apr_brigade_split(apr_bucket_brigade *b, + apr_bucket *e) +{ + return apr_brigade_split_ex(b, e, NULL); +} + +APR_DECLARE(apr_status_t) apr_brigade_partition(apr_bucket_brigade *b, + apr_off_t point, + apr_bucket **after_point) +{ + apr_bucket *e; + const char *s; + apr_size_t len; + apr_uint64_t point64; + apr_status_t rv; + + if (point < 0) { + /* this could cause weird (not necessarily SEGV) things to happen */ + return APR_EINVAL; + } + if (point == 0) { + *after_point = APR_BRIGADE_FIRST(b); + return APR_SUCCESS; + } + + /* + * Try to reduce the following casting mess: We know that point will be + * larger equal 0 now and forever and thus that point (apr_off_t) and + * apr_size_t will fit into apr_uint64_t in any case. + */ + point64 = (apr_uint64_t)point; + + APR_BRIGADE_CHECK_CONSISTENCY(b); + + for (e = APR_BRIGADE_FIRST(b); + e != APR_BRIGADE_SENTINEL(b); + e = APR_BUCKET_NEXT(e)) + { + /* For an unknown length bucket, while 'point64' is beyond the possible + * size contained in apr_size_t, read and continue... + */ + if ((e->length == (apr_size_t)(-1)) + && (point64 > (apr_uint64_t)APR_SIZE_MAX)) { + /* point64 is too far out to simply split this bucket, + * we must fix this bucket's size and keep going... */ + rv = apr_bucket_read(e, &s, &len, APR_BLOCK_READ); + if (rv != APR_SUCCESS) { + *after_point = e; + return rv; + } + } + else if ((point64 < (apr_uint64_t)e->length) + || (e->length == (apr_size_t)(-1))) { + /* We already consumed buckets where point64 is beyond + * our interest ( point64 > APR_SIZE_MAX ), above. + * Here point falls between 0 and APR_SIZE_MAX + * and is within this bucket, or this bucket's len + * is undefined, so now we are ready to split it. + * First try to split the bucket natively... */ + if ((rv = apr_bucket_split(e, (apr_size_t)point64)) + != APR_ENOTIMPL) { + *after_point = APR_BUCKET_NEXT(e); + return rv; + } + + /* if the bucket cannot be split, we must read from it, + * changing its type to one that can be split */ + rv = apr_bucket_read(e, &s, &len, APR_BLOCK_READ); + if (rv != APR_SUCCESS) { + *after_point = e; + return rv; + } + + /* this assumes that len == e->length, which is okay because e + * might have been morphed by the apr_bucket_read() above, but + * if it was, the length would have been adjusted appropriately */ + if (point64 < (apr_uint64_t)e->length) { + rv = apr_bucket_split(e, (apr_size_t)point64); + *after_point = APR_BUCKET_NEXT(e); + return rv; + } + } + if (point64 == (apr_uint64_t)e->length) { + *after_point = APR_BUCKET_NEXT(e); + return APR_SUCCESS; + } + point64 -= (apr_uint64_t)e->length; + } + *after_point = APR_BRIGADE_SENTINEL(b); + return APR_INCOMPLETE; +} + +APR_DECLARE(apr_status_t) apr_brigade_length(apr_bucket_brigade *bb, + int read_all, apr_off_t *length) +{ + apr_off_t total = 0; + apr_bucket *bkt; + apr_status_t status = APR_SUCCESS; + + for (bkt = APR_BRIGADE_FIRST(bb); + bkt != APR_BRIGADE_SENTINEL(bb); + bkt = APR_BUCKET_NEXT(bkt)) + { + if (bkt->length == (apr_size_t)(-1)) { + const char *ignore; + apr_size_t len; + + if (!read_all) { + total = -1; + break; + } + + if ((status = apr_bucket_read(bkt, &ignore, &len, + APR_BLOCK_READ)) != APR_SUCCESS) { + break; + } + } + + total += bkt->length; + } + + *length = total; + return status; +} + +APR_DECLARE(apr_status_t) apr_brigade_flatten(apr_bucket_brigade *bb, + char *c, apr_size_t *len) +{ + apr_size_t actual = 0; + apr_bucket *b; + + for (b = APR_BRIGADE_FIRST(bb); + b != APR_BRIGADE_SENTINEL(bb); + b = APR_BUCKET_NEXT(b)) + { + const char *str; + apr_size_t str_len; + apr_status_t status; + + status = apr_bucket_read(b, &str, &str_len, APR_BLOCK_READ); + if (status != APR_SUCCESS) { + return status; + } + + /* If we would overflow. */ + if (str_len + actual > *len) { + str_len = *len - actual; + } + + /* XXX: It appears that overflow of the final bucket + * is DISCARDED without any warning to the caller. + * + * No, we only copy the data up to their requested size. -- jre + */ + memcpy(c, str, str_len); + + c += str_len; + actual += str_len; + + /* This could probably be actual == *len, but be safe from stray + * photons. */ + if (actual >= *len) { + break; + } + } + + *len = actual; + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_brigade_pflatten(apr_bucket_brigade *bb, + char **c, + apr_size_t *len, + apr_pool_t *pool) +{ + apr_off_t actual; + apr_size_t total; + apr_status_t rv; + + apr_brigade_length(bb, 1, &actual); + + /* XXX: This is dangerous beyond belief. At least in the + * apr_brigade_flatten case, the user explicitly stated their + * buffer length - so we don't up and palloc 4GB for a single + * file bucket. This API must grow a useful max boundry, + * either compiled-in or preset via the *len value. + * + * Shouldn't both fn's grow an additional return value for + * the case that the brigade couldn't be flattened into the + * provided or allocated buffer (such as APR_EMOREDATA?) + * Not a failure, simply an advisory result. + */ + total = (apr_size_t)actual; + + *c = apr_palloc(pool, total); + + rv = apr_brigade_flatten(bb, *c, &total); + + if (rv != APR_SUCCESS) { + return rv; + } + + *len = total; + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_brigade_split_line(apr_bucket_brigade *bbOut, + apr_bucket_brigade *bbIn, + apr_read_type_e block, + apr_off_t maxbytes) +{ + apr_off_t readbytes = 0; + apr_bucket *prev = NULL; + + while (!APR_BRIGADE_EMPTY(bbIn)) { + const char *pos; + const char *str; + apr_size_t len; + apr_status_t rv; + apr_bucket *e; + + e = APR_BRIGADE_FIRST(bbIn); + if (e == prev) { /* PR#51062: prevent infinite loop on a corrupt brigade */ + return APR_EGENERAL; /* FIXME: this should definitely be a "can't happen"! */ + } + prev = e; + rv = apr_bucket_read(e, &str, &len, block); + + if (rv != APR_SUCCESS) { + return rv; + } + + pos = memchr(str, APR_ASCII_LF, len); + /* We found a match. */ + if (pos != NULL) { + apr_bucket_split(e, pos - str + 1); + APR_BUCKET_REMOVE(e); + APR_BRIGADE_INSERT_TAIL(bbOut, e); + return APR_SUCCESS; + } + APR_BUCKET_REMOVE(e); + if (APR_BUCKET_IS_METADATA(e) || len > APR_BUCKET_BUFF_SIZE/4) { + APR_BRIGADE_INSERT_TAIL(bbOut, e); + } + else { + if (len > 0) { + rv = apr_brigade_write(bbOut, NULL, NULL, str, len); + if (rv != APR_SUCCESS) { + return rv; + } + } + apr_bucket_destroy(e); + } + readbytes += len; + /* We didn't find an APR_ASCII_LF within the maximum line length. */ + if (readbytes >= maxbytes) { + break; + } + } + + return APR_SUCCESS; +} + + +APR_DECLARE(apr_status_t) apr_brigade_to_iovec(apr_bucket_brigade *b, + struct iovec *vec, int *nvec) +{ + int left = *nvec; + apr_bucket *e; + struct iovec *orig; + apr_size_t iov_len; + const char *iov_base; + apr_status_t rv; + + orig = vec; + + for (e = APR_BRIGADE_FIRST(b); + e != APR_BRIGADE_SENTINEL(b); + e = APR_BUCKET_NEXT(e)) + { + if (left-- == 0) + break; + + rv = apr_bucket_read(e, &iov_base, &iov_len, APR_NONBLOCK_READ); + if (rv != APR_SUCCESS) + return rv; + /* Set indirectly since types differ: */ + vec->iov_len = iov_len; + vec->iov_base = (void *)iov_base; + ++vec; + } + + *nvec = (int)(vec - orig); + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_brigade_vputstrs(apr_bucket_brigade *b, + apr_brigade_flush flush, + void *ctx, + va_list va) +{ +#define MAX_VECS 8 + struct iovec vec[MAX_VECS]; + apr_size_t i = 0; + + for (;;) { + char *str = va_arg(va, char *); + apr_status_t rv; + + if (str == NULL) + break; + + vec[i].iov_base = str; + vec[i].iov_len = strlen(str); + i++; + + if (i == MAX_VECS) { + rv = apr_brigade_writev(b, flush, ctx, vec, i); + if (rv != APR_SUCCESS) + return rv; + i = 0; + } + } + if (i != 0) + return apr_brigade_writev(b, flush, ctx, vec, i); + + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_brigade_putc(apr_bucket_brigade *b, + apr_brigade_flush flush, void *ctx, + const char c) +{ + return apr_brigade_write(b, flush, ctx, &c, 1); +} + +APR_DECLARE(apr_status_t) apr_brigade_write(apr_bucket_brigade *b, + apr_brigade_flush flush, + void *ctx, + const char *str, apr_size_t nbyte) +{ + apr_bucket *e = APR_BRIGADE_LAST(b); + apr_size_t remaining = APR_BUCKET_BUFF_SIZE; + char *buf = NULL; + + /* + * If the last bucket is a heap bucket and its buffer is not shared with + * another bucket, we may write into that bucket. + */ + if (!APR_BRIGADE_EMPTY(b) && APR_BUCKET_IS_HEAP(e) + && ((apr_bucket_heap *)(e->data))->refcount.refcount == 1) { + apr_bucket_heap *h = e->data; + + /* HEAP bucket start offsets are always in-memory, safe to cast */ + remaining = h->alloc_len - (e->length + (apr_size_t)e->start); + buf = h->base + e->start + e->length; + } + + if (nbyte > remaining) { + /* either a buffer bucket exists but is full, + * or no buffer bucket exists and the data is too big + * to buffer. In either case, we should flush. */ + if (flush) { + e = apr_bucket_transient_create(str, nbyte, b->bucket_alloc); + APR_BRIGADE_INSERT_TAIL(b, e); + return flush(b, ctx); + } + else { + e = apr_bucket_heap_create(str, nbyte, NULL, b->bucket_alloc); + APR_BRIGADE_INSERT_TAIL(b, e); + return APR_SUCCESS; + } + } + else if (!buf) { + /* we don't have a buffer, but the data is small enough + * that we don't mind making a new buffer */ + buf = apr_bucket_alloc(APR_BUCKET_BUFF_SIZE, b->bucket_alloc); + e = apr_bucket_heap_create(buf, APR_BUCKET_BUFF_SIZE, + apr_bucket_free, b->bucket_alloc); + APR_BRIGADE_INSERT_TAIL(b, e); + e->length = 0; /* We are writing into the brigade, and + * allocating more memory than we need. This + * ensures that the bucket thinks it is empty just + * after we create it. We'll fix the length + * once we put data in it below. + */ + } + + /* there is a sufficiently big buffer bucket available now */ + memcpy(buf, str, nbyte); + e->length += nbyte; + + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_brigade_writev(apr_bucket_brigade *b, + apr_brigade_flush flush, + void *ctx, + const struct iovec *vec, + apr_size_t nvec) +{ + apr_bucket *e; + apr_size_t total_len; + apr_size_t i; + char *buf; + + /* Compute the total length of the data to be written. + */ + total_len = 0; + for (i = 0; i < nvec; i++) { + total_len += vec[i].iov_len; + } + + /* If the data to be written is very large, try to convert + * the iovec to transient buckets rather than copying. + */ + if (total_len > APR_BUCKET_BUFF_SIZE) { + if (flush) { + for (i = 0; i < nvec; i++) { + e = apr_bucket_transient_create(vec[i].iov_base, + vec[i].iov_len, + b->bucket_alloc); + APR_BRIGADE_INSERT_TAIL(b, e); + } + return flush(b, ctx); + } + else { + for (i = 0; i < nvec; i++) { + e = apr_bucket_heap_create((const char *) vec[i].iov_base, + vec[i].iov_len, NULL, + b->bucket_alloc); + APR_BRIGADE_INSERT_TAIL(b, e); + } + return APR_SUCCESS; + } + } + + i = 0; + + /* If there is a heap bucket at the end of the brigade + * already, and its refcount is 1, copy into the existing bucket. + */ + e = APR_BRIGADE_LAST(b); + if (!APR_BRIGADE_EMPTY(b) && APR_BUCKET_IS_HEAP(e) + && ((apr_bucket_heap *)(e->data))->refcount.refcount == 1) { + apr_bucket_heap *h = e->data; + apr_size_t remaining = h->alloc_len - + (e->length + (apr_size_t)e->start); + buf = h->base + e->start + e->length; + + if (remaining >= total_len) { + /* Simple case: all the data will fit in the + * existing heap bucket + */ + for (; i < nvec; i++) { + apr_size_t len = vec[i].iov_len; + memcpy(buf, (const void *) vec[i].iov_base, len); + buf += len; + } + e->length += total_len; + return APR_SUCCESS; + } + else { + /* More complicated case: not all of the data + * will fit in the existing heap bucket. The + * total data size is <= APR_BUCKET_BUFF_SIZE, + * so we'll need only one additional bucket. + */ + const char *start_buf = buf; + for (; i < nvec; i++) { + apr_size_t len = vec[i].iov_len; + if (len > remaining) { + break; + } + memcpy(buf, (const void *) vec[i].iov_base, len); + buf += len; + remaining -= len; + } + e->length += (buf - start_buf); + total_len -= (buf - start_buf); + + if (flush) { + apr_status_t rv = flush(b, ctx); + if (rv != APR_SUCCESS) { + return rv; + } + } + + /* Now fall through into the case below to + * allocate another heap bucket and copy the + * rest of the array. (Note that i is not + * reset to zero here; it holds the index + * of the first vector element to be + * written to the new bucket.) + */ + } + } + + /* Allocate a new heap bucket, and copy the data into it. + * The checks above ensure that the amount of data to be + * written here is no larger than APR_BUCKET_BUFF_SIZE. + */ + buf = apr_bucket_alloc(APR_BUCKET_BUFF_SIZE, b->bucket_alloc); + e = apr_bucket_heap_create(buf, APR_BUCKET_BUFF_SIZE, + apr_bucket_free, b->bucket_alloc); + for (; i < nvec; i++) { + apr_size_t len = vec[i].iov_len; + memcpy(buf, (const void *) vec[i].iov_base, len); + buf += len; + } + e->length = total_len; + APR_BRIGADE_INSERT_TAIL(b, e); + + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_brigade_puts(apr_bucket_brigade *bb, + apr_brigade_flush flush, void *ctx, + const char *str) +{ + return apr_brigade_write(bb, flush, ctx, str, strlen(str)); +} + +APR_DECLARE_NONSTD(apr_status_t) apr_brigade_putstrs(apr_bucket_brigade *b, + apr_brigade_flush flush, + void *ctx, ...) +{ + va_list va; + apr_status_t rv; + + va_start(va, ctx); + rv = apr_brigade_vputstrs(b, flush, ctx, va); + va_end(va); + return rv; +} + +APR_DECLARE_NONSTD(apr_status_t) apr_brigade_printf(apr_bucket_brigade *b, + apr_brigade_flush flush, + void *ctx, + const char *fmt, ...) +{ + va_list ap; + apr_status_t rv; + + va_start(ap, fmt); + rv = apr_brigade_vprintf(b, flush, ctx, fmt, ap); + va_end(ap); + return rv; +} + +struct brigade_vprintf_data_t { + apr_vformatter_buff_t vbuff; + + apr_bucket_brigade *b; /* associated brigade */ + apr_brigade_flush *flusher; /* flushing function */ + void *ctx; + + char *cbuff; /* buffer to flush from */ +}; + +static apr_status_t brigade_flush(apr_vformatter_buff_t *buff) +{ + /* callback function passed to ap_vformatter to be + * called when vformatter needs to buff and + * buff.curpos > buff.endpos + */ + + /* "downcast," have really passed a brigade_vprintf_data_t* */ + struct brigade_vprintf_data_t *vd = (struct brigade_vprintf_data_t*)buff; + apr_status_t res = APR_SUCCESS; + + res = apr_brigade_write(vd->b, *vd->flusher, vd->ctx, vd->cbuff, + APR_BUCKET_BUFF_SIZE); + + if(res != APR_SUCCESS) { + return -1; + } + + vd->vbuff.curpos = vd->cbuff; + vd->vbuff.endpos = vd->cbuff + APR_BUCKET_BUFF_SIZE; + + return res; +} + +APR_DECLARE(apr_status_t) apr_brigade_vprintf(apr_bucket_brigade *b, + apr_brigade_flush flush, + void *ctx, + const char *fmt, va_list va) +{ + /* the cast, in order of appearance */ + struct brigade_vprintf_data_t vd; + char buf[APR_BUCKET_BUFF_SIZE]; + int written; + + vd.vbuff.curpos = buf; + vd.vbuff.endpos = buf + APR_BUCKET_BUFF_SIZE; + vd.b = b; + vd.flusher = &flush; + vd.ctx = ctx; + vd.cbuff = buf; + + written = apr_vformatter(brigade_flush, &vd.vbuff, fmt, va); + + if (written == -1) { + return -1; + } + + /* write out what remains in the buffer */ + return apr_brigade_write(b, flush, ctx, buf, vd.vbuff.curpos - buf); +} + +/* A "safe" maximum bucket size, 1Gb */ +#define MAX_BUCKET_SIZE (0x40000000) + +APR_DECLARE(apr_bucket *) apr_brigade_insert_file(apr_bucket_brigade *bb, + apr_file_t *f, + apr_off_t start, + apr_off_t length, + apr_pool_t *p) +{ + apr_bucket *e; + + if (sizeof(apr_off_t) == sizeof(apr_size_t) || length < MAX_BUCKET_SIZE) { + e = apr_bucket_file_create(f, start, (apr_size_t)length, p, + bb->bucket_alloc); + } + else { + /* Several buckets are needed. */ + e = apr_bucket_file_create(f, start, MAX_BUCKET_SIZE, p, + bb->bucket_alloc); + + while (length > MAX_BUCKET_SIZE) { + apr_bucket *ce; + apr_bucket_copy(e, &ce); + APR_BRIGADE_INSERT_TAIL(bb, ce); + e->start += MAX_BUCKET_SIZE; + length -= MAX_BUCKET_SIZE; + } + e->length = (apr_size_t)length; /* Resize just the last bucket */ + } + + APR_BRIGADE_INSERT_TAIL(bb, e); + return e; +} diff --git a/buckets/apr_buckets.c b/buckets/apr_buckets.c new file mode 100644 index 00000000000..0c2caa3755b --- /dev/null +++ b/buckets/apr_buckets.c @@ -0,0 +1,46 @@ +/* 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_buckets.h" + +APR_DECLARE_NONSTD(apr_status_t) apr_bucket_setaside_noop(apr_bucket *data, + apr_pool_t *pool) +{ + return APR_SUCCESS; +} + +APR_DECLARE_NONSTD(apr_status_t) apr_bucket_setaside_notimpl(apr_bucket *data, + apr_pool_t *pool) +{ + return APR_ENOTIMPL; +} + +APR_DECLARE_NONSTD(apr_status_t) apr_bucket_split_notimpl(apr_bucket *data, + apr_size_t point) +{ + return APR_ENOTIMPL; +} + +APR_DECLARE_NONSTD(apr_status_t) apr_bucket_copy_notimpl(apr_bucket *e, + apr_bucket **c) +{ + return APR_ENOTIMPL; +} + +APR_DECLARE_NONSTD(void) apr_bucket_destroy_noop(void *data) +{ + return; +} diff --git a/buckets/apr_buckets_alloc.c b/buckets/apr_buckets_alloc.c new file mode 100644 index 00000000000..a2a25d42628 --- /dev/null +++ b/buckets/apr_buckets_alloc.c @@ -0,0 +1,240 @@ +/* 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 <stdlib.h> + +#include "apr_buckets.h" +#include "apr_allocator.h" +#include "apr_support.h" + +#define ALLOC_AMT (8192 - APR_MEMNODE_T_SIZE) + +typedef struct node_header_t { + apr_size_t size; + apr_bucket_alloc_t *alloc; + apr_memnode_t *memnode; + struct node_header_t *next; +} node_header_t; + +#define SIZEOF_NODE_HEADER_T APR_ALIGN_DEFAULT(sizeof(node_header_t)) +#define SMALL_NODE_SIZE (APR_BUCKET_ALLOC_SIZE + SIZEOF_NODE_HEADER_T) + +/** A list of free memory from which new buckets or private bucket + * structures can be allocated. + */ +struct apr_bucket_alloc_t { + apr_pool_t *pool; + apr_allocator_t *allocator; + node_header_t *freelist; + apr_memnode_t *blocks; +}; + +static apr_status_t alloc_cleanup(void *data) +{ + apr_bucket_alloc_t *list = data; +#if APR_POOL_DEBUG + apr_allocator_t *allocator = NULL; +#endif + +#if APR_POOL_DEBUG + if (list->pool && list->allocator != apr_pool_allocator_get(list->pool)) { + allocator = list->allocator; + } +#endif + + apr_allocator_free(list->allocator, list->blocks); + +#if APR_POOL_DEBUG + if (allocator) { + apr_allocator_destroy(allocator); + } +#endif + + return APR_SUCCESS; +} + +APR_DECLARE_NONSTD(apr_bucket_alloc_t *) apr_bucket_alloc_create(apr_pool_t *p) +{ + apr_allocator_t *allocator = apr_pool_allocator_get(p); + apr_bucket_alloc_t *list; + +#if APR_POOL_DEBUG + /* may be NULL for debug mode. */ + if (allocator == NULL) { + if (apr_allocator_create(&allocator) != APR_SUCCESS) { + apr_abortfunc_t fn = apr_pool_abort_get(p); + if (fn) + (fn)(APR_ENOMEM); + abort(); + } + } +#endif + list = apr_bucket_alloc_create_ex(allocator); + if (list == NULL) { + apr_abortfunc_t fn = apr_pool_abort_get(p); + if (fn) + (fn)(APR_ENOMEM); + abort(); + } + list->pool = p; + apr_pool_cleanup_register(list->pool, list, alloc_cleanup, + apr_pool_cleanup_null); + + return list; +} + +APR_DECLARE_NONSTD(apr_bucket_alloc_t *) apr_bucket_alloc_create_ex( + apr_allocator_t *allocator) +{ + apr_bucket_alloc_t *list; + apr_memnode_t *block; + + block = apr_allocator_alloc(allocator, ALLOC_AMT); + if (!block) { + return NULL; + } + list = (apr_bucket_alloc_t *)block->first_avail; + list->pool = NULL; + list->allocator = allocator; + list->freelist = NULL; + list->blocks = block; + block->first_avail += APR_ALIGN_DEFAULT(sizeof(*list)); + APR_VALGRIND_NOACCESS(block->first_avail, + block->endp - block->first_avail); + return list; +} + +APR_DECLARE_NONSTD(void) apr_bucket_alloc_destroy(apr_bucket_alloc_t *list) +{ + if (list->pool) { + apr_pool_cleanup_kill(list->pool, list, alloc_cleanup); + } + + apr_allocator_free(list->allocator, list->blocks); + +#if APR_POOL_DEBUG + if (list->pool && list->allocator != apr_pool_allocator_get(list->pool)) { + apr_allocator_destroy(list->allocator); + } +#endif +} + +APR_DECLARE_NONSTD(apr_size_t) apr_bucket_alloc_aligned_floor(apr_bucket_alloc_t *list, + apr_size_t size) +{ + if (size <= SMALL_NODE_SIZE) { + size = SMALL_NODE_SIZE; + } + else { + if (size < APR_MEMNODE_T_SIZE) { + size = apr_allocator_align(list->allocator, 0); + } + else { + size = apr_allocator_align(list->allocator, + size - APR_MEMNODE_T_SIZE); + } + size -= APR_MEMNODE_T_SIZE; + } + size -= SIZEOF_NODE_HEADER_T; + return size; +} + +APR_DECLARE_NONSTD(void *) apr_bucket_alloc(apr_size_t in_size, + apr_bucket_alloc_t *list) +{ + node_header_t *node; + apr_memnode_t *active = list->blocks; + char *endp; + apr_size_t size; + + size = in_size + SIZEOF_NODE_HEADER_T; + if (size <= SMALL_NODE_SIZE) { + if (list->freelist) { + node = list->freelist; + list->freelist = node->next; + APR_VALGRIND_UNDEFINED((char *)node + SIZEOF_NODE_HEADER_T, + SMALL_NODE_SIZE - SIZEOF_NODE_HEADER_T); + } + else { + endp = active->first_avail + SMALL_NODE_SIZE; + if (endp >= active->endp) { + list->blocks = apr_allocator_alloc(list->allocator, ALLOC_AMT); + if (!list->blocks) { + list->blocks = active; + return NULL; + } + list->blocks->next = active; + active = list->blocks; + endp = active->first_avail + SMALL_NODE_SIZE; + APR_VALGRIND_NOACCESS(active->first_avail, + active->endp - active->first_avail); + } + node = (node_header_t *)active->first_avail; + APR_VALGRIND_UNDEFINED(node, SMALL_NODE_SIZE); + node->alloc = list; + node->memnode = active; + node->size = SMALL_NODE_SIZE; + active->first_avail = endp; + } + } + else { + apr_memnode_t *memnode = apr_allocator_alloc(list->allocator, size); + if (!memnode) { + return NULL; + } + node = (node_header_t *)memnode->first_avail; + node->alloc = list; + node->memnode = memnode; + node->size = size; + } + return ((char *)node) + SIZEOF_NODE_HEADER_T; +} + +#ifdef APR_BUCKET_DEBUG +#if APR_HAVE_STDLIB_H +#include <stdlib.h> +#endif +static void check_not_already_free(node_header_t *node) +{ + apr_bucket_alloc_t *list = node->alloc; + node_header_t *curr = list->freelist; + + while (curr) { + if (node == curr) { + abort(); + } + curr = curr->next; + } +} +#else +#define check_not_already_free(node) +#endif + +APR_DECLARE_NONSTD(void) apr_bucket_free(void *mem) +{ + node_header_t *node = (node_header_t *)((char *)mem - SIZEOF_NODE_HEADER_T); + apr_bucket_alloc_t *list = node->alloc; + + if (node->size == SMALL_NODE_SIZE) { + check_not_already_free(node); + node->next = list->freelist; + list->freelist = node; + APR_VALGRIND_NOACCESS(mem, SMALL_NODE_SIZE - SIZEOF_NODE_HEADER_T); + } + else { + apr_allocator_free(list->allocator, node->memnode); + } +} diff --git a/buckets/apr_buckets_eos.c b/buckets/apr_buckets_eos.c new file mode 100644 index 00000000000..446cd3c23c1 --- /dev/null +++ b/buckets/apr_buckets_eos.c @@ -0,0 +1,54 @@ +/* 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_buckets.h" + +static apr_status_t eos_bucket_read(apr_bucket *b, const char **str, + apr_size_t *len, apr_read_type_e block) +{ + *str = NULL; + *len = 0; + return APR_SUCCESS; +} + +APR_DECLARE(apr_bucket *) apr_bucket_eos_make(apr_bucket *b) +{ + b->length = 0; + b->start = 0; + b->data = NULL; + b->type = &apr_bucket_type_eos; + + return b; +} + +APR_DECLARE(apr_bucket *) apr_bucket_eos_create(apr_bucket_alloc_t *list) +{ + apr_bucket *b = apr_bucket_alloc(sizeof(*b), list); + + APR_BUCKET_INIT(b); + b->free = apr_bucket_free; + b->list = list; + return apr_bucket_eos_make(b); +} + +APR_DECLARE_DATA const apr_bucket_type_t apr_bucket_type_eos = { + "EOS", 5, APR_BUCKET_METADATA, + apr_bucket_destroy_noop, + eos_bucket_read, + apr_bucket_setaside_noop, + apr_bucket_split_notimpl, + apr_bucket_simple_copy +}; diff --git a/buckets/apr_buckets_file.c b/buckets/apr_buckets_file.c new file mode 100644 index 00000000000..82bb2d1721e --- /dev/null +++ b/buckets/apr_buckets_file.c @@ -0,0 +1,242 @@ +/* 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_file_io.h" +#include "apr_buckets.h" + +#if APR_HAS_MMAP +#include "apr_mmap.h" + +/* mmap support for static files based on ideas from John Heidemann's + * patch against 1.0.5. See + * <http://www.isi.edu/~johnh/SOFTWARE/APACHE/index.html>. + */ + +#endif /* APR_HAS_MMAP */ + +static void file_bucket_destroy(void *data) +{ + apr_bucket_file *f = data; + + if (apr_bucket_shared_destroy(f)) { + /* no need to close the file here; it will get + * done automatically when the pool gets cleaned up */ + apr_bucket_free(f); + } +} + +#if APR_HAS_MMAP +static int file_make_mmap(apr_bucket *e, apr_size_t filelength, + apr_off_t fileoffset, apr_pool_t *p) +{ + apr_bucket_file *a = e->data; + apr_mmap_t *mm; + + if (!a->can_mmap) { + return 0; + } + + if (filelength > APR_MMAP_LIMIT) { + if (apr_mmap_create(&mm, a->fd, fileoffset, APR_MMAP_LIMIT, + APR_MMAP_READ, p) != APR_SUCCESS) + { + return 0; + } + apr_bucket_split(e, APR_MMAP_LIMIT); + filelength = APR_MMAP_LIMIT; + } + else if ((filelength < APR_MMAP_THRESHOLD) || + (apr_mmap_create(&mm, a->fd, fileoffset, filelength, + APR_MMAP_READ, p) != APR_SUCCESS)) + { + return 0; + } + apr_bucket_mmap_make(e, mm, 0, filelength); + file_bucket_destroy(a); + return 1; +} +#endif + +static apr_status_t file_bucket_read(apr_bucket *e, const char **str, + apr_size_t *len, apr_read_type_e block) +{ + apr_bucket_file *a = e->data; + apr_file_t *f = a->fd; + apr_bucket *b = NULL; + char *buf; + apr_status_t rv; + apr_size_t filelength = e->length; /* bytes remaining in file past offset */ + apr_off_t fileoffset = e->start; +#if APR_HAS_THREADS && !APR_HAS_XTHREAD_FILES + apr_int32_t flags; +#endif + +#if APR_HAS_MMAP + if (file_make_mmap(e, filelength, fileoffset, a->readpool)) { + return apr_bucket_read(e, str, len, block); + } +#endif + +#if APR_HAS_THREADS && !APR_HAS_XTHREAD_FILES + if ((flags = apr_file_flags_get(f)) & APR_FOPEN_XTHREAD) { + /* this file descriptor is shared across multiple threads and + * this OS doesn't support that natively, so as a workaround + * we must reopen the file into a->readpool */ + const char *fname; + apr_file_name_get(&fname, f); + + rv = apr_file_open(&f, fname, (flags & ~APR_FOPEN_XTHREAD), 0, a->readpool); + if (rv != APR_SUCCESS) + return rv; + + a->fd = f; + } +#endif + + *str = NULL; /* in case we die prematurely */ + *len = (filelength > a->read_size) ? a->read_size : filelength; + buf = apr_bucket_alloc(*len, e->list); + + /* Handle offset ... */ + rv = apr_file_seek(f, APR_SET, &fileoffset); + if (rv != APR_SUCCESS) { + apr_bucket_free(buf); + return rv; + } + rv = apr_file_read(f, buf, len); + if (rv != APR_SUCCESS && rv != APR_EOF) { + apr_bucket_free(buf); + return rv; + } + filelength -= *len; + /* + * Change the current bucket to refer to what we read, + * even if we read nothing because we hit EOF. + */ + apr_bucket_heap_make(e, buf, *len, apr_bucket_free); + + /* If we have more to read from the file, then create another bucket */ + if (filelength > 0 && rv != APR_EOF) { + /* for efficiency, we can just build a new apr_bucket struct + * to wrap around the existing file bucket */ + b = apr_bucket_alloc(sizeof(*b), e->list); + b->start = fileoffset + (*len); + b->length = filelength; + b->data = a; + b->type = &apr_bucket_type_file; + b->free = apr_bucket_free; + b->list = e->list; + APR_BUCKET_INSERT_AFTER(e, b); + } + else { + file_bucket_destroy(a); + } + + *str = buf; + return rv; +} + +APR_DECLARE(apr_bucket *) apr_bucket_file_make(apr_bucket *b, apr_file_t *fd, + apr_off_t offset, + apr_size_t len, apr_pool_t *p) +{ + apr_bucket_file *f; + + f = apr_bucket_alloc(sizeof(*f), b->list); + f->fd = fd; + f->readpool = p; +#if APR_HAS_MMAP + f->can_mmap = 1; +#endif + f->read_size = APR_BUCKET_BUFF_SIZE; + + b = apr_bucket_shared_make(b, f, offset, len); + b->type = &apr_bucket_type_file; + + return b; +} + +APR_DECLARE(apr_bucket *) apr_bucket_file_create(apr_file_t *fd, + apr_off_t offset, + apr_size_t len, apr_pool_t *p, + apr_bucket_alloc_t *list) +{ + apr_bucket *b = apr_bucket_alloc(sizeof(*b), list); + + APR_BUCKET_INIT(b); + b->free = apr_bucket_free; + b->list = list; + return apr_bucket_file_make(b, fd, offset, len, p); +} + +APR_DECLARE(apr_status_t) apr_bucket_file_enable_mmap(apr_bucket *e, + int enabled) +{ +#if APR_HAS_MMAP + apr_bucket_file *a = e->data; + a->can_mmap = enabled; + return APR_SUCCESS; +#else + return APR_ENOTIMPL; +#endif /* APR_HAS_MMAP */ +} + +APR_DECLARE(apr_status_t) apr_bucket_file_set_buf_size(apr_bucket *e, + apr_size_t size) +{ + apr_bucket_file *a = e->data; + + if (size <= APR_BUCKET_BUFF_SIZE) { + a->read_size = APR_BUCKET_BUFF_SIZE; + } + else { + apr_size_t floor = apr_bucket_alloc_aligned_floor(e->list, size); + a->read_size = (size < floor) ? size : floor; + } + + return APR_SUCCESS; +} + +static apr_status_t file_bucket_setaside(apr_bucket *data, apr_pool_t *reqpool) +{ + apr_bucket_file *a = data->data; + apr_file_t *fd = NULL; + apr_file_t *f = a->fd; + apr_pool_t *curpool = apr_file_pool_get(f); + + if (apr_pool_is_ancestor(curpool, reqpool)) { + return APR_SUCCESS; + } + + if (!apr_pool_is_ancestor(a->readpool, reqpool)) { + a->readpool = reqpool; + } + + apr_file_setaside(&fd, f, reqpool); + a->fd = fd; + return APR_SUCCESS; +} + +APR_DECLARE_DATA const apr_bucket_type_t apr_bucket_type_file = { + "FILE", 5, APR_BUCKET_DATA, + file_bucket_destroy, + file_bucket_read, + file_bucket_setaside, + apr_bucket_shared_split, + apr_bucket_shared_copy +}; diff --git a/buckets/apr_buckets_flush.c b/buckets/apr_buckets_flush.c new file mode 100644 index 00000000000..dbb4fb9ba04 --- /dev/null +++ b/buckets/apr_buckets_flush.c @@ -0,0 +1,54 @@ +/* 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_buckets.h" + +static apr_status_t flush_bucket_read(apr_bucket *b, const char **str, + apr_size_t *len, apr_read_type_e block) +{ + *str = NULL; + *len = 0; + return APR_SUCCESS; +} + +APR_DECLARE(apr_bucket *) apr_bucket_flush_make(apr_bucket *b) +{ + b->length = 0; + b->start = 0; + b->data = NULL; + b->type = &apr_bucket_type_flush; + + return b; +} + +APR_DECLARE(apr_bucket *) apr_bucket_flush_create(apr_bucket_alloc_t *list) +{ + apr_bucket *b = apr_bucket_alloc(sizeof(*b), list); + + APR_BUCKET_INIT(b); + b->free = apr_bucket_free; + b->list = list; + return apr_bucket_flush_make(b); +} + +APR_DECLARE_DATA const apr_bucket_type_t apr_bucket_type_flush = { + "FLUSH", 5, APR_BUCKET_METADATA, + apr_bucket_destroy_noop, + flush_bucket_read, + apr_bucket_setaside_noop, + apr_bucket_split_notimpl, + apr_bucket_simple_copy +}; diff --git a/buckets/apr_buckets_heap.c b/buckets/apr_buckets_heap.c new file mode 100644 index 00000000000..7405d2caffc --- /dev/null +++ b/buckets/apr_buckets_heap.c @@ -0,0 +1,96 @@ +/* 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_buckets.h" +#define APR_WANT_MEMFUNC +#include "apr_want.h" + +static apr_status_t heap_bucket_read(apr_bucket *b, const char **str, + apr_size_t *len, apr_read_type_e block) +{ + apr_bucket_heap *h = b->data; + + *str = h->base + b->start; + *len = b->length; + return APR_SUCCESS; +} + +static void heap_bucket_destroy(void *data) +{ + apr_bucket_heap *h = data; + + if (apr_bucket_shared_destroy(h)) { + (*h->free_func)(h->base); + apr_bucket_free(h); + } +} + +/* Warning: if you change this function, be sure to + * change apr_bucket_pool_make() too! */ +APR_DECLARE(apr_bucket *) apr_bucket_heap_make(apr_bucket *b, const char *buf, + apr_size_t length, + void (*free_func)(void *data)) +{ + apr_bucket_heap *h; + + h = apr_bucket_alloc(sizeof(*h), b->list); + + if (!free_func) { + h->alloc_len = length; + h->base = apr_bucket_alloc(h->alloc_len, b->list); + if (h->base == NULL) { + apr_bucket_free(h); + return NULL; + } + h->free_func = apr_bucket_free; + memcpy(h->base, buf, length); + } + else { + /* XXX: we lose the const qualifier here which indicates + * there's something screwy with the API... + */ + h->base = (char *) buf; + h->alloc_len = length; + h->free_func = free_func; + } + + b = apr_bucket_shared_make(b, h, 0, length); + b->type = &apr_bucket_type_heap; + + return b; +} + +APR_DECLARE(apr_bucket *) apr_bucket_heap_create(const char *buf, + apr_size_t length, + void (*free_func)(void *data), + apr_bucket_alloc_t *list) +{ + apr_bucket *b = apr_bucket_alloc(sizeof(*b), list); + + APR_BUCKET_INIT(b); + b->free = apr_bucket_free; + b->list = list; + return apr_bucket_heap_make(b, buf, length, free_func); +} + +APR_DECLARE_DATA const apr_bucket_type_t apr_bucket_type_heap = { + "HEAP", 5, APR_BUCKET_DATA, + heap_bucket_destroy, + heap_bucket_read, + apr_bucket_setaside_noop, + apr_bucket_shared_split, + apr_bucket_shared_copy +}; diff --git a/buckets/apr_buckets_mmap.c b/buckets/apr_buckets_mmap.c new file mode 100644 index 00000000000..116b7886811 --- /dev/null +++ b/buckets/apr_buckets_mmap.c @@ -0,0 +1,144 @@ +/* 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_buckets.h" + +#if APR_HAS_MMAP + +static apr_status_t mmap_bucket_read(apr_bucket *b, const char **str, + apr_size_t *length, apr_read_type_e block) +{ + apr_bucket_mmap *m = b->data; + apr_status_t ok; + void *addr; + + if (!m->mmap) { + /* the apr_mmap_t was already cleaned up out from under us */ + return APR_EINVAL; + } + + ok = apr_mmap_offset(&addr, m->mmap, b->start); + if (ok != APR_SUCCESS) { + return ok; + } + *str = addr; + *length = b->length; + return APR_SUCCESS; +} + +static apr_status_t mmap_bucket_cleanup(void *data) +{ + /* the apr_mmap_t is about to disappear out from under us, so we + * have no choice but to pretend it doesn't exist anymore. the + * refcount is now useless because there's nothing to refer to + * anymore. so the only valid action on any remaining referrer + * is to delete it. no more reads, no more anything. */ + apr_bucket_mmap *m = data; + + m->mmap = NULL; + return APR_SUCCESS; +} + +static void mmap_bucket_destroy(void *data) +{ + apr_bucket_mmap *m = data; + + if (apr_bucket_shared_destroy(m)) { + if (m->mmap) { + apr_pool_cleanup_kill(m->mmap->cntxt, m, mmap_bucket_cleanup); + apr_mmap_delete(m->mmap); + } + apr_bucket_free(m); + } +} + +/* + * XXX: are the start and length arguments useful? + */ +APR_DECLARE(apr_bucket *) apr_bucket_mmap_make(apr_bucket *b, apr_mmap_t *mm, + apr_off_t start, + apr_size_t length) +{ + apr_bucket_mmap *m; + + m = apr_bucket_alloc(sizeof(*m), b->list); + m->mmap = mm; + + apr_pool_cleanup_register(mm->cntxt, m, mmap_bucket_cleanup, + apr_pool_cleanup_null); + + b = apr_bucket_shared_make(b, m, start, length); + b->type = &apr_bucket_type_mmap; + + return b; +} + + +APR_DECLARE(apr_bucket *) apr_bucket_mmap_create(apr_mmap_t *mm, + apr_off_t start, + apr_size_t length, + apr_bucket_alloc_t *list) +{ + apr_bucket *b = apr_bucket_alloc(sizeof(*b), list); + + APR_BUCKET_INIT(b); + b->free = apr_bucket_free; + b->list = list; + return apr_bucket_mmap_make(b, mm, start, length); +} + +static apr_status_t mmap_bucket_setaside(apr_bucket *b, apr_pool_t *p) +{ + apr_bucket_mmap *m = b->data; + apr_mmap_t *mm = m->mmap; + apr_mmap_t *new_mm; + apr_status_t ok; + + if (!mm) { + /* the apr_mmap_t was already cleaned up out from under us */ + return APR_EINVAL; + } + + /* shortcut if possible */ + if (apr_pool_is_ancestor(mm->cntxt, p)) { + return APR_SUCCESS; + } + + /* duplicate apr_mmap_t into new pool */ + ok = apr_mmap_dup(&new_mm, mm, p); + if (ok != APR_SUCCESS) { + return ok; + } + + /* decrement refcount on old apr_bucket_mmap */ + mmap_bucket_destroy(m); + + /* create new apr_bucket_mmap pointing to new apr_mmap_t */ + apr_bucket_mmap_make(b, new_mm, b->start, b->length); + + return APR_SUCCESS; +} + +APR_DECLARE_DATA const apr_bucket_type_t apr_bucket_type_mmap = { + "MMAP", 5, APR_BUCKET_DATA, + mmap_bucket_destroy, + mmap_bucket_read, + mmap_bucket_setaside, + apr_bucket_shared_split, + apr_bucket_shared_copy +}; + +#endif diff --git a/buckets/apr_buckets_pipe.c b/buckets/apr_buckets_pipe.c new file mode 100644 index 00000000000..574610b02d7 --- /dev/null +++ b/buckets/apr_buckets_pipe.c @@ -0,0 +1,119 @@ +/* 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_buckets.h" + +static apr_status_t pipe_bucket_read(apr_bucket *a, const char **str, + apr_size_t *len, apr_read_type_e block) +{ + apr_file_t *p = a->data; + char *buf; + apr_status_t rv; + apr_interval_time_t timeout; + + if (block == APR_NONBLOCK_READ) { + apr_file_pipe_timeout_get(p, &timeout); + apr_file_pipe_timeout_set(p, 0); + } + + *str = NULL; + *len = APR_BUCKET_BUFF_SIZE; + buf = apr_bucket_alloc(*len, a->list); /* XXX: check for failure? */ + + rv = apr_file_read(p, buf, len); + + if (block == APR_NONBLOCK_READ) { + apr_file_pipe_timeout_set(p, timeout); + } + + if (rv != APR_SUCCESS && rv != APR_EOF) { + apr_bucket_free(buf); + return rv; + } + /* + * If there's more to read we have to keep the rest of the pipe + * for later. Otherwise, we'll close the pipe. + * XXX: Note that more complicated bucket types that + * refer to data not in memory and must therefore have a read() + * function similar to this one should be wary of copying this + * code because if they have a destroy function they probably + * want to migrate the bucket's subordinate structure from the + * old bucket to a raw new one and adjust it as appropriate, + * rather than destroying the old one and creating a completely + * new bucket. + */ + if (*len > 0) { + apr_bucket_heap *h; + /* Change the current bucket to refer to what we read */ + a = apr_bucket_heap_make(a, buf, *len, apr_bucket_free); + h = a->data; + h->alloc_len = APR_BUCKET_BUFF_SIZE; /* note the real buffer size */ + *str = buf; + APR_BUCKET_INSERT_AFTER(a, apr_bucket_pipe_create(p, a->list)); + } + else { + apr_bucket_free(buf); + a = apr_bucket_immortal_make(a, "", 0); + *str = a->data; + if (rv == APR_EOF) { + apr_file_close(p); + } + } + return APR_SUCCESS; +} + +APR_DECLARE(apr_bucket *) apr_bucket_pipe_make(apr_bucket *b, apr_file_t *p) +{ + /* + * A pipe is closed when the end is reached in pipe_bucket_read(). If + * the pipe isn't read to the end (e.g., error path), the pipe will be + * closed when its pool goes away. + * + * Note that typically the pipe is allocated from the request pool + * so it will disappear when the request is finished. However the + * core filter may decide to set aside the tail end of a CGI + * response if the connection is pipelined. This turns out not to + * be a problem because the core will have read to the end of the + * stream so the bucket(s) that it sets aside will be the heap + * buckets created by pipe_bucket_read() above. + */ + b->type = &apr_bucket_type_pipe; + b->length = (apr_size_t)(-1); + b->start = -1; + b->data = p; + + return b; +} + +APR_DECLARE(apr_bucket *) apr_bucket_pipe_create(apr_file_t *p, + apr_bucket_alloc_t *list) +{ + apr_bucket *b = apr_bucket_alloc(sizeof(*b), list); + + APR_BUCKET_INIT(b); + b->free = apr_bucket_free; + b->list = list; + return apr_bucket_pipe_make(b, p); +} + +APR_DECLARE_DATA const apr_bucket_type_t apr_bucket_type_pipe = { + "PIPE", 5, APR_BUCKET_DATA, + apr_bucket_destroy_noop, + pipe_bucket_read, + apr_bucket_setaside_notimpl, + apr_bucket_split_notimpl, + apr_bucket_copy_notimpl +}; diff --git a/buckets/apr_buckets_pool.c b/buckets/apr_buckets_pool.c new file mode 100644 index 00000000000..da6029072e0 --- /dev/null +++ b/buckets/apr_buckets_pool.c @@ -0,0 +1,142 @@ +/* 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_buckets.h" +#define APR_WANT_MEMFUNC +#include "apr_want.h" + +static apr_status_t pool_bucket_cleanup(void *data) +{ + apr_bucket_pool *p = data; + + /* + * If the pool gets cleaned up, we have to copy the data out + * of the pool and onto the heap. But the apr_buckets out there + * that point to this pool bucket need to be notified such that + * they can morph themselves into a regular heap bucket the next + * time they try to read. To avoid having to manipulate + * reference counts and b->data pointers, the apr_bucket_pool + * actually _contains_ an apr_bucket_heap as its first element, + * so the two share their apr_bucket_refcount member, and you + * can typecast a pool bucket struct to make it look like a + * regular old heap bucket struct. + */ + p->heap.base = apr_bucket_alloc(p->heap.alloc_len, p->list); + memcpy(p->heap.base, p->base, p->heap.alloc_len); + p->base = NULL; + p->pool = NULL; + + return APR_SUCCESS; +} + +static apr_status_t pool_bucket_read(apr_bucket *b, const char **str, + apr_size_t *len, apr_read_type_e block) +{ + apr_bucket_pool *p = b->data; + const char *base = p->base; + + if (p->pool == NULL) { + /* + * pool has been cleaned up... masquerade as a heap bucket from now + * on. subsequent bucket operations will use the heap bucket code. + */ + b->type = &apr_bucket_type_heap; + base = p->heap.base; + } + *str = base + b->start; + *len = b->length; + return APR_SUCCESS; +} + +static void pool_bucket_destroy(void *data) +{ + apr_bucket_pool *p = data; + + /* If the pool is cleaned up before the last reference goes + * away, the data is really now on the heap; heap_destroy() takes + * over. free() in heap_destroy() thinks it's freeing + * an apr_bucket_heap, when in reality it's freeing the whole + * apr_bucket_pool for us. + */ + if (p->pool) { + /* the shared resource is still in the pool + * because the pool has not been cleaned up yet + */ + if (apr_bucket_shared_destroy(p)) { + apr_pool_cleanup_kill(p->pool, p, pool_bucket_cleanup); + apr_bucket_free(p); + } + } + else { + /* the shared resource is no longer in the pool, it's + * on the heap, but this reference still thinks it's a pool + * bucket. we should just go ahead and pass control to + * heap_destroy() for it since it doesn't know any better. + */ + apr_bucket_type_heap.destroy(p); + } +} + +APR_DECLARE(apr_bucket *) apr_bucket_pool_make(apr_bucket *b, + const char *buf, apr_size_t length, apr_pool_t *pool) +{ + apr_bucket_pool *p; + + p = apr_bucket_alloc(sizeof(*p), b->list); + + /* XXX: we lose the const qualifier here which indicates + * there's something screwy with the API... + */ + /* XXX: why is this? buf is const, p->base is const... what's + * the problem? --jcw */ + p->base = (char *) buf; + p->pool = pool; + p->list = b->list; + + b = apr_bucket_shared_make(b, p, 0, length); + b->type = &apr_bucket_type_pool; + + /* pre-initialize heap bucket member */ + p->heap.alloc_len = length; + p->heap.base = NULL; + p->heap.free_func = apr_bucket_free; + + apr_pool_cleanup_register(p->pool, p, pool_bucket_cleanup, + apr_pool_cleanup_null); + return b; +} + +APR_DECLARE(apr_bucket *) apr_bucket_pool_create(const char *buf, + apr_size_t length, + apr_pool_t *pool, + apr_bucket_alloc_t *list) +{ + apr_bucket *b = apr_bucket_alloc(sizeof(*b), list); + + APR_BUCKET_INIT(b); + b->free = apr_bucket_free; + b->list = list; + return apr_bucket_pool_make(b, buf, length, pool); +} + +APR_DECLARE_DATA const apr_bucket_type_t apr_bucket_type_pool = { + "POOL", 5, APR_BUCKET_DATA, + pool_bucket_destroy, + pool_bucket_read, + apr_bucket_setaside_noop, /* don't need to setaside thanks to the cleanup*/ + apr_bucket_shared_split, + apr_bucket_shared_copy +}; diff --git a/buckets/apr_buckets_refcount.c b/buckets/apr_buckets_refcount.c new file mode 100644 index 00000000000..b1b57897bce --- /dev/null +++ b/buckets/apr_buckets_refcount.c @@ -0,0 +1,64 @@ +/* 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_buckets.h" + +APR_DECLARE_NONSTD(apr_status_t) apr_bucket_shared_split(apr_bucket *a, + apr_size_t point) +{ + apr_bucket_refcount *r = a->data; + apr_status_t rv; + + if ((rv = apr_bucket_simple_split(a, point)) != APR_SUCCESS) { + return rv; + } + r->refcount++; + + return APR_SUCCESS; +} + +APR_DECLARE_NONSTD(apr_status_t) apr_bucket_shared_copy(apr_bucket *a, + apr_bucket **b) +{ + apr_bucket_refcount *r = a->data; + + apr_bucket_simple_copy(a, b); + r->refcount++; + + return APR_SUCCESS; +} + +APR_DECLARE(int) apr_bucket_shared_destroy(void *data) +{ + apr_bucket_refcount *r = data; + r->refcount--; + return (r->refcount == 0); +} + +APR_DECLARE(apr_bucket *) apr_bucket_shared_make(apr_bucket *b, void *data, + apr_off_t start, + apr_size_t length) +{ + apr_bucket_refcount *r = data; + + b->data = r; + b->start = start; + b->length = length; + /* caller initializes the type field */ + r->refcount = 1; + + return b; +} diff --git a/buckets/apr_buckets_simple.c b/buckets/apr_buckets_simple.c new file mode 100644 index 00000000000..14f11ba7d80 --- /dev/null +++ b/buckets/apr_buckets_simple.c @@ -0,0 +1,137 @@ +/* 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_buckets.h" + +APR_DECLARE_NONSTD(apr_status_t) apr_bucket_simple_copy(apr_bucket *a, + apr_bucket **b) +{ + *b = apr_bucket_alloc(sizeof(**b), a->list); /* XXX: check for failure? */ + **b = *a; + + return APR_SUCCESS; +} + +APR_DECLARE_NONSTD(apr_status_t) apr_bucket_simple_split(apr_bucket *a, + apr_size_t point) +{ + apr_bucket *b; + + if (point > a->length) { + return APR_EINVAL; + } + + apr_bucket_simple_copy(a, &b); + + a->length = point; + b->length -= point; + b->start += point; + + APR_BUCKET_INSERT_AFTER(a, b); + + return APR_SUCCESS; +} + +static apr_status_t simple_bucket_read(apr_bucket *b, const char **str, + apr_size_t *len, apr_read_type_e block) +{ + *str = (char *)b->data + b->start; + *len = b->length; + return APR_SUCCESS; +} + +APR_DECLARE(apr_bucket *) apr_bucket_immortal_make(apr_bucket *b, + const char *buf, + apr_size_t length) +{ + b->data = (char *)buf; + b->length = length; + b->start = 0; + b->type = &apr_bucket_type_immortal; + + return b; +} + +APR_DECLARE(apr_bucket *) apr_bucket_immortal_create(const char *buf, + apr_size_t length, + apr_bucket_alloc_t *list) +{ + apr_bucket *b = apr_bucket_alloc(sizeof(*b), list); + + APR_BUCKET_INIT(b); + b->free = apr_bucket_free; + b->list = list; + return apr_bucket_immortal_make(b, buf, length); +} + +/* + * XXX: This function could do with some tweaking to reduce memory + * usage in various cases, e.g. share buffers in the heap between all + * the buckets that are set aside, or even spool set-aside data to + * disk if it gets too voluminous (but if it does then that's probably + * a bug elsewhere). There should probably be a apr_brigade_setaside() + * function that co-ordinates the action of all the bucket setaside + * functions to improve memory efficiency. + */ +static apr_status_t transient_bucket_setaside(apr_bucket *b, apr_pool_t *pool) +{ + b = apr_bucket_heap_make(b, (char *)b->data + b->start, b->length, NULL); + if (b == NULL) { + return APR_ENOMEM; + } + return APR_SUCCESS; +} + +APR_DECLARE(apr_bucket *) apr_bucket_transient_make(apr_bucket *b, + const char *buf, + apr_size_t length) +{ + b->data = (char *)buf; + b->length = length; + b->start = 0; + b->type = &apr_bucket_type_transient; + return b; +} + +APR_DECLARE(apr_bucket *) apr_bucket_transient_create(const char *buf, + apr_size_t length, + apr_bucket_alloc_t *list) +{ + apr_bucket *b = apr_bucket_alloc(sizeof(*b), list); + + APR_BUCKET_INIT(b); + b->free = apr_bucket_free; + b->list = list; + return apr_bucket_transient_make(b, buf, length); +} + +const apr_bucket_type_t apr_bucket_type_immortal = { + "IMMORTAL", 5, APR_BUCKET_DATA, + apr_bucket_destroy_noop, + simple_bucket_read, + apr_bucket_setaside_noop, + apr_bucket_simple_split, + apr_bucket_simple_copy +}; + +APR_DECLARE_DATA const apr_bucket_type_t apr_bucket_type_transient = { + "TRANSIENT", 5, APR_BUCKET_DATA, + apr_bucket_destroy_noop, + simple_bucket_read, + transient_bucket_setaside, + apr_bucket_simple_split, + apr_bucket_simple_copy +}; diff --git a/buckets/apr_buckets_socket.c b/buckets/apr_buckets_socket.c new file mode 100644 index 00000000000..5563049622a --- /dev/null +++ b/buckets/apr_buckets_socket.c @@ -0,0 +1,114 @@ +/* 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_buckets.h" + +static apr_status_t socket_bucket_read(apr_bucket *a, const char **str, + apr_size_t *len, apr_read_type_e block) +{ + apr_socket_t *p = a->data; + char *buf; + apr_status_t rv; + apr_interval_time_t timeout; + + if (block == APR_NONBLOCK_READ) { + apr_socket_timeout_get(p, &timeout); + apr_socket_timeout_set(p, 0); + } + + *str = NULL; + *len = APR_BUCKET_BUFF_SIZE; + buf = apr_bucket_alloc(*len, a->list); /* XXX: check for failure? */ + + rv = apr_socket_recv(p, buf, len); + + if (block == APR_NONBLOCK_READ) { + apr_socket_timeout_set(p, timeout); + } + + if (rv != APR_SUCCESS && rv != APR_EOF) { + apr_bucket_free(buf); + return rv; + } + /* + * If there's more to read we have to keep the rest of the socket + * for later. XXX: Note that more complicated bucket types that + * refer to data not in memory and must therefore have a read() + * function similar to this one should be wary of copying this + * code because if they have a destroy function they probably + * want to migrate the bucket's subordinate structure from the + * old bucket to a raw new one and adjust it as appropriate, + * rather than destroying the old one and creating a completely + * new bucket. + * + * Even if there is nothing more to read, don't close the socket here + * as we have to use it to send any response :) We could shut it + * down for reading, but there is no benefit to doing so. + */ + if (*len > 0) { + apr_bucket_heap *h; + /* Change the current bucket to refer to what we read */ + a = apr_bucket_heap_make(a, buf, *len, apr_bucket_free); + h = a->data; + h->alloc_len = APR_BUCKET_BUFF_SIZE; /* note the real buffer size */ + *str = buf; + APR_BUCKET_INSERT_AFTER(a, apr_bucket_socket_create(p, a->list)); + } + else { + apr_bucket_free(buf); + a = apr_bucket_immortal_make(a, "", 0); + *str = a->data; + } + return APR_SUCCESS; +} + +APR_DECLARE(apr_bucket *) apr_bucket_socket_make(apr_bucket *b, apr_socket_t *p) +{ + /* + * XXX: We rely on a cleanup on some pool or other to actually + * destroy the socket. We should probably explicitly call apr to + * destroy it instead. + * + * Note that typically the socket is allocated from the connection pool + * so it will disappear when the connection is finished. + */ + b->type = &apr_bucket_type_socket; + b->length = (apr_size_t)(-1); + b->start = -1; + b->data = p; + + return b; +} + +APR_DECLARE(apr_bucket *) apr_bucket_socket_create(apr_socket_t *p, + apr_bucket_alloc_t *list) +{ + apr_bucket *b = apr_bucket_alloc(sizeof(*b), list); + + APR_BUCKET_INIT(b); + b->free = apr_bucket_free; + b->list = list; + return apr_bucket_socket_make(b, p); +} + +APR_DECLARE_DATA const apr_bucket_type_t apr_bucket_type_socket = { + "SOCKET", 5, APR_BUCKET_DATA, + apr_bucket_destroy_noop, + socket_bucket_read, + apr_bucket_setaside_notimpl, + apr_bucket_split_notimpl, + apr_bucket_copy_notimpl +}; diff --git a/build.conf b/build.conf new file mode 100644 index 00000000000..d01fd1dc627 --- /dev/null +++ b/build.conf @@ -0,0 +1,112 @@ +# +# Configuration file for APR. Used by APR/build/gen-build.py +# + +[options] + +# paths to platform-independent .c files to build +paths = + passwd/*.c + strings/*.c + tables/*.c + buckets/*.c + crypto/apr_crypto.c + crypto/apr_md4.c + crypto/apr_md5.c + crypto/apr_passwd.c + crypto/apr_sha1.c + crypto/apr_siphash.c + crypto/getuuid.c + crypto/uuid.c + crypto/crypt_blowfish.c + dbm/apr_dbm_sdbm.c + dbm/apr_dbm.c + dbm/sdbm/*.c + encoding/*.c + hooks/*.c + misc/*.c + memcache/*.c + redis/*.c + uri/apr_uri.c + xml/*.c + strmatch/*.c + xlate/*.c + dbd/apr_dbd.c + util-misc/*.c + + +# directories that have platform-specific code in them. the resulting +# pattern will be: SUBDIR/PLATFORM/*.c +platform_dirs = + dso file_io locks memory misc mmap network_io poll random + shmem support threadproc time user atomic + +# all the public headers +headers = include/*.h + +# aplibtool is manually built by the configure process +# build/aplibtool.c + +# we have a recursive makefile for the test files (for now) +# test/*.c + +dsp = libapr.dsp + +modules = + crypto_openssl crypto_nss crypto_commoncrypto dbd_pgsql + dbd_sqlite2 dbd_sqlite3 dbd_oracle dbd_mysql dbd_odbc + dbm_db dbm_gdbm dbm_ndbm + +# gen_uri_delim.c + +# we have a recursive makefile for the test files (for now) +# test/*.c + +[crypto_commoncrypto] +paths = crypto/apr_crypto_commoncrypto.c +target = crypto/apr_crypto_commoncrypto.la + +[crypto_openssl] +paths = crypto/apr_crypto_openssl.c +target = crypto/apr_crypto_openssl.la + +[crypto_nss] +paths = crypto/apr_crypto_nss.c +target = crypto/apr_crypto_nss.la + +[dbd_pgsql] +paths = dbd/apr_dbd_pgsql.c +target = dbd/apr_dbd_pgsql.la + +[dbd_sqlite2] +paths = dbd/apr_dbd_sqlite2.c +target = dbd/apr_dbd_sqlite2.la + +[dbd_sqlite3] +paths = dbd/apr_dbd_sqlite3.c +target = dbd/apr_dbd_sqlite3.la + +[dbd_oracle] +paths = dbd/apr_dbd_oracle.c +target = dbd/apr_dbd_oracle.la + +[dbd_mysql] +paths = dbd/apr_dbd_mysql.c +target = dbd/apr_dbd_mysql.la + +[dbd_odbc] +paths = dbd/apr_dbd_odbc.c +target = dbd/apr_dbd_odbc.la + +[dbm_db] +paths = dbm/apr_dbm_berkeleydb.c +target = dbm/apr_dbm_db.la + +[dbm_gdbm] +paths = dbm/apr_dbm_gdbm.c +target = dbm/apr_dbm_gdbm.la + +[dbm_ndbm] +paths = dbm/apr_dbm_ndbm.c +target = dbm/apr_dbm_ndbm.la + diff --git a/helpers/MakeEtags b/build/MakeEtags similarity index 58% rename from helpers/MakeEtags rename to build/MakeEtags index 25f6bdab176..3b82c3a8c2a 100755 --- a/helpers/MakeEtags +++ b/build/MakeEtags @@ -1,33 +1,34 @@ #!/bin/sh # This file illustrates how to generate a useful TAGS file via etags -# for emacs. This should be invoked from the src directory i.e.: -# > helpers/MakeEtags -# and will create a TAGS file in the src directory. +# for emacs. This should be invoked from the top source directory i.e.: +# > build/MakeEtags +# and will create a TAGS file in the top source directory. # This script falls under the Apache License. # See http://www.apache.org/docs/LICENSE -# Once you have created src/TAGS in emacs you'll need to setup -# tag-table-alist with an entry to assure it finds the single src/TAGS +# Once you have created ./TAGS in emacs you'll need to setup +# tag-table-alist with an entry to assure it finds the single ./TAGS # file from the many source directories. Something along these lines: # (setq tag-table-alist -# '(("/home/me/work/apache-1.3/src/" -# . "/home/me/work/apache-1.3/src/") +# '(("/home/me/work/apr-x.y/" . "/home/me/work/apr-x.y/") +# ("/home/me/work/apr-util-x.y/" . "/home/me/work/apr-util-x.y/") +# ("/home/me/work/httpd-x.y/" . "/home/me/work/httpd-x.y/") # )) # This requires a special version of etags, i.e. the # one called "Exuberant ctags" available at: -# http://fly.hiwaay.net/~darren/ctags/ +# http://ctags.sourceforge.net/ # Once that is setup you'll need to point to the # executable here: -etags=~/local/bin/etags +etags=${ETAGS-etags} # Exuberant etags is necessary since it can ignore some defined symbols # that obscure the function signatures. -ignore=API_EXPORT,API_EXPORT_NONSTD,__declspec +ignore=AP_DECLARE,AP_DECLARE_NONSTD,__declspec,APR_DECLARE,APR_DECLARE_NONSTD # Create an etags file at the root of the source # tree, then create symbol links to it from each diff --git a/build/NWGNUenvironment.inc b/build/NWGNUenvironment.inc new file mode 100644 index 00000000000..9b6c5e4761c --- /dev/null +++ b/build/NWGNUenvironment.inc @@ -0,0 +1,392 @@ +# +# Setup needed Tools and Libraries +# + +ifeq "$(wildcard $(APR_WORK)/build/NWGNUcustom.inc)" "$(APR_WORK)/build/NWGNUcustom.inc" +include $(APR_WORK)/build/NWGNUcustom.inc +CUSTOM_INI = $(AP_WORK)/NWGNUcustom.ini +endif + +ifndef VERBOSE +.SILENT: +endif + +# +# Treat like an include +# +ifndef EnvironmentDefined + +# +# simple macros for parsing makefiles +# +EOLIST:= +EMPTY := +COMMA := , +SPACE := $(EMPTY) $(EMPTY) + +# +# Base environment +# + +# Try and handle case issues +ifndef NOVELLLIBC +ifdef NovellLibC +NOVELLLIBC = $(NovellLibC) +endif +endif + +ifndef NOVELLLIBC +NOVELLLIBC = C:/novell/ndk/libc +endif +ifneq "$(wildcard $(NOVELLLIBC)/include/ndkvers.h)" "$(NOVELLLIBC)/include/ndkvers.h" +$(error NOVELLLIBC does not point to a valid Novell LIBC SDK) +endif + +ifdef EXPATSDK +ifeq "$(wildcard $(EXPATSDK)/include/expat.h)" "$(EXPATSDK)/include/expat.h" +EXPAT_IMP = $(EXPATSDK)/imports/expatlbc.imp +EXPAT_INC = $(EXPATSDK)/include +EXPAT_LIB = $(EXPATSDK)/lib/expat.lib +EXPAT_NLM = EXPATLBC +else +$(error EXPATSDK does not point to a valid EXPAT SDK) +endif +endif +ifdef EXPATSRC +ifeq "$(wildcard $(EXPATSRC)/lib/xmlparse.c)" "$(EXPATSRC)/lib/xmlparse.c" +EXPAT_INC = $(EXPATSRC)/lib +EXPAT_LIB = $(EXPATSRC)/lib/$(OBJDIR)/expat.lib +else +$(error EXPATSRC does not point to a valid EXPAT source tree) +endif +endif +ifndef EXPAT_INC +$(error neither EXPATSDK nor EXPATSRC defined - cant compile without EXPAT SDK or source tree) +endif + +# If LM_LICENSE_FILE isn't defined, define a variable that can be used to +# restart make with it defined +ifndef LM_LICENSE_FILE +NO_LICENSE_FILE = NO_LICENSE_FILE +endif + +# +# Set the Release type that you want to build, possible values are: +# +# debug - full debug switches are set +# noopt - normal switches are set +# release - optimization switches are set (default) + +ifdef reltype +RELEASE = $(reltype) +endif + +ifdef RELTYPE +RELEASE = $(RELTYPE) +endif + +ifdef debug +RELEASE = debug +endif + +ifdef DEBUG +RELEASE = debug +endif + +ifdef noopt +RELEASE = noopt +endif + +ifdef NOOPT +RELEASE = noopt +endif + +ifdef optimized +RELEASE = release +endif + +ifdef OPTIMIZED +RELEASE = release +endif + +ifndef RELEASE +RELEASE = release +endif + +ifeq "$(strip $(RELEASE))" "optimized" +RELEASE = release +endif + +OBJDIR = obj_$(RELEASE) + +# +# Setup compiler information +# + +ifdef METROWERKS +# MetroWerks NLM tools +#ifndef METROWERKS +#METROWERKS = $(ProgramFiles)\Metrowerks\CodeWarrior +#endif + +CC = mwccnlm -w nocmdline -gccinc +CPP = $(CC) +CPRE = $(CC) -EP +LINK = mwldnlm -w nocmdline +AR = $(LINK) -type library -o +WIN_CC = mwcc + +ifneq ($(findstring /sh,$(SHELL)),/sh) +PATH:=$(PATH);$(METROWERKS)\bin;$(METROWERKS)\Other Metrowerks Tools\Command Line Tools +endif + +# MetroWerks static Libraries +CLIB3S = $(METROWERKS)/Novell Support/Metrowerks Support/Libraries/Runtime/mwcrtl.lib +MATH3S = +PLIB3S = $(METROWERKS)/Novell Support/Metrowerks Support/Libraries/MSL C++/MWCPP.lib + +ifeq "$(OS)" "Windows_NT" +# MetroWerks Win32 build flags to create build tools +MWCW_MSL = "$(METROWERKS)/MSL" +MWCW_W32 = "$(METROWERKS)/Win32-x86 Support" +CC_FOR_BUILD = $(WIN_CC) +CFLAGS_FOR_BUILD = -O2 -gccinc -nodefaults -proc 586 -w off +CFLAGS_FOR_BUILD += -ir $(MWCW_MSL) -ir $(MWCW_W32) -lr $(MWCW_MSL) -lr $(MWCW_W32) +CFLAGS_FOR_BUILD += -lMSL_All_x86.lib -lkernel32.lib -luser32.lib +else +# GNUC build flags to create build tools +CC_FOR_BUILD = gcc +CFLAGS_FOR_BUILD = -Wall -O2 +endif + +# Base compile flags +# and prefix or precompiled header added here. + +# The default flags are as follows: +# +# -w nocmdline disable command-line driver/parser warnings +# -gccinc search directory of referencing file first for #includes +# -Cpp_exceptions off disable C++ exceptions +# -RTTI off disable C++ run-time typing information +# -align 4 align on 4 byte bounderies +# -proc PII generate code base on Pentium II instruction set +# -inst mmx use MMX extensions (not used) + +CFLAGS = -proc PII -align 4 +CPFLAGS = -Cpp_exceptions off -RTTI off + +ifdef CC_MAX_ERRORS +CFLAGS += -maxerrors $(CC_MAX_ERRORS) +else +CFLAGS += -maxerrors 1 +endif + +ifeq "$(REQUIRE_PROTOTYPES)" "1" +CFLAGS += -r +endif + +# -g generate debugging information +# -O0 level 0 optimizations +ifeq "$(RELEASE)" "debug" +CFLAGS += -g -O0 +endif + +# -O4,p level 4 optimizations, optimize for speed +ifeq "$(RELEASE)" "release" +CFLAGS += -O4,p +endif + +PRELUDE = $(NOVI)/libcpre.o + +else +# GNU NLM tools (gcc / nlmconv) + +CC = gcc +CPP = g++ +CPRE = $(CC) -P -E +LINK = nlmconv +AR = ar cru +RANLIB = ranlib + +CFLAGS = -m32 -fno-builtin -fpcc-struct-return -fno-strict-aliasing +CFLAGS += -fpack-struct=4 +CFLAGS += -Wall +CFLAGS += -Wdeclaration-after-statement -Wmissing-declarations -Wmissing-prototypes + +ifdef MAINTAINER +CFLAGS += \ + -W -Wpointer-arith -Wwrite-strings -Wunused -Wshadow -Winline \ + -Wnested-externs -Wcast-align -Wtype-limits -Wstrict-prototypes \ + -Wfloat-equal -Wno-multichar -Wsign-compare -Wundef -Wendif-labels \ + -Wold-style-declaration -Wmissing-parameter-type -Wempty-body \ + -Wclobbered -Wignored-qualifiers -Wconversion -Wvla -pedantic +endif + +# -g generate debugging information +# -O0 level 0 optimizations +ifeq "$(RELEASE)" "debug" +CFLAGS += -g -O0 +endif + +# -O3 level 3 optimizations, optimize for speed +ifeq "$(RELEASE)" "release" +CFLAGS += -O3 +endif + +PRELUDE = $(NOVI)/libcpre.gcc.o + +endif + +# -include apr_arch_pre_nw.h #include apr_arch_pre_nw.h for all files +CFLAGS += -include apr_arch_pre_nw.h + + +# Setup build tools +AWK = awk + +# +# Declare Command and tool macros here +# + +ifeq ($(findstring /sh,$(SHELL)),/sh) +DEL = rm -f $1 +RMDIR = rm -rf $1 +MKDIR = mkdir -p $1 +COPY = cp -av $1 $2 +COPYR = cp -ar $1 $2 +ECHONL = echo "" +DL = ' +CAT = cat +else +ifeq "$(OS)" "Windows_NT" +DEL = $(shell if exist $(subst /,\,$1) del /q /f 2>NUL $(subst /,\,$1)) +RMDIR = $(shell if exist $(subst /,\,$1)\NUL rd /q /s 2>NUL $(subst /,\,$1)) +else +DEL = $(shell if exist $(subst /,\,$1) del 2>NUL $(subst /,\,$1)) +RMDIR = $(shell if exist $(subst /,\,$1)\NUL deltree /y 2>NUL $(subst /,\,$1)) +endif +ECHONL = $(ComSpec) /c echo. +MKDIR = $(shell if not exist $(subst /,\,$1)\NUL md 2>NUL $(subst /,\,$1)) +COPY = copy /y 2>NUL $(subst /,\,$1) $(subst /,\,$2) +COPYR = xcopy /y /e 2>NUL $(subst /,\,$1) $(subst /,\,$2) +CAT = type +endif + +ifdef IPV6 +ifndef USE_STDSOCKETS +USE_STDSOCKETS=1 +endif +endif + +NOVI = $(NOVELLLIBC)/imports +INCDIRS = $(NOVELLLIBC)/include + +DEFINES = -DNETWARE +ifdef USE_STDSOCKETS +DEFINES += -DUSE_BSD_SOCKETS +else +DEFINES += -DUSE_WINSOCK +INCDIRS += $(NOVELLLIBC)/include/winsock +endif +ifndef DEBUG +DEFINES += -DNDEBUG +endif + +ifdef USE_STDSOCKETS +VERSION_SKT = (BSDSOCK) +else +VERSION_SKT = (WINSOCK) +endif + +# +# Declare major project deliverables output directories here +# + +ifdef DEST +INSTALL = $(DEST) +ifeq (\, $(findstring \,$(INSTALL))) +INSTDIRS = $(DEST) +endif +endif + +ifdef dest +INSTALL = $(dest) +ifeq (\, $(findstring \,$(INSTALL))) +INSTDIRS = $(dest) +endif +endif + +ifndef INSTALL +INSTALL = $(APR_WORK)/Dist +INSTDIRS = $(APR_WORK)/Dist +BASEDIR = Apr +endif + +# Add support for building IPV6 alongside +ifneq "$(IPV6)" "" +DEFINES += -DNW_BUILD_IPV6 +# INCDIRS := $(NOVELLLIBC)/include/winsock/IPV6 $(INCDIRS) + +ifneq "$(findstring IPV6,$(OBJDIR))" "IPV6" +OBJDIR := $(OBJDIR)_IPV6 +endif + +ifneq "$(findstring IPV6,$(INSTALL))" "IPV6" +INSTALL := $(INSTALL)_IPV6 +endif + +ifneq "$(findstring IPV6,$(INSTDIRS))" "IPV6" +INSTDIRS := $(INSTDIRS)_IPV6 +endif + +endif + +ifdef DEST + +ifndef BASEDIR +BASEDIR = Apache2 +endif + +endif + +INSTALLBASE := $(INSTALL)/$(BASEDIR) + +INSTDEVDIRS := \ + $(INSTDIRS) \ + $(INSTALLBASE) \ + $(INSTALLBASE)/include \ + $(INSTALLBASE)/lib \ + $(INSTALLBASE)/bin + +INSTDIRS += \ + $(INSTALLBASE) + +# +# Common directories +# + +APR = $(subst \,/,$(APR_WORK)) +APRBUILD = $(APR)/build +APRXML = $(APR)/xml +APRTEST = $(APR)/test + +# +# Internal Libraries +# + +APRLIB = $(APR)/$(OBJDIR)/aprlib.lib +APRXMLLIB = $(APRXML)/$(OBJDIR)/xml.lib + +# +# Additional general defines +# + +EnvironmentDefined = 1 +endif # ifndef EnvironmentDefined + +# This is always set so that it will show up in lower directories + +ifdef Path +Path = $(PATH) +endif + diff --git a/build/NWGNUhead.inc b/build/NWGNUhead.inc new file mode 100644 index 00000000000..316454dcbec --- /dev/null +++ b/build/NWGNUhead.inc @@ -0,0 +1,102 @@ +# +# Obtain the global build environment +# + +include $(APR_WORK)/build/NWGNUenvironment.inc + +# +# Define base targets and rules +# + +TARGETS = libs nlms install clobber_libs clobber_nlms clean installdev + +.PHONY : $(TARGETS) default all help $(NO_LICENSE_FILE) + +# Here is where we will use the NO_LICENSE_FILE variable to see if we need to +# restart the make with it defined + +ifdef NO_LICENSE_FILE + +default: NO_LICENSE_FILE + +all: NO_LICENSE_FILE + +install :: NO_LICENSE_FILE + +installdev :: NO_LICENSE_FILE + +NO_LICENSE_FILE : + $(MAKE) $(MAKECMDGOALS) -f NWGNUmakefile RELEASE=$(RELEASE) DEST="$(INSTALL)" LM_LICENSE_FILE="$(METROWERKS)/license.dat" + +else # LM_LICENSE_FILE must be defined so use the real targets + +default: $(SUBDIRS) libs nlms + +all: $(SUBDIRS) libs nlms install + +$(TARGETS) :: $(SUBDIRS) + +endif #NO_LICENSE_FILE check + +help : + @echo $(DL)targets for RELEASE=$(RELEASE):$(DL) + @echo $(DL)(default) . . . . libs nlms$(DL) + @echo $(DL)all . . . . . . . does everything (libs nlms install)$(DL) + @echo $(DL)libs. . . . . . . builds all libs$(DL) + @echo $(DL)nlms. . . . . . . builds all nlms$(DL) + @echo $(DL)install . . . . . builds libs and nlms and copies install files to$(DL) + @echo $(DL) "$(INSTALL)"$(DL) + @echo $(DL)installdev. . . . copies headers and files needed for development to$(DL) + @echo $(DL) "$(INSTALL)"$(DL) + @echo $(DL)clean . . . . . . deletes $(OBJDIR) dirs, *.err, and *.map$(DL) + @echo $(DL)clobber_all . . . deletes all possible output from the make$(DL) + @echo $(DL)clobber_install . deletes all files in $(INSTALL)$(DL) + @$(ECHONL) + @echo $(DL)Multiple targets can be used on a single make command line -$(DL) + @echo $(DL)(i.e. $(MAKE) clean all)$(DL) + @$(ECHONL) + @echo $(DL)You can also specify RELEASE=debug, RELEASE=noopt, or RELEASE=release$(DL) + @echo $(DL)The default is RELEASE=release$(DL) + +clobber_all :: clean clobber_install + +clobber_install :: + $(call RMDIR,$(INSTALL)) + +test :: default + $(MAKE) -C $(APRTEST) -f NWGNUmakefile RELEASE=$(RELEASE) DEST="$(INSTALL)" LM_LICENSE_FILE="$(LM_LICENSE_FILE)" + +# +# build recursive targets +# + +$(SUBDIRS) : FORCE +ifneq "$(MAKECMDGOALS)" "clean" +ifneq "$(findstring clobber_,$(MAKECMDGOALS))" "clobber_" + @$(ECHONL) + @echo Building $(CURDIR)/$@ +endif +endif + $(MAKE) -C $@ $(MAKECMDGOALS) -f NWGNUmakefile RELEASE=$(RELEASE) DEST="$(INSTALL)" LM_LICENSE_FILE="$(LM_LICENSE_FILE)" + @$(ECHONL) + +FORCE : ; + +# +# Standard targets +# + +clean :: $(SUBDIRS) + @echo Cleaning up $(CURDIR) + $(call RMDIR,$(OBJDIR)) + $(call DEL,*.err) + $(call DEL,*.map) + $(call DEL,*.tmp) +# $(call DEL,*.d) + +test-clean :: + $(MAKE) -C $(APRTEST) -f NWGNUmakefile clean + +$(OBJDIR) :: + $(call MKDIR,$@) + diff --git a/build/NWGNUmakefile b/build/NWGNUmakefile new file mode 100644 index 00000000000..3d323be4496 --- /dev/null +++ b/build/NWGNUmakefile @@ -0,0 +1,89 @@ +# +# Declare the sub-directories to be built here +# + +SUBDIRS = \ + $(EOLIST) + +# +# Get the 'head' of the build environment. This includes default targets and +# paths to tools +# + +include $(APR_WORK)/build/NWGNUhead.inc + +# +# build this level's files + +# +# Make sure all needed macro's are defined +# + +# +# These directories will be at the beginning of the include list, followed by +# INCDIRS +# +XINCDIRS += \ + $(APR)/include \ + $(APR)/include/private \ + $(APR)/include/arch/netware \ + $(APR)/include/arch/unix \ + $(APRBUILD) \ + $(EOLIST) + +FILES_prebuild_headers = \ + $(APR)/include/apr.h \ + $(APR)/include/apu_want.h \ + $(APR)/include/private/apu_select_dbm.h \ + $(APR)/include/private/apr_escape_test_char.h \ + $(EOLIST) + +nlms :: $(APR)/aprlib.imp + +$(APR)/aprlib.imp : make_nw_export.awk nw_export.i + @echo $(DL)GEN $@$(DL) + $(AWK) -v EXPPREFIX=APR$(VERSION_MAJMIN) -f $^ >$@ + +nw_export.i : nw_export.h $(FILES_prebuild_headers) $(CCOPT_DEPENDS) + @echo $(DL)GEN $@$(DL) + $(CPRE) $(CCFLAGS) -DGENEXPORTS $< -o $@ + +%.h: %.hnw + @echo Creating $@ + $(call COPY,$<,$@) + +%.h: %.hw + @echo Creating $@ + $(call COPY,$<,$@) + +$(APR)/include/private/apr_escape_test_char.h: gen_test_char.exe $(APR)/tools/gen_test_char.c + @echo $(DL)GEN $@$(DL) + $< > $@ + +%.exe: $(APR)/tools/%.c + @echo $(DL)Creating Build Helper $@$(DL) + $(CC_FOR_BUILD) $(CFLAGS_FOR_BUILD) -DCROSS_COMPILE $< -o $@ + +# +# You can use this target if all that is needed is to copy files to the +# installation area +# +install :: nlms FORCE + + +clean :: + $(call DEL,nw_export.i) + $(call DEL,cc.opt) + $(call DEL,NWGNUversion.inc) + $(call DEL,$(APR)/aprlib.imp) + $(foreach file,$(FILES_prebuild_headers),$(call DEL,$(file))) + $(call DEL,gen_test_char.exe) + +# +# Include the 'tail' makefile that has targets that depend on variables defined +# in this makefile +# + +include $(APRBUILD)/NWGNUtail.inc + + diff --git a/build/NWGNUtail.inc b/build/NWGNUtail.inc new file mode 100644 index 00000000000..b98ed96f7f8 --- /dev/null +++ b/build/NWGNUtail.inc @@ -0,0 +1,383 @@ +# +# This contains final targets and should be included at the end of any +# NWGNUmakefile file +# + +# +# If we are going to create an nlm, make sure we have assigned variables to +# use during the link. +# +ifndef NLM_NAME +NLM_NAME = $(TARGET_nlm) +endif + +ifndef NLM_DESCRIPTION +NLM_DESCRIPTION = $(NLM_NAME) +endif + +ifndef NLM_THREAD_NAME +NLM_THREAD_NAME = $(NLM_NAME) Thread +endif + +ifndef NLM_SCREEN_NAME +NLM_SCREEN_NAME = DEFAULT +endif + +ifndef NLM_COPYRIGHT +NLM_COPYRIGHT = Licensed under the Apache License, Version 2.0 +endif + +ifeq "$(NLM_FLAGS)" "" +#NLM_FLAGS = AUTOUNLOAD, PSEUDOPREEMPTION +NLM_FLAGS = flag_on 72 +endif + +ifeq "$(NLM_STACK_SIZE)" "" +NLM_STACK_SIZE = 65536 +endif + +ifeq "$(NLM_ENTRY_SYM)" "" +NLM_ENTRY_SYM = _LibCPrelude +endif + +ifeq "$(NLM_EXIT_SYM)" "" +NLM_EXIT_SYM = _LibCPostlude +endif + +ifeq "$(NLM_VERSION)" "" +NLM_VERSION = $(VERSION) +endif + +# if APACHE_UNIPROC is defined, don't include XDCData +ifndef APACHE_UNIPROC +ifneq "$(XDCDATA)" "" +NLM_XDCDATA = $(XDCDATA) +else +NLM_XDCDATA = $(APR)/misc/netware/apr.xdc +endif +endif + +# +# Create dependency lists based on the files available +# + +CCOPT_DEPENDS = \ + $(APRBUILD)/NWGNUhead.inc \ + $(APRBUILD)/NWGNUenvironment.inc \ + $(APRBUILD)/NWGNUtail.inc \ + NWGNUmakefile \ + $(CUSTOM_INI) \ + $(EOLIST) + +CPPOPT_DEPENDS = \ + $(APRBUILD)/NWGNUhead.inc \ + $(APRBUILD)/NWGNUenvironment.inc \ + $(APRBUILD)/NWGNUtail.inc \ + NWGNUmakefile \ + $(CUSTOM_INI) \ + $(EOLIST) + +$(NLM_NAME)_LINKOPT_DEPENDS = \ + $(TARGET_lib) \ + $(APRBUILD)/NWGNUenvironment.inc \ + NWGNUmakefile \ + $(APRBUILD)/NWGNUtail.inc \ + $(CUSTOM_INI) \ + $(VERSION_INC) \ + $(EOLIST) + +ifeq "$(words $(strip $(TARGET_lib)))" "1" +LIB_NAME = $(basename $(notdir $(TARGET_lib))) +$(LIB_NAME)_LIBLST_DEPENDS = \ + $(FILES_lib_objs) \ + $(APRBUILD)/NWGNUenvironment.inc \ + NWGNUmakefile \ + $(APRBUILD)/NWGNUtail.inc \ + $(CUSTOM_INI) \ + $(EOLIST) +endif + +ifeq "$(wildcard NWGNU$(LIB_NAME))" "NWGNU$(LIB_NAME)" +$(LIB_NAME)_LIBLST_DEPENDS += NWGNU$(LIB_NAME) +endif + +ifeq "$(wildcard NWGNU$(NLM_NAME))" "NWGNU$(NLM_NAME)" +$(NLM_NAME)_LINKOPT_DEPENDS += NWGNU$(NLM_NAME) +CCOPT_DEPENDS += NWGNU$(NLM_NAME) +CPPOPT_DEPENDS += NWGNU$(NLM_NAME) +endif + +# +# Generic compiler rules +# + +ifneq "$(MAKECMDGOALS)" "clean" +ifneq "$(findstring clobber_,$(MAKECMDGOALS))" "clobber_" +$(APRBUILD)/NWGNUversion.inc : $(APRBUILD)/nw_ver.awk $(APR)/include/apr_version.h + @echo $(DL)GEN $@$(DL) + $(AWK) -f $^ $(APR)/.svn/all-wcprops > $@ + +-include $(APRBUILD)/NWGNUversion.inc + +ifneq "$(strip $(VERSION_STR))" "" +VERSION_INC = $(APRBUILD)/NWGNUversion.inc +else +VERSION = 2,0,0 +VERSION_STR = 2.0.0 +VERSION_MAJMIN = 20 +endif +endif +endif +ifeq "$(USE_SVNREV)" "1" +ifneq "$(strip $(SVN_REVISION))" "" +CFLAGS += -DAPR_IS_DEV_STRING=\"$(SVN_REVISION)\" +endif +endif + +ifeq "$(words $(strip $(TARGET_nlm)))" "1" +INCLUDE_BLDCMDS = 1 +CCOPT_NAME = $(NLM_NAME) +endif + +ifeq "$(words $(strip $(TARGET_lib)))" "1" +INCLUDE_BLDCMDS = 1 +CCOPT_NAME = $(LIB_NAME) +endif + +CCFLAGS = +ifneq "$(strip $(CFLAGS))" "" +CCFLAGS += $(CFLAGS) +endif +ifneq "$(strip $(XCFLAGS))" "" +CCFLAGS += $(XCFLAGS) +endif +ifneq "$(strip $(XINCDIRS))" "" +CCFLAGS += $(foreach xincdir,$(strip $(XINCDIRS)),-I$(xincdir)) +endif +ifneq "$(strip $(INCDIRS))" "" +CCFLAGS += $(foreach incdir,$(strip $(INCDIRS)),-I$(incdir)) +endif +ifneq "$(strip $(DEFINES))" "" +CCFLAGS += $(DEFINES) +endif +ifneq "$(strip $(XDEFINES))" "" +CCFLAGS += $(XDEFINES) +endif + +ifeq "$(INCLUDE_BLDCMDS)" "1" + +$(OBJDIR)/%.o: %.c $(CCOPT_DEPENDS) + @echo $(DL)CC $<$(DL) +ifdef VERBOSE + @echo CCOPT_DEPENDS=$(CCOPT_DEPENDS) +endif + $(CC) $(CCFLAGS) -c -o $@ $< + +CCPFLAGS = $(CPFLAGS) $(CCFLAGS) + +$(OBJDIR)/%.o: %.cpp $(CPPOPT_DEPENDS) + @echo $(DL)CPP $<$(DL) +ifdef VERBOSE + @echo CPPOPT_DEPENDS=$(CPPOPT_DEPENDS) +endif + $(CPP) $(CCPFLAGS) -c -o $@ $< + +endif # one target nlm or lib + +# +# Rules to build libraries +# + +# If we only have one target library then build it + +ifeq "$(words $(strip $(TARGET_lib)))" "1" + +$(TARGET_lib) : $(OBJDIR)/$(LIB_NAME)_lib.lst + $(call DEL,$@) + @echo $(DL)AR $@$(DL) + $(AR) $@ @$< +ifdef RANLIB + $(RANLIB) $@ +endif + +$(OBJDIR)/aprlib_lib.lst: $(aprlib_LIBLST_DEPENDS) + $(call DEL,$@) +ifneq "$(strip $(FILES_lib_objs))" "" + @echo $(DL)GEN $@$(DL) + @echo $(DL)$(wordlist 1, 10, $(FILES_lib_objs))$(DL)>> $@ + @echo $(DL)$(wordlist 11, 20, $(FILES_lib_objs))$(DL)>> $@ + @echo $(DL)$(wordlist 21, 30, $(FILES_lib_objs))$(DL)>> $@ + @echo $(DL)$(wordlist 31, 40, $(FILES_lib_objs))$(DL)>> $@ + @echo $(DL)$(wordlist 41, 50, $(FILES_lib_objs))$(DL)>> $@ + @echo $(DL)$(wordlist 51, 60, $(FILES_lib_objs))$(DL)>> $@ + @echo $(DL)$(wordlist 61, 70, $(FILES_lib_objs))$(DL)>> $@ + @echo $(DL)$(wordlist 71, 80, $(FILES_lib_objs))$(DL)>> $@ + @echo $(DL)$(wordlist 81, 90, $(FILES_lib_objs))$(DL)>> $@ + @echo $(DL)$(wordlist 91, 100, $(FILES_lib_objs))$(DL)>> $@ + @echo $(DL)$(wordlist 101, 110, $(FILES_lib_objs))$(DL)>> $@ + @echo $(DL)$(wordlist 111, 120, $(FILES_lib_objs))$(DL)>> $@ +endif + +$(OBJDIR)/%_lib.lst: $($(LIB_NAME)_LIBLST_DEPENDS) + $(call DEL,$@) +ifneq "$(strip $(FILES_lib_objs))" "" + @echo $(DL)GEN $@$(DL) + @echo $(DL)$(FILES_lib_objs)$(DL)>> $@ +endif + +else # We must have more than one target library so load the individual makefiles + +$(OBJDIR)/%.lib: NWGNU% $(APRBUILD)/NWGNUhead.inc $(APRBUILD)/NWGNUtail.inc $(APRBUILD)/NWGNUenvironment.inc FORCE + @echo $(DL)Calling $<$(DL) + $(MAKE) -f $< $(MAKECMDGOALS) RELEASE=$(RELEASE) + +endif + +# +# Rules to build nlms. +# + +# If we only have one target NLM then build it +ifeq "$(words $(strip $(TARGET_nlm)))" "1" + +$(TARGET_nlm) : $(FILES_nlm_objs) $(FILES_nlm_libs) $(OBJDIR)/$(NLM_NAME)_link.opt $(OBJDIR)/$(NLM_NAME)_link.def + @echo $(DL)LINK $@$(DL) + $(LINK) @$(OBJDIR)/$(NLM_NAME)_link.opt + +# This will force the link option file to be rebuilt if we change the +# corresponding makefile + +$(OBJDIR)/$(NLM_NAME)_link.opt : $($(NLM_NAME)_LINKOPT_DEPENDS) + $(call DEL,$@) + @echo $(DL)GEN $@$(DL) +ifeq "$(findstring mwldnlm,$(LINK))" "mwldnlm" # for Metrowerks CodeWarrior + @echo $(DL)# Do not edit this file - it is created by make!$(DL) > $@ + @echo $(DL)# All your changes will be lost!!$(DL)>> $@ + @echo $(DL)-nlmversion=$(NLM_VERSION)$(DL)>> $@ + @echo $(DL)-warnings off$(DL)>> $@ + @echo $(DL)-zerobss$(DL)>> $@ + @echo $(DL)-nodefaults$(DL)>> $@ + @echo $(DL)-map $(OBJDIR)/$(NLM_NAME).map$(DL)>> $@ + @echo $(DL)-o $(TARGET_nlm)$(DL)>> $@ +ifneq "$(FILE_nlm_copyright)" "" + @-$(CAT) $(FILE_nlm_copyright) >> $@ +endif +ifeq "$(RELEASE)" "debug" + @echo $(DL)-g$(DL)>> $@ + @echo $(DL)-sym codeview4$(DL)>> $@ + @echo $(DL)-osym $(OBJDIR)/$(NLM_NAME).sym$(DL)>> $@ +endif + @echo $(DL)-sym internal$(DL)>> $@ + @echo $(DL)-L$(APR)/misc/netware$(DL)>> $@ + @echo $(DL)-L"$(METROWERKS)/Novell Support/Metrowerks Support/Libraries/Runtime"$(DL)>> $@ + @echo $(DL)-L"$(METROWERKS)/Novell Support/Metrowerks Support/Libraries/MSL C++"$(DL)>> $@ +ifneq "$(IPV6)" "" + @echo $(DL)-L$(NOVELLLIBC)/include/winsock/IPV6$(DL)>> $@ +endif + @echo $(DL)-L$(NOVELLLIBC)/imports$(DL)>> $@ +ifneq "$(strip $(XLFLAGS))" "" + @echo $(DL)$(XLFLAGS)$(DL)>> $@ +endif +ifneq "$(strip $(FILES_nlm_objs))" "" + @echo $(DL)$(foreach objfile,$(strip $(FILES_nlm_objs)),$(objfile))$(DL)>> $@ +endif +ifneq "$(FILES_nlm_libs)" "" + @echo $(DL)$(foreach libpath,$(dir $(strip $(FILES_nlm_libs))),-L$(libpath))$(DL)>> $@ + @echo $(DL)$(foreach libfile,$(notdir $(strip $(FILES_nlm_libs))),-l$(libfile))$(DL)>> $@ +endif +ifneq "$(FILES_nlm_Ximports)" "" + @echo $(DL)$(foreach imppath,$(dir $(strip $(FILES_nlm_Ximports))),$(subst @,-L,$(imppath)))$(DL)>> $@ +endif + @echo $(DL)-commandfile $(@:.opt=.def)$(DL)>> $@ +else # for GNU nlmconv + @echo $(DL)-UT $(@:.opt=.def)$(DL)>> $@ +endif + +$(OBJDIR)/$(NLM_NAME)_link.def : $($(NLM_NAME)_LINKOPT_DEPENDS) + $(call DEL,$@) + @echo $(DL)GEN $@$(DL) + @echo $(DL)# Do not edit this file - it is created by make!$(DL)> $@ + @echo $(DL)# All your changes will be lost!!$(DL)>> $@ +ifneq "$(FILE_nlm_msg)" "" + @echo $(DL)Messages $(FILE_nlm_msg)$(DL)>> $@ +endif +ifneq "$(FILE_nlm_hlp)" "" + @echo $(DL)Help $(FILE_nlm_hlp)$(DL)>> $@ +endif +ifeq "$(FILE_nlm_copyright)" "" + @echo $(DL)copyright "$(NLM_COPYRIGHT)"$(DL)>> $@ +endif + @echo $(DL)description "$(NLM_DESCRIPTION)"$(DL)>> $@ + @echo $(DL)threadname "$(NLM_THREAD_NAME)"$(DL)>> $@ + @echo $(DL)screenname "$(NLM_SCREEN_NAME)"$(DL)>> $@ + @echo $(DL)stacksize $(subst K,000,$(subst k,K,$(strip $(NLM_STACK_SIZE))))$(DL)>> $@ + @echo $(DL)$(strip $(NLM_FLAGS))$(DL)>> $@ + @echo $(DL)start $(NLM_ENTRY_SYM)$(DL)>> $@ + @echo $(DL)exit $(NLM_EXIT_SYM)$(DL)>> $@ +ifneq "$(NLM_CHECK_SYM)" "" + @echo $(DL)check $(NLM_CHECK_SYM)$(DL)>> $@ +endif +ifneq "$(FILES_nlm_modules)" "" + @echo $(DL)module $(strip $(FILES_nlm_modules))$(DL)>> $@ +endif +ifneq "$(FILES_nlm_imports)" "" + @echo $(DL)import $(strip $(FILES_nlm_imports))$(DL)>> $@ +endif +ifeq "$(findstring mwldnlm,$(LINK))" "mwldnlm" # for Metrowerks CodeWarrior +ifneq "$(FILES_nlm_Ximports)" "" + @echo $(DL)import $(foreach import,$(notdir $(strip $(FILES_nlm_Ximports))),@$(import))$(DL)>> $@ +endif +ifneq "$(FILES_nlm_exports)" "" + @echo $(DL)export $(foreach export,$(subst $(SPACE),$(COMMA),$(strip $(FILES_nlm_exports))),$(export))$(DL)>> $@ +endif +ifneq "$(NLM_XDCDATA)" "" + @echo $(DL)xdcdata $(notdir $(NLM_XDCDATA))$(DL)>> $@ +endif + @echo $(DL)map $(OBJDIR)/$(NLM_NAME).map$(DL)>> $@ +else # for GNU nlmconv +ifneq "$(FILES_nlm_Ximports)" "" + @echo $(DL)import $(strip $(FILES_nlm_Ximports))$(DL)>> $@ +endif +ifneq "$(FILES_nlm_exports)" "" + @echo $(DL)export $(foreach export,$(subst $(SPACE),$(COMMA),$(strip $(FILES_nlm_exports))),$(export))$(DL)>> $@ +endif +ifneq "$(NLM_XDCDATA)" "" + @echo $(DL)xdcdata $(NLM_XDCDATA)$(DL)>> $@ +endif +ifneq "$(strip $(FILES_nlm_objs))" "" + @echo $(DL)input $(strip $(FILES_nlm_objs))$(DL)>> $@ +endif +ifneq "$(FILES_nlm_libs)" "" + @echo $(DL)input $(strip $(FILES_nlm_libs))$(DL)>> $@ +endif + @echo $(DL)output $(TARGET_nlm)$(DL)>> $@ +ifeq "$(RELEASE)" "debug" + @echo $(DL)debug$(DL)>> $@ +endif + @echo $(DL)version $(NLM_VERSION) $(DL)>> $@ +endif + +else # more than one target so look for individual makefiles. + +# Only include these if NO_LICENSE_FILE isn't set to prevent excessive +# recursion + +ifndef NO_LICENSE_FILE + +$(OBJDIR)/%.nlm: NWGNU% $(APRBUILD)/NWGNUhead.inc $(APRBUILD)/NWGNUtail.inc $(APRBUILD)/NWGNUenvironment.inc $(CUSTOM_INI) $(VERSION_INC) FORCE + @echo $(DL)Calling $<$(DL) + $(MAKE) -f $< $(MAKECMDGOALS) RELEASE=$(RELEASE) + @$(ECHONL) + +else + +$(TARGET_nlm): + +endif # NO_LICENSE_FILE + +endif # multiple targets + +$(INSTDIRS) :: + $(call MKDIR,$@) + + diff --git a/helpers/PrintPath b/build/PrintPath similarity index 74% rename from helpers/PrintPath rename to build/PrintPath index 68435f3744c..2a2b48b6349 100755 --- a/helpers/PrintPath +++ b/build/PrintPath @@ -1,4 +1,21 @@ #!/bin/sh +# +# 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. +# +# # Look for program[s] somewhere in $PATH. # # Options: @@ -12,9 +29,6 @@ # # Initially written by Jim Jagielski for the Apache configuration mechanism # (with kudos to Kernighan/Pike) -# -# This script falls under the Apache License. -# See http://www.apache.org/docs/LICENSE ## # Some "constants" @@ -45,7 +59,7 @@ done # # First of all, all OS/2 programs have the '.exe' extension. # Next, we adjust PATH (or what was given to us as PATH) to -# be whitespace seperated directories. +# be whitespace separated directories. # Finally, we try to determine the best flag to use for # test/[] to look for an executable file. OS/2 just has '-r' # but with other OSs, we do some funny stuff to check to see diff --git a/build/__init__.py b/build/__init__.py new file mode 100644 index 00000000000..b03ce7247f7 --- /dev/null +++ b/build/__init__.py @@ -0,0 +1 @@ +from aprenv import * diff --git a/build/aplibtool.c b/build/aplibtool.c new file mode 100644 index 00000000000..1604e051ca2 --- /dev/null +++ b/build/aplibtool.c @@ -0,0 +1,913 @@ +/* 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 <stdio.h> +#include <process.h> +#include <string.h> +#include <stdlib.h> +#include <sys/types.h> +#include <dirent.h> + +typedef char bool; +#define false 0 +#define true (!false) + +bool silent = false; +bool shared = false; +bool export_all = false; +enum mode_t { mCompile, mLink, mInstall }; +enum output_type_t { otGeneral, otObject, otProgram, otStaticLibrary, otDynamicLibrary }; + +#ifdef __EMX__ +# define SHELL_CMD "sh" +# define CC "gcc" +# define GEN_EXPORTS "emxexp" +# define DEF2IMPLIB_CMD "emximp" +# define SHARE_SW "-Zdll -Zmtd" +# define USE_OMF true +# define TRUNCATE_DLL_NAME +# define DYNAMIC_LIB_EXT "dll" +# define EXE_EXT ".exe" + +# if USE_OMF + /* OMF is the native format under OS/2 */ +# define STATIC_LIB_EXT "lib" +# define OBJECT_EXT "obj" +# define LIBRARIAN "emxomfar -p256" +# else + /* but the alternative, a.out, can fork() which is sometimes necessary */ +# define STATIC_LIB_EXT "a" +# define OBJECT_EXT "o" +# define LIBRARIAN "ar" +# endif +#endif + + +typedef struct { + char *arglist[1024]; + int num_args; + enum mode_t mode; + enum output_type_t output_type; + char *output_name; + char *stub_name; + char *tmp_dirs[1024]; + int num_tmp_dirs; + char *obj_files[1024]; + int num_obj_files; + char *dep_libs[1024]; + int num_dep_libs; +} cmd_data_t; + +void parse_args(int argc, char *argv[], cmd_data_t *cmd_data); +bool parse_long_opt(char *arg, cmd_data_t *cmd_data); +int parse_short_opt(char *arg, cmd_data_t *cmd_data); +bool parse_input_file_name(char *arg, cmd_data_t *cmd_data); +bool parse_output_file_name(char *arg, cmd_data_t *cmd_data); +void post_parse_fixup(cmd_data_t *cmd_data); +void append_depenent_libs(cmd_data_t *cmd_data); +int execute_command(cmd_data_t *cmd_data); +char *shell_esc(const char *str); +void cleanup_tmp_dirs(cmd_data_t *cmd_data); +void generate_def_file(cmd_data_t *cmd_data); +char *nameof(char *fullpath); +char *truncate_dll_name(char *path); +void add_dep_lib(char *lib, cmd_data_t *cmd_data); +void add_lib_dep_libs(char *la_file, cmd_data_t *cmd_data); +void write_dep_libs(FILE *stub_handle, cmd_data_t *cmd_data); + + +int main(int argc, char *argv[]) +{ + int rc; + cmd_data_t cmd_data; + + memset(&cmd_data, 0, sizeof(cmd_data)); + cmd_data.mode = mCompile; + cmd_data.output_type = otGeneral; + + parse_args(argc, argv, &cmd_data); + rc = execute_command(&cmd_data); + + if (rc == 0 && cmd_data.stub_name) { + FILE *stub_handle = fopen(cmd_data.stub_name, "w"); + + if (cmd_data.output_type == otStaticLibrary) { + write_dep_libs(stub_handle, &cmd_data); + } + + fclose(stub_handle); + } + + cleanup_tmp_dirs(&cmd_data); + return rc; +} + + + +void parse_args(int argc, char *argv[], cmd_data_t *cmd_data) +{ + int a; + char *arg; + bool argused; + + for (a=1; a < argc; a++) { + arg = argv[a]; + argused = false; + + if (arg[0] == '-') { + if (arg[1] == '-') { + argused = parse_long_opt(arg + 2, cmd_data); + } else if (arg[1] == 'o' && a+1 < argc) { + cmd_data->arglist[cmd_data->num_args++] = arg; + arg = argv[++a]; + argused = parse_output_file_name(arg, cmd_data); + } else { + int num_used = parse_short_opt(arg + 1, cmd_data); + argused = num_used > 0; + + if (num_used > 1) { + a += num_used - 1; + } + } + } else { + argused = parse_input_file_name(arg, cmd_data); + } + + if (!argused) { + cmd_data->arglist[cmd_data->num_args++] = arg; + } + } + + post_parse_fixup(cmd_data); + + if (cmd_data->output_type == otProgram || cmd_data->output_type == otDynamicLibrary) { + append_depenent_libs(cmd_data); + } +} + + + +bool parse_long_opt(char *arg, cmd_data_t *cmd_data) +{ + char *equal_pos = strchr(arg, '='); + char var[50]; + char value[500]; + + if (equal_pos) { + strncpy(var, arg, equal_pos - arg); + var[equal_pos - arg] = 0; + strcpy(value, equal_pos + 1); + } else { + strcpy(var, arg); + } + + if (strcmp(var, "silent") == 0 || strcmp(var, "quiet") == 0) { + silent = true; + } else if (strcmp(var, "mode") == 0) { + if (strcmp(value, "compile") == 0) { + cmd_data->mode = mCompile; + cmd_data->output_type = otObject; + } + + if (strcmp(value, "link") == 0) { + cmd_data->mode = mLink; + } + + if (strcmp(value, "install") == 0) { + cmd_data->mode = mInstall; + } + } else if (strcmp(var, "shared") == 0) { + shared = true; + } else if (strcmp(var, "export-all") == 0) { + export_all = true; + } else if (strcmp(var, "tag") == 0) { + /* What's this for? Ignore for now */ + } else { + return false; + } + + return true; +} + + + +int parse_short_opt(char *arg, cmd_data_t *cmd_data) +{ + if (strcmp(arg, "export-dynamic") == 0) { + return 1; + } + + if (strcmp(arg, "module") == 0) { + shared = true; + return 1; + } + + if (strcmp(arg, "Zexe") == 0) { + return 1; + } + + if (strcmp(arg, "avoid-version") == 0) { + return 1; + } + + if (strcmp(arg, "prefer-pic") == 0) { + return 1; + } + + if (strcmp(arg, "prefer-non-pic") == 0) { + return 1; + } + + if (strcmp(arg, "version-info") == 0 ) { + return 2; + } + + if (strcmp(arg, "no-install") == 0) { + return 1; + } + + if (strcmp(arg, "release") == 0 ) { + return 2; + } + + if (strcmp(arg, "export-symbols-regex") == 0) { + return 2; + } + + return 0; +} + + + +void parse_la_input_file_name(char *arg, cmd_data_t *cmd_data) +{ + char *name = strrchr(arg, '/'); + char *ext; + char *newarg; + int pathlen; + + if (name == NULL) { + name = strrchr(arg, '\\'); + + if (name == NULL) { + name = arg; + } else { + name++; + } + } else { + name++; + } + + pathlen = name - arg; + newarg = (char *)malloc(strlen(arg) + 10); + strcpy(newarg, arg); + newarg[pathlen] = 0; + strcat(newarg, ".libs/"); + + if (strncmp(name, "lib", 3) == 0) { + name += 3; + } + + strcat(newarg, name); + ext = strrchr(newarg, '.') + 1; + + if (shared && cmd_data->mode == mInstall) { + strcpy(ext, DYNAMIC_LIB_EXT); + newarg = truncate_dll_name(newarg); + } else { + strcpy(ext, STATIC_LIB_EXT); + } + + cmd_data->arglist[cmd_data->num_args++] = newarg; +} + + + +bool parse_input_file_name(char *arg, cmd_data_t *cmd_data) +{ + char *ext = strrchr(arg, '.'); + char *name = strrchr(arg, '/'); + char *newarg; + + if (!ext) { + return false; + } + + ext++; + + if (name == NULL) { + name = strrchr(arg, '\\'); + + if (name == NULL) { + name = arg; + } else { + name++; + } + } else { + name++; + } + + if (strcmp(ext, "lo") == 0) { + newarg = (char *)malloc(strlen(arg) + 10); + strcpy(newarg, arg); + strcpy(newarg + (ext - arg), OBJECT_EXT); + cmd_data->arglist[cmd_data->num_args++] = newarg; + cmd_data->obj_files[cmd_data->num_obj_files++] = newarg; + return true; + } + + if (strcmp(ext, "la") == 0) { + add_lib_dep_libs(arg, cmd_data); + parse_la_input_file_name(arg, cmd_data); + return true; + } + + if (strcmp(ext, "c") == 0) { + if (cmd_data->stub_name == NULL) { + cmd_data->stub_name = (char *)malloc(strlen(arg) + 4); + strcpy(cmd_data->stub_name, arg); + strcpy(strrchr(cmd_data->stub_name, '.') + 1, "lo"); + } + } + + if (strcmp(name, CC) == 0 || strcmp(name, CC EXE_EXT) == 0) { + if (cmd_data->output_type == otGeneral) { + cmd_data->output_type = otObject; + } + } + + return false; +} + + + +bool parse_output_file_name(char *arg, cmd_data_t *cmd_data) +{ + char *name = strrchr(arg, '/'); + char *ext = strrchr(arg, '.'); + char *newarg = NULL, *newext; + + if (name == NULL) { + name = strrchr(arg, '\\'); + + if (name == NULL) { + name = arg; + } else { + name++; + } + } else { + name++; + } + + if (!ext || stricmp(ext, EXE_EXT) == 0) { + cmd_data->output_type = otProgram; + newarg = (char *)malloc(strlen(arg) + 5); + strcpy(newarg, arg); + + if (!ext) { + strcat(newarg, EXE_EXT); + cmd_data->stub_name = arg; + } + + cmd_data->arglist[cmd_data->num_args++] = newarg; + cmd_data->output_name = newarg; + return true; + } + + ext++; + + if (strcmp(ext, "exe") == 0) { + cmd_data->output_type = otProgram; + cmd_data->output_name = newarg; + return false; + } + + if (strcmp(ext, "dll") == 0) { + cmd_data->output_type = otDynamicLibrary; + cmd_data->output_name = newarg; + return false; + } + + if (strcmp(ext, "la") == 0) { + cmd_data->stub_name = arg; + cmd_data->output_type = shared ? otDynamicLibrary : otStaticLibrary; + newarg = (char *)malloc(strlen(arg) + 10); + mkdir(".libs", 0); + strcpy(newarg, ".libs/"); + + if (strrchr(arg, '/')) { + arg = strrchr(arg, '/') + 1; + } + + if (strncmp(arg, "lib", 3) == 0) { + arg += 3; + } + + strcat(newarg, arg); + newext = strrchr(newarg, '.') + 1; + strcpy(newext, shared ? DYNAMIC_LIB_EXT : STATIC_LIB_EXT); + +#ifdef TRUNCATE_DLL_NAME + if (shared) { + newarg = truncate_dll_name(newarg); + } +#endif + + cmd_data->arglist[cmd_data->num_args++] = newarg; + cmd_data->output_name = newarg; + return true; + } + + if (strcmp(ext, "lo") == 0) { + cmd_data->stub_name = arg; + cmd_data->output_type = otObject; + newarg = (char *)malloc(strlen(arg) + 2); + strcpy(newarg, arg); + ext = strrchr(newarg, '.') + 1; + strcpy(ext, OBJECT_EXT); + cmd_data->arglist[cmd_data->num_args++] = newarg; + cmd_data->output_name = newarg; + return true; + } + + return false; +} + + + +void post_parse_fixup(cmd_data_t *cmd_data) +{ + int a; + char *arg; + char *ext; + + if (cmd_data->output_type == otStaticLibrary && cmd_data->mode == mLink) { + /* We do a real hatchet job on the args when making a static library + * removing all compiler switches & any other cruft that ar won't like + * We also need to explode any libraries listed + */ + + for (a=0; a < cmd_data->num_args; a++) { + arg = cmd_data->arglist[a]; + + if (arg) { + ext = strrchr(arg, '.'); + + if (ext) { + ext++; + } + + if (arg[0] == '-') { + cmd_data->arglist[a] = NULL; + + if (strcmp(arg, "-rpath") == 0 && a+1 < cmd_data->num_args) { + cmd_data->arglist[a+1] = NULL; + } + + if (strcmp(arg, "-R") == 0 && a+1 < cmd_data->num_args) { + cmd_data->arglist[a+1] = NULL; + } + + if (strcmp(arg, "-version-info") == 0 && a+1 < cmd_data->num_args) { + cmd_data->arglist[a+1] = NULL; + } + + if (strcmp(arg, "-Zstack") == 0 && a+1 < cmd_data->num_args) { + cmd_data->arglist[a+1] = NULL; + } + + if (strcmp(arg, "-o") == 0) { + a++; + } + + if (arg[1] == 'l') { + add_dep_lib(arg, cmd_data); + } + } + + if (strcmp(arg, CC) == 0 || strcmp(arg, CC EXE_EXT) == 0) { + cmd_data->arglist[a] = LIBRARIAN " cr"; + } + + if (ext) { + if (strcmp(ext, "h") == 0 || strcmp(ext, "c") == 0) { + /* ignore source files, they don't belong in a library */ + cmd_data->arglist[a] = NULL; + } + + if (strcmp(ext, STATIC_LIB_EXT) == 0) { + cmd_data->arglist[a] = NULL; + } + } + } + } + } + + if (cmd_data->output_type == otDynamicLibrary) { + for (a=0; a < cmd_data->num_args; a++) { + arg = cmd_data->arglist[a]; + + if (arg) { + if (strcmp(arg, "-rpath") == 0 && a+1 < cmd_data->num_args) { + cmd_data->arglist[a] = NULL; + cmd_data->arglist[a+1] = NULL; + } + } + } + + if (export_all) { + generate_def_file(cmd_data); + } + } + + if (cmd_data->output_type == otProgram || cmd_data->output_type == otGeneral) { + for (a=0; a < cmd_data->num_args; a++) { + arg = cmd_data->arglist[a]; + + if (arg) { + if (strcmp(arg, "-rpath") == 0 && a+1 < cmd_data->num_args) { + cmd_data->arglist[a] = NULL; + cmd_data->arglist[a+1] = NULL; + } + } + } + } + +#if USE_OMF + if (cmd_data->output_type == otObject || + cmd_data->output_type == otProgram || + cmd_data->output_type == otDynamicLibrary) { + cmd_data->arglist[cmd_data->num_args++] = "-Zomf"; + } +#endif + + if (shared && (cmd_data->output_type == otObject || cmd_data->output_type == otDynamicLibrary)) { + cmd_data->arglist[cmd_data->num_args++] = SHARE_SW; + } +} + + + +void append_depenent_libs(cmd_data_t *cmd_data) +{ + int l; + + for (l = 0; l < cmd_data->num_dep_libs; l++) { + char *arg = cmd_data->dep_libs[l]; + char *ext = strrchr(arg, '.'); + + if (ext && strcmp(ext, ".la") == 0) { + parse_la_input_file_name(cmd_data->dep_libs[l], cmd_data); + } + else { + cmd_data->arglist[cmd_data->num_args++] = arg; + } + } +} + + + +int execute_command(cmd_data_t *cmd_data) +{ + int target = 0; + char *command; + int a, total_len = 0; + char *args[4]; + + for (a=0; a < cmd_data->num_args; a++) { + if (cmd_data->arglist[a]) { + total_len += strlen(cmd_data->arglist[a]) + 1; + } + } + + command = (char *)malloc( total_len ); + command[0] = 0; + + for (a=0; a < cmd_data->num_args; a++) { + if (cmd_data->arglist[a]) { + strcat(command, cmd_data->arglist[a]); + strcat(command, " "); + } + } + + command[strlen(command)-1] = 0; + + if (!silent) { + puts(command); + } + + cmd_data->num_args = target; + cmd_data->arglist[cmd_data->num_args] = NULL; + command = shell_esc(command); + + args[0] = SHELL_CMD; + args[1] = "-c"; + args[2] = command; + args[3] = NULL; + return spawnvp(P_WAIT, args[0], args); +} + + + +char *shell_esc(const char *str) +{ + char *cmd; + unsigned char *d; + const unsigned char *s; + + cmd = (char *)malloc(2 * strlen(str) + 1); + d = (unsigned char *)cmd; + s = (const unsigned char *)str; + + for (; *s; ++s) { + if (*s == '"' || *s == '\\') { + *d++ = '\\'; + } + *d++ = *s; + } + + *d = '\0'; + return cmd; +} + + + +void add_dep_lib(char *lib, cmd_data_t *cmd_data) +{ + int l; + + while (isspace(*lib)) { + lib++; + } + + if (*lib) { + for (l = 0; l < cmd_data->num_dep_libs; l++) { + if (stricmp(cmd_data->dep_libs[l], lib) == 0) { + return; + } + } + } + + if (*lib) { + cmd_data->dep_libs[cmd_data->num_dep_libs++] = strdup(lib); + } +} + + + +void write_dep_libs(FILE *stub_handle, cmd_data_t *cmd_data) +{ + int l; + char cwd[MAXPATHLEN]; + + getwd(cwd); + fputs("dependency_libs='", stub_handle); + + for (l = 0; l < cmd_data->num_dep_libs; l++) { + if (l) { + fputs(" ", stub_handle); + } + + if (cmd_data->dep_libs[l][0] != '/' && cmd_data->dep_libs[l][0] != '-') { + fprintf(stub_handle, "%s/%s", cwd, cmd_data->dep_libs[l]); + } + else { + fputs(cmd_data->dep_libs[l], stub_handle); + } + } + + fputs("'\n", stub_handle); +} + + + +void add_lib_dep_libs(char *la_file, cmd_data_t *cmd_data) +{ + FILE *hla; + char line[16384]; + + add_dep_lib(la_file, cmd_data); + hla = fopen(la_file, "r"); + + if (hla == NULL) { + fprintf(stderr, "warning: couldn't open %s\n", la_file); + return; + } + + while (fgets(line, sizeof(line), hla) != NULL) { + char *pos = strchr(line, '='); + + if (pos) { + *pos = 0; + pos++; + + if (*pos == '\'') { + char *end; + pos++; + end = strchr(pos, '\''); + + if (end != NULL) { + *end = 0; + } + } + + if (strcmp(line, "dependency_libs") == 0) { + while (*pos) { + char *end = strchr(pos, ' '); + + if (end != NULL) { + *end = 0; + } + + add_dep_lib(pos, cmd_data); + + if (end) { + pos = end + 1; + } + else { + break; + } + } + } + } + } + + fclose(hla); +} + + + +void cleanup_tmp_dir(char *dirname) +{ + DIR *dir; + struct dirent *entry; + char fullname[1024]; + + dir = opendir(dirname); + + if (dir == NULL) + return; + + while ((entry = readdir(dir)) != NULL) { + if (entry->d_name[0] != '.') { + strcpy(fullname, dirname); + strcat(fullname, "/"); + strcat(fullname, entry->d_name); + remove(fullname); + } + } + + rmdir(dirname); +} + + + +void cleanup_tmp_dirs(cmd_data_t *cmd_data) +{ + int d; + + for (d=0; d < cmd_data->num_tmp_dirs; d++) { + cleanup_tmp_dir(cmd_data->tmp_dirs[d]); + } +} + + + +void generate_def_file(cmd_data_t *cmd_data) +{ + char def_file[1024]; + char implib_file[1024]; + char *ext; + FILE *hDef; + char *export_args[1024]; + int num_export_args = 0; + char *cmd; + int cmd_size = 0; + int a; + + if (cmd_data->output_name) { + strcpy(def_file, cmd_data->output_name); + strcat(def_file, ".def"); + hDef = fopen(def_file, "w"); + + if (hDef != NULL) { + fprintf(hDef, "LIBRARY '%s' INITINSTANCE\n", nameof(cmd_data->output_name)); + fprintf(hDef, "DATA NONSHARED\n"); + fprintf(hDef, "EXPORTS\n"); + fclose(hDef); + + for (a=0; a < cmd_data->num_obj_files; a++) { + cmd_size += strlen(cmd_data->obj_files[a]) + 1; + } + + cmd_size += strlen(GEN_EXPORTS) + strlen(def_file) + 3; + cmd = (char *)malloc(cmd_size); + strcpy(cmd, GEN_EXPORTS); + + for (a=0; a < cmd_data->num_obj_files; a++) { + strcat(cmd, " "); + strcat(cmd, cmd_data->obj_files[a] ); + } + + strcat(cmd, ">>"); + strcat(cmd, def_file); + puts(cmd); + export_args[num_export_args++] = SHELL_CMD; + export_args[num_export_args++] = "-c"; + export_args[num_export_args++] = cmd; + export_args[num_export_args++] = NULL; + spawnvp(P_WAIT, export_args[0], export_args); + cmd_data->arglist[cmd_data->num_args++] = strdup(def_file); + + /* Now make an import library for the dll */ + num_export_args = 0; + export_args[num_export_args++] = DEF2IMPLIB_CMD; + export_args[num_export_args++] = "-o"; + + strcpy(implib_file, ".libs/"); + strcat(implib_file, cmd_data->stub_name); + ext = strrchr(implib_file, '.'); + + if (ext) + *ext = 0; + + strcat(implib_file, "."); + strcat(implib_file, STATIC_LIB_EXT); + + export_args[num_export_args++] = implib_file; + export_args[num_export_args++] = def_file; + export_args[num_export_args++] = NULL; + spawnvp(P_WAIT, export_args[0], export_args); + } + } +} + + + +/* returns just a file's name without path or extension */ +char *nameof(char *fullpath) +{ + char buffer[1024]; + char *ext; + char *name = strrchr(fullpath, '/'); + + if (name == NULL) { + name = strrchr(fullpath, '\\'); + } + + if (name == NULL) { + name = fullpath; + } else { + name++; + } + + strcpy(buffer, name); + ext = strrchr(buffer, '.'); + + if (ext) { + *ext = 0; + return strdup(buffer); + } + + return name; +} + + + +char *truncate_dll_name(char *path) +{ + /* Cut DLL name down to 8 characters after removing any mod_ prefix */ + char *tmppath = strdup(path); + char *newname = strrchr(tmppath, '/') + 1; + char *ext = strrchr(tmppath, '.'); + int len; + + if (ext == NULL) + return tmppath; + + len = ext - newname; + + if (strncmp(newname, "mod_", 4) == 0) { + strcpy(newname, newname + 4); + len -= 4; + } + + if (len > 8) { + strcpy(newname + 8, strchr(newname, '.')); + } + + return tmppath; +} diff --git a/build/apr_common.m4 b/build/apr_common.m4 new file mode 100644 index 00000000000..6b5c0f033b9 --- /dev/null +++ b/build/apr_common.m4 @@ -0,0 +1,990 @@ +dnl -------------------------------------------------------- -*- autoconf -*- +dnl Licensed to the Apache Software Foundation (ASF) under one or more +dnl contributor license agreements. See the NOTICE file distributed with +dnl this work for additional information regarding copyright ownership. +dnl The ASF licenses this file to You under the Apache License, Version 2.0 +dnl (the "License"); you may not use this file except in compliance with +dnl the License. You may obtain a copy of the License at +dnl +dnl http://www.apache.org/licenses/LICENSE-2.0 +dnl +dnl Unless required by applicable law or agreed to in writing, software +dnl distributed under the License is distributed on an "AS IS" BASIS, +dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +dnl See the License for the specific language governing permissions and +dnl limitations under the License. + +dnl +dnl apr_common.m4: APR's general-purpose autoconf macros +dnl + +dnl +dnl APR_CONFIG_NICE(filename) +dnl +dnl Saves a snapshot of the configure command-line for later reuse +dnl +AC_DEFUN([APR_CONFIG_NICE], [ + rm -f $1 + cat >$1<<EOF +#! /bin/sh +# +# Created by configure + +EOF + if test -n "$CC"; then + echo "CC=\"$CC\"; export CC" >> $1 + fi + if test -n "$CFLAGS"; then + echo "CFLAGS=\"$CFLAGS\"; export CFLAGS" >> $1 + fi + if test -n "$CPPFLAGS"; then + echo "CPPFLAGS=\"$CPPFLAGS\"; export CPPFLAGS" >> $1 + fi + if test -n "$LDFLAGS"; then + echo "LDFLAGS=\"$LDFLAGS\"; export LDFLAGS" >> $1 + fi + if test -n "$LTFLAGS"; then + echo "LTFLAGS=\"$LTFLAGS\"; export LTFLAGS" >> $1 + fi + if test -n "$LIBS"; then + echo "LIBS=\"$LIBS\"; export LIBS" >> $1 + fi + if test -n "$INCLUDES"; then + echo "INCLUDES=\"$INCLUDES\"; export INCLUDES" >> $1 + fi + if test -n "$NOTEST_CFLAGS"; then + echo "NOTEST_CFLAGS=\"$NOTEST_CFLAGS\"; export NOTEST_CFLAGS" >> $1 + fi + if test -n "$NOTEST_CPPFLAGS"; then + echo "NOTEST_CPPFLAGS=\"$NOTEST_CPPFLAGS\"; export NOTEST_CPPFLAGS" >> $1 + fi + if test -n "$NOTEST_LDFLAGS"; then + echo "NOTEST_LDFLAGS=\"$NOTEST_LDFLAGS\"; export NOTEST_LDFLAGS" >> $1 + fi + if test -n "$NOTEST_LIBS"; then + echo "NOTEST_LIBS=\"$NOTEST_LIBS\"; export NOTEST_LIBS" >> $1 + fi + + # Retrieve command-line arguments. + eval "set x $[0] $ac_configure_args" + shift + + for arg + do + APR_EXPAND_VAR(arg, $arg) + echo "\"[$]arg\" \\" >> $1 + done + echo '"[$]@"' >> $1 + chmod +x $1 +])dnl + +dnl APR_MKDIR_P_CHECK(fallback-mkdir-p) +dnl checks whether mkdir -p works +AC_DEFUN([APR_MKDIR_P_CHECK], [ + AC_CACHE_CHECK(for working mkdir -p, ac_cv_mkdir_p,[ + test -d conftestdir && rm -rf conftestdir + mkdir -p conftestdir/somedir >/dev/null 2>&1 + if test -d conftestdir/somedir; then + ac_cv_mkdir_p=yes + else + ac_cv_mkdir_p=no + fi + rm -rf conftestdir + ]) + if test "$ac_cv_mkdir_p" = "yes"; then + mkdir_p="mkdir -p" + else + mkdir_p="$1" + fi +]) + +dnl +dnl APR_SUBDIR_CONFIG(dir [, sub-package-cmdline-args, args-to-drop]) +dnl +dnl dir: directory to find configure in +dnl sub-package-cmdline-args: arguments to add to the invocation (optional) +dnl args-to-drop: arguments to drop from the invocation (optional) +dnl +dnl Note: This macro relies on ac_configure_args being set properly. +dnl +dnl The args-to-drop argument is shoved into a case statement, so +dnl multiple arguments can be separated with a |. +dnl +dnl Note: Older versions of autoconf do not single-quote args, while 2.54+ +dnl places quotes around every argument. So, if you want to drop the +dnl argument called --enable-layout, you must pass the third argument as: +dnl [--enable-layout=*|\'--enable-layout=*] +dnl +dnl Trying to optimize this is left as an exercise to the reader who wants +dnl to put up with more autoconf craziness. I give up. +dnl +AC_DEFUN([APR_SUBDIR_CONFIG], [ + # save our work to this point; this allows the sub-package to use it + AC_CACHE_SAVE + + echo "configuring package in $1 now" + ac_popdir=`pwd` + apr_config_subdirs="$1" + test -d $1 || $mkdir_p $1 + ac_abs_srcdir=`(cd $srcdir/$1 && pwd)` + cd $1 + +changequote(, )dnl + # A "../" for each directory in /$config_subdirs. + ac_dots=`echo $apr_config_subdirs|sed -e 's%^\./%%' -e 's%[^/]$%&/%' -e 's%[^/]*/%../%g'` +changequote([, ])dnl + + # Make the cache file pathname absolute for the subdirs + # required to correctly handle subdirs that might actually + # be symlinks + case "$cache_file" in + /*) # already absolute + ac_sub_cache_file=$cache_file ;; + *) # Was relative path. + ac_sub_cache_file="$ac_popdir/$cache_file" ;; + esac + + ifelse($3, [], [apr_configure_args=$ac_configure_args],[ + apr_configure_args= + apr_sep= + for apr_configure_arg in $ac_configure_args + do + case "$apr_configure_arg" in + $3) + continue ;; + esac + apr_configure_args="$apr_configure_args$apr_sep'$apr_configure_arg'" + apr_sep=" " + done + ]) + + dnl autoconf doesn't add --silent to ac_configure_args; explicitly pass it + test "x$silent" = "xyes" && apr_configure_args="$apr_configure_args --silent" + + dnl AC_CONFIG_SUBDIRS silences option warnings, emulate this for 2.62 + apr_configure_args="--disable-option-checking $apr_configure_args" + + dnl The eval makes quoting arguments work - specifically the second argument + dnl where the quoting mechanisms used is "" rather than []. + dnl + dnl We need to execute another shell because some autoconf/shell combinations + dnl will choke after doing repeated APR_SUBDIR_CONFIG()s. (Namely Solaris + dnl and autoconf-2.54+) + if eval $SHELL $ac_abs_srcdir/configure $apr_configure_args --cache-file=$ac_sub_cache_file --srcdir=$ac_abs_srcdir $2 + then : + echo "$1 configured properly" + else + echo "configure failed for $1" + exit 1 + fi + + cd $ac_popdir + + # grab any updates from the sub-package + AC_CACHE_LOAD +])dnl + +dnl +dnl APR_SAVE_THE_ENVIRONMENT(variable_name) +dnl +dnl Stores the variable (usually a Makefile macro) for later restoration +dnl +AC_DEFUN([APR_SAVE_THE_ENVIRONMENT], [ + apr_ste_save_$1="$$1" +])dnl + +dnl +dnl APR_RESTORE_THE_ENVIRONMENT(variable_name, prefix_) +dnl +dnl Uses the previously saved variable content to figure out what configure +dnl has added to the variable, moving the new bits to prefix_variable_name +dnl and restoring the original variable contents. This makes it possible +dnl for a user to override configure when it does something stupid. +dnl +AC_DEFUN([APR_RESTORE_THE_ENVIRONMENT], [ +dnl Check whether $apr_ste_save_$1 is empty or +dnl only whitespace. The verbatim "X" is token number 1, +dnl the following whitespace will be ignored. +set X $apr_ste_save_$1 +if test ${#} -eq 1; then + $2$1="$$1" + $1= +else + if test "x$apr_ste_save_$1" = "x$$1"; then + $2$1= + else + $2$1=`echo "$$1" | sed -e "s%${apr_ste_save_$1}%%"` + $1="$apr_ste_save_$1" + fi +fi +if test "x$silent" != "xyes"; then + echo " restoring $1 to \"$$1\"" + echo " setting $2$1 to \"$$2$1\"" +fi +AC_SUBST($2$1) +])dnl + +dnl +dnl APR_SETIFNULL(variable, value) +dnl +dnl Set variable iff it's currently null +dnl +AC_DEFUN([APR_SETIFNULL], [ + if test -z "$$1"; then + test "x$silent" != "xyes" && echo " setting $1 to \"$2\"" + $1="$2" + fi +])dnl + +dnl +dnl APR_SETVAR(variable, value) +dnl +dnl Set variable no matter what +dnl +AC_DEFUN([APR_SETVAR], [ + test "x$silent" != "xyes" && echo " forcing $1 to \"$2\"" + $1="$2" +])dnl + +dnl +dnl APR_ADDTO(variable, value) +dnl +dnl Add value to variable +dnl +AC_DEFUN([APR_ADDTO], [ + if test "x$$1" = "x"; then + test "x$silent" != "xyes" && echo " setting $1 to \"$2\"" + $1="$2" + else + apr_addto_bugger="$2" + for i in $apr_addto_bugger; do + apr_addto_duplicate="0" + for j in $$1; do + if test "x$i" = "x$j"; then + apr_addto_duplicate="1" + break + fi + done + if test $apr_addto_duplicate = "0"; then + test "x$silent" != "xyes" && echo " adding \"$i\" to $1" + $1="$$1 $i" + fi + done + fi +])dnl + +dnl +dnl APR_REMOVEFROM(variable, value) +dnl +dnl Remove a value from a variable +dnl +AC_DEFUN([APR_REMOVEFROM], [ + if test "x$$1" = "x$2"; then + test "x$silent" != "xyes" && echo " nulling $1" + $1="" + else + apr_new_bugger="" + apr_removed=0 + for i in $$1; do + if test "x$i" != "x$2"; then + apr_new_bugger="$apr_new_bugger $i" + else + apr_removed=1 + fi + done + if test $apr_removed = "1"; then + test "x$silent" != "xyes" && echo " removed \"$2\" from $1" + $1=$apr_new_bugger + fi + fi +]) dnl + +dnl +dnl APR_CHECK_DEFINE_FILES( symbol, header_file [header_file ...] ) +dnl +AC_DEFUN([APR_CHECK_DEFINE_FILES], [ + AC_CACHE_CHECK([for $1 in $2],ac_cv_define_$1,[ + ac_cv_define_$1=no + for curhdr in $2 + do + AC_EGREP_CPP(YES_IS_DEFINED, [ +#include <$curhdr> +#ifdef $1 +YES_IS_DEFINED +#endif + ], ac_cv_define_$1=yes) + done + ]) + if test "$ac_cv_define_$1" = "yes"; then + AC_DEFINE(HAVE_$1, 1, [Define if $1 is defined]) + fi +]) + + +dnl +dnl APR_CHECK_DEFINE(symbol, header_file) +dnl +AC_DEFUN([APR_CHECK_DEFINE], [ + AC_CACHE_CHECK([for $1 in $2],ac_cv_define_$1,[ + AC_EGREP_CPP(YES_IS_DEFINED, [ +#include <$2> +#ifdef $1 +YES_IS_DEFINED +#endif + ], ac_cv_define_$1=yes, ac_cv_define_$1=no) + ]) + if test "$ac_cv_define_$1" = "yes"; then + AC_DEFINE(HAVE_$1, 1, [Define if $1 is defined in $2]) + fi +]) + +dnl +dnl APR_CHECK_APR_DEFINE( symbol ) +dnl +AC_DEFUN([APR_CHECK_APR_DEFINE], [ +apr_old_cppflags=$CPPFLAGS +CPPFLAGS="$CPPFLAGS $INCLUDES" +AC_EGREP_CPP(YES_IS_DEFINED, [ +#include <apr.h> +#if $1 +YES_IS_DEFINED +#endif +], ac_cv_define_$1=yes, ac_cv_define_$1=no) +CPPFLAGS=$apr_old_cppflags +]) + +dnl APR_CHECK_FILE(filename); set ac_cv_file_filename to +dnl "yes" if 'filename' is readable, else "no". +dnl @deprecated! - use AC_CHECK_FILE instead +AC_DEFUN([APR_CHECK_FILE], [ +dnl Pick a safe variable name +define([apr_cvname], ac_cv_file_[]translit([$1], [./+-], [__p_])) +AC_CACHE_CHECK([for $1], [apr_cvname], +[if test -r $1; then + apr_cvname=yes + else + apr_cvname=no + fi]) +]) + +define(APR_IFALLYES,[dnl +ac_rc=yes +for ac_spec in $1; do + ac_type=`echo "$ac_spec" | sed -e 's/:.*$//'` + ac_item=`echo "$ac_spec" | sed -e 's/^.*://'` + case $ac_type in + header ) + ac_item=`echo "$ac_item" | sed 'y%./+-%__p_%'` + ac_var="ac_cv_header_$ac_item" + ;; + file ) + ac_item=`echo "$ac_item" | sed 'y%./+-%__p_%'` + ac_var="ac_cv_file_$ac_item" + ;; + func ) ac_var="ac_cv_func_$ac_item" ;; + struct ) ac_var="ac_cv_struct_$ac_item" ;; + define ) ac_var="ac_cv_define_$ac_item" ;; + custom ) ac_var="$ac_item" ;; + esac + eval "ac_val=\$$ac_var" + if test ".$ac_val" != .yes; then + ac_rc=no + break + fi +done +if test ".$ac_rc" = .yes; then + : + $2 +else + : + $3 +fi +]) + + +define(APR_BEGIN_DECISION,[dnl +ac_decision_item='$1' +ac_decision_msg='FAILED' +ac_decision='' +]) + + +AC_DEFUN([APR_DECIDE],[dnl +dnl Define the flag (or not) in apr_private.h via autoheader +AH_TEMPLATE($1, [Define if $2 will be used]) +ac_decision='$1' +ac_decision_msg='$2' +ac_decision_$1=yes +ac_decision_$1_msg='$2' +]) + + +define(APR_DECISION_OVERRIDE,[dnl + ac_decision='' + for ac_item in $1; do + eval "ac_decision_this=\$ac_decision_${ac_item}" + if test ".$ac_decision_this" = .yes; then + ac_decision=$ac_item + eval "ac_decision_msg=\$ac_decision_${ac_item}_msg" + fi + done +]) + + +define(APR_DECISION_FORCE,[dnl +ac_decision="$1" +eval "ac_decision_msg=\"\$ac_decision_${ac_decision}_msg\"" +]) + + +define(APR_END_DECISION,[dnl +if test ".$ac_decision" = .; then + echo "[$]0:Error: decision on $ac_decision_item failed" 1>&2 + exit 1 +else + if test ".$ac_decision_msg" = .; then + ac_decision_msg="$ac_decision" + fi + AC_DEFINE_UNQUOTED(${ac_decision_item}) + AC_MSG_RESULT([decision on $ac_decision_item... $ac_decision_msg]) +fi +]) + + +dnl +dnl APR_CHECK_SIZEOF_EXTENDED(INCLUDES, TYPE [, CROSS_SIZE]) +dnl +dnl A variant of AC_CHECK_SIZEOF which allows the checking of +dnl sizes of non-builtin types +dnl +AC_DEFUN([APR_CHECK_SIZEOF_EXTENDED], +[changequote(<<, >>)dnl +dnl The name to #define. +define(<<AC_TYPE_NAME>>, translit(sizeof_$2, [a-z *], [A-Z_P]))dnl +dnl The cache variable name. +define(<<AC_CV_NAME>>, translit(ac_cv_sizeof_$2, [ *], [_p]))dnl +changequote([, ])dnl +AC_MSG_CHECKING(size of $2) +AC_CACHE_VAL(AC_CV_NAME, +[AC_TRY_RUN([#include <stdio.h> +$1 +#ifdef WIN32 +#define binmode "b" +#else +#define binmode +#endif +main() +{ + FILE *f=fopen("conftestval", "w" binmode); + if (!f) exit(1); + fprintf(f, "%d\n", sizeof($2)); + exit(0); +}], AC_CV_NAME=`cat conftestval`, AC_CV_NAME=0, ifelse([$3],,, +AC_CV_NAME=$3))])dnl +AC_MSG_RESULT($AC_CV_NAME) +AC_DEFINE_UNQUOTED(AC_TYPE_NAME, $AC_CV_NAME, [The size of ]$2) +undefine([AC_TYPE_NAME])dnl +undefine([AC_CV_NAME])dnl +]) + + +dnl +dnl APR_TRY_COMPILE_NO_WARNING(INCLUDES, FUNCTION-BODY, +dnl [ACTIONS-IF-NO-WARNINGS], [ACTIONS-IF-WARNINGS]) +dnl +dnl Tries a compile test with warnings activated so that the result +dnl is false if the code doesn't compile cleanly. For compilers +dnl where it is not known how to activate a "fail-on-error" mode, +dnl it is undefined which of the sets of actions will be run. +dnl +AC_DEFUN([APR_TRY_COMPILE_NO_WARNING], +[apr_save_CFLAGS=$CFLAGS + CFLAGS="$CFLAGS $CFLAGS_WARN" + if test "$ac_cv_prog_gcc" = "yes"; then + CFLAGS="$CFLAGS -Werror" + fi + AC_COMPILE_IFELSE( + [AC_LANG_SOURCE( + [#include "confdefs.h" + ] + [[$1]] + [int main(int argc, const char *const *argv) {] + [[$2]] + [ return 0; }] + )], + [$3], [$4]) + CFLAGS=$apr_save_CFLAGS +]) + +dnl +dnl APR_CHECK_STRERROR_R_RC +dnl +dnl Decide which style of retcode is used by this system's +dnl strerror_r(). It either returns int (0 for success, -1 +dnl for failure), or it returns a pointer to the error +dnl string. +dnl +dnl +AC_DEFUN([APR_CHECK_STRERROR_R_RC], [ +AC_MSG_CHECKING(for type of return code from strerror_r) +AC_TRY_RUN([ +#include <errno.h> +#include <string.h> +#include <stdio.h> +main() +{ + char buf[1024]; + if (strerror_r(ERANGE, buf, sizeof buf) < 1) { + exit(0); + } + else { + exit(1); + } +}], [ + ac_cv_strerror_r_rc_int=yes ], [ + ac_cv_strerror_r_rc_int=no ], [ + ac_cv_strerror_r_rc_int=no ] ) +if test "x$ac_cv_strerror_r_rc_int" = xyes; then + AC_DEFINE(STRERROR_R_RC_INT, 1, [Define if strerror returns int]) + msg="int" +else + msg="pointer" +fi +AC_MSG_RESULT([$msg]) +] ) + +dnl +dnl APR_CHECK_DIRENT_INODE +dnl +dnl Decide if d_fileno or d_ino are available in the dirent +dnl structure on this platform. Single UNIX Spec says d_ino, +dnl BSD uses d_fileno. Undef to find the real beast. +dnl +AC_DEFUN([APR_CHECK_DIRENT_INODE], [ +AC_CACHE_CHECK([for inode member of struct dirent], apr_cv_dirent_inode, [ +apr_cv_dirent_inode=no +AC_TRY_COMPILE([ +#include <sys/types.h> +#include <dirent.h> +],[ +#ifdef d_ino +#undef d_ino +#endif +struct dirent de; de.d_fileno; +], apr_cv_dirent_inode=d_fileno) +if test "$apr_cv_dirent_inode" = "no"; then +AC_TRY_COMPILE([ +#include <sys/types.h> +#include <dirent.h> +],[ +#ifdef d_fileno +#undef d_fileno +#endif +struct dirent de; de.d_ino; +], apr_cv_dirent_inode=d_ino) +fi +]) +if test "$apr_cv_dirent_inode" != "no"; then + AC_DEFINE_UNQUOTED(DIRENT_INODE, $apr_cv_dirent_inode, + [Define if struct dirent has an inode member]) +fi +]) + +dnl +dnl APR_CHECK_DIRENT_TYPE +dnl +dnl Decide if d_type is available in the dirent structure +dnl on this platform. Not part of the Single UNIX Spec. +dnl Note that this is worthless without DT_xxx macros, so +dnl look for one while we are at it. +dnl +AC_DEFUN([APR_CHECK_DIRENT_TYPE], [ +AC_CACHE_CHECK([for file type member of struct dirent], apr_cv_dirent_type,[ +apr_cv_dirent_type=no +AC_TRY_COMPILE([ +#include <sys/types.h> +#include <dirent.h> +],[ +struct dirent de; de.d_type = DT_REG; +], apr_cv_dirent_type=d_type) +]) +if test "$apr_cv_dirent_type" != "no"; then + AC_DEFINE_UNQUOTED(DIRENT_TYPE, $apr_cv_dirent_type, + [Define if struct dirent has a d_type member]) +fi +]) + +dnl the following is a newline, a space, a tab, and a backslash (the +dnl backslash is used by the shell to skip newlines, but m4 sees it; +dnl treat it like whitespace). +dnl WARNING: don't reindent these lines, or the space/tab will be lost! +define([apr_whitespace],[ + \]) + +dnl +dnl APR_COMMA_ARGS(ARG1 ...) +dnl convert the whitespace-separated arguments into comman-separated +dnl arguments. +dnl +dnl APR_FOREACH(CODE-BLOCK, ARG1, ARG2, ...) +dnl subsitute CODE-BLOCK for each ARG[i]. "eachval" will be set to ARG[i] +dnl within each iteration. +dnl +changequote({,}) +define({APR_COMMA_ARGS},{patsubst([$}{1],[[}apr_whitespace{]+],[,])}) +define({APR_FOREACH}, + {ifelse($}{2,,, + [define([eachval], + $}{2)$}{1[]APR_FOREACH([$}{1], + builtin([shift], + builtin([shift], $}{@)))])}) +changequote([,]) + +dnl APR_FLAG_HEADERS(HEADER-FILE ... [, FLAG-TO-SET ] [, "yes" ]) +dnl we set FLAG-TO-SET to 1 if we find HEADER-FILE, otherwise we set to 0 +dnl if FLAG-TO-SET is null, we automagically determine it's name +dnl by changing all "/" to "_" in the HEADER-FILE and dropping +dnl all "." and "-" chars. If the 3rd parameter is "yes" then instead of +dnl setting to 1 or 0, we set FLAG-TO-SET to yes or no. +dnl +AC_DEFUN([APR_FLAG_HEADERS], [ +AC_CHECK_HEADERS($1) +for aprt_i in $1 +do + ac_safe=`echo "$aprt_i" | sed 'y%./+-%__p_%'` + aprt_2=`echo "$aprt_i" | sed -e 's%/%_%g' -e 's/\.//g' -e 's/-//g'` + if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + eval "ifelse($2,,$aprt_2,$2)=ifelse($3,yes,yes,1)" + else + eval "ifelse($2,,$aprt_2,$2)=ifelse($3,yes,no,0)" + fi +done +]) + +dnl APR_FLAG_FUNCS(FUNC ... [, FLAG-TO-SET] [, "yes" ]) +dnl if FLAG-TO-SET is null, we automagically determine it's name +dnl prepending "have_" to the function name in FUNC, otherwise +dnl we use what's provided as FLAG-TO-SET. If the 3rd parameter +dnl is "yes" then instead of setting to 1 or 0, we set FLAG-TO-SET +dnl to yes or no. +dnl +AC_DEFUN([APR_FLAG_FUNCS], [ +AC_CHECK_FUNCS($1) +for aprt_j in $1 +do + aprt_3="have_$aprt_j" + if eval "test \"`echo '$ac_cv_func_'$aprt_j`\" = yes"; then + eval "ifelse($2,,$aprt_3,$2)=ifelse($3,yes,yes,1)" + else + eval "ifelse($2,,$aprt_3,$2)=ifelse($3,yes,no,0)" + fi +done +]) + +dnl Iteratively interpolate the contents of the second argument +dnl until interpolation offers no new result. Then assign the +dnl final result to $1. +dnl +dnl Example: +dnl +dnl foo=1 +dnl bar='${foo}/2' +dnl baz='${bar}/3' +dnl APR_EXPAND_VAR(fraz, $baz) +dnl $fraz is now "1/2/3" +dnl +AC_DEFUN([APR_EXPAND_VAR], [ +ap_last= +ap_cur="$2" +while test "x${ap_cur}" != "x${ap_last}"; +do + ap_last="${ap_cur}" + ap_cur=`eval "echo ${ap_cur}"` +done +$1="${ap_cur}" +]) + +dnl +dnl Removes the value of $3 from the string in $2, strips of any leading +dnl slashes, and returns the value in $1. +dnl +dnl Example: +dnl orig_path="${prefix}/bar" +dnl APR_PATH_RELATIVE(final_path, $orig_path, $prefix) +dnl $final_path now contains "bar" +AC_DEFUN([APR_PATH_RELATIVE], [ +ap_stripped=`echo $2 | sed -e "s#^$3##"` +# check if the stripping was successful +if test "x$2" != "x${ap_stripped}"; then + # it was, so strip of any leading slashes + $1="`echo ${ap_stripped} | sed -e 's#^/*##'`" +else + # it wasn't so return the original + $1="$2" +fi +]) + +dnl APR_HELP_STRING(LHS, RHS) +dnl Autoconf 2.50 can not handle substr correctly. It does have +dnl AC_HELP_STRING, so let's try to call it if we can. +dnl Note: this define must be on one line so that it can be properly returned +dnl as the help string. When using this macro with a multi-line RHS, ensure +dnl that you surround the macro invocation with []s +AC_DEFUN([APR_HELP_STRING], [ifelse(regexp(AC_ACVERSION, 2\.1), -1, AC_HELP_STRING([$1],[$2]),[ ][$1] substr([ ],len($1))[$2])]) + +dnl +dnl APR_LAYOUT(configlayout, layoutname [, extravars]) +dnl +AC_DEFUN([APR_LAYOUT], [ + if test ! -f $srcdir/config.layout; then + echo "** Error: Layout file $srcdir/config.layout not found" + echo "** Error: Cannot use undefined layout '$LAYOUT'" + exit 1 + fi + # Catch layout names including a slash which will otherwise + # confuse the heck out of the sed script. + case $2 in + */*) + echo "** Error: $2 is not a valid layout name" + exit 1 ;; + esac + pldconf=./config.pld + changequote({,}) + sed -e "1s/[ ]*<[lL]ayout[ ]*$2[ ]*>[ ]*//;1t" \ + -e "1,/[ ]*<[lL]ayout[ ]*$2[ ]*>[ ]*/d" \ + -e '/[ ]*<\/Layout>[ ]*/,$d' \ + -e "s/^[ ]*//g" \ + -e "s/:[ ]*/=\'/g" \ + -e "s/[ ]*$/'/g" \ + $1 > $pldconf + layout_name=$2 + if test ! -s $pldconf; then + echo "** Error: unable to find layout $layout_name" + exit 1 + fi + . $pldconf + rm $pldconf + for var in prefix exec_prefix bindir sbindir libexecdir mandir \ + sysconfdir datadir includedir localstatedir runtimedir \ + logfiledir libdir installbuilddir libsuffix $3; do + eval "val=\"\$$var\"" + case $val in + *+) + val=`echo $val | sed -e 's;\+$;;'` + eval "$var=\"\$val\"" + autosuffix=yes + ;; + *) + autosuffix=no + ;; + esac + val=`echo $val | sed -e 's:\(.\)/*$:\1:'` + val=`echo $val | sed -e 's:[\$]\([a-z_]*\):${\1}:g'` + if test "$autosuffix" = "yes"; then + if echo $val | grep apache >/dev/null; then + addtarget=no + else + addtarget=yes + fi + if test "$addtarget" = "yes"; then + val="$val/apache2" + fi + fi + eval "$var='$val'" + done + changequote([,]) +])dnl + +dnl +dnl APR_ENABLE_LAYOUT(default layout name [, extra vars]) +dnl +AC_DEFUN([APR_ENABLE_LAYOUT], [ +AC_ARG_ENABLE(layout, +[ --enable-layout=LAYOUT],[ + LAYOUT=$enableval +]) + +if test -z "$LAYOUT"; then + LAYOUT="$1" +fi +APR_LAYOUT($srcdir/config.layout, $LAYOUT, $2) + +AC_MSG_CHECKING(for chosen layout) +AC_MSG_RESULT($layout_name) +]) + + +dnl +dnl APR_PARSE_ARGUMENTS +dnl a reimplementation of autoconf's argument parser, +dnl used here to allow us to co-exist layouts and argument based +dnl set ups. +AC_DEFUN([APR_PARSE_ARGUMENTS], [ +ac_prev= +# Retrieve the command-line arguments. The eval is needed because +# the arguments are quoted to preserve accuracy. +eval "set x $ac_configure_args" +shift +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval "$ac_prev=\$ac_option" + ac_prev= + continue + fi + + ac_optarg=`expr "x$ac_option" : 'x[[^=]]*=\(.*\)'` + + case $ac_option in + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir="$ac_optarg" ;; + + -datadir | --datadir | --datadi | --datad | --data | --dat | --da) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ + | --da=*) + datadir="$ac_optarg" ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix="$ac_optarg" ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir="$ac_optarg" ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir="$ac_optarg" ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir="$ac_optarg" ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir="$ac_optarg" ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst \ + | --locals | --local | --loca | --loc | --lo) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* \ + | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) + localstatedir="$ac_optarg" ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir="$ac_optarg" ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix="$ac_optarg" ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir="$ac_optarg" ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir="$ac_optarg" ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir="$ac_optarg" ;; + + esac +done + +# Be sure to have absolute paths. +for ac_var in exec_prefix prefix +do + eval ac_val=$`echo $ac_var` + case $ac_val in + [[\\/$]]* | ?:[[\\/]]* | NONE | '' ) ;; + *) AC_MSG_ERROR([expected an absolute path for --$ac_var: $ac_val]);; + esac +done + +])dnl + +dnl +dnl APR_CHECK_DEPEND +dnl +dnl Determine what program we can use to generate .deps-style dependencies +dnl +AC_DEFUN([APR_CHECK_DEPEND], [ +dnl Try to determine what depend program we can use +dnl All GCC-variants should have -MM. +dnl If not, then we can check on those, too. +if test "$GCC" = "yes"; then + MKDEP='$(CC) -MM' +else + rm -f conftest.c +dnl <sys/types.h> should be available everywhere! + cat > conftest.c <<EOF +#include <sys/types.h> + int main() { return 0; } +EOF + MKDEP="true" + for i in "$CC -MM" "$CC -M" "$CPP -MM" "$CPP -M" "cpp -M"; do + AC_MSG_CHECKING([if $i can create proper make dependencies]) + if $i conftest.c 2>/dev/null | grep 'conftest.o: conftest.c' >/dev/null; then + MKDEP=$i + AC_MSG_RESULT(yes) + break; + fi + AC_MSG_RESULT(no) + done + rm -f conftest.c +fi + +AC_SUBST(MKDEP) +]) + +dnl +dnl APR_CHECK_TYPES_COMPATIBLE(TYPE-1, TYPE-2, [ACTION-IF-TRUE]) +dnl +dnl Try to determine whether two types are the same. Only works +dnl for gcc and icc. +dnl +AC_DEFUN([APR_CHECK_TYPES_COMPATIBLE], [ +define([apr_cvname], apr_cv_typematch_[]translit([$1], [ ], [_])_[]translit([$2], [ ], [_])) +AC_CACHE_CHECK([whether $1 and $2 are the same], apr_cvname, [ +AC_TRY_COMPILE(AC_INCLUDES_DEFAULT, [ + int foo[0 - !__builtin_types_compatible_p($1, $2)]; +], [apr_cvname=yes +$3], [apr_cvname=no])]) +]) diff --git a/build/apr_hints.m4 b/build/apr_hints.m4 new file mode 100644 index 00000000000..fd3d33de059 --- /dev/null +++ b/build/apr_hints.m4 @@ -0,0 +1,522 @@ +dnl -------------------------------------------------------- -*- autoconf -*- +dnl Licensed to the Apache Software Foundation (ASF) under one or more +dnl contributor license agreements. See the NOTICE file distributed with +dnl this work for additional information regarding copyright ownership. +dnl The ASF licenses this file to You under the Apache License, Version 2.0 +dnl (the "License"); you may not use this file except in compliance with +dnl the License. You may obtain a copy of the License at +dnl +dnl http://www.apache.org/licenses/LICENSE-2.0 +dnl +dnl Unless required by applicable law or agreed to in writing, software +dnl distributed under the License is distributed on an "AS IS" BASIS, +dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +dnl See the License for the specific language governing permissions and +dnl limitations under the License. + +dnl ----------------------------------------------------------------- +dnl apr_hints.m4: APR's autoconf macros for platform-specific hints +dnl +dnl We preload various configure settings depending +dnl on previously obtained platform knowledge. +dnl We allow all settings to be overridden from +dnl the command-line. +dnl +dnl We maintain the "format" that we've used +dnl under 1.3.x, so we don't exactly follow +dnl what is "recommended" by autoconf. + +dnl +dnl APR_PRELOAD +dnl +dnl Preload various ENV/makefile params such as CC, CFLAGS, etc +dnl based on outside knowledge +dnl +dnl Generally, we force the setting of CC, and add flags +dnl to CFLAGS, CPPFLAGS, LIBS and LDFLAGS. +dnl +AC_DEFUN(APR_PRELOAD, [ +if test "x$apr_preload_done" != "xyes" ; then + + apr_preload_done="yes" + + echo "Applying APR hints file rules for $host" + + case "$host" in + *mint) + APR_ADDTO(CPPFLAGS, [-DMINT -D_GNU_SOURCE]) + ;; + *MPE/iX*) + APR_ADDTO(CPPFLAGS, [-DMPE -D_POSIX_SOURCE -D_SOCKET_SOURCE]) + APR_ADDTO(LIBS, [-lsvipc -lcurses]) + APR_ADDTO(LDFLAGS, [-Xlinker \"-WL,cap=ia,ba,ph;nmstack=1024000\"]) + ;; + *-apple-aux3*) + APR_ADDTO(CPPFLAGS, [-DAUX3 -D_POSIX_SOURCE]) + APR_ADDTO(LIBS, [-lposix -lbsd]) + APR_ADDTO(LDFLAGS, [-s]) + APR_SETVAR(SHELL, [/bin/ksh]) + ;; + *-ibm-aix*) + APR_ADDTO(CPPFLAGS, [-U__STR__ -D_THREAD_SAFE]) + dnl _USR_IRS gets us the hstrerror() proto in netdb.h + case $host in + *-ibm-aix4.3) + APR_ADDTO(CPPFLAGS, [-D_USE_IRS]) + ;; + *-ibm-aix5*) + APR_ADDTO(CPPFLAGS, [-D_USE_IRS]) + ;; + *-ibm-aix4.3.*) + APR_ADDTO(CPPFLAGS, [-D_USE_IRS]) + ;; + esac + dnl If using xlc, remember it, and give it the right options. + if $CC 2>&1 | grep 'xlc' > /dev/null; then + APR_SETIFNULL(AIX_XLC, [yes]) + APR_ADDTO(CFLAGS, [-qHALT=E]) + fi + APR_SETIFNULL(apr_sysvsem_is_global, [yes]) + APR_SETIFNULL(apr_lock_method, [USE_SYSVSEM_SERIALIZE]) + case $host in + *-ibm-aix3* | *-ibm-aix4.1.*) + ;; + *) + APR_ADDTO(LDFLAGS, [-Wl,-brtl]) + ;; + esac + ;; + *-apollo-*) + APR_ADDTO(CPPFLAGS, [-DAPOLLO]) + ;; + *-dg-dgux*) + APR_ADDTO(CPPFLAGS, [-DDGUX]) + ;; + *-os2*) + APR_SETVAR(SHELL, [sh]) + APR_SETIFNULL(apr_gethostbyname_is_thread_safe, [yes]) + APR_SETIFNULL(apr_gethostbyaddr_is_thread_safe, [yes]) + APR_SETIFNULL(apr_getservbyname_is_thread_safe, [yes]) + ;; + *-hi-hiux) + APR_ADDTO(CPPFLAGS, [-DHIUX]) + ;; + *-hp-hpux11.*) + APR_ADDTO(CPPFLAGS, [-DHPUX11 -D_REENTRANT -D_HPUX_SOURCE]) + ;; + *-hp-hpux10.*) + case $host in + *-hp-hpux10.01) +dnl # We know this is a problem in 10.01. +dnl # Not a problem in 10.20. Otherwise, who knows? + APR_ADDTO(CPPFLAGS, [-DSELECT_NEEDS_CAST]) + ;; + esac + APR_ADDTO(CPPFLAGS, [-D_REENTRANT]) + ;; + *-hp-hpux*) + APR_ADDTO(CPPFLAGS, [-DHPUX -D_REENTRANT]) + ;; + *-linux*) + APR_ADDTO(CPPFLAGS, [-DLINUX -D_REENTRANT -D_GNU_SOURCE]) + ;; + *-lynx-lynxos) + APR_ADDTO(CPPFLAGS, [-D__NO_INCLUDE_WARN__ -DLYNXOS]) + APR_ADDTO(LIBS, [-lbsd]) + ;; + *486-*-bsdi*) + APR_ADDTO(CFLAGS, [-m486]) + ;; + *-*-bsdi*) + case $host in + *bsdi4.1) + APR_ADDTO(CFLAGS, [-D_REENTRANT]) + ;; + esac + ;; + *-openbsd*) + APR_ADDTO(CPPFLAGS, [-D_POSIX_THREADS]) + # binding to an ephemeral port fails on OpenBSD so override + # the test for O_NONBLOCK inheritance across accept(). + APR_SETIFNULL(ac_cv_o_nonblock_inherited, [yes]) + ;; + *-netbsd*) + APR_ADDTO(CPPFLAGS, [-DNETBSD]) + # fcntl() lies about O_NONBLOCK on an accept()ed socket (PR kern/26950) + APR_SETIFNULL(ac_cv_o_nonblock_inherited, [yes]) + ;; + *-freebsd*) + APR_SETIFNULL(apr_lock_method, [USE_FLOCK_SERIALIZE]) + if test -x /sbin/sysctl; then + os_version=`/sbin/sysctl -n kern.osreldate` + else + os_version=000000 + fi + # 502102 is when libc_r switched to libpthread (aka libkse). + if test $os_version -ge "502102"; then + apr_cv_pthreads_cflags="none" + apr_cv_pthreads_lib="-lpthread" + else + APR_ADDTO(CPPFLAGS, [-D_THREAD_SAFE -D_REENTRANT]) + APR_SETIFNULL(enable_threads, [no]) + fi + # prevent use of KQueue before FreeBSD 4.8 + if test $os_version -lt "480000"; then + APR_SETIFNULL(ac_cv_func_kqueue, no) + fi + ;; + *-k*bsd*-gnu) + APR_ADDTO(CPPFLAGS, [-D_REENTRANT -D_GNU_SOURCE]) + ;; + *-gnu*|*-GNU*) + APR_ADDTO(CPPFLAGS, [-D_REENTRANT -D_GNU_SOURCE -DHURD]) + ;; + *-next-nextstep*) + APR_SETIFNULL(CFLAGS, [-O]) + APR_ADDTO(CPPFLAGS, [-DNEXT]) + ;; + *-next-openstep*) + APR_SETIFNULL(CFLAGS, [-O]) + APR_ADDTO(CPPFLAGS, [-DNEXT]) + ;; + *-apple-rhapsody*) + APR_ADDTO(CPPFLAGS, [-DRHAPSODY]) + ;; + *-apple-darwin*) + APR_ADDTO(CPPFLAGS, [-DDARWIN -DSIGPROCMASK_SETS_THREAD_MASK]) + APR_SETIFNULL(apr_posixsem_is_global, [yes]) + case $host in + *-apple-darwin[[1-9]].*) + # APR's use of kqueue has triggered kernel panics for some + # 10.5.x (Darwin 9.x) users when running the entire test suite. + # In 10.4.x, use of kqueue would cause the socket tests to hang. + # 10.6+ (Darwin 10.x is supposed to fix the KQueue issues + APR_SETIFNULL(ac_cv_func_kqueue, [no]) + APR_SETIFNULL(ac_cv_func_poll, [no]) # See issue 34332 + ;; + *-apple-darwin1?.*) + APR_ADDTO(CPPFLAGS, [-DDARWIN_10]) + ;; + esac + ;; + *-dec-osf*) + APR_ADDTO(CPPFLAGS, [-DOSF1]) + # process-shared mutexes don't seem to work in Tru64 5.0 + APR_SETIFNULL(apr_cv_process_shared_works, [no]) + ;; + *-nto-qnx*) + ;; + *-qnx) + APR_ADDTO(CPPFLAGS, [-DQNX]) + APR_ADDTO(LIBS, [-N128k -lunix]) + ;; + *-qnx32) + APR_ADDTO(CPPFLAGS, [-DQNX]) + APR_ADDTO(CFLAGS, [-mf -3]) + APR_ADDTO(LIBS, [-N128k -lunix]) + ;; + *-isc4*) + APR_ADDTO(CPPFLAGS, [-posix -DISC]) + APR_ADDTO(LDFLAGS, [-posix]) + APR_ADDTO(LIBS, [-linet]) + ;; + *-sco3.2v[[234]]*) + APR_ADDTO(CPPFLAGS, [-DSCO -D_REENTRANT]) + if test "$GCC" = "no"; then + APR_ADDTO(CFLAGS, [-Oacgiltz]) + fi + APR_ADDTO(LIBS, [-lPW -lmalloc]) + ;; + *-sco3.2v5*) + APR_ADDTO(CPPFLAGS, [-DSCO5 -D_REENTRANT]) + ;; + *-sco_sv*|*-SCO_SV*) + APR_ADDTO(CPPFLAGS, [-DSCO -D_REENTRANT]) + APR_ADDTO(LIBS, [-lPW -lmalloc]) + ;; + *-solaris2*) + PLATOSVERS=`echo $host | sed 's/^.*solaris2.//'` + APR_ADDTO(CPPFLAGS, [-DSOLARIS2=$PLATOSVERS -D_POSIX_PTHREAD_SEMANTICS -D_REENTRANT]) + if test $PLATOSVERS -eq 10; then + # pthread_mutex_timedlock is broken on Solaris 10. + # It can block without timeout in case of EDEADLK. + APR_SETIFNULL(ac_cv_func_pthread_mutex_timedlock, [no]) + fi + if test $PLATOSVERS -ge 10; then + APR_SETIFNULL(apr_lock_method, [USE_PROC_PTHREAD_SERIALIZE]) + else + APR_SETIFNULL(apr_lock_method, [USE_FCNTL_SERIALIZE]) + fi + # readdir64_r error handling seems broken on Solaris (at least + # up till 2.8) -- it will return -1 at end-of-directory. + APR_SETIFNULL(ac_cv_func_readdir64_r, [no]) + ;; + *-sunos4*) + APR_ADDTO(CPPFLAGS, [-DSUNOS4]) + ;; + *-unixware1) + APR_ADDTO(CPPFLAGS, [-DUW=100]) + ;; + *-unixware2) + APR_ADDTO(CPPFLAGS, [-DUW=200]) + APR_ADDTO(LIBS, [-lgen]) + ;; + *-unixware211) + APR_ADDTO(CPPFLAGS, [-DUW=211]) + APR_ADDTO(LIBS, [-lgen]) + ;; + *-unixware212) + APR_ADDTO(CPPFLAGS, [-DUW=212]) + APR_ADDTO(LIBS, [-lgen]) + ;; + *-unixware7) + APR_ADDTO(CPPFLAGS, [-DUW=700]) + APR_ADDTO(LIBS, [-lgen]) + ;; + maxion-*-sysv4*) + APR_ADDTO(CPPFLAGS, [-DSVR4]) + APR_ADDTO(LIBS, [-lc -lgen]) + ;; + *-*-powermax*) + APR_ADDTO(CPPFLAGS, [-DSVR4]) + APR_ADDTO(LIBS, [-lgen]) + ;; + TPF) + APR_ADDTO(CPPFLAGS, [-DTPF -D_POSIX_SOURCE]) + ;; + bs2000*-siemens-sysv*) + APR_SETIFNULL(CFLAGS, [-O]) + APR_ADDTO(CPPFLAGS, [-DSVR4 -D_XPG_IV -D_KMEMUSER]) + APR_ADDTO(LIBS, [-lsocket]) + APR_SETIFNULL(enable_threads, [no]) + ;; + *-siemens-sysv4*) + APR_ADDTO(CPPFLAGS, [-DSVR4 -D_XPG_IV -DHAS_DLFCN -DUSE_MMAP_FILES -DUSE_SYSVSEM_SERIALIZED_ACCEPT]) + APR_ADDTO(LIBS, [-lc]) + ;; + pyramid-pyramid-svr4) + APR_ADDTO(CPPFLAGS, [-DSVR4 -DNO_LONG_DOUBLE]) + APR_ADDTO(LIBS, [-lc]) + ;; + DS/90\ 7000-*-sysv4*) + APR_ADDTO(CPPFLAGS, [-DUXPDS]) + ;; + *-tandem-sysv4*) + APR_ADDTO(CPPFLAGS, [-DSVR4]) + ;; + *-ncr-sysv4) + APR_ADDTO(CPPFLAGS, [-DSVR4 -DMPRAS]) + APR_ADDTO(LIBS, [-lc -L/usr/ucblib -lucb]) + ;; + *-sysv4*) + APR_ADDTO(CPPFLAGS, [-DSVR4]) + APR_ADDTO(LIBS, [-lc]) + ;; + 88k-encore-sysv4) + APR_ADDTO(CPPFLAGS, [-DSVR4 -DENCORE]) + APR_ADDTO(LIBS, [-lPW]) + ;; + *-uts*) + PLATOSVERS=`echo $host | sed 's/^.*,//'` + case $PLATOSVERS in + 2*) APR_ADDTO(CPPFLAGS, [-DUTS21]) + APR_ADDTO(CFLAGS, [-Xa -eft]) + APR_ADDTO(LIBS, [-lbsd -la]) + ;; + *) APR_ADDTO(CPPFLAGS, [-DSVR4]) + APR_ADDTO(CFLAGS, [-Xa]) + ;; + esac + ;; + *-ultrix) + APR_ADDTO(CPPFLAGS, [-DULTRIX]) + APR_SETVAR(SHELL, [/bin/sh5]) + ;; + *powerpc-tenon-machten*) + APR_ADDTO(LDFLAGS, [-Xlstack=0x14000 -Xldelcsect]) + ;; + *-machten*) + APR_ADDTO(LDFLAGS, [-stack 0x14000]) + ;; + *convex-v11*) + APR_ADDTO(CPPFLAGS, [-DCONVEXOS11]) + APR_SETIFNULL(CFLAGS, [-O1]) + APR_ADDTO(CFLAGS, [-ext]) + ;; + i860-intel-osf1) + APR_ADDTO(CPPFLAGS, [-DPARAGON]) + ;; + *-sequent-ptx2.*.*) + APR_ADDTO(CPPFLAGS, [-DSEQUENT=20]) + APR_ADDTO(CFLAGS, [-Wc,-pw]) + APR_ADDTO(LIBS, [-linet -lc -lseq]) + ;; + *-sequent-ptx4.0.*) + APR_ADDTO(CPPFLAGS, [-DSEQUENT=40]) + APR_ADDTO(CFLAGS, [-Wc,-pw]) + APR_ADDTO(LIBS, [-linet -lc]) + ;; + *-sequent-ptx4.[[123]].*) + APR_ADDTO(CPPFLAGS, [-DSEQUENT=41]) + APR_ADDTO(CFLAGS, [-Wc,-pw]) + APR_ADDTO(LIBS, [-lc]) + ;; + *-sequent-ptx4.4.*) + APR_ADDTO(CPPFLAGS, [-DSEQUENT=44]) + APR_ADDTO(CFLAGS, [-Wc,-pw]) + APR_ADDTO(LIBS, [-lc]) + ;; + *-sequent-ptx4.5.*) + APR_ADDTO(CPPFLAGS, [-DSEQUENT=45]) + APR_ADDTO(CFLAGS, [-Wc,-pw]) + APR_ADDTO(LIBS, [-lc]) + ;; + *-sequent-ptx5.0.*) + APR_ADDTO(CPPFLAGS, [-DSEQUENT=50]) + APR_ADDTO(CFLAGS, [-Wc,-pw]) + APR_ADDTO(LIBS, [-lc]) + ;; + *NEWS-OS*) + APR_ADDTO(CPPFLAGS, [-DNEWSOS]) + ;; + *-riscix) + APR_ADDTO(CPPFLAGS, [-DRISCIX]) + APR_SETIFNULL(CFLAGS, [-O]) + ;; + *-irix*) + APR_ADDTO(CPPFLAGS, [-D_POSIX_THREAD_SAFE_FUNCTIONS]) + ;; + *beos*) + APR_ADDTO(CPPFLAGS, [-DBEOS]) + PLATOSVERS=`uname -r` + APR_SETIFNULL(apr_process_lock_is_global, [yes]) + case $PLATOSVERS in + 5.0.4) + APR_ADDTO(LDFLAGS, [-L/boot/beos/system/lib]) + APR_ADDTO(LIBS, [-lbind -lsocket]) + APR_ADDTO(CPPFLAGS,[-DBONE7]) + ;; + 5.1) + APR_ADDTO(LDFLAGS, [-L/boot/beos/system/lib]) + APR_ADDTO(LIBS, [-lbind -lsocket]) + ;; + esac + APR_ADDTO(CPPFLAGS, [-DSIGPROCMASK_SETS_THREAD_MASK]) + ;; + 4850-*.*) + APR_ADDTO(CPPFLAGS, [-DSVR4 -DMPRAS]) + APR_ADDTO(LIBS, [-lc -L/usr/ucblib -lucb]) + ;; + drs6000*) + APR_ADDTO(CPPFLAGS, [-DSVR4]) + APR_ADDTO(LIBS, [-lc -L/usr/ucblib -lucb]) + ;; + m88k-*-CX/SX|CYBER) + APR_ADDTO(CPPFLAGS, [-D_CX_SX]) + APR_ADDTO(CFLAGS, [-Xa]) + ;; + *-tandem-oss) + APR_ADDTO(CPPFLAGS, [-D_TANDEM_SOURCE -D_XOPEN_SOURCE_EXTENDED=1]) + ;; + *-ibm-os390) + APR_SETIFNULL(apr_lock_method, [USE_SYSVSEM_SERIALIZE]) + APR_SETIFNULL(apr_sysvsem_is_global, [yes]) + APR_SETIFNULL(apr_gethostbyname_is_thread_safe, [yes]) + APR_SETIFNULL(apr_gethostbyaddr_is_thread_safe, [yes]) + APR_SETIFNULL(apr_getservbyname_is_thread_safe, [yes]) + AC_DEFINE(HAVE_ZOS_PTHREADS, 1, [Define for z/OS pthread API nuances]) + APR_ADDTO(CPPFLAGS, [-U_NO_PROTO -DSIGPROCMASK_SETS_THREAD_MASK -DTCP_NODELAY=1]) + ;; + *-ibm-as400) + APR_SETIFNULL(apr_lock_method, [USE_SYSVSEM_SERIALIZE]) + APR_SETIFNULL(apr_process_lock_is_global, [yes]) + APR_SETIFNULL(apr_gethostbyname_is_thread_safe, [yes]) + APR_SETIFNULL(apr_gethostbyaddr_is_thread_safe, [yes]) + APR_SETIFNULL(apr_getservbyname_is_thread_safe, [yes]) + ;; + *mingw*) + APR_ADDTO(INTERNAL_CPPFLAGS, -DBINPATH=$apr_builddir/test/.libs) + APR_ADDTO(CPPFLAGS, [-DWIN32 -D__MSVCRT__]) + APR_ADDTO(LDFLAGS, [-Wl,--enable-auto-import,--subsystem,console]) + APR_SETIFNULL(have_unicode_fs, [1]) + APR_SETIFNULL(have_proc_invoked, [1]) + APR_SETIFNULL(apr_lock_method, [win32]) + APR_SETIFNULL(apr_process_lock_is_global, [yes]) + APR_SETIFNULL(apr_cv_use_lfs64, [yes]) + APR_SETIFNULL(apr_cv_osuuid, [yes]) + APR_SETIFNULL(apr_cv_tcp_nodelay_with_cork, [no]) + APR_SETIFNULL(apr_thread_func, [__stdcall]) + APR_SETIFNULL(ac_cv_o_nonblock_inherited, [yes]) + APR_SETIFNULL(ac_cv_tcp_nodelay_inherited, [yes]) + APR_SETIFNULL(ac_cv_file__dev_zero, [no]) + APR_SETIFNULL(ac_cv_func_setpgrp_void, [no]) + APR_SETIFNULL(ac_cv_func_mmap, [yes]) + APR_SETIFNULL(ac_cv_define_sockaddr_in6, [yes]) + APR_SETIFNULL(ac_cv_working_getaddrinfo, [yes]) + APR_SETIFNULL(ac_cv_working_getnameinfo, [yes]) + APR_SETIFNULL(ac_cv_func_gai_strerror, [yes]) + case $host in + *mingw32*) + APR_SETIFNULL(apr_has_xthread_files, [1]) + APR_SETIFNULL(apr_has_user, [1]) + APR_SETIFNULL(apr_procattr_user_set_requires_password, [1]) + dnl The real function is TransmitFile(), not sendfile(), but + dnl this bypasses the Linux/Solaris/AIX/etc. test and enables + dnl the TransmitFile() implementation. + APR_SETIFNULL(ac_cv_func_sendfile, [yes]) + ;; + *mingwce) + APR_SETIFNULL(apr_has_xthread_files, [0]) + APR_SETIFNULL(apr_has_user, [0]) + APR_SETIFNULL(apr_procattr_user_set_requires_password, [0]) + APR_SETIFNULL(ac_cv_func_sendfile, [no]) + ;; + esac + ;; + esac + +fi +]) + +dnl +dnl APR_CC_HINTS +dnl +dnl Allows us to provide a default choice of compiler which +dnl the user can override. +AC_DEFUN(APR_CC_HINTS, [ +case "$host" in + *-apple-aux3*) + APR_SETIFNULL(CC, [gcc]) + ;; + bs2000*-siemens-sysv*) + APR_SETIFNULL(CC, [c89 -XLLML -XLLMK -XL -Kno_integer_overflow]) + ;; + *convex-v11*) + APR_SETIFNULL(CC, [cc]) + ;; + *-ibm-os390) + APR_SETIFNULL(CC, [cc]) + ;; + *-ibm-as400) + APR_SETIFNULL(CC, [icc]) + ;; + *-isc4*) + APR_SETIFNULL(CC, [gcc]) + ;; + m88k-*-CX/SX|CYBER) + APR_SETIFNULL(CC, [cc]) + ;; + *-next-openstep*) + APR_SETIFNULL(CC, [cc]) + ;; + *-qnx32) + APR_SETIFNULL(CC, [cc -F]) + ;; + *-tandem-oss) + APR_SETIFNULL(CC, [c89]) + ;; + TPF) + APR_SETIFNULL(CC, [c89]) + ;; +esac +]) diff --git a/build/apr_network.m4 b/build/apr_network.m4 new file mode 100644 index 00000000000..24889828308 --- /dev/null +++ b/build/apr_network.m4 @@ -0,0 +1,994 @@ +dnl -------------------------------------------------------- -*- autoconf -*- +dnl Licensed to the Apache Software Foundation (ASF) under one or more +dnl contributor license agreements. See the NOTICE file distributed with +dnl this work for additional information regarding copyright ownership. +dnl The ASF licenses this file to You under the Apache License, Version 2.0 +dnl (the "License"); you may not use this file except in compliance with +dnl the License. You may obtain a copy of the License at +dnl +dnl http://www.apache.org/licenses/LICENSE-2.0 +dnl +dnl Unless required by applicable law or agreed to in writing, software +dnl distributed under the License is distributed on an "AS IS" BASIS, +dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +dnl See the License for the specific language governing permissions and +dnl limitations under the License. + +dnl ----------------------------------------------------------------- +dnl apr_network.m4: APR's autoconf macros for testing network support +dnl + +dnl +dnl check for type in_addr +dnl +AC_DEFUN(APR_TYPE_IN_ADDR,[ + AC_CACHE_CHECK(for type in_addr, ac_cv_type_in_addr,[ + AC_TRY_COMPILE([ +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#ifdef HAVE_NETINET_IN_H +#include <netinet/in.h> +#endif +#ifdef HAVE_WINSOCK2_H +#include <winsock2.h> +#endif +],[ + struct in_addr arg; + arg.s_addr = htonl(INADDR_ANY); +], [ ac_cv_type_in_addr="yes"] , [ +ac_cv_type_in_addr="no"]) +]) +]) + +dnl +dnl check for working getaddrinfo() +dnl +dnl Note that if the system doesn't have gai_strerror(), we +dnl can't use getaddrinfo() because we can't get strings +dnl describing the error codes. +dnl +AC_DEFUN([APR_CHECK_WORKING_GETADDRINFO], [ + AC_CACHE_CHECK(for working getaddrinfo, ac_cv_working_getaddrinfo,[ + AC_TRY_RUN( [ +#ifdef HAVE_NETDB_H +#include <netdb.h> +#endif +#ifdef HAVE_STRING_H +#include <string.h> +#endif +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#ifdef HAVE_SYS_SOCKET_H +#include <sys/socket.h> +#endif + +int main(void) { + struct addrinfo hints, *ai; + int error; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + error = getaddrinfo("127.0.0.1", NULL, &hints, &ai); + if (error) { + exit(1); + } + if (ai->ai_addr->sa_family != AF_INET) { + exit(1); + } + exit(0); +} +],[ + ac_cv_working_getaddrinfo="yes" +],[ + ac_cv_working_getaddrinfo="no" +],[ + ac_cv_working_getaddrinfo="yes" +])]) +if test "$ac_cv_working_getaddrinfo" = "yes"; then + if test "$ac_cv_func_gai_strerror" != "yes"; then + ac_cv_working_getaddrinfo="no" + else + AC_DEFINE(HAVE_GETADDRINFO, 1, [Define if getaddrinfo exists and works well enough for APR]) + fi +fi +]) + +dnl Check whether the AI_ADDRCONFIG flag can be used with getaddrinfo +AC_DEFUN([APR_CHECK_GETADDRINFO_ADDRCONFIG], [ + AC_CACHE_CHECK(for working AI_ADDRCONFIG, apr_cv_gai_addrconfig, [ + AC_TRY_RUN([ +#ifdef HAVE_NETDB_H +#include <netdb.h> +#endif +#ifdef HAVE_STRING_H +#include <string.h> +#endif +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#ifdef HAVE_SYS_SOCKET_H +#include <sys/socket.h> +#endif + +int main(int argc, char **argv) { + struct addrinfo hints, *ai; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_ADDRCONFIG; + return getaddrinfo("localhost", NULL, &hints, &ai) != 0; +}], [apr_cv_gai_addrconfig=yes], + [apr_cv_gai_addrconfig=no], + [apr_cv_gai_addrconfig=no])]) + +if test $apr_cv_gai_addrconfig = yes; then + AC_DEFINE(HAVE_GAI_ADDRCONFIG, 1, [Define if getaddrinfo accepts the AI_ADDRCONFIG flag]) +fi +]) + +dnl +dnl check for working getnameinfo() +dnl +AC_DEFUN([APR_CHECK_WORKING_GETNAMEINFO], [ + AC_CACHE_CHECK(for working getnameinfo, ac_cv_working_getnameinfo,[ + AC_TRY_RUN( [ +#ifdef HAVE_NETDB_H +#include <netdb.h> +#endif +#ifdef HAVE_STRING_H +#include <string.h> +#endif +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#ifdef HAVE_SYS_SOCKET_H +#include <sys/socket.h> +#endif +#ifdef HAVE_NETINET_IN_H +#include <netinet/in.h> +#endif + +int main(void) { + struct sockaddr_in sa; + char hbuf[256]; + int error; + + sa.sin_family = AF_INET; + sa.sin_port = 0; + sa.sin_addr.s_addr = inet_addr("127.0.0.1"); +#ifdef SIN6_LEN + sa.sin_len = sizeof(sa); +#endif + + error = getnameinfo((const struct sockaddr *)&sa, sizeof(sa), + hbuf, 256, NULL, 0, + NI_NUMERICHOST); + if (error) { + exit(1); + } else { + exit(0); + } +} +],[ + ac_cv_working_getnameinfo="yes" +],[ + ac_cv_working_getnameinfo="no" +],[ + ac_cv_working_getnameinfo="yes" +])]) +if test "$ac_cv_working_getnameinfo" = "yes"; then + AC_DEFINE(HAVE_GETNAMEINFO, 1, [Define if getnameinfo exists]) +fi +]) + +dnl +dnl check for negative error codes for getaddrinfo() +dnl +AC_DEFUN([APR_CHECK_NEGATIVE_EAI], [ + AC_CACHE_CHECK(for negative error codes for getaddrinfo, ac_cv_negative_eai,[ + AC_TRY_RUN( [ +#ifdef HAVE_NETDB_H +#include <netdb.h> +#endif + +int main(void) { + if (EAI_ADDRFAMILY < 0) { + exit(0); + } + exit(1); +} +],[ + ac_cv_negative_eai="yes" +],[ + ac_cv_negative_eai="no" +],[ + ac_cv_negative_eai="no" +])]) +if test "$ac_cv_negative_eai" = "yes"; then + AC_DEFINE(NEGATIVE_EAI, 1, [Define if EAI_ error codes from getaddrinfo are negative]) +fi +]) + +dnl +dnl Checks the definition of gethostbyname_r and gethostbyaddr_r +dnl which are different for glibc, solaris and assorted other operating +dnl systems +dnl +dnl Note that this test is executed too early to see if we have all of +dnl the headers. +AC_DEFUN([APR_CHECK_GETHOSTBYNAME_R_STYLE], [ + +dnl Try and compile a glibc2 gethostbyname_r piece of code, and set the +dnl style of the routines to glibc2 on success +AC_CACHE_CHECK([style of gethostbyname_r routine], ac_cv_gethostbyname_r_style, +APR_TRY_COMPILE_NO_WARNING([ +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#ifdef HAVE_NETINET_IN_H +#include <netinet/in.h> +#endif +#ifdef HAVE_ARPA_INET_H +#include <arpa/inet.h> +#endif +#ifdef HAVE_NETDB_H +#include <netdb.h> +#endif +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif +],[ +int tmp = gethostbyname_r((const char *) 0, (struct hostent *) 0, + (char *) 0, 0, (struct hostent **) 0, &tmp); +/* use tmp to suppress the warning */ +tmp=0; +], ac_cv_gethostbyname_r_style=glibc2, ac_cv_gethostbyname_r_style=none)) + +if test "$ac_cv_gethostbyname_r_style" = "glibc2"; then + AC_DEFINE(GETHOSTBYNAME_R_GLIBC2, 1, [Define if gethostbyname_r has the glibc style]) +fi + +AC_CACHE_CHECK([3rd argument to the gethostbyname_r routines], ac_cv_gethostbyname_r_arg, +APR_TRY_COMPILE_NO_WARNING([ +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#ifdef HAVE_NETINET_IN_H +#include <netinet/in.h> +#endif +#ifdef HAVE_ARPA_INET_H +#include <arpa/inet.h> +#endif +#ifdef HAVE_NETDB_H +#include <netdb.h> +#endif +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif +],[ +int tmp = gethostbyname_r((const char *) 0, (struct hostent *) 0, + (struct hostent_data *) 0); +/* use tmp to suppress the warning */ +tmp=0; +], ac_cv_gethostbyname_r_arg=hostent_data, ac_cv_gethostbyname_r_arg=char)) + +if test "$ac_cv_gethostbyname_r_arg" = "hostent_data"; then + AC_DEFINE(GETHOSTBYNAME_R_HOSTENT_DATA, 1, [Define if gethostbyname_r has the hostent_data for the third argument]) +fi +]) + +dnl +dnl Checks the definition of getservbyname_r +dnl which are different for glibc, solaris and assorted other operating +dnl systems +dnl +dnl Note that this test is executed too early to see if we have all of +dnl the headers. +AC_DEFUN([APR_CHECK_GETSERVBYNAME_R_STYLE], [ + +dnl Try and compile a glibc2 getservbyname_r piece of code, and set the +dnl style of the routines to glibc2 on success +AC_CACHE_CHECK([style of getservbyname_r routine], ac_cv_getservbyname_r_style, [ +APR_TRY_COMPILE_NO_WARNING([ +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#ifdef HAVE_NETINET_IN_H +#include <netinet/in.h> +#endif +#ifdef HAVE_ARPA_INET_H +#include <arpa/inet.h> +#endif +#ifdef HAVE_NETDB_H +#include <netdb.h> +#endif +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif +],[ +int tmp = getservbyname_r((const char *) 0, (const char *) 0, + (struct servent *) 0, (char *) 0, 0, + (struct servent **) 0); +/* use tmp to suppress the warning */ +tmp=0; +], ac_cv_getservbyname_r_style=glibc2, ac_cv_getservbyname_r_style=none) + +if test "$ac_cv_getservbyname_r_style" = "none"; then + dnl Try and compile a Solaris getservbyname_r piece of code, and set the + dnl style of the routines to solaris on success + APR_TRY_COMPILE_NO_WARNING([ + #ifdef HAVE_SYS_TYPES_H + #include <sys/types.h> + #endif + #ifdef HAVE_NETINET_IN_H + #include <netinet/in.h> + #endif + #ifdef HAVE_ARPA_INET_H + #include <arpa/inet.h> + #endif + #ifdef HAVE_NETDB_H + #include <netdb.h> + #endif + #ifdef HAVE_STDLIB_H + #include <stdlib.h> + #endif + ],[ + struct servent *tmp = getservbyname_r((const char *) 0, (const char *) 0, + (struct servent *) 0, (char *) 0, 0); + /* use tmp to suppress the warning */ + tmp=NULL; + ], ac_cv_getservbyname_r_style=solaris, ac_cv_getservbyname_r_style=none) +fi + +if test "$ac_cv_getservbyname_r_style" = "none"; then + dnl Try and compile a OSF/1 getservbyname_r piece of code, and set the + dnl style of the routines to osf1 on success + APR_TRY_COMPILE_NO_WARNING([ + #ifdef HAVE_SYS_TYPES_H + #include <sys/types.h> + #endif + #ifdef HAVE_NETINET_IN_H + #include <netinet/in.h> + #endif + #ifdef HAVE_ARPA_INET_H + #include <arpa/inet.h> + #endif + #ifdef HAVE_NETDB_H + #include <netdb.h> + #endif + #ifdef HAVE_STDLIB_H + #include <stdlib.h> + #endif + ],[ + int tmp = getservbyname_r((const char *) 0, (const char *) 0, + (struct servent *) 0, (struct servent_data *) 0); + /* use tmp to suppress the warning */ + tmp=0; + ], ac_cv_getservbyname_r_style=osf1, ac_cv_getservbyname_r_style=none) +fi +]) + +if test "$ac_cv_getservbyname_r_style" = "glibc2"; then + AC_DEFINE(GETSERVBYNAME_R_GLIBC2, 1, [Define if getservbyname_r has the glibc style]) +elif test "$ac_cv_getservbyname_r_style" = "solaris"; then + AC_DEFINE(GETSERVBYNAME_R_SOLARIS, 1, [Define if getservbyname_r has the Solaris style]) +elif test "$ac_cv_getservbyname_r_style" = "osf1"; then + AC_DEFINE(GETSERVBYNAME_R_OSF1, 1, [Define if getservbyname_r has the OSF/1 style]) +fi +]) + +dnl +dnl see if TCP_NODELAY setting is inherited from listening sockets +dnl +AC_DEFUN([APR_CHECK_TCP_NODELAY_INHERITED], [ + AC_CACHE_CHECK(if TCP_NODELAY setting is inherited from listening sockets, ac_cv_tcp_nodelay_inherited,[ + AC_TRY_RUN( [ +#include <stdio.h> +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#ifdef HAVE_SYS_SOCKET_H +#include <sys/socket.h> +#endif +#ifdef HAVE_NETINET_IN_H +#include <netinet/in.h> +#endif +#ifdef HAVE_NETINET_TCP_H +#include <netinet/tcp.h> +#endif +#ifndef HAVE_SOCKLEN_T +typedef int socklen_t; +#endif +int main(void) { + int listen_s, connected_s, client_s; + int listen_port, rc; + struct sockaddr_in sa; + socklen_t sa_len; + socklen_t option_len; + int option; + + listen_s = socket(AF_INET, SOCK_STREAM, 0); + if (listen_s < 0) { + perror("socket"); + exit(1); + } + option = 1; + rc = setsockopt(listen_s, IPPROTO_TCP, TCP_NODELAY, &option, sizeof option); + if (rc < 0) { + perror("setsockopt TCP_NODELAY"); + exit(1); + } + memset(&sa, 0, sizeof sa); + sa.sin_family = AF_INET; +#ifdef BEOS + sa.sin_addr.s_addr = htonl(INADDR_LOOPBACK); +#endif + /* leave port 0 to get ephemeral */ + rc = bind(listen_s, (struct sockaddr *)&sa, sizeof sa); + if (rc < 0) { + perror("bind for ephemeral port"); + exit(1); + } + /* find ephemeral port */ + sa_len = sizeof(sa); + rc = getsockname(listen_s, (struct sockaddr *)&sa, &sa_len); + if (rc < 0) { + perror("getsockname"); + exit(1); + } + listen_port = sa.sin_port; + rc = listen(listen_s, 5); + if (rc < 0) { + perror("listen"); + exit(1); + } + client_s = socket(AF_INET, SOCK_STREAM, 0); + if (client_s < 0) { + perror("socket"); + exit(1); + } + memset(&sa, 0, sizeof sa); + sa.sin_family = AF_INET; + sa.sin_port = listen_port; +#ifdef BEOS + sa.sin_addr.s_addr = htonl(INADDR_LOOPBACK); +#endif + /* leave sin_addr all zeros to use loopback */ + rc = connect(client_s, (struct sockaddr *)&sa, sizeof sa); + if (rc < 0) { + perror("connect"); + exit(1); + } + sa_len = sizeof sa; + connected_s = accept(listen_s, (struct sockaddr *)&sa, &sa_len); + if (connected_s < 0) { + perror("accept"); + exit(1); + } + option_len = sizeof option; + rc = getsockopt(connected_s, IPPROTO_TCP, TCP_NODELAY, &option, &option_len); + if (rc < 0) { + perror("getsockopt"); + exit(1); + } + if (!option) { + fprintf(stderr, "TCP_NODELAY is not set in the child.\n"); + exit(1); + } + return 0; +} +],[ + ac_cv_tcp_nodelay_inherited="yes" +],[ + ac_cv_tcp_nodelay_inherited="no" +],[ + ac_cv_tcp_nodelay_inherited="yes" +])]) +if test "$ac_cv_tcp_nodelay_inherited" = "yes"; then + tcp_nodelay_inherited=1 +else + tcp_nodelay_inherited=0 +fi +]) + +dnl +dnl Determine whether TCP_NODELAY and TCP_CORK can both be set +dnl on a TCP socket. +dnl +AC_DEFUN([APR_CHECK_TCP_NODELAY_WITH_CORK], [ +AC_CACHE_CHECK([whether TCP_NODELAY and TCP_CORK can both be enabled], +[apr_cv_tcp_nodelay_with_cork], +[AC_RUN_IFELSE([AC_LANG_PROGRAM([[ +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#ifdef HAVE_SYS_SOCKET_H +#include <sys/socket.h> +#endif +#ifdef HAVE_NETINET_IN_H +#include <netinet/in.h> +#endif +#ifdef HAVE_NETINET_TCP_H +#include <netinet/tcp.h> +#endif +#include <stdio.h> +#include <stdlib.h> +]], [[ + int fd, flag, rc; + + fd = socket(AF_INET, SOCK_STREAM, 0); + if (fd < 0) { + exit(1); + } + + flag = 1; + rc = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof flag); + if (rc < 0) { + perror("setsockopt TCP_NODELAY"); + exit(2); + } + + flag = 1; + rc = setsockopt(fd, IPPROTO_TCP, TCP_CORK, &flag, sizeof flag); + if (rc < 0) { + perror("setsockopt TCP_CORK"); + exit(3); + } + + exit(0); +]])], [apr_cv_tcp_nodelay_with_cork=yes], [apr_cv_tcp_nodelay_with_cork=no])]) + +if test "$apr_cv_tcp_nodelay_with_cork" = "yes"; then + AC_DEFINE([HAVE_TCP_NODELAY_WITH_CORK], 1, + [Define if TCP_NODELAY and TCP_CORK can be enabled at the same time]) +fi +]) + + +dnl +dnl see if O_NONBLOCK setting is inherited from listening sockets +dnl +AC_DEFUN([APR_CHECK_O_NONBLOCK_INHERITED], [ + AC_CACHE_CHECK(if O_NONBLOCK setting is inherited from listening sockets, ac_cv_o_nonblock_inherited,[ + AC_TRY_RUN( [ +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif +#ifdef HAVE_STRING_H +#include <string.h> +#endif +#ifdef HAVE_STDIO_H +#include <stdio.h> +#endif +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#ifdef HAVE_SYS_SOCKET_H +#include <sys/socket.h> +#endif +#ifdef HAVE_SYS_TIME_H +#include <sys/time.h> +#endif +#ifdef HAVE_SYS_SELECT_H +#include <sys/select.h> +#endif +#ifdef HAVE_NETINET_IN_H +#include <netinet/in.h> +#endif +#ifdef HAVE_NETINET_TCP_H +#include <netinet/tcp.h> +#endif +#ifndef HAVE_SOCKLEN_T +typedef int socklen_t; +#endif +#ifdef HAVE_FCNTL_H +#include <fcntl.h> +#endif +int main(void) { + int listen_s, connected_s, client_s; + int listen_port, rc; + struct sockaddr_in sa; + socklen_t sa_len; + fd_set fds; + struct timeval tv; + + listen_s = socket(AF_INET, SOCK_STREAM, 0); + if (listen_s < 0) { + perror("socket"); + exit(1); + } + memset(&sa, 0, sizeof sa); + sa.sin_family = AF_INET; +#ifdef BEOS + sa.sin_addr.s_addr = htonl(INADDR_LOOPBACK); +#endif + /* leave port 0 to get ephemeral */ + rc = bind(listen_s, (struct sockaddr *)&sa, sizeof sa); + if (rc < 0) { + perror("bind for ephemeral port"); + exit(1); + } + /* find ephemeral port */ + sa_len = sizeof(sa); + rc = getsockname(listen_s, (struct sockaddr *)&sa, &sa_len); + if (rc < 0) { + perror("getsockname"); + exit(1); + } + listen_port = sa.sin_port; + rc = listen(listen_s, 5); + if (rc < 0) { + perror("listen"); + exit(1); + } + rc = fcntl(listen_s, F_SETFL, O_NONBLOCK); + if (rc < 0) { + perror("fcntl(F_SETFL)"); + exit(1); + } + client_s = socket(AF_INET, SOCK_STREAM, 0); + if (client_s < 0) { + perror("socket"); + exit(1); + } + memset(&sa, 0, sizeof sa); + sa.sin_family = AF_INET; + sa.sin_port = listen_port; +#ifdef BEOS + sa.sin_addr.s_addr = htonl(INADDR_LOOPBACK); +#endif + /* leave sin_addr all zeros to use loopback */ + rc = connect(client_s, (struct sockaddr *)&sa, sizeof sa); + if (rc < 0) { + perror("connect"); + exit(1); + } + sa_len = sizeof sa; + /* 1 second select timeout */ + tv.tv_sec = 1; + tv.tv_usec = 0; + /* Set up fd set */ + FD_ZERO(&fds); + FD_SET(listen_s, &fds); + /* Wait for socket to become readable */ + rc = select(listen_s + 1, &fds, NULL, NULL, &tv); + if (rc < 0) { + perror("select"); + exit(1); + } + if (rc == 0) { + fprintf(stderr, "Socket failed to become readable (timeout)\n"); + exit(1); + } + if (!FD_ISSET(listen_s, &fds)) { + fprintf(stderr, "Socket failed to become readable (selected another fd)\n"); + exit(1); + } + connected_s = accept(listen_s, (struct sockaddr *)&sa, &sa_len); + if (connected_s < 0) { + perror("accept"); + exit(1); + } + rc = fcntl(connected_s, F_GETFL, 0); + if (rc < 0) { + perror("fcntl(F_GETFL)"); + exit(1); + } + if (!(rc & O_NONBLOCK)) { + fprintf(stderr, "O_NONBLOCK is not set in the child.\n"); + exit(1); + } + return 0; +} +],[ + ac_cv_o_nonblock_inherited="yes" +],[ + ac_cv_o_nonblock_inherited="no" +],[ + ac_cv_o_nonblock_inherited="yes" +])]) +if test "$ac_cv_o_nonblock_inherited" = "yes"; then + o_nonblock_inherited=1 +else + o_nonblock_inherited=0 +fi +]) + +dnl +dnl check for socklen_t, fall back to unsigned int +dnl +AC_DEFUN([APR_CHECK_SOCKLEN_T], [ +AC_CACHE_CHECK(for socklen_t, ac_cv_socklen_t,[ +AC_TRY_COMPILE([ +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#ifdef HAVE_SYS_SOCKET_H +#include <sys/socket.h> +#endif +],[ +socklen_t foo = (socklen_t) 0; +],[ + ac_cv_socklen_t=yes +],[ + ac_cv_socklen_t=no +]) +]) + +if test "$ac_cv_socklen_t" = "yes"; then + AC_DEFINE(HAVE_SOCKLEN_T, 1, [Whether you have socklen_t]) +fi +]) + + +AC_DEFUN([APR_CHECK_INET_ADDR], [ +AC_CACHE_CHECK(for inet_addr, ac_cv_func_inet_addr,[ +AC_TRY_COMPILE([ +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#ifdef HAVE_ARPA_INET_H +#include <arpa/inet.h> +#endif +],[ +inet_addr("127.0.0.1"); +],[ + ac_cv_func_inet_addr=yes +],[ + ac_cv_func_inet_addr=no +]) +]) + +if test "$ac_cv_func_inet_addr" = "yes"; then + have_inet_addr=1 +else + have_inet_addr=0 +fi +]) + + +AC_DEFUN([APR_CHECK_INET_NETWORK], [ +AC_CACHE_CHECK(for inet_network, ac_cv_func_inet_network,[ +AC_TRY_COMPILE([ +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#ifdef HAVE_ARPA_INET_H +#include <arpa/inet.h> +#endif +],[ +inet_network("127.0.0.1"); +],[ + ac_cv_func_inet_network=yes +],[ + ac_cv_func_inet_network=no +]) +]) + +if test "$ac_cv_func_inet_network" = "yes"; then + have_inet_network=1 +else + have_inet_network=0 +fi +]) + +dnl Check for presence of struct sockaddr_storage. +AC_DEFUN([APR_CHECK_SOCKADDR_STORAGE], [ +AC_CACHE_CHECK(for sockaddr_storage, apr_cv_define_sockaddr_storage,[ +AC_TRY_COMPILE([ +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#ifdef HAVE_NETINET_IN_H +#include <netinet/in.h> +#endif +],[struct sockaddr_storage sa;], +[apr_cv_define_sockaddr_storage=yes], +[apr_cv_define_sockaddr_storage=no])]) + +if test "$apr_cv_define_sockaddr_storage" = "yes"; then + have_sa_storage=1 +else + have_sa_storage=0 +fi +AC_SUBST(have_sa_storage) +]) + +dnl Check for presence of struct sockaddr_in6. +AC_DEFUN([APR_CHECK_SOCKADDR_IN6], [ +AC_CACHE_CHECK(for sockaddr_in6, ac_cv_define_sockaddr_in6,[ +AC_TRY_COMPILE([ +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#ifdef HAVE_NETINET_IN_H +#include <netinet/in.h> +#endif +],[ +struct sockaddr_in6 sa; +],[ + ac_cv_define_sockaddr_in6=yes +],[ + ac_cv_define_sockaddr_in6=no +]) +]) + +if test "$ac_cv_define_sockaddr_in6" = "yes"; then + have_sockaddr_in6=1 +else + have_sockaddr_in6=0 +fi +]) + +dnl Check for presence of struct sockaddr_un. +AC_DEFUN([APR_CHECK_SOCKADDR_UN], [ +AC_CACHE_CHECK(for sockaddr_un, ac_cv_define_sockaddr_un,[ +AC_TRY_COMPILE([ +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#ifdef HAVE_NETINET_IN_H +#include <netinet/in.h> +#endif +#ifdef HAVE_SYS_UN_H +#include <sys/un.h> +#endif +],[ +struct sockaddr_un sa; +],[ + ac_cv_define_sockaddr_un=yes +],[ + ac_cv_define_sockaddr_un=no +]) +]) + +if test "$ac_cv_define_sockaddr_un" = "yes"; then + have_sockaddr_un=1 +else + have_sockaddr_un=0 +fi +AC_SUBST(have_sockaddr_un) +]) + +dnl +dnl APR_H_ERRNO_COMPILE_CHECK +dnl +AC_DEFUN([APR_H_ERRNO_COMPILE_CHECK], [ + if test x$1 != x; then + CPPFLAGS="-D$1 $CPPFLAGS" + fi + AC_TRY_COMPILE([ +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#ifdef HAVE_NETDB_H +#include <netdb.h> +#endif +],[ +int h_e = h_errno; +],[ + if test x$1 != x; then + ac_cv_h_errno_cppflags="$1" + else + ac_cv_h_errno_cppflags=yes + fi +],[ + ac_cv_h_errno_cppflags=no +])]) + + +dnl +dnl APR_CHECK_SCTP +dnl +dnl check for presence of SCTP protocol support +dnl +AC_DEFUN([APR_CHECK_SCTP], +[ + AC_CACHE_CHECK([whether SCTP is supported], [apr_cv_sctp], [ + AC_TRY_RUN([ +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#ifdef HAVE_SYS_SOCKET_H +#include <sys/socket.h> +#endif +#ifdef HAVE_NETINET_IN_H +#include <netinet/in.h> +#endif +#ifdef HAVE_NETINET_SCTP_H +#include <netinet/sctp.h> +#endif +#ifdef HAVE_NETINET_SCTP_UIO_H +#include <netinet/sctp_uio.h> +#endif +#include <stdlib.h> +int main(void) { + int s, opt = 1; + if ((s = socket(AF_INET, SOCK_STREAM, IPPROTO_SCTP)) < 0) + exit(1); + if (setsockopt(s, IPPROTO_SCTP, SCTP_NODELAY, &opt, sizeof(int)) < 0) + exit(2); + exit(0); +}], [apr_cv_sctp=yes], [apr_cv_sctp=no], [apr_cv_sctp=no])]) + +if test "$apr_cv_sctp" = "yes"; then + have_sctp=1 +else + have_sctp=0 +fi +]) + +dnl APR_CHECK_MCAST: check for multicast interfaces +AC_DEFUN([APR_CHECK_MCAST], [ +AC_CACHE_CHECK([for struct ip_mreq], [apr_cv_struct_ipmreq], [ +AC_TRY_COMPILE([ +#include <sys/types.h> +#include <netinet/in.h> +], [ + struct ip_mreq mip; + mip.imr_interface.s_addr = INADDR_ANY; +], [apr_cv_struct_ipmreq=yes], [apr_cv_struct_ipmreq=no], [apr_cv_struct_ipmreq=yes])]) + +if test $apr_cv_struct_ipmreq = yes; then + AC_DEFINE([HAVE_STRUCT_IPMREQ], 1, [Define if struct impreq was found]) +fi +]) + +dnl +dnl APR_CHECK_H_ERRNO_FLAG +dnl +dnl checks which flags are necessary for <netdb.h> to define h_errno +dnl +AC_DEFUN([APR_CHECK_H_ERRNO_FLAG], [ + AC_MSG_CHECKING([for h_errno in netdb.h]) + AC_CACHE_VAL(ac_cv_h_errno_cppflags,[ + APR_H_ERRNO_COMPILE_CHECK + if test "$ac_cv_h_errno_cppflags" = "no"; then + ac_save="$CPPFLAGS" + for flag in _XOPEN_SOURCE_EXTENDED; do + APR_H_ERRNO_COMPILE_CHECK($flag) + if test "$ac_cv_h_errno_cppflags" != "no"; then + break + fi + done + CPPFLAGS="$ac_save" + fi + ]) + if test "$ac_cv_h_errno_cppflags" != "no"; then + if test "$ac_cv_h_errno_cppflags" != "yes"; then + CPPFLAGS="-D$ac_cv_h_errno_cppflags $CPPFLAGS" + AC_MSG_RESULT([yes, with -D$ac_cv_h_errno_cppflags]) + else + AC_MSG_RESULT([$ac_cv_h_errno_cppflags]) + fi + else + AC_MSG_RESULT([$ac_cv_h_errno_cppflags]) + fi +]) + + +AC_DEFUN([APR_EBCDIC], [ + AC_CACHE_CHECK([whether system uses EBCDIC],ac_cv_ebcdic,[ + AC_TRY_RUN( [ +int main(void) { + return (unsigned char)'A' != (unsigned char)0xC1; +} +],[ + ac_cv_ebcdic="yes" +],[ + ac_cv_ebcdic="no" +],[ + ac_cv_ebcdic="no" +])]) + if test "$ac_cv_ebcdic" = "yes"; then + apr_charset_ebcdic=1 + else + apr_charset_ebcdic=0 + fi + AC_SUBST(apr_charset_ebcdic) +]) + diff --git a/build/apr_rules.mk.in b/build/apr_rules.mk.in new file mode 100644 index 00000000000..9362a20efcf --- /dev/null +++ b/build/apr_rules.mk.in @@ -0,0 +1,211 @@ +# 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. +# +# + +# +# rules.mk: standard rules for APR +# + +@SET_MAKE@ + +# +# Configuration variables +# +apr_builddir=@apr_builddir@ +apr_builders=@apr_builders@ + +# Some layouts require knowing what version we are at. +APR_MAJOR_VERSION=@APR_MAJOR_VERSION@ +APR_DOTTED_VERSION=@APR_DOTTED_VERSION@ + +CC=@CC@ +RM=@RM@ +AWK=@AWK@ +SHELL=@SHELL@ +LIBTOOL=@LIBTOOL@ + +# compilation and linking flags that are supposed to be set only by the user. +# configure adds to them for tests, but we restore them at the end. +# +CFLAGS=@CFLAGS@ +CPPFLAGS=@CPPFLAGS@ +LDFLAGS=@LDFLAGS@ +LIBS=@LIBS@ +DEFS=@DEFS@ + +# anything added to the standard flags by configure is moved to EXTRA_* +# at the end of the process. +# +EXTRA_CFLAGS=@EXTRA_CFLAGS@ +EXTRA_CPPFLAGS=@EXTRA_CPPFLAGS@ +EXTRA_LDFLAGS=@EXTRA_LDFLAGS@ +EXTRA_LIBS=@EXTRA_LIBS@ +EXTRA_INCLUDES=@EXTRA_INCLUDES@ + +# CPPFLAGS which are used only while building APR itself +# +INTERNAL_CPPFLAGS=@INTERNAL_CPPFLAGS@ + +# NOTEST_* are flags and libraries that can be added by the user without +# causing them to be used in configure tests (necessary for things like +# -Werror and other strict warnings that maintainers like to use). +# +NOTEST_CFLAGS=@NOTEST_CFLAGS@ +NOTEST_CPPFLAGS=@NOTEST_CPPFLAGS@ +NOTEST_LDFLAGS=@NOTEST_LDFLAGS@ +NOTEST_LIBS=@NOTEST_LIBS@ + +# Finally, combine all of the flags together in the proper order so that +# the user-defined flags can always override the configure ones, if needed. +# Note that includes are listed after the flags because -I options have +# left-to-right precedence and CPPFLAGS may include user-defined overrides. +# +ALL_CFLAGS = $(EXTRA_CFLAGS) $(NOTEST_CFLAGS) $(CFLAGS) +ALL_CPPFLAGS = $(DEFS) $(INTERNAL_CPPFLAGS) $(EXTRA_CPPFLAGS) $(NOTEST_CPPFLAGS) $(CPPFLAGS) +ALL_LDFLAGS = $(EXTRA_LDFLAGS) $(NOTEST_LDFLAGS) $(LDFLAGS) +ALL_LIBS = $(LIBS) $(NOTEST_LIBS) $(EXTRA_LIBS) +ALL_INCLUDES = $(INCLUDES) $(EXTRA_INCLUDES) + +LTFLAGS = @LTFLAGS@ +LT_LDFLAGS = @LT_LDFLAGS@ + +# The set of object files that will be linked into the target library. +# The build-outputs.mk specifies a different set for each platform. The +# configure script will select the appropriate set. +# +OBJECTS = @OBJECTS_PLATFORM@ + +# +# Basic macro setup +# +COMPILE = $(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(ALL_INCLUDES) +LT_COMPILE = @lt_compile@ + +LINK = @link@ + +APR_MKDIR = $(apr_builders)/mkdir.sh +APR_MKEXPORT = $(AWK) -f $(apr_builders)/make_exports.awk +APR_MKVAREXPORT = $(AWK) -f $(apr_builders)/make_var_export.awk +MKDEP = @MKDEP@ + +# +# Standard build rules +# +all: all-recursive +depend: depend-recursive +clean: clean-recursive +distclean: distclean-recursive +extraclean: extraclean-recursive + +install: all-recursive + + +all-recursive depend-recursive: + @otarget=`echo $@ | sed s/-recursive//`; \ + list='$(SOURCE_DIRS)'; \ + for i in $$list; do \ + if test -f "$$i/Makefile"; then \ + target="$$otarget"; \ + echo "Making $$target in $$i"; \ + if test "$$i" = "."; then \ + made_local=yes; \ + target="local-$$target"; \ + fi; \ + (cd $$i && $(MAKE) $$target) || exit 1; \ + fi; \ + done; \ + if test "$$otarget" = "all" && test -z "$(TARGETS)"; then \ + made_local=yes; \ + fi; \ + if test "$$made_local" != "yes"; then \ + $(MAKE) "local-$$otarget" || exit 1; \ + fi + +clean-recursive distclean-recursive extraclean-recursive: + @otarget=`echo $@ | sed s/-recursive//`; \ + list='$(CLEAN_SUBDIRS)'; \ + for i in $$list; do \ + if test -f "$$i/Makefile"; then \ + target="$$otarget"; \ + echo "Making $$target in $$i"; \ + if test "$$i" = "."; then \ + made_local=yes; \ + target="local-$$target"; \ + fi; \ + (cd $$i && $(MAKE) $$target); \ + fi; \ + done; \ + if test "$$otarget" = "all" && test -z "$(TARGETS)"; then \ + made_local=yes; \ + fi; \ + if test "$$made_local" != "yes"; then \ + $(MAKE) "local-$$otarget"; \ + fi + +# autoconf 2.5x is creating a 'autom4te.cache' directory +# In case someone ran autoconf by hand, get rid of that directory +# as well. +local-clean: x-local-clean + @list='. $(SOURCE_DIRS)'; \ + for i in $$list; do \ + echo $(RM) -f $$i/*.o $$i/*.lo $$i/*.a $$i/*.la $$i/*.so $$i/*.obj; \ + $(RM) -f $$i/*.o $$i/*.lo $$i/*.a $$i/*.la $$i/*.so $$i/*.obj; \ + echo $(RM) -rf $$i/.libs; \ + $(RM) -rf $$i/.libs; \ + done + $(RM) -f $(CLEAN_TARGETS) $(PROGRAMS) + $(RM) -rf autom4te.cache + +local-distclean: local-clean x-local-distclean + $(RM) -f Makefile $(DISTCLEAN_TARGETS) + +local-extraclean: local-distclean x-local-extraclean + @if test -n "$(EXTRACLEAN_TARGETS)"; then \ + echo $(RM) -f $(EXTRACLEAN_TARGETS) ; \ + $(RM) -f $(EXTRACLEAN_TARGETS) ; \ + fi + +local-all: $(TARGETS) + +local-depend: x-local-depend + @if test -n "`ls $(srcdir)/*.c 2> /dev/null`"; then \ + $(RM) -f .deps; \ + list='$(srcdir)/*.c'; \ + for i in $$list; do \ + $(MKDEP) $(ALL_CPPFLAGS) $(ALL_INCLUDES) $$i | sed 's/\.o:/.lo:/' >> .deps; \ + done; \ + fi + +# to be filled in by the actual Makefile +x-local-depend x-local-clean x-local-distclean x-local-extraclean: + +# +# Implicit rules for creating outputs from input files +# +.SUFFIXES: +.SUFFIXES: .c .lo .o + +.c.o: + $(COMPILE) -c $< + +.c.lo: + $(LT_COMPILE) + +.PHONY: all all-recursive local-all install \ + depend depend-recursive local-depend x-local-depend \ + clean clean-recursive local-clean x-local-clean \ + distclean distclean-recursive local-distclean x-local-distclean \ + extraclean extraclean-recursive local-extraclean x-local-extraclean diff --git a/build/apr_threads.m4 b/build/apr_threads.m4 new file mode 100644 index 00000000000..cbc677b1467 --- /dev/null +++ b/build/apr_threads.m4 @@ -0,0 +1,283 @@ +dnl -------------------------------------------------------- -*- autoconf -*- +dnl Licensed to the Apache Software Foundation (ASF) under one or more +dnl contributor license agreements. See the NOTICE file distributed with +dnl this work for additional information regarding copyright ownership. +dnl The ASF licenses this file to You under the Apache License, Version 2.0 +dnl (the "License"); you may not use this file except in compliance with +dnl the License. You may obtain a copy of the License at +dnl +dnl http://www.apache.org/licenses/LICENSE-2.0 +dnl +dnl Unless required by applicable law or agreed to in writing, software +dnl distributed under the License is distributed on an "AS IS" BASIS, +dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +dnl See the License for the specific language governing permissions and +dnl limitations under the License. + +dnl ----------------------------------------------------------------- +dnl apr_threads.m4: APR's autoconf macros for testing thread support +dnl + +dnl +dnl APR_CHECK_PTHREADS_H([ ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]) +dnl +dnl gcc issues warnings when parsing AIX 4.3.3's pthread.h +dnl which causes autoconf to incorrectly conclude that +dnl pthreads is not available. +dnl Turn off warnings if we're using gcc. +dnl +AC_DEFUN(APR_CHECK_PTHREADS_H, [ + if test "$GCC" = "yes"; then + SAVE_FL="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS -w" + AC_CHECK_HEADERS(pthread.h, [ $1 ] , [ $2 ] ) + CPPFLAGS="$SAVE_FL" + else + AC_CHECK_HEADERS(pthread.h, [ $1 ] , [ $2 ] ) + fi +])dnl + + +dnl +dnl APR_CHECK_PTHREAD_GETSPECIFIC_TWO_ARGS +dnl +AC_DEFUN(APR_CHECK_PTHREAD_GETSPECIFIC_TWO_ARGS, [ +AC_CACHE_CHECK(whether pthread_getspecific takes two arguments, ac_cv_pthread_getspecific_two_args,[ +AC_TRY_COMPILE([ +#include <pthread.h> +],[ +pthread_key_t key; +void *tmp; +pthread_getspecific(key,&tmp); +],[ + ac_cv_pthread_getspecific_two_args=yes +],[ + ac_cv_pthread_getspecific_two_args=no +]) +]) + +if test "$ac_cv_pthread_getspecific_two_args" = "yes"; then + AC_DEFINE(PTHREAD_GETSPECIFIC_TAKES_TWO_ARGS, 1, [Define if pthread_getspecific() has two args]) +fi +])dnl + + +dnl +dnl APR_CHECK_PTHREAD_ATTR_GETDETACHSTATE_ONE_ARG +dnl +AC_DEFUN(APR_CHECK_PTHREAD_ATTR_GETDETACHSTATE_ONE_ARG, [ +AC_CACHE_CHECK(whether pthread_attr_getdetachstate takes one argument, ac_cv_pthread_attr_getdetachstate_one_arg,[ +AC_TRY_COMPILE([ +#include <pthread.h> +],[ +pthread_attr_t *attr; +pthread_attr_getdetachstate(attr); +],[ + ac_cv_pthread_attr_getdetachstate_one_arg=yes +],[ + ac_cv_pthread_attr_getdetachstate_one_arg=no +]) +]) + +if test "$ac_cv_pthread_attr_getdetachstate_one_arg" = "yes"; then + AC_DEFINE(PTHREAD_ATTR_GETDETACHSTATE_TAKES_ONE_ARG, 1, [Define if pthread_attr_getdetachstate() has one arg]) +fi +])dnl + + +dnl +dnl APR_PTHREADS_TRY_RUN(actions-if-success) +dnl +dnl Try running a program which uses pthreads, executing the +dnl actions-if-success commands on success. +dnl +AC_DEFUN(APR_PTHREADS_TRY_RUN, [ +AC_TRY_RUN( [ +#include <pthread.h> +#include <stddef.h> + +void *thread_routine(void *data) { + return data; +} + +int main() { + pthread_t thd; + pthread_mutexattr_t mattr; + pthread_once_t once_init = PTHREAD_ONCE_INIT; + int data = 1; + pthread_mutexattr_init(&mattr); + return pthread_create(&thd, NULL, thread_routine, &data); +} ], [apr_p_t_r=yes], [apr_p_t_r=no], [apr_p_t_r=no]) + +if test $apr_p_t_r = yes; then + $1 +fi + +])dnl + + +dnl +dnl APR_PTHREADS_CHECK() +dnl +dnl Try to find a way to enable POSIX threads. Sets the +dnl pthreads_working variable to "yes" on success. +dnl +AC_DEFUN([APR_PTHREADS_CHECK], [ + +AC_CACHE_CHECK([for CFLAGS needed for pthreads], [apr_cv_pthreads_cflags], +[apr_ptc_cflags=$CFLAGS + for flag in none -kthread -pthread -pthreads -mt -mthreads -Kthread -threads; do + CFLAGS=$apr_ptc_cflags + test "x$flag" != "xnone" && CFLAGS="$CFLAGS $flag" + APR_PTHREADS_TRY_RUN([ + apr_cv_pthreads_cflags="$flag" + break + ]) + done + CFLAGS=$apr_ptc_cflags +]) + +if test -n "$apr_cv_pthreads_cflags"; then + pthreads_working=yes + if test "x$apr_cv_pthreads_cflags" != "xnone"; then + APR_ADDTO(CFLAGS,[$apr_cv_pthreads_cflags]) + fi +fi + +# The CFLAGS may or may not be sufficient to ensure that libapr +# depends on the pthreads library: some versions of libtool +# drop -pthread when passed on the link line; some versions of +# gcc ignore -pthread when linking a shared object. So always +# try and add the relevant library to LIBS too. + +AC_CACHE_CHECK([for LIBS needed for pthreads], [apr_cv_pthreads_lib], [ + apr_ptc_libs=$LIBS + for lib in -lpthread -lpthreads -lc_r; do + LIBS="$apr_ptc_libs $lib" + APR_PTHREADS_TRY_RUN([ + apr_cv_pthreads_lib=$lib + break + ]) + done + LIBS=$apr_ptc_libs +]) + +if test -n "$apr_cv_pthreads_lib"; then + pthreads_working=yes + APR_ADDTO(LIBS,[$apr_cv_pthreads_lib]) +fi + +if test "$pthreads_working" = "yes"; then + threads_result="POSIX Threads found" +else + threads_result="POSIX Threads not found" +fi +])dnl + +dnl +dnl APR_PTHREADS_CHECK_SAVE +dnl APR_PTHREADS_CHECK_RESTORE +dnl +dnl Save the global environment variables that might be modified during +dnl the checks for threading support so that they can restored if the +dnl result is not what the caller wanted. +dnl +AC_DEFUN(APR_PTHREADS_CHECK_SAVE, [ + apr_pthsv_CFLAGS="$CFLAGS" + apr_pthsv_LIBS="$LIBS" +])dnl + +AC_DEFUN(APR_PTHREADS_CHECK_RESTORE, [ + CFLAGS="$apr_pthsv_CFLAGS" + LIBS="$apr_pthsv_LIBS" +])dnl + +dnl +dnl APR_CHECK_SIGWAIT_ONE_ARG +dnl +AC_DEFUN([APR_CHECK_SIGWAIT_ONE_ARG], [ + AC_CACHE_CHECK(whether sigwait takes one argument,ac_cv_sigwait_one_arg,[ + AC_TRY_COMPILE([ +#if defined(__NETBSD__) || defined(DARWIN) + /* When using the unproven-pthreads package, we need to pull in this + * header to get a prototype for sigwait(). Else things will fail later + * on. XXX Should probably be fixed in the unproven-pthreads package. + * Darwin is declaring sigwait() in the wrong place as well. + */ +#include <pthread.h> +#endif +#include <signal.h> +],[ + sigset_t set; + + sigwait(&set); +],[ + ac_cv_sigwait_one_arg=yes +],[ + ac_cv_sigwait_one_arg=no +])]) + if test "$ac_cv_sigwait_one_arg" = "yes"; then + AC_DEFINE(SIGWAIT_TAKES_ONE_ARG,1,[ ]) + fi +]) + +dnl Check for recursive mutex support (per SUSv3). +AC_DEFUN([APR_CHECK_PTHREAD_RECURSIVE_MUTEX], [ + AC_CACHE_CHECK([for recursive mutex support], [apr_cv_mutex_recursive], +[AC_TRY_RUN([#include <sys/types.h> +#include <pthread.h> +#include <stdlib.h> + +int main() { + pthread_mutexattr_t attr; + pthread_mutex_t m; + + exit (pthread_mutexattr_init(&attr) + || pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE) + || pthread_mutex_init(&m, &attr)); +}], [apr_cv_mutex_recursive=yes], [apr_cv_mutex_recursive=no], +[apr_cv_mutex_recursive=no])]) + +if test "$apr_cv_mutex_recursive" = "yes"; then + AC_DEFINE([HAVE_PTHREAD_MUTEX_RECURSIVE], 1, + [Define if recursive pthread mutexes are available]) +fi +]) + +dnl Check for robust process-shared mutex support +AC_DEFUN([APR_CHECK_PTHREAD_ROBUST_SHARED_MUTEX], [ +AC_CACHE_CHECK([for robust cross-process mutex support], +[apr_cv_mutex_robust_shared], +[AC_TRY_RUN([ +#include <sys/types.h> +#include <pthread.h> +#include <stdlib.h> + +int main(int argc, char **argv) +{ + pthread_mutex_t mutex; + pthread_mutexattr_t attr; + + if (pthread_mutexattr_init(&attr)) + exit(1); + if (pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED)) + exit(2); + if (pthread_mutexattr_setrobust_np(&attr, PTHREAD_MUTEX_ROBUST_NP)) + exit(3); + if (pthread_mutexattr_setprotocol(&attr, PTHREAD_PRIO_INHERIT)) + exit(4); + if (pthread_mutex_init(&mutex, &attr)) + exit(5); + if (pthread_mutexattr_destroy(&attr)) + exit(6); + if (pthread_mutex_destroy(&mutex)) + exit(7); + + exit(0); +}], [apr_cv_mutex_robust_shared=yes], [apr_cv_mutex_robust_shared=no])]) + +if test "$apr_cv_mutex_robust_shared" = "yes"; then + AC_DEFINE([HAVE_PTHREAD_MUTEX_ROBUST], 1, + [Define if cross-process robust mutexes are available]) +fi +]) diff --git a/build/apr_win32.m4 b/build/apr_win32.m4 new file mode 100644 index 00000000000..f98137421a1 --- /dev/null +++ b/build/apr_win32.m4 @@ -0,0 +1,33 @@ + +dnl if $2 contains '@dd', links against mingw symbols +dnl otherwise calls AC_CHECK_LIB +AC_DEFUN([APR_CHECK_DLL_FUNC],[ +m4_define($1_function_name,m4_substr($2,0,m4_index($2,[@]))) +m4_define($1_function_arglength,m4_substr($2,m4_incr(m4_index($2,[@])))) +m4_define($1_[function_name]_arglength,m4_substr($2,m4_incr(m4_index($2,[@])))) +dnl m4_define(apr_check_dll_id,$1_m4_defn($1_function_name)) + +AC_CACHE_CHECK([for $2 in $1],[ac_cv_lib_$1_]$1_function_name,[ + +ac_func_search_save_LIBS=$LIBS +LIBS="$LIBS -l$1" + +AC_TRY_LINK([ +#pragma pack(1) +struct x { +]m4_for([byte_id], 1, m4_defn([$1_function_name_arglength]), 1,[[ char c]]byte_id; +)[}; +__stdcall ]$1_function_name[(]struct x[);],[ +struct x s = {0}; +]$1_function_name[(s)], +[ac_cv_lib_$1_]$1_function_name[=yes],[ac_cv_lib_$1_]$1_function_name[=no]) +LIBS=$ac_func_search_save_LIBS +])dnl AC_CACHE_CHECK + +AS_IF([test $ac_cv_lib_$1_]$1_function_name[ = yes], + [m4_default([$3], [AC_DEFINE_UNQUOTED(AS_TR_CPP(HAVE_LIB$1),,Enable if this library is available) + LIBS="-l$1 $LIBS" +])], + [$4])dnl +]) + diff --git a/build/aprapp.dsp b/build/aprapp.dsp new file mode 100644 index 00000000000..30fcc1d56bb --- /dev/null +++ b/build/aprapp.dsp @@ -0,0 +1,140 @@ +# Microsoft Developer Studio Project File - Name="aprapp" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=aprapp - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "aprapp.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "aprapp.mak" CFG="aprapp - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "aprapp - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "aprapp - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "aprapp - x64 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "aprapp - x64 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "aprapp - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "..\LibR" +# PROP BASE Intermediate_Dir "LibR" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\LibR" +# PROP Intermediate_Dir "LibR" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c +# ADD CPP /nologo /MD /W3 /O2 /Oy- /Zi /I "../include" /I "../include/arch" /I "../include/arch/win32" /I "../include/arch/unix" /D "NDEBUG" /D "WINNT" /D "WIN32" /D "_WINDOWS" /D APR_APP /D "APR_DECLARE_STATIC" /Fo"$(INTDIR)\" /Fd"$(OUTDIR)\aprapp-2" /FD /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"..\LibR\aprapp-2.lib" + +!ELSEIF "$(CFG)" == "aprapp - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "..\LibD" +# PROP BASE Intermediate_Dir "LibD" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\LibD" +# PROP Intermediate_Dir "LibD" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /EHsc /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /c +# ADD CPP /nologo /MDd /W3 /EHsc /Zi /Od /I "../include" /I "../include/arch" /I "../include/arch/win32" /I "../include/arch/unix" /D "_DEBUG" /D "WINNT" /D "WIN32" /D "_WINDOWS" /D APR_APP /D "APR_DECLARE_STATIC" /Fo"$(INTDIR)\" /Fd"$(OUTDIR)\aprapp-2" /FD /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"..\LibD\aprapp-2.lib" + +!ELSEIF "$(CFG)" == "aprapp - x64 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "..\x64\LibR" +# PROP BASE Intermediate_Dir "x64\LibR" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\x64\LibR" +# PROP Intermediate_Dir "x64\LibR" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c +# ADD CPP /nologo /MD /W3 /O2 /Oy- /Zi /I "../include" /I "../include/arch" /I "../include/arch/win32" /I "../include/arch/unix" /D "NDEBUG" /D "WINNT" /D "WIN32" /D "_WINDOWS" /D APR_APP /D "APR_DECLARE_STATIC" /Fo"$(INTDIR)\" /Fd"$(OUTDIR)\aprapp-2" /FD /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"..\x64\LibR\aprapp-2.lib" + +!ELSEIF "$(CFG)" == "aprapp - x64 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "..\x64\LibD" +# PROP BASE Intermediate_Dir "x64\LibD" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\x64\LibD" +# PROP Intermediate_Dir "x64\LibD" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /EHsc /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /c +# ADD CPP /nologo /MDd /W3 /EHsc /Zi /Od /I "../include" /I "../include/arch" /I "../include/arch/win32" /I "../include/arch/unix" /D "_DEBUG" /D "WINNT" /D "WIN32" /D "_WINDOWS" /D APR_APP /D "APR_DECLARE_STATIC" /Fo"$(INTDIR)\" /Fd"$(OUTDIR)\aprapp-2" /FD /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"..\x64\LibD\aprapp-2.lib" + +!ENDIF + +# Begin Target + +# Name "aprapp - Win32 Release" +# Name "aprapp - Win32 Debug" +# Name "aprapp - x64 Release" +# Name "aprapp - x64 Debug" +# Begin Source File + +SOURCE=..\misc\win32\apr_app.c +# End Source File +# End Target +# End Project diff --git a/build/aprconf.py b/build/aprconf.py new file mode 100644 index 00000000000..74df43f1341 --- /dev/null +++ b/build/aprconf.py @@ -0,0 +1,432 @@ +import os +import sys + +class APRConfigureBase: + def __init__(self, env): + self.env = env + + def Check_apr_big_endian(self, context): + import struct + context.Message("Checking for big endianess... ") + array = struct.pack('cccc', '\x01', '\x02', '\x03', '\x04') + i = struct.unpack('i', array) + if i == struct.unpack('>i', array): + context.Result('yes') + return 1 + else: + context.Result('no') + return 0 + + def CheckFile(self, context, path): + context.Message("Checking if %s exists... " % (path)) + if os.path.exists(path): + context.Result('yes') + return 1 + else: + context.Result('no') + return 0 + + def CheckTypesCompatible(self, context, t1, t2, includes): + context.Message('Checking %s is the same as %s... ' % (t1, t2)) + source = """ + %s +void main(void) +{ + int foo[0 - !__builtin_types_compatible_p(%s, %s)]; +} + """ % (includes, t1, t2) + result = context.TryCompile(source, '.c') + self.env.Filter(CPPFLAGS = ['-D_LARGEFILE64_SOURCE']) + context.Result(result) + return result + + def Check_apr_atomic_builtins(self, context): + context.Message('Checking whether the compiler provides atomic builtins... ') + source = """ +int main() +{ + unsigned long val = 1010, tmp, *mem = &val; + + if (__sync_fetch_and_add(&val, 1010) != 1010 || val != 2020) + return 1; + + tmp = val; + + if (__sync_fetch_and_sub(mem, 1010) != tmp || val != 1010) + return 1; + + if (__sync_sub_and_fetch(&val, 1010) != 0 || val != 0) + return 1; + + tmp = 3030; + + if (__sync_val_compare_and_swap(mem, 0, tmp) != 0 || val != tmp) + return 1; + + if (__sync_lock_test_and_set(&val, 4040) != 3030) + return 1; + + mem = &tmp; + + if (__sync_val_compare_and_swap(&mem, &tmp, &val) != &tmp) + return 1; + + __sync_synchronize(); + + if (mem != &val) + return 1; + + return 0; +} + """ + result = context.TryRun(source, '.c') + context.Result(result[0] == 1) + return result[0] == 1 + + def Check_apr_ebcdic(self, context): + context.Message('Checking whether system uses EBCDIC.. ') + source = """ +int main(void) { + return (unsigned char)'A' != (unsigned char)0xC1; +}""" + result = context.TryRun(source, '.c') + context.Result(result[0] == 1) + return result[0] == 1 + + def Check_apr_nonblock_inherited(self, context): + context.Message('Checking whether O_NONBLOCK setting is inherited from listening sockets... ') + source = """ +#include <stdio.h> +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#ifdef HAVE_SYS_SOCKET_H +#include <sys/socket.h> +#endif +#ifdef HAVE_NETINET_IN_H +#include <netinet/in.h> +#endif +#ifdef HAVE_NETINET_TCP_H +#include <netinet/tcp.h> +#endif +#ifndef HAVE_SOCKLEN_T +typedef int socklen_t; +#endif +#ifdef HAVE_FCNTL_H +#include <fcntl.h> +#endif +int main(void) { + int listen_s, connected_s, client_s; + int listen_port, rc; + struct sockaddr_in sa; + socklen_t sa_len; + + listen_s = socket(AF_INET, SOCK_STREAM, 0); + if (listen_s < 0) { + perror("socket"); + exit(1); + } + memset(&sa, 0, sizeof sa); + sa.sin_family = AF_INET; +#ifdef BEOS + sa.sin_addr.s_addr = htonl(INADDR_LOOPBACK); +#endif + /* leave port 0 to get ephemeral */ + rc = bind(listen_s, (struct sockaddr *)&sa, sizeof sa); + if (rc < 0) { + perror("bind for ephemeral port"); + exit(1); + } + /* find ephemeral port */ + sa_len = sizeof(sa); + rc = getsockname(listen_s, (struct sockaddr *)&sa, &sa_len); + if (rc < 0) { + perror("getsockname"); + exit(1); + } + listen_port = sa.sin_port; + rc = listen(listen_s, 5); + if (rc < 0) { + perror("listen"); + exit(1); + } + rc = fcntl(listen_s, F_SETFL, O_NONBLOCK); + if (rc < 0) { + perror("fcntl(F_SETFL)"); + exit(1); + } + client_s = socket(AF_INET, SOCK_STREAM, 0); + if (client_s < 0) { + perror("socket"); + exit(1); + } + memset(&sa, 0, sizeof sa); + sa.sin_family = AF_INET; + sa.sin_port = listen_port; +#ifdef BEOS + sa.sin_addr.s_addr = htonl(INADDR_LOOPBACK); +#endif + /* leave sin_addr all zeros to use loopback */ + rc = connect(client_s, (struct sockaddr *)&sa, sizeof sa); + if (rc < 0) { + perror("connect"); + exit(1); + } + sa_len = sizeof sa; + connected_s = accept(listen_s, (struct sockaddr *)&sa, &sa_len); + if (connected_s < 0) { + perror("accept"); + exit(1); + } + rc = fcntl(connected_s, F_GETFL, 0); + if (rc < 0) { + perror("fcntl(F_GETFL)"); + exit(1); + } + if (!(rc & O_NONBLOCK)) { + fprintf(stderr, "O_NONBLOCK is not set in the child.\n"); + exit(1); + } + return 0; +}""" + result = context.TryRun(source, '.c') + context.Result(result[0] == 1) + return result[0] == 1 + + def Check_apr_largefile64(self, context): + context.Message('Checking whether to enable -D_LARGEFILE64_SOURCE... ') + self.env.AppendUnique(CPPFLAGS = ['-D_LARGEFILE64_SOURCE']) + source = """ +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> + +void main(void) +{ + int fd, ret = 0; + struct stat64 st; + off64_t off = 4242; + + if (sizeof(off64_t) != 8 || sizeof(off_t) != 4) + exit(1); + if ((fd = open("conftest.lfs", O_LARGEFILE|O_CREAT|O_WRONLY, 0644)) < 0) + exit(2); + if (ftruncate64(fd, off) != 0) + ret = 3; + else if (fstat64(fd, &st) != 0 || st.st_size != off) + ret = 4; + else if (lseek64(fd, off, SEEK_SET) != off) + ret = 5; + else if (close(fd) != 0) + ret = 6; + else if (lstat64("conftest.lfs", &st) != 0 || st.st_size != off) + ret = 7; + else if (stat64("conftest.lfs", &st) != 0 || st.st_size != off) + ret = 8; + unlink("conftest.lfs"); + + exit(ret); +}""" + result = context.TryRun(source, '.c') + self.env.Filter(CPPFLAGS = ['-D_LARGEFILE64_SOURCE']) + context.Result(result[0] == 1) + return result[0] == 1 + + + def Check_apr_mmap_mapping_dev_zero(self, context): + context.Message('Checking for mmap that can map /dev/zero... ') + source = """ +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <sys/mman.h> + int main() + { + int fd; + void *m; + fd = open("/dev/zero", O_RDWR); + if (fd < 0) { + return 1; + } + m = mmap(0, sizeof(void*), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); + if (m == (void *)-1) { /* aka MAP_FAILED */ + return 2; + } + if (munmap(m, sizeof(void*)) < 0) { + return 3; + } + return 0; + } + """ + result = context.TryRun(source, '.c') + context.Result(result[0] == 1) + return result[0] == 1 + + def Check_apr_semaphores(self, context): + context.Message('Checking for sem_open, sem_close, sem_unlink... ') + source = """ +#include <errno.h> +#include <stdlib.h> +#include <fcntl.h> +#include <semaphore.h> +#ifndef SEM_FAILED +#define SEM_FAILED (-1) +#endif +main() +{ + sem_t *psem; + const char *sem_name = "/apr_autoconf"; + + psem = sem_open(sem_name, O_CREAT, 0644, 1); + if (psem == (sem_t *)SEM_FAILED) { + exit(1); + } + sem_close(psem); + psem = sem_open(sem_name, O_CREAT | O_EXCL, 0644, 1); + if (psem != (sem_t *)SEM_FAILED) { + sem_close(psem); + exit(1); + } + sem_unlink(sem_name); + exit(0); +} + """ + result = context.TryCompile(source, '.c') + context.Result(result) + return result + + def Check_apr_check_tcp_nodelay_inherited(self, context): + context.Message('Checking for tcp nodelay inherited... ') + source = """ +#include <stdio.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <netinet/tcp.h> +int main(void) { + int listen_s, connected_s, client_s; + int listen_port, rc; + struct sockaddr_in sa; + socklen_t sa_len; + socklen_t option_len; + int option; + + listen_s = socket(AF_INET, SOCK_STREAM, 0); + if (listen_s < 0) { + perror("socket"); + exit(1); + } + option = 1; + rc = setsockopt(listen_s, IPPROTO_TCP, TCP_NODELAY, &option, sizeof option); + if (rc < 0) { + perror("setsockopt TCP_NODELAY"); + exit(1); + } + memset(&sa, 0, sizeof sa); + sa.sin_family = AF_INET; +#ifdef BEOS + sa.sin_addr.s_addr = htonl(INADDR_LOOPBACK); +#endif + /* leave port 0 to get ephemeral */ + rc = bind(listen_s, (struct sockaddr *)&sa, sizeof sa); + if (rc < 0) { + perror("bind for ephemeral port"); + exit(1); + } + /* find ephemeral port */ + sa_len = sizeof(sa); + rc = getsockname(listen_s, (struct sockaddr *)&sa, &sa_len); + if (rc < 0) { + perror("getsockname"); + exit(1); + } + listen_port = sa.sin_port; + rc = listen(listen_s, 5); + if (rc < 0) { + perror("listen"); + exit(1); + } + client_s = socket(AF_INET, SOCK_STREAM, 0); + if (client_s < 0) { + perror("socket"); + exit(1); + } + memset(&sa, 0, sizeof sa); + sa.sin_family = AF_INET; + sa.sin_port = listen_port; +#ifdef BEOS + sa.sin_addr.s_addr = htonl(INADDR_LOOPBACK); +#endif + /* leave sin_addr all zeros to use loopback */ + rc = connect(client_s, (struct sockaddr *)&sa, sizeof sa); + if (rc < 0) { + perror("connect"); + exit(1); + } + sa_len = sizeof sa; + connected_s = accept(listen_s, (struct sockaddr *)&sa, &sa_len); + if (connected_s < 0) { + perror("accept"); + exit(1); + } + option_len = sizeof option; + rc = getsockopt(connected_s, IPPROTO_TCP, TCP_NODELAY, &option, &option_len); + if (rc < 0) { + perror("getsockopt"); + exit(1); + } + if (!option) { + fprintf(stderr, "TCP_NODELAY is not set in the child.\n"); + exit(1); + } + return 0; +} """ + result = context.TryRun(source, '.c') + context.Result(result[0] == 1) + return result[0] == 1 + + def Check_apr_semun(self, context): + context.Message('Checking for semun... ') + source = """ +#include <sys/types.h> +#include <sys/ipc.h> +#include <sys/sem.h> +main() +{ + union semun arg; + semctl(0, 0, 0, arg); + exit(0); +} + """ + result = context.TryCompile(source, '.c') + context.Result(result) + return result + + def Check_apr_sctp(self, context): + context.Message('Checking for sctp support... ') + source = """ +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <netinet/sctp.h> +#include <netinet/sctp_uio.h> +#include <stdlib.h> +int main(void) { + int s, opt = 1; + if ((s = socket(AF_INET, SOCK_STREAM, IPPROTO_SCTP)) < 0) + exit(1); + if (setsockopt(s, IPPROTO_SCTP, SCTP_NODELAY, &opt, sizeof(int)) < 0) + exit(2); + exit(0); +} +""" + result = context.TryRun(source, '.c') + context.Result(result[0] == 1) + return result[0] == 1 + +class APRConfigure(APRConfigureBase): + def __init__(self, env): + APRConfigureBase.__init__(self, env) diff --git a/build/aprenv.py b/build/aprenv.py new file mode 100644 index 00000000000..b1e7c0c30ef --- /dev/null +++ b/build/aprenv.py @@ -0,0 +1,693 @@ +# +# + +from SCons.Environment import Environment +from os.path import join as pjoin +import aprconf +import re +import os +import traceback + +_platforms = [ + 'aix', + 'beos', + 'netware', + 'os2', + 'os390', + 'unix', + 'win32' +] + +_platform_dirs = [ + 'atomic', + 'dso', + 'file_io', + 'helpers', + 'locks', + 'memory', + 'misc', + 'mmap', + 'network_io', + 'passwd', + 'poll', + 'random', + 'shmem', + 'strings', + 'support', + 'tables', + 'threadproc', + 'time', + 'user' +] + +_simple_dirs = [ + 'buckets', + 'crypto', + 'dbd', + 'dbm', + 'dbm/sdbm', + 'encoding', + 'hooks', + 'memcache', + 'tables', + 'strings', + 'strmatch', + 'util-misc', + 'uri', + 'xlate', + 'xml' +] + +class APREnv(Environment): + def __init__(self, parent=None, args=None, **kw): + Environment.__init__(self, ENV=os.environ, + tools = ['default', 'subst'], + toolpath = [pjoin(os.getcwd(), 'build')], + **kw) + + # See SCons/Platform/__init__.py for possible values + if self['PLATFORM'] in _platforms: + self['APR_PLATFORM'] = self['PLATFORM'] + else: + self['APR_PLATFORM'] = 'unix' + + # if no *.c files are found in the original APR_PLATFORM, we switch to + # using this fallback platform. + self['APR_FALLBACK_PLATFORM'] = 'unix' + + self.AppendUnique(CPPPATH = ['include', 'include/private', 'include/arch/'+self['APR_PLATFORM']]) + self.autoconf = aprconf.APRConfigure(self) + self.AppendUnique(LIBS = ['expat']) + + def is_gcc(self): + # TOOD: This detection should be smarter, need look at SCons Internals + # for how it works/base it on the Tool selection. + return self['CC'] == 'gcc' + + def core_lib_files(self): + rv = [] + for d in _platform_dirs: + p = pjoin(d, self['APR_PLATFORM'], '*.c') + files = self.Glob(p) + if not files and self['APR_PLATFORM'] != self['APR_FALLBACK_PLATFORM']: + p = pjoin(d, self['APR_FALLBACK_PLATFORM'], '*.c') + files = self.Glob(p) + rv.extend(files) + + for d in _simple_dirs: + p = pjoin(d, '*.c') + files = self.Glob(p) + rv.extend(files) + return rv + + def APRVersion(self): + if not self.has_key('APR_VERSION'): + self['APR_VERSION'] = self.read_version('APR', '#include/apr_version.h') + return self['APR_VERSION'] + + def read_version(self, prefix, path): + version_re = re.compile("(.*)%s_(?P<id>MAJOR|MINOR|PATCH)_VERSION(\s+)(?P<num>\d)(.*)" % prefix) + versions = {} + fp = self.File(path).get_contents() + for line in fp.splitlines(): + m = version_re.match(line) + if m: + versions[m.group('id')] = int(m.group('num')) + return (versions['MAJOR'], versions['MINOR'], versions['PATCH']) + + def Filter(self, **kw): + for k in kw.keys(): + self[k] = [x for x in self[k] if x is not kw[k]] + + def APRHints(self): + # TOOD: port more from apr_hints.m4 + if self['PLATFORM'] == 'darwin': + self.AppendUnique(CPPFLAGS=['-DDARWIN', '-DSIGPROCMASK_SETS_THREAD_MASK']) + + + def critical_value(self, f, value, *args): + rv = f(*args) + + if rv != value: + traceback.print_stack() + print "Critial Test failed." + self.Exit(1) + return rv + + def critical(self, f, *args): + rv = f(*args) + + if not rv: + traceback.print_stack() + print "Critial Test failed." + self.Exit(1) + + def APRAutoconf(self): + self.apr_config_h = 'include/arch/%s/apr_private.h' % (self['APR_PLATFORM']) + self.apu_config_h = 'include/private/apu_config.h' + subst = {} + + if self.GetOption('clean') or self.GetOption('help'): + return self + + # TODO Port header detection here etc + conf = self.Configure(custom_tests = { + 'CheckFile': + self.autoconf.CheckFile, + 'CheckTypesCompatible': + self.autoconf.CheckTypesCompatible, + 'Check_apr_atomic_builtins': + self.autoconf.Check_apr_atomic_builtins, + 'Check_apr_largefile64': + self.autoconf.Check_apr_largefile64, + 'Check_apr_big_endian': + self.autoconf.Check_apr_big_endian, + 'Check_apr_mmap_mapping_dev_zero': + self.autoconf.Check_apr_mmap_mapping_dev_zero, + 'Check_apr_semaphores': + self.autoconf.Check_apr_semaphores, + 'Check_apr_semun': + self.autoconf.Check_apr_semun, + 'Check_apr_check_tcp_nodelay_inherited': + self.autoconf.Check_apr_check_tcp_nodelay_inherited, + 'Check_apr_nonblock_inherited': + self.autoconf.Check_apr_nonblock_inherited, + 'Check_apr_ebcdic': + self.autoconf.Check_apr_ebcdic, + 'Check_apr_sctp': + self.autoconf.Check_apr_sctp, + }, + config_h = self.apr_config_h) + + # Do we have a working C Compiler? + self.critical(conf.CheckCC) + + flag_headers = self.Split("""ByteOrder.h + conio.h + crypt.h + ctype.h + dir.h + dirent.h + dl.h + dlfcn.h + errno.h + fcntl.h + grp.h + io.h + limits.h + mach-o/dyld.h + malloc.h + memory.h + netdb.h + osreldate.h + poll.h + process.h + pwd.h + semaphore.h + signal.h + stdarg.h + stddef.h + stdio.h + stdlib.h + string.h + strings.h + sysapi.h + sysgtime.h + termios.h + time.h + tpfeq.h + tpfio.h + unistd.h + unix.h + windows.h + winsock2.h + arpa/inet.h + kernel/OS.h + net/errno.h + netinet/in.h + netinet/sctp.h + netinet/tcp.h + netinet/sctp_uio.h + sys/file.h + sys/ioctl.h + sys/mman.h + sys/param.h + sys/poll.h + sys/resource.h + sys/select.h + sys/sem.h + sys/sendfile.h + sys/signal.h + sys/socket.h + sys/sockio.h + sys/stat.h + sys/sysctl.h + sys/syslimits.h + sys/time.h + sys/types.h + sys/uio.h + sys/un.h + sys/wait.h + pthread.h + """) + for x in flag_headers: + s = x.replace('/', '_').replace('.', '').replace('-', '') + if conf.CheckCHeader(x): + subst['@%s@' % (s)] = 1 + else: + subst['@%s@' % (s)] = 0 + + sizeof_char = conf.CheckTypeSize('char') + sizeof_int = self.critical_value(conf.CheckTypeSize, 4, 'int') + subst['@int_value@'] = 'int' + sizeof_long = conf.CheckTypeSize('long') + sizeof_short = self.critical_value(conf.CheckTypeSize, 2, 'short') + subst['@short_value@'] = 'short' + sizeof_long_long = conf.CheckTypeSize('long long') + sizeof_longlong = conf.CheckTypeSize('longlong') + sizeof_pid_t = conf.CheckTypeSize('pid_t', includes='#include <sys/types.h>') + sizeof_off_t = conf.CheckTypeSize('off_t', includes='#include <sys/types.h>') + sizeof_size_t = conf.CheckTypeSize('size_t', includes='#include <sys/types.h>') + sizeof_ssize_t = conf.CheckTypeSize('ssize_t', includes='#include <sys/types.h>') + subst['@voidp_size@'] = conf.CheckTypeSize('void*') + + if sizeof_size_t: + subst['@size_t_value@'] = 'size_t' + subst['@size_t_fmt@'] = '#define APR_SIZE_T_FMT "lu"' + else: + subst['@size_t_value@'] = 'apr_int32_t' + subst['@size_t_fmt@'] = '#define APR_SIZE_T_FMT "u"' + + if sizeof_ssize_t: + subst['@ssize_t_value@'] = 'ssize_t' + subst['@ssize_t_fmt@'] = '#define APR_SSIZE_T_FMT "ld"' + else: + subst['@ssize_t_value@'] = 'apr_int32_t' + subst['@ssize_t_fmt@'] = '#define APR_SSIZE_T_FMT "d"' + + if conf.Check_apr_big_endian(): + subst['@bigendian@'] = 1 + else: + subst['@bigendian@'] = 0 + # Now we need to find what apr_int64_t (sizeof == 8) will be. + # The first match is our preference. + if sizeof_int == 8: + subst['@int64_literal@'] = '#define APR_INT64_C(val) (val)' + subst['@uint64_literal@'] = '#define APR_UINT64_C(val) (val##U)' + subst['@int64_t_fmt@'] = '#define APR_INT64_T_FMT "d"' + subst['@uint64_t_fmt@'] = '#define APR_UINT64_T_FMT "u"' + subst['@uint64_t_hex_fmt@'] = '#define APR_UINT64_T_HEX_FMT "x"' + subst['@int64_value@'] = 'int' + subst['@long_value@'] = 'int' + subst['@int64_strfn=@'] = 'strtoi' + elif sizeof_long == 8: + subst['@int64_literal@'] = '#define APR_INT64_C(val) (val##L)' + subst['@uint64_literal@'] = '#define APR_UINT64_C(val) (val##UL)' + subst['@int64_t_fmt@'] = '#define APR_INT64_T_FMT "ld"' + subst['@uint64_t_fmt@'] = '#define APR_UINT64_T_FMT "lu"' + subst['@uint64_t_hex_fmt@'] = '#define APR_UINT64_T_HEX_FMT "lx"' + subst['@int64_value@'] = 'long' + subst['@long_value@'] = 'long' + subst['@int64_strfn=@'] = 'strtol' + elif sizeof_long_long == 8: + subst['@int64_literal@'] = '#define APR_INT64_C(val) (val##LL)' + subst['@uint64_literal@'] = '#define APR_UINT64_C(val) (val##ULL)' + # Linux, Solaris, FreeBSD all support ll with printf. + # BSD 4.4 originated 'q'. Solaris is more popular and + # doesn't support 'q'. Solaris wins. Exceptions can + # go to the OS-dependent section. + subst['@int64_t_fmt@'] = '#define APR_INT64_T_FMT "lld"' + subst['@uint64_t_fmt@'] = '#define APR_UINT64_T_FMT "llu"' + subst['@uint64_t_hex_fmt@'] = '#define APR_UINT64_T_HEX_FMT "llx"' + subst['@int64_value@'] = 'long long' + subst['@long_value@'] = 'long long' + subst['@int64_strfn=@'] = 'strtoll' + elif sizeof_longlong == 8: + subst['@int64_literal@'] = '#define APR_INT64_C(val) (val##LL)' + subst['@uint64_literal@'] = '#define APR_UINT64_C(val) (val##ULL)' + subst['@int64_t_fmt@'] = '#define APR_INT64_T_FMT "qd"' + subst['@uint64_t_fmt@'] = '#define APR_UINT64_T_FMT "qu"' + subst['@uint64_t_hex_fmt@'] = '#define APR_UINT64_T_HEX_FMT "qx"' + subst['@int64_value@'] = '__int64' + subst['@long_value@'] = '__int64' + subst['@int64_strfn=@'] = 'strtoll' + else: + print("could not detect a 64-bit integer type") + self.Exit(1) + + if conf.CheckDeclaration('INT64_C', includes='#include <stdint.h>'): + subst['@int64_literal@'] = '#define APR_INT64_C(val) INT64_C(val)' + subst['@uint64_literal@'] = '#define APR_UINT64_C(val) UINT64_C(val)' + subst['@stdint@'] = 1 + + if sizeof_pid_t == sizeof_short: + subst['@pid_t_fmt@'] = '#define APR_PID_T_FMT "hd"' + elif sizeof_pid_t == sizeof_int: + subst['@pid_t_fmt@'] = '#define APR_PID_T_FMT "d"' + elif sizeof_pid_t == sizeof_long: + subst['@pid_t_fmt@'] = '#define APR_PID_T_FMT "ld"' + elif sizeof_pid_t == sizeof_long_long: + subst['@pid_t_fmt@'] = '#define APR_PID_T_FMT APR_INT64_T_FMT' + else: + subst['@pid_t_fmt@'] = '#error Can not determine the proper size for pid_t' + + # TODO: Per OS changing of these + + if conf.Check_apr_largefile64(): + self.AppendUnique(CPPFLAGS = ['-D_LARGEFILE64_SOURCE']) + + aprlfs=0 + if self['lfs'] and sizeof_off_t == 4: + # Check whether the transitional LFS API is sufficient + aprlfs=1 + for f in ['mmap64', 'sendfile64', 'sendfilev64', 'mkstemp64', 'readdir64_r']: + conf.CheckFunc(f) + elif sizeof_off_t == sizeof_size_t: + aprlfs=1 + + if aprlfs and sizeof_off_t == 4: + # LFS is go! + subst['@off_t_fmt@'] = '#define APR_OFF_T_FMT APR_INT64_T_FMT' + subst['@off_t_value@'] = 'off64_t' + subst['@off_t_strfn@'] = 'apr_strtoi64' + elif sizeof_off_t == 4 and sizeof_long == 4: + # Special case: off_t may change size with _FILE_OFFSET_BITS + # on 32-bit systems with LFS support. To avoid compatibility + # issues when other packages do define _FILE_OFFSET_BITS, + # hard-code apr_off_t to long. + subst['@off_t_fmt@'] = '#define APR_OFF_T_FMT "ld"' + subst['@off_t_value@'] = 'long' + subst['@off_t_strfn@'] = 'strtol' + elif sizeof_off_t != 0: + subst['@off_t_value@'] = 'off_t' + if sizeof_off_t == sizeof_long: + subst['@off_t_fmt@'] = '#define APR_OFF_T_FMT "ld"' + subst['@off_t_strfn@'] = 'strtol' + elif sizeof_off_t == sizeof_int: + subst['@off_t_fmt@'] = '#define APR_OFF_T_FMT "d"' + subst['@off_t_strfn@'] = 'strtoi' + elif sizeof_off_t == sizeof_long_long: + subst['@off_t_fmt@'] = '#define APR_OFF_T_FMT APR_INT64_T_FMT' + subst['@off_t_strfn@'] = 'apr_strtoi64' + else: + print("could not determine the size of off_t") + self.Exit(1) + else: + # Fallback on int + subst['@off_t_fmt@'] = '#define APR_OFF_T_FMT "d"' + subst['@off_t_value@'] = 'apr_int32_t' + subst['@off_t_strfn@'] = 'strtoi' + + if conf.Check_apr_atomic_builtins(): + conf.Define('HAVE_ATOMIC_BUILTINS', 1) + + if not conf.CheckType('size_t', includes='#include <sys/types.h>'): + subst['@size_t_value@'] = 'apr_int32_t' + + if not conf.CheckType('ssize_t', includes='#include <sys/types.h>'): + subst['@ssize_t_value@'] = 'apr_int32_t' + + if not conf.CheckType('socklen_t', includes='#include <sys/socket.h>'): + subst['@socklen_t_value@'] = 'int' + else: + if self['PLATFORM'] == 'hpux' and sizeof_long == 8: + # 64-bit HP-UX requires 32-bit socklens in + # kernel, but user-space declarations say + # 64-bit (socklen_t == size_t == long). + # This will result in many compile warnings, + # but we're functionally busted otherwise. + subst['@socklen_t_value@'] = 'int' + else: + subst['@socklen_t_value@'] = 'socklen_t' + + # Regardless of whether _LARGEFILE64_SOURCE is used, on 32-bit + # platforms _FILE_OFFSET_BITS will affect the size of ino_t and hence + # the build-time ABI may be different from the apparent ABI when using + # APR with another package which *does* define _FILE_OFFSET_BITS. + # (Exactly as per the case above with off_t where LFS is *not* used) + # + # To be safe, hard-code apr_ino_t as 'unsigned long' iff that is + # exactly the size of ino_t here; otherwise use ino_t as existing + # releases did. To be correct, apr_ino_t should have been made an + # ino64_t as apr_off_t is off64_t, but this can't be done now without + # breaking ABI. + subst['@ino_t_value@'] = 'ino_t' + if sizeof_long == 4 and conf.CheckTypesCompatible('ino_t', 'unsigned long', '#include <fts.h>'): + subst['@ino_t_value@'] = 'unsigned long' + + # check for mmap functions + # store the results into mmap_results dictionary for use later + mmap_funcs = ['mmap', 'mmap', 'shm_open', 'shm_unlink', 'shm_get', + 'shmat', 'shmdt', 'shmctl'] + mmap_results = dict([[k, conf.CheckFunc(k)] for k in mmap_funcs]) + + # check for mmap mapping dev zero + if mmap_results['mmap'] and \ + conf.CheckFile("/dev/zero") and \ + conf.Check_apr_mmap_mapping_dev_zero(): + subst['@havemmapzero@'] = 1 + else: + subst['@havemmapzero@'] = 0 + + # check for locking mechanisms + if conf.Check_apr_semaphores(): + subst['@hassysvser@'] = 1 + else: + subst['@hassysvser@'] = 0 + + if conf.CheckDeclaration('F_SETLK', '#include <fcntl.h>'): + subst['@hasfcntlser@'] = 1 + else: + subst['@hasfcntlser@'] = 0 + + if conf.CheckFunc('flock'): + subst['@hasflockser@'] = 1 + else: + subst['@hasflockser@'] = 0 + + apr_tcp_nopush_flag="0" + if conf.CheckDeclaration('TCP_CORK', '#include <netinet/tcp.h>'): + subst['@have_corkable_tcp@'] = 1 + apr_tcp_nopush_flag="TCP_CORK" + else: + subst['@have_corkable_tcp@'] = 0 + + if conf.CheckDeclaration('TCP_NOPUSH', '#include <netinet/tcp.h>'): + subst['@apr_tcp_nopush_flag@'] = 3 + subst['@have_corkable_tcp@'] = 1 + + subst['@apr_tcp_nopush_flag@'] = apr_tcp_nopush_flag + + if conf.CheckFunc('flock'): + subst['@hasflockser@'] = 1 + else: + subst['@hasflockser@'] = 0 + + if conf.CheckFunc('getrlimit'): + subst['@have_getrlimit@'] = 1 + else: + subst['@have_getrlimit@'] = 0 + + if conf.CheckFunc('setrlimit'): + subst['@have_setrlimit@'] = 1 + else: + subst['@have_setrlimit@'] = 0 + + if conf.CheckType('struct in_addr', includes='#include <netinet/in.h>'): + subst['@have_in_addr@'] = 1 + else: + subst['@have_in_addr@'] = 0 + + if conf.CheckType('struct sockaddr_storage', includes='#include <netinet/in.h>'): + subst['@have_sa_storage@'] = 1 + else: + subst['@have_sa_storage@'] = 0 + + if conf.CheckType('struct rlimit', includes='#include <sys/resource.h>'): + subst['@struct_rlimit@'] = 1 + else: + subst['@struct_rlimit@'] = 0 + + if conf.Check_apr_semun(): + subst['@have_union_semun@'] = 1 + else: + subst['@have_union_semun@'] = 0 + + check_functions = [ + 'inet_addr', + 'inet_network', + 'memmove', + 'sigaction', + 'sigsuspend', + 'sigwait', + 'strdup', + 'stricmp', + 'strcasecmp', + 'strncasecmp', + 'strnicmp', + 'strstr', + 'memchr', + 'iovec', + 'fork', + 'mmap', + 'uuid_create', + 'uuid_generate', + 'waitpid' + ] + + for func in check_functions: + if conf.CheckFunc(func): + subst['@have_%s@' % func] = 1 + else: + subst['@have_%s@' % func] = 0 + + if self['PLATFORM'] in ['sunos']: + conf.Define("SIGWAIT_TAKES_ONE_ARG") + + # Set Features + # TODO: Not done yet + subst['@sharedmem@'] = 1 + subst['@threads@'] = 1 + subst['@sendfile@'] = 0 + subst['@mmap@'] = subst['@have_mmap@'] + subst['@fork@'] = subst['@have_fork@'] + subst['@rand@'] = 0 + subst['@oc@'] = 0 + subst['@aprdso@'] = 0 + subst['@have_unicode_fs@'] = 0 + subst['@have_proc_invoked@'] = 0 + subst['@aprlfs@'] = 0 + subst['@osuuid@'] = subst['@have_uuid_generate@'] or subst['@have_uuid_create@'] + subst['@file_as_socket@'] = 1 + + # check for IPv6 (the user is allowed to disable this via commandline + # options + subst['@have_ipv6@'] = 0 + if self['ipv6']: + if conf.CheckType('struct sockaddr_in6', + includes='#include <netinet/in.h>') and \ + conf.CheckFunc('getaddrinfo') and \ + conf.CheckFunc('getnameinfo'): + subst['@have_ipv6@'] = 1 + + if conf.CheckDeclaration('SO_ACCEPTFILTER', '#include <sys/socket.h>'): + subst['@acceptfilter@'] = 1 + else: + subst['@acceptfilter@'] = 0 + + if conf.CheckDeclaration('IPPROTO_SCTP', '#include <netinet/in.h>') and \ + conf.Check_apr_sctp(): + subst['@have_sctp@'] = 1 + else: + subst['@have_sctp@'] = 0 + + if conf.CheckDeclaration('SO_ACCEPTFILTER', '#include <sys/socket.h>'): + subst['@acceptfilter@'] = 1 + else: + subst['@acceptfilter@'] = 0 + + if conf.Check_apr_check_tcp_nodelay_inherited(): + subst['@tcp_nodelay_inherited@'] = 1 + else: + subst['@tcp_nodelay_inherited@'] = 0 + + if conf.Check_apr_nonblock_inherited(): + subst['@o_nonblock_inherited@'] = 1 + else: + subst['@o_nonblock_inherited@'] = 0 + + if conf.Check_apr_ebcdic(): + subst['@apr_charset_ebcdic@'] = 1 + else: + subst['@apr_charset_ebcdic@'] = 0 + + if conf.CheckType('struct iovec', includes='#include <sys/types.h>\n#include <sys/uio.h>'): + subst['@have_iovec@'] = 1 + else: + subst['@have_iovec@'] = 0 + + + if conf.CheckType('struct sockaddr_un', includes='#include <sys/un.h>'): + subst['@have_sockaddr_un@'] = 1 + else: + subst['@have_sockaddr_un@'] = 0 + + subst['@proc_mutex_is_global@'] = 0 + if self['PLATFORM'] in ['os2', 'beos', 'win32', 'cygwin']: + subst['@proc_mutex_is_global@'] = 1 + + # note: the current APR use of shared mutex requires /dev/zero + if conf.CheckFile('/dev/zero') and \ + conf.CheckDeclaration('PTHREAD_PROCESS_SHARED', includes='#include <pthread.h>') and \ + conf.CheckFunc('pthread_mutexattr_setpshared'): + subst['@hasprocpthreadser@'] = 1 + else: + subst['@hasprocpthreadser@'] = 0 + + + subst['@havemmaptmp@'] = 0 + subst['@havemmapshm@'] = 0 + subst['@haveshmgetanon@'] = 0 + subst['@haveshmget@'] = 0 + subst['@havemmapanon@'] = 0 + subst['@havebeosarea@'] = 0 + + subst['@usemmaptmp@'] = 0 + subst['@usemmapshm@'] = 0 + subst['@usemmapzero@'] = 0 + subst['@useshmgetanon@'] = 0 + subst['@useshmget@'] = 0 + subst['@usemmapanon@'] = 0 + subst['@usebeosarea@'] = 0 + + subst['@flockser@'] = 0 + subst['@sysvser@'] = 0 + subst['@posixser@'] = 0 + subst['@fcntlser@'] = 0 + subst['@procpthreadser@'] = 0 + subst['@pthreadser@'] = 0 + subst['@hasposixser@'] = 0 + subst['@proclockglobal@'] = 0 + + if self['APR_PLATFORM'] in ['win32']: + subst['@eolstr@'] = "\\\\r\\\\n" + else: + subst['@eolstr@'] = "\\\\n" + + subst['@shlibpath_var@'] = pjoin(self['prefix'], 'lib') + + # APR Util things to fix: + subst['@apu_have_sdbm@'] = 1 + subst['@apu_have_gdbm@'] = 0 + subst['@apu_have_ndbm@'] = 0 + subst['@apu_have_db@'] = 0 + subst['@apu_use_sdbm@'] = 1 + subst['@apu_use_ndbm@'] = 0 + subst['@apu_use_gdbm@'] = 0 + subst['@apu_use_db@'] = 0 + + subst['@apu_db_version@'] = 0 + + subst['@apu_have_pgsql@'] = 0 + subst['@apu_have_mysql@'] = 0 + subst['@apu_have_sqlite3@'] = 0 + subst['@apu_have_sqlite2@'] = 0 + subst['@apu_have_oracle@'] = 0 + subst['@apu_have_odbc@'] = 0 + + + subst['@apu_have_crypto@'] = 0 + subst['@apu_have_openssl@'] = 0 + subst['@apu_have_nss@'] = 0 + + subst['@have_iconv@'] = 0 + + self.SubstFile('include/apr.h', 'include/apr.h.in', SUBST_DICT = subst) + self.SubstFile('include/apu.h', 'include/apu.h.in', SUBST_DICT = subst) + self.SubstFile('include/apu_want.h', 'include/apu_want.h.in', SUBST_DICT = subst) + self.SubstFile('include/private/apu_select_dbm.h', 'include/private/apu_select_dbm.h.in', SUBST_DICT = subst) + if hasattr(conf, "config_h_text"): + conf.Define("APR_OFF_T_STRFN", subst['@off_t_strfn@']) + conf.config_h_text = conf.config_h_text + '#include "arch/apr_private_common.h"\n' + + return conf.Finish() diff --git a/build/apu-conf.m4 b/build/apu-conf.m4 new file mode 100644 index 00000000000..61f27d83b77 --- /dev/null +++ b/build/apu-conf.m4 @@ -0,0 +1,74 @@ +dnl -------------------------------------------------------- -*- autoconf -*- +dnl Licensed to the Apache Software Foundation (ASF) under one or more +dnl contributor license agreements. See the NOTICE file distributed with +dnl this work for additional information regarding copyright ownership. +dnl The ASF licenses this file to You under the Apache License, Version 2.0 +dnl (the "License"); you may not use this file except in compliance with +dnl the License. You may obtain a copy of the License at +dnl +dnl http://www.apache.org/licenses/LICENSE-2.0 +dnl +dnl Unless required by applicable law or agreed to in writing, software +dnl distributed under the License is distributed on an "AS IS" BASIS, +dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +dnl See the License for the specific language governing permissions and +dnl limitations under the License. + + +dnl +dnl custom autoconf rules for APRUTIL +dnl + +dnl +dnl APU_FIND_APR: figure out where APR is located +dnl +AC_DEFUN([APU_FIND_APR], [ + + dnl use the find_apr.m4 script to locate APR. sets apr_found and apr_config + APR_FIND_APR(,,,[2]) + if test "$apr_found" = "no"; then + AC_MSG_ERROR(APR could not be located. Please use the --with-apr option.) + fi + + APR_BUILD_DIR="`$apr_config --installbuilddir`" + + dnl make APR_BUILD_DIR an absolute directory (we'll need it in the + dnl sub-projects in some cases) + APR_BUILD_DIR="`cd $APR_BUILD_DIR && pwd`" + + APR_INCLUDES="`$apr_config --includes`" + APR_LIBS="`$apr_config --link-libtool --libs`" + APR_SO_EXT="`$apr_config --apr-so-ext`" + APR_LIB_TARGET="`$apr_config --apr-lib-target`" + + AC_SUBST(APR_INCLUDES) + AC_SUBST(APR_LIBS) + AC_SUBST(APR_BUILD_DIR) +]) + + +dnl +dnl APU_CHECK_CRYPT_R_STYLE +dnl +dnl Decide which of a couple of flavors of crypt_r() is necessary for +dnl this platform. +dnl +AC_DEFUN([APU_CHECK_CRYPT_R_STYLE], [ + +AC_CACHE_CHECK([style of crypt_r], apr_cv_crypt_r_style, +[AC_TRY_COMPILE([#include <crypt.h>], + [CRYPTD buffer; + crypt_r("passwd", "hash", &buffer);], + [apr_cv_crypt_r_style=cryptd], + [AC_TRY_COMPILE([#include <crypt.h>], + [struct crypt_data buffer; + crypt_r("passwd", "hash", &buffer);], + [apr_cv_crypt_r_style=struct_crypt_data], + [apr_cv_crypt_r_style=none])])]) + +if test "$apr_cv_crypt_r_style" = "cryptd"; then + AC_DEFINE(CRYPT_R_CRYPTD, 1, [Define if crypt_r has uses CRYPTD]) +elif test "$apr_cv_crypt_r_style" = "struct_crypt_data"; then + AC_DEFINE(CRYPT_R_STRUCT_CRYPT_DATA, 1, [Define if crypt_r uses struct crypt_data]) +fi +]) diff --git a/build/apu-hints.m4 b/build/apu-hints.m4 new file mode 100644 index 00000000000..6d6784a8d5c --- /dev/null +++ b/build/apu-hints.m4 @@ -0,0 +1,62 @@ +dnl -------------------------------------------------------- -*- autoconf -*- +dnl Licensed to the Apache Software Foundation (ASF) under one or more +dnl contributor license agreements. See the NOTICE file distributed with +dnl this work for additional information regarding copyright ownership. +dnl The ASF licenses this file to You under the Apache License, Version 2.0 +dnl (the "License"); you may not use this file except in compliance with +dnl the License. You may obtain a copy of the License at +dnl +dnl http://www.apache.org/licenses/LICENSE-2.0 +dnl +dnl Unless required by applicable law or agreed to in writing, software +dnl distributed under the License is distributed on an "AS IS" BASIS, +dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +dnl See the License for the specific language governing permissions and +dnl limitations under the License. + +dnl ----------------------------------------------------------------- +dnl apu-hints.m4: apr-util's autoconf macros for platform-specific hints +dnl +dnl We preload various configure settings depending +dnl on previously obtained platform knowledge. +dnl We allow all settings to be overridden from +dnl the command-line. + +dnl +dnl APU_PRELOAD +dnl +dnl Preload various build parameters based on outside knowledge. +dnl +AC_DEFUN([APU_PRELOAD], [ +if test "x$apu_preload_done" != "xyes" ; then + apu_preload_done="yes" + + echo "Applying apr-util hints file rules for $host" + + case "$host" in + *-dec-osf*) + APR_SETIFNULL(apu_crypt_threadsafe, [1]) + ;; + *-hp-hpux11.*) + APR_SETIFNULL(apu_crypt_threadsafe, [1]) + ;; + *-ibm-aix4*|*-ibm-aix5.1*) + APR_SETIFNULL(apu_iconv_inbuf_const, [1]) + ;; + *-ibm-os390) + APR_SETIFNULL(apu_crypt_threadsafe, [1]) + ;; + *-solaris2*) + APR_SETIFNULL(apu_iconv_inbuf_const, [1]) + APR_SETIFNULL(apu_crypt_threadsafe, [1]) + AC_SEARCH_LIBS(fdatasync, [rt posix4]) + ;; + *-sco3.2v5*) + APR_SETIFNULL(apu_db_xtra_libs, [-lsocket]) + ;; + esac + +fi +]) + + diff --git a/build/buildcheck.sh b/build/buildcheck.sh new file mode 100755 index 00000000000..ab5df445c4a --- /dev/null +++ b/build/buildcheck.sh @@ -0,0 +1,70 @@ +#! /bin/sh + +echo "buildconf: checking installation..." +res=0 + +# any python +python=`build/PrintPath python` +if test -z "$python"; then + echo "buildconf: python not found." + echo " You need python installed" + echo " to build APR from SVN." + res=1 +else + py_version=`python -c 'import sys; print sys.version' 2>&1|sed 's/ .*//;q'` + echo "buildconf: python version $py_version (ok)" +fi + +# autoconf 2.59 or newer +ac_version=`${AUTOCONF:-autoconf} --version 2>/dev/null|sed -e 's/^[^0-9]*//;s/[a-z]* *$//;q'` +if test -z "$ac_version"; then + echo "buildconf: autoconf not found." + echo " You need autoconf version 2.59 or newer installed" + echo " to build APR from SVN." + res=1 +else + IFS=.; set $ac_version; IFS=' ' + if test "$1" = "2" -a "$2" -lt "59" || test "$1" -lt "2"; then + echo "buildconf: autoconf version $ac_version found." + echo " You need autoconf version 2.59 or newer installed" + echo " to build APR from SVN." + res=1 + else + echo "buildconf: autoconf version $ac_version (ok)" + fi +fi + +# Sample libtool --version outputs: +# ltmain.sh (GNU libtool) 1.3.3 (1.385.2.181 1999/07/02 15:49:11) +# ltmain.sh (GNU libtool 1.1361 2004/01/02 23:10:52) 1.5a +# output is multiline from 1.5 onwards + +# Require libtool 1.4 or newer +libtool=`build/PrintPath glibtool1 glibtool libtool libtool15 libtool14` +lt_pversion=`$libtool --version 2>/dev/null|sed -e 's/([^)]*)//g;s/^[^0-9]*//;s/[- ].*//g;q'` +if test -z "$lt_pversion"; then + echo "buildconf: libtool not found." + echo " You need libtool version 1.4 or newer installed" + echo " to build APR from SVN." + res=1 +else + lt_version=`echo $lt_pversion|sed -e 's/\([a-z]*\)$/.\1/'` + IFS=.; set $lt_version; IFS=' ' + lt_status="good" + if test "$1" = "1"; then + if test "$2" -lt "4"; then + lt_status="bad" + fi + fi + if test $lt_status = "good"; then + echo "buildconf: libtool version $lt_pversion (ok)" + else + echo "buildconf: libtool version $lt_pversion found." + echo " You need libtool version 1.4 or newer installed" + echo " to build APR from SVN." + res=1 + fi +fi + +exit $res + diff --git a/build/config.guess b/build/config.guess new file mode 100755 index 00000000000..588fe82a42a --- /dev/null +++ b/build/config.guess @@ -0,0 +1,1466 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright 1992-2018 Free Software Foundation, Inc. + +timestamp='2018-01-01' + +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see <https://www.gnu.org/licenses/>. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that +# program. This Exception is an additional permission under section 7 +# of the GNU General Public License, version 3 ("GPLv3"). +# +# Originally written by Per Bothner; maintained since 2000 by Ben Elliston. +# +# You can get the latest version of this script from: +# https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess +# +# Please send patches to <config-patches@gnu.org>. + + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] + +Output the configuration name of the system \`$me' is run on. + +Options: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to <config-patches@gnu.org>." + +version="\ +GNU config.guess ($timestamp) + +Originally written by Per Bothner. +Copyright 1992-2018 Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" >&2 + exit 1 ;; + * ) + break ;; + esac +done + +if test $# != 0; then + echo "$me: too many arguments$help" >&2 + exit 1 +fi + +trap 'exit 1' 1 2 15 + +# CC_FOR_BUILD -- compiler used by this script. Note that the use of a +# compiler to aid in system detection is discouraged as it requires +# temporary files to be created and, as you can see below, it is a +# headache to deal with in a portable fashion. + +# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still +# use `HOST_CC' if defined, but it is deprecated. + +# Portable tmp directory creation inspired by the Autoconf team. + +set_cc_for_build=' +trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; +trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; +: ${TMPDIR=/tmp} ; + { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || + { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || + { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || + { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; +dummy=$tmp/dummy ; +tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; +case $CC_FOR_BUILD,$HOST_CC,$CC in + ,,) echo "int x;" > $dummy.c ; + for c in cc gcc c89 c99 ; do + if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then + CC_FOR_BUILD="$c"; break ; + fi ; + done ; + if test x"$CC_FOR_BUILD" = x ; then + CC_FOR_BUILD=no_compiler_found ; + fi + ;; + ,,*) CC_FOR_BUILD=$CC ;; + ,*,*) CC_FOR_BUILD=$HOST_CC ;; +esac ; set_cc_for_build= ;' + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 1994-08-24) +if (test -f /.attbin/uname) >/dev/null 2>&1 ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +case "${UNAME_SYSTEM}" in +Linux|GNU|GNU/*) + # If the system lacks a compiler, then just pick glibc. + # We could probably try harder. + LIBC=gnu + + eval $set_cc_for_build + cat <<-EOF > $dummy.c + #include <features.h> + #if defined(__UCLIBC__) + LIBC=uclibc + #elif defined(__dietlibc__) + LIBC=dietlibc + #else + LIBC=gnu + #endif + EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC' | sed 's, ,,g'` + ;; +esac + +# Note: order is significant - the case branches are not exclusive. + +case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in + *:NetBSD:*:*) + # NetBSD (nbsd) targets should (where applicable) match one or + # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, + # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently + # switched to ELF, *-*-netbsd* would select the old + # object file format. This provides both forward + # compatibility and a consistent mechanism for selecting the + # object file format. + # + # Note: NetBSD doesn't particularly care about the vendor + # portion of the name. We always set it to "unknown". + sysctl="sysctl -n hw.machine_arch" + UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \ + /sbin/$sysctl 2>/dev/null || \ + /usr/sbin/$sysctl 2>/dev/null || \ + echo unknown)` + case "${UNAME_MACHINE_ARCH}" in + armeb) machine=armeb-unknown ;; + arm*) machine=arm-unknown ;; + sh3el) machine=shl-unknown ;; + sh3eb) machine=sh-unknown ;; + sh5el) machine=sh5le-unknown ;; + earmv*) + arch=`echo ${UNAME_MACHINE_ARCH} | sed -e 's,^e\(armv[0-9]\).*$,\1,'` + endian=`echo ${UNAME_MACHINE_ARCH} | sed -ne 's,^.*\(eb\)$,\1,p'` + machine=${arch}${endian}-unknown + ;; + *) machine=${UNAME_MACHINE_ARCH}-unknown ;; + esac + # The Operating System including object format, if it has switched + # to ELF recently (or will in the future) and ABI. + case "${UNAME_MACHINE_ARCH}" in + earm*) + os=netbsdelf + ;; + arm*|i386|m68k|ns32k|sh3*|sparc|vax) + eval $set_cc_for_build + if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ELF__ + then + # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). + # Return netbsd for either. FIX? + os=netbsd + else + os=netbsdelf + fi + ;; + *) + os=netbsd + ;; + esac + # Determine ABI tags. + case "${UNAME_MACHINE_ARCH}" in + earm*) + expr='s/^earmv[0-9]/-eabi/;s/eb$//' + abi=`echo ${UNAME_MACHINE_ARCH} | sed -e "$expr"` + ;; + esac + # The OS release + # Debian GNU/NetBSD machines have a different userland, and + # thus, need a distinct triplet. However, they do not need + # kernel version information, so it can be replaced with a + # suitable tag, in the style of linux-gnu. + case "${UNAME_VERSION}" in + Debian*) + release='-gnu' + ;; + *) + release=`echo ${UNAME_RELEASE} | sed -e 's/[-_].*//' | cut -d. -f1,2` + ;; + esac + # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: + # contains redundant information, the shorter form: + # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. + echo "${machine}-${os}${release}${abi}" + exit ;; + *:Bitrig:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE} + exit ;; + *:OpenBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} + exit ;; + *:LibertyBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-libertybsd${UNAME_RELEASE} + exit ;; + *:MidnightBSD:*:*) + echo ${UNAME_MACHINE}-unknown-midnightbsd${UNAME_RELEASE} + exit ;; + *:ekkoBSD:*:*) + echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} + exit ;; + *:SolidBSD:*:*) + echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} + exit ;; + macppc:MirBSD:*:*) + echo powerpc-unknown-mirbsd${UNAME_RELEASE} + exit ;; + *:MirBSD:*:*) + echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} + exit ;; + *:Sortix:*:*) + echo ${UNAME_MACHINE}-unknown-sortix + exit ;; + *:Redox:*:*) + echo ${UNAME_MACHINE}-unknown-redox + exit ;; + mips:OSF1:*.*) + echo mips-dec-osf1 + exit ;; + alpha:OSF1:*:*) + case $UNAME_RELEASE in + *4.0) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + ;; + *5.*) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` + ;; + esac + # According to Compaq, /usr/sbin/psrinfo has been available on + # OSF/1 and Tru64 systems produced since 1995. I hope that + # covers most systems running today. This code pipes the CPU + # types through head -n 1, so we only detect the type of CPU 0. + ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` + case "$ALPHA_CPU_TYPE" in + "EV4 (21064)") + UNAME_MACHINE=alpha ;; + "EV4.5 (21064)") + UNAME_MACHINE=alpha ;; + "LCA4 (21066/21068)") + UNAME_MACHINE=alpha ;; + "EV5 (21164)") + UNAME_MACHINE=alphaev5 ;; + "EV5.6 (21164A)") + UNAME_MACHINE=alphaev56 ;; + "EV5.6 (21164PC)") + UNAME_MACHINE=alphapca56 ;; + "EV5.7 (21164PC)") + UNAME_MACHINE=alphapca57 ;; + "EV6 (21264)") + UNAME_MACHINE=alphaev6 ;; + "EV6.7 (21264A)") + UNAME_MACHINE=alphaev67 ;; + "EV6.8CB (21264C)") + UNAME_MACHINE=alphaev68 ;; + "EV6.8AL (21264B)") + UNAME_MACHINE=alphaev68 ;; + "EV6.8CX (21264D)") + UNAME_MACHINE=alphaev68 ;; + "EV6.9A (21264/EV69A)") + UNAME_MACHINE=alphaev69 ;; + "EV7 (21364)") + UNAME_MACHINE=alphaev7 ;; + "EV7.9 (21364A)") + UNAME_MACHINE=alphaev79 ;; + esac + # A Pn.n version is a patched version. + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` + # Reset EXIT trap before exiting to avoid spurious non-zero exit code. + exitcode=$? + trap '' 0 + exit $exitcode ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-unknown-sysv4 + exit ;; + *:[Aa]miga[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-amigaos + exit ;; + *:[Mm]orph[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-morphos + exit ;; + *:OS/390:*:*) + echo i370-ibm-openedition + exit ;; + *:z/VM:*:*) + echo s390-ibm-zvmoe + exit ;; + *:OS400:*:*) + echo powerpc-ibm-os400 + exit ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit ;; + arm*:riscos:*:*|arm*:RISCOS:*:*) + echo arm-unknown-riscos + exit ;; + SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit ;; + Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + if test "`(/bin/universe) 2>/dev/null`" = att ; then + echo pyramid-pyramid-sysv3 + else + echo pyramid-pyramid-bsd + fi + exit ;; + NILE*:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit ;; + DRS?6000:unix:4.0:6*) + echo sparc-icl-nx6 + exit ;; + DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) + case `/usr/bin/uname -p` in + sparc) echo sparc-icl-nx7; exit ;; + esac ;; + s390x:SunOS:*:*) + echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4H:SunOS:5.*:*) + echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) + echo i386-pc-auroraux${UNAME_RELEASE} + exit ;; + i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) + eval $set_cc_for_build + SUN_ARCH=i386 + # If there is a compiler, see if it is configured for 64-bit objects. + # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. + # This test works for both compilers. + if [ "$CC_FOR_BUILD" != no_compiler_found ]; then + if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + SUN_ARCH=x86_64 + fi + fi + echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:*:*) + case "`/usr/bin/arch -k`" in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` + exit ;; + sun3*:SunOS:*:*) + echo m68k-sun-sunos${UNAME_RELEASE} + exit ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x${UNAME_RELEASE}" = x && UNAME_RELEASE=3 + case "`/bin/arch`" in + sun3) + echo m68k-sun-sunos${UNAME_RELEASE} + ;; + sun4) + echo sparc-sun-sunos${UNAME_RELEASE} + ;; + esac + exit ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos${UNAME_RELEASE} + exit ;; + # The situation for MiNT is a little confusing. The machine name + # can be virtually everything (everything which is not + # "atarist" or "atariste" at least should have a processor + # > m68000). The system name ranges from "MiNT" over "FreeMiNT" + # to the lowercase version "mint" (or "freemint"). Finally + # the system name "TOS" denotes a system which is actually not + # MiNT. But MiNT is downward compatible to TOS, so this should + # be no problem. + atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) + echo m68k-milan-mint${UNAME_RELEASE} + exit ;; + hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) + echo m68k-hades-mint${UNAME_RELEASE} + exit ;; + *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) + echo m68k-unknown-mint${UNAME_RELEASE} + exit ;; + m68k:machten:*:*) + echo m68k-apple-machten${UNAME_RELEASE} + exit ;; + powerpc:machten:*:*) + echo powerpc-apple-machten${UNAME_RELEASE} + exit ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit ;; + RISC*:ULTRIX:*:*) + echo mips-dec-ultrix${UNAME_RELEASE} + exit ;; + VAX*:ULTRIX*:*:*) + echo vax-dec-ultrix${UNAME_RELEASE} + exit ;; + 2020:CLIX:*:* | 2430:CLIX:*:*) + echo clipper-intergraph-clix${UNAME_RELEASE} + exit ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c +#ifdef __cplusplus +#include <stdio.h> /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && + dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && + SYSTEM_NAME=`$dummy $dummyarg` && + { echo "$SYSTEM_NAME"; exit; } + echo mips-mips-riscos${UNAME_RELEASE} + exit ;; + Motorola:PowerMAX_OS:*:*) + echo powerpc-motorola-powermax + exit ;; + Motorola:*:4.3:PL8-*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit ;; + m88k:CX/UX:7*:*) + echo m88k-harris-cxux7 + exit ;; + m88k:*:4*:R4*) + echo m88k-motorola-sysv4 + exit ;; + m88k:*:3*:R3*) + echo m88k-motorola-sysv3 + exit ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] + then + if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ + [ ${TARGET_BINARY_INTERFACE}x = x ] + then + echo m88k-dg-dgux${UNAME_RELEASE} + else + echo m88k-dg-dguxbcs${UNAME_RELEASE} + fi + else + echo i586-dg-dgux${UNAME_RELEASE} + fi + exit ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + echo m88k-motorola-sysv3 + exit ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + echo m88k-tektronix-sysv3 + exit ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + echo m68k-tektronix-bsd + exit ;; + *:IRIX*:*:*) + echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` + exit ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id + exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i*86:AIX:*:*) + echo i386-ibm-aix + exit ;; + ia64:AIX:*:*) + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} + exit ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include <sys/systemcfg.h> + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` + then + echo "$SYSTEM_NAME" + else + echo rs6000-ibm-aix3.2.5 + fi + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + echo rs6000-ibm-aix3.2.4 + else + echo rs6000-ibm-aix3.2 + fi + exit ;; + *:AIX:*:[4567]) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` + if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if [ -x /usr/bin/lslpp ] ; then + IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | + awk -F: '{ print $3 }' | sed s/[0-9]*$/0/` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${IBM_ARCH}-ibm-aix${IBM_REV} + exit ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit ;; + ibmrt:4.4BSD:*|romp-ibm:4.4BSD:*) + echo romp-ibm-bsd4.4 + exit ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and + echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + exit ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit ;; + 9000/[34678]??:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + case "${UNAME_MACHINE}" in + 9000/31?) HP_ARCH=m68000 ;; + 9000/[34]??) HP_ARCH=m68k ;; + 9000/[678][0-9][0-9]) + if [ -x /usr/bin/getconf ]; then + sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` + sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` + case "${sc_cpu_version}" in + 523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0 + 528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1 + 532) # CPU_PA_RISC2_0 + case "${sc_kernel_bits}" in + 32) HP_ARCH=hppa2.0n ;; + 64) HP_ARCH=hppa2.0w ;; + '') HP_ARCH=hppa2.0 ;; # HP-UX 10.20 + esac ;; + esac + fi + if [ "${HP_ARCH}" = "" ]; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + + #define _HPUX_SOURCE + #include <stdlib.h> + #include <unistd.h> + + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); + + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } +EOF + (CCOPTS="" $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` + test -z "$HP_ARCH" && HP_ARCH=hppa + fi ;; + esac + if [ ${HP_ARCH} = hppa2.0w ] + then + eval $set_cc_for_build + + # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating + # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler + # generating 64-bit code. GNU and HP use different nomenclature: + # + # $ CC_FOR_BUILD=cc ./config.guess + # => hppa2.0w-hp-hpux11.23 + # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess + # => hppa64-hp-hpux11.23 + + if echo __LP64__ | (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | + grep -q __LP64__ + then + HP_ARCH=hppa2.0w + else + HP_ARCH=hppa64 + fi + fi + echo ${HP_ARCH}-hp-hpux${HPUX_REV} + exit ;; + ia64:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + echo ia64-hp-hpux${HPUX_REV} + exit ;; + 3050*:HI-UX:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include <unistd.h> + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + echo unknown-hitachi-hiuxwe2 + exit ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:*) + echo hppa1.1-hp-bsd + exit ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit ;; + *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) + echo hppa1.0-hp-mpeix + exit ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:*) + echo hppa1.1-hp-osf + exit ;; + hp8??:OSF1:*:*) + echo hppa1.0-hp-osf + exit ;; + i*86:OSF1:*:*) + if [ -x /usr/sbin/sysversion ] ; then + echo ${UNAME_MACHINE}-unknown-osf1mk + else + echo ${UNAME_MACHINE}-unknown-osf1 + fi + exit ;; + parisc*:Lites*:*:*) + echo hppa1.1-hp-lites + exit ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd + exit ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd + exit ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd + exit ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd + exit ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*[A-Z]90:*:*:*) + echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ + -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*T3E:*:*:*) + echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*SV1:*:*:*) + echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + *:UNICOS/mp:*:*) + echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) + FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` + FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + 5000:UNIX_System_V:4.*:*) + FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'` + echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) + echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + exit ;; + sparc*:BSD/OS:*:*) + echo sparc-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:BSD/OS:*:*) + echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:FreeBSD:*:*) + UNAME_PROCESSOR=`/usr/bin/uname -p` + case ${UNAME_PROCESSOR} in + amd64) + UNAME_PROCESSOR=x86_64 ;; + i386) + UNAME_PROCESSOR=i586 ;; + esac + echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit ;; + i*:CYGWIN*:*) + echo ${UNAME_MACHINE}-pc-cygwin + exit ;; + *:MINGW64*:*) + echo ${UNAME_MACHINE}-pc-mingw64 + exit ;; + *:MINGW*:*) + echo ${UNAME_MACHINE}-pc-mingw32 + exit ;; + *:MSYS*:*) + echo ${UNAME_MACHINE}-pc-msys + exit ;; + i*:PW*:*) + echo ${UNAME_MACHINE}-pc-pw32 + exit ;; + *:Interix*:*) + case ${UNAME_MACHINE} in + x86) + echo i586-pc-interix${UNAME_RELEASE} + exit ;; + authenticamd | genuineintel | EM64T) + echo x86_64-unknown-interix${UNAME_RELEASE} + exit ;; + IA64) + echo ia64-unknown-interix${UNAME_RELEASE} + exit ;; + esac ;; + i*:UWIN*:*) + echo ${UNAME_MACHINE}-pc-uwin + exit ;; + amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) + echo x86_64-unknown-cygwin + exit ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + *:GNU:*:*) + # the GNU system + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit ;; + *:GNU/*:*:*) + # other systems with GNU libc and userland + echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC} + exit ;; + i*86:Minix:*:*) + echo ${UNAME_MACHINE}-pc-minix + exit ;; + aarch64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + aarch64_be:Linux:*:*) + UNAME_MACHINE=aarch64_be + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + alpha:Linux:*:*) + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in + EV5) UNAME_MACHINE=alphaev5 ;; + EV56) UNAME_MACHINE=alphaev56 ;; + PCA56) UNAME_MACHINE=alphapca56 ;; + PCA57) UNAME_MACHINE=alphapca56 ;; + EV6) UNAME_MACHINE=alphaev6 ;; + EV67) UNAME_MACHINE=alphaev67 ;; + EV68*) UNAME_MACHINE=alphaev68 ;; + esac + objdump --private-headers /bin/sh | grep -q ld.so.1 + if test "$?" = 0 ; then LIBC=gnulibc1 ; fi + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + arc:Linux:*:* | arceb:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + arm*:Linux:*:*) + eval $set_cc_for_build + if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_EABI__ + then + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + else + if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_PCS_VFP + then + echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi + else + echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf + fi + fi + exit ;; + avr32*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + cris:Linux:*:*) + echo ${UNAME_MACHINE}-axis-linux-${LIBC} + exit ;; + crisv32:Linux:*:*) + echo ${UNAME_MACHINE}-axis-linux-${LIBC} + exit ;; + e2k:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + frv:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + hexagon:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + i*86:Linux:*:*) + echo ${UNAME_MACHINE}-pc-linux-${LIBC} + exit ;; + ia64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + k1om:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + m32r*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + m68*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + mips:Linux:*:* | mips64:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef ${UNAME_MACHINE} + #undef ${UNAME_MACHINE}el + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=${UNAME_MACHINE}el + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=${UNAME_MACHINE} + #else + CPU= + #endif + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` + test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; } + ;; + mips64el:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + openrisc*:Linux:*:*) + echo or1k-unknown-linux-${LIBC} + exit ;; + or32:Linux:*:* | or1k*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + padre:Linux:*:*) + echo sparc-unknown-linux-${LIBC} + exit ;; + parisc64:Linux:*:* | hppa64:Linux:*:*) + echo hppa64-unknown-linux-${LIBC} + exit ;; + parisc:Linux:*:* | hppa:Linux:*:*) + # Look for CPU level + case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in + PA7*) echo hppa1.1-unknown-linux-${LIBC} ;; + PA8*) echo hppa2.0-unknown-linux-${LIBC} ;; + *) echo hppa-unknown-linux-${LIBC} ;; + esac + exit ;; + ppc64:Linux:*:*) + echo powerpc64-unknown-linux-${LIBC} + exit ;; + ppc:Linux:*:*) + echo powerpc-unknown-linux-${LIBC} + exit ;; + ppc64le:Linux:*:*) + echo powerpc64le-unknown-linux-${LIBC} + exit ;; + ppcle:Linux:*:*) + echo powerpcle-unknown-linux-${LIBC} + exit ;; + riscv32:Linux:*:* | riscv64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + s390:Linux:*:* | s390x:Linux:*:*) + echo ${UNAME_MACHINE}-ibm-linux-${LIBC} + exit ;; + sh64*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + sh*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + sparc:Linux:*:* | sparc64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + tile*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + vax:Linux:*:*) + echo ${UNAME_MACHINE}-dec-linux-${LIBC} + exit ;; + x86_64:Linux:*:*) + echo ${UNAME_MACHINE}-pc-linux-${LIBC} + exit ;; + xtensa*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + i*86:DYNIX/ptx:4*:*) + # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. + # earlier versions are messed up and put the nodename in both + # sysname and nodename. + echo i386-sequent-sysv4 + exit ;; + i*86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} + exit ;; + i*86:OS/2:*:*) + # If we were able to find `uname', then EMX Unix compatibility + # is probably installed. + echo ${UNAME_MACHINE}-pc-os2-emx + exit ;; + i*86:XTS-300:*:STOP) + echo ${UNAME_MACHINE}-unknown-stop + exit ;; + i*86:atheos:*:*) + echo ${UNAME_MACHINE}-unknown-atheos + exit ;; + i*86:syllable:*:*) + echo ${UNAME_MACHINE}-pc-syllable + exit ;; + i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit ;; + i*86:*DOS:*:*) + echo ${UNAME_MACHINE}-pc-msdosdjgpp + exit ;; + i*86:*:4.*:*) + UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} + fi + exit ;; + i*86:*:5:[678]*) + # UnixWare 7.x, OpenUNIX and OpenServer 6. + case `/bin/uname -X | grep "^Machine"` in + *486*) UNAME_MACHINE=i486 ;; + *Pentium) UNAME_MACHINE=i586 ;; + *Pent*|*Celeron) UNAME_MACHINE=i686 ;; + esac + echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} + exit ;; + i*86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name` + echo ${UNAME_MACHINE}-pc-isc$UNAME_REL + elif /bin/uname -X 2>/dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` + (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ + && UNAME_MACHINE=i686 + (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ + && UNAME_MACHINE=i686 + echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + else + echo ${UNAME_MACHINE}-pc-sysv32 + fi + exit ;; + pc:*:*:*) + # Left here for compatibility: + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i586. + # Note: whatever this is, it MUST be the same as what config.sub + # prints for the "djgpp" host, or else GDB configure will decide that + # this is a cross-build. + echo i586-pc-msdosdjgpp + exit ;; + Intel:Mach:3*:*) + echo i386-pc-mach3 + exit ;; + paragon:*:*:*) + echo i860-intel-osf1 + exit ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + fi + exit ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit ;; + mc68k:UNIX:SYSTEM5:3.51m) + echo m68k-convergent-sysv + exit ;; + M680?0:D-NIX:5.3:*) + echo m68k-diab-dnix + exit ;; + M68*:*:R3V[5678]*:*) + test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; + 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4; exit; } ;; + NCR*:*:4.2:* | MPRAS*:*:4.2:*) + OS_REL='.3' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) + echo m68k-unknown-lynxos${UNAME_RELEASE} + exit ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos${UNAME_RELEASE} + exit ;; + rs6000:LynxOS:2.*:*) + echo rs6000-unknown-lynxos${UNAME_RELEASE} + exit ;; + PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) + echo powerpc-unknown-lynxos${UNAME_RELEASE} + exit ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv${UNAME_RELEASE} + exit ;; + RM*:ReliantUNIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + RM*:SINIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + echo ${UNAME_MACHINE}-sni-sysv4 + else + echo ns32k-sni-sysv + fi + exit ;; + PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says <Richard.M.Bartel@ccMail.Census.GOV> + echo i586-unisys-sysv4 + exit ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes <hewes@openmarket.com>. + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit ;; + i*86:VOS:*:*) + # From Paul.Green@stratus.com. + echo ${UNAME_MACHINE}-stratus-vos + exit ;; + *:VOS:*:*) + # From Paul.Green@stratus.com. + echo hppa1.1-stratus-vos + exit ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux${UNAME_RELEASE} + exit ;; + news*:NEWS-OS:6*:*) + echo mips-sony-newsos6 + exit ;; + R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv${UNAME_RELEASE} + else + echo mips-unknown-sysv${UNAME_RELEASE} + fi + exit ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + echo powerpc-be-beos + exit ;; + BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. + echo powerpc-apple-beos + exit ;; + BePC:BeOS:*:*) # BeOS running on Intel PC compatible. + echo i586-pc-beos + exit ;; + BePC:Haiku:*:*) # Haiku running on Intel PC compatible. + echo i586-pc-haiku + exit ;; + x86_64:Haiku:*:*) + echo x86_64-unknown-haiku + exit ;; + SX-4:SUPER-UX:*:*) + echo sx4-nec-superux${UNAME_RELEASE} + exit ;; + SX-5:SUPER-UX:*:*) + echo sx5-nec-superux${UNAME_RELEASE} + exit ;; + SX-6:SUPER-UX:*:*) + echo sx6-nec-superux${UNAME_RELEASE} + exit ;; + SX-7:SUPER-UX:*:*) + echo sx7-nec-superux${UNAME_RELEASE} + exit ;; + SX-8:SUPER-UX:*:*) + echo sx8-nec-superux${UNAME_RELEASE} + exit ;; + SX-8R:SUPER-UX:*:*) + echo sx8r-nec-superux${UNAME_RELEASE} + exit ;; + SX-ACE:SUPER-UX:*:*) + echo sxace-nec-superux${UNAME_RELEASE} + exit ;; + Power*:Rhapsody:*:*) + echo powerpc-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Rhapsody:*:*) + echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Darwin:*:*) + UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown + eval $set_cc_for_build + if test "$UNAME_PROCESSOR" = unknown ; then + UNAME_PROCESSOR=powerpc + fi + if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then + if [ "$CC_FOR_BUILD" != no_compiler_found ]; then + if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + case $UNAME_PROCESSOR in + i386) UNAME_PROCESSOR=x86_64 ;; + powerpc) UNAME_PROCESSOR=powerpc64 ;; + esac + fi + # On 10.4-10.6 one might compile for PowerPC via gcc -arch ppc + if (echo '#ifdef __POWERPC__'; echo IS_PPC; echo '#endif') | \ + (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_PPC >/dev/null + then + UNAME_PROCESSOR=powerpc + fi + fi + elif test "$UNAME_PROCESSOR" = i386 ; then + # Avoid executing cc on OS X 10.9, as it ships with a stub + # that puts up a graphical alert prompting to install + # developer tools. Any system running Mac OS X 10.7 or + # later (Darwin 11 and later) is required to have a 64-bit + # processor. This is not true of the ARM version of Darwin + # that Apple uses in portable devices. + UNAME_PROCESSOR=x86_64 + fi + echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} + exit ;; + *:procnto*:*:* | *:QNX:[0123456789]*:*) + UNAME_PROCESSOR=`uname -p` + if test "$UNAME_PROCESSOR" = x86; then + UNAME_PROCESSOR=i386 + UNAME_MACHINE=pc + fi + echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} + exit ;; + *:QNX:*:4*) + echo i386-pc-qnx + exit ;; + NEO-*:NONSTOP_KERNEL:*:*) + echo neo-tandem-nsk${UNAME_RELEASE} + exit ;; + NSE-*:NONSTOP_KERNEL:*:*) + echo nse-tandem-nsk${UNAME_RELEASE} + exit ;; + NSR-*:NONSTOP_KERNEL:*:*) + echo nsr-tandem-nsk${UNAME_RELEASE} + exit ;; + NSX-*:NONSTOP_KERNEL:*:*) + echo nsx-tandem-nsk${UNAME_RELEASE} + exit ;; + *:NonStop-UX:*:*) + echo mips-compaq-nonstopux + exit ;; + BS2000:POSIX*:*:*) + echo bs2000-siemens-sysv + exit ;; + DS/*:UNIX_System_V:*:*) + echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} + exit ;; + *:Plan9:*:*) + # "uname -m" is not consistent, so use $cputype instead. 386 + # is converted to i386 for consistency with other x86 + # operating systems. + if test "$cputype" = 386; then + UNAME_MACHINE=i386 + else + UNAME_MACHINE="$cputype" + fi + echo ${UNAME_MACHINE}-unknown-plan9 + exit ;; + *:TOPS-10:*:*) + echo pdp10-unknown-tops10 + exit ;; + *:TENEX:*:*) + echo pdp10-unknown-tenex + exit ;; + KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) + echo pdp10-dec-tops20 + exit ;; + XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) + echo pdp10-xkl-tops20 + exit ;; + *:TOPS-20:*:*) + echo pdp10-unknown-tops20 + exit ;; + *:ITS:*:*) + echo pdp10-unknown-its + exit ;; + SEI:*:*:SEIUX) + echo mips-sei-seiux${UNAME_RELEASE} + exit ;; + *:DragonFly:*:*) + echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit ;; + *:*VMS:*:*) + UNAME_MACHINE=`(uname -p) 2>/dev/null` + case "${UNAME_MACHINE}" in + A*) echo alpha-dec-vms ; exit ;; + I*) echo ia64-dec-vms ; exit ;; + V*) echo vax-dec-vms ; exit ;; + esac ;; + *:XENIX:*:SysV) + echo i386-pc-xenix + exit ;; + i*86:skyos:*:*) + echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE} | sed -e 's/ .*$//'` + exit ;; + i*86:rdos:*:*) + echo ${UNAME_MACHINE}-pc-rdos + exit ;; + i*86:AROS:*:*) + echo ${UNAME_MACHINE}-pc-aros + exit ;; + x86_64:VMkernel:*:*) + echo ${UNAME_MACHINE}-unknown-esx + exit ;; + amd64:Isilon\ OneFS:*:*) + echo x86_64-unknown-onefs + exit ;; +esac + +echo "$0: unable to guess system type" >&2 + +case "${UNAME_MACHINE}:${UNAME_SYSTEM}" in + mips:Linux | mips64:Linux) + # If we got here on MIPS GNU/Linux, output extra information. + cat >&2 <<EOF + +NOTE: MIPS GNU/Linux systems require a C compiler to fully recognize +the system type. Please install a C compiler and try again. +EOF + ;; +esac + +cat >&2 <<EOF + +This script (version $timestamp), has failed to recognize the +operating system you are using. If your script is old, overwrite *all* +copies of config.guess and config.sub with the latest versions from: + + https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess +and + https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub + +If $0 has already been updated, send the following data and any +information you think might be pertinent to config-patches@gnu.org to +provide the necessary information to handle your system. + +config.guess timestamp = $timestamp + +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null` + +hostinfo = `(hostinfo) 2>/dev/null` +/bin/universe = `(/bin/universe) 2>/dev/null` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` +/bin/arch = `(/bin/arch) 2>/dev/null` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` + +UNAME_MACHINE = ${UNAME_MACHINE} +UNAME_RELEASE = ${UNAME_RELEASE} +UNAME_SYSTEM = ${UNAME_SYSTEM} +UNAME_VERSION = ${UNAME_VERSION} +EOF + +exit 1 + +# Local variables: +# eval: (add-hook 'write-file-functions 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/config.sub b/build/config.sub similarity index 50% rename from config.sub rename to build/config.sub index 8e7cdd62ce4..f2632cd8a2b 100755 --- a/config.sub +++ b/build/config.sub @@ -1,35 +1,40 @@ #! /bin/sh -# Configuration validation subroutine script, version 1.1. -# Copyright (C) 1991, 92-97, 1998, 1999 Free Software Foundation, Inc. -# This file is (in principle) common to ALL GNU software. -# The presence of a machine in this file suggests that SOME GNU software -# can handle that machine. It does not imply ALL GNU software can. -# -# This file is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or +# Configuration validation subroutine script. +# Copyright 1992-2018 Free Software Foundation, Inc. + +timestamp='2018-01-01' + +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, -# Boston, MA 02111-1307, USA. - +# along with this program; if not, see <https://www.gnu.org/licenses/>. +# # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under -# the same distribution terms that you use for the rest of that program. +# the same distribution terms that you use for the rest of that +# program. This Exception is an additional permission under section 7 +# of the GNU General Public License, version 3 ("GPLv3"). + +# Please send patches to <config-patches@gnu.org>. +# # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. # If it is invalid, we print an error message on stderr and exit with code 1. # Otherwise, we print the canonical config type on stdout and succeed. +# You can get the latest version of this script from: +# https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub + # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases # that are meaningful with *any* GNU software. @@ -45,33 +50,82 @@ # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. -if [ x$1 = x ] -then - echo Configuration name missing. 1>&2 - echo "Usage: $0 CPU-MFR-OPSYS" 1>&2 - echo "or $0 ALIAS" 1>&2 - echo where ALIAS is a recognized configuration type. 1>&2 - exit 1 -fi +me=`echo "$0" | sed -e 's,.*/,,'` -# First pass through any local machine types. -case $1 in - *local*) - echo $1 - exit 0 - ;; - *) - ;; +usage="\ +Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS + +Canonicalize a configuration name. + +Options: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to <config-patches@gnu.org>." + +version="\ +GNU config.sub ($timestamp) + +Copyright 1992-2018 Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" + exit 1 ;; + + *local*) + # First pass through any local machine types. + echo $1 + exit ;; + + * ) + break ;; + esac +done + +case $# in + 0) echo "$me: missing argument$help" >&2 + exit 1;; + 1) ;; + *) echo "$me: too many arguments$help" >&2 + exit 1;; esac # Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). # Here we must recognize all the valid KERNEL-OS combinations. maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` case $maybe_os in - linux-gnu*) + nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ + linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ + knetbsd*-gnu* | netbsd*-gnu* | netbsd*-eabi* | \ + kopensolaris*-gnu* | cloudabi*-eabi* | \ + storm-chaos* | os2-emx* | rtmk-nova*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` ;; + android-linux) + os=-linux-android + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown + ;; *) basic_machine=`echo $1 | sed 's/-[^-]*$//'` if [ $basic_machine != $1 ] @@ -94,10 +148,13 @@ case $os in -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ - -apple) + -apple | -axis | -knuth | -cray | -microblaze*) os= basic_machine=$1 ;; + -bluegene*) + os=-cnk + ;; -sim | -cisco | -oki | -wec | -winbond) os= basic_machine=$1 @@ -105,12 +162,24 @@ case $os in -scout) ;; -wrs) - os=vxworks + os=-vxworks + basic_machine=$1 + ;; + -chorusos*) + os=-chorusos + basic_machine=$1 + ;; + -chorusrdb) + os=-chorusrdb basic_machine=$1 ;; -hiux*) os=-hiuxwe2 ;; + -sco6) + os=-sco5v6 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; -sco5) os=-sco3.2v5 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` @@ -127,6 +196,10 @@ case $os in # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; + -sco5v6*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; -sco*) os=-sco3.2v2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` @@ -144,45 +217,147 @@ case $os in -isc*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; + -lynx*178) + os=-lynxos178 + ;; + -lynx*5) + os=-lynxos5 + ;; -lynx*) os=-lynxos ;; -ptx*) basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` ;; - -windowsnt*) - os=`echo $os | sed -e 's/windowsnt/winnt/'` - ;; -psos*) os=-psos ;; + -mint | -mint[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; esac # Decode aliases for certain CPU-COMPANY combinations. case $basic_machine in # Recognize the basic CPU types without company name. # Some are omitted here because they have special meanings below. - tahoe | i860 | m32r | m68k | m68000 | m88k | ns32k | arc | arm \ - | arme[lb] | pyramid | mn10200 | mn10300 | tron | a29k \ - | 580 | i960 | h8300 \ - | hppa | hppa1.0 | hppa1.1 | hppa2.0 | hppa2.0w | hppa2.0n \ - | alpha | alphaev[4-7] | alphaev56 | alphapca5[67] \ - | we32k | ns16k | clipper | i370 | sh | powerpc | powerpcle \ - | 1750a | dsp16xx | pdp11 | mips16 | mips64 | mipsel | mips64el \ - | mips64orion | mips64orionel | mipstx39 | mipstx39el \ - | mips64vr4300 | mips64vr4300el | mips64vr4100 | mips64vr4100el \ - | mips64vr5000 | miprs64vr5000el \ - | armv[34][lb] | sparc | sparclet | sparclite | sparc64 | sparcv9 | v850 | c4x \ - | thumb | d10v) + 1750a | 580 \ + | a29k \ + | aarch64 | aarch64_be \ + | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ + | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ + | am33_2.0 \ + | arc | arceb \ + | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \ + | avr | avr32 \ + | ba \ + | be32 | be64 \ + | bfin \ + | c4x | c8051 | clipper \ + | d10v | d30v | dlx | dsp16xx \ + | e2k | epiphany \ + | fido | fr30 | frv | ft32 \ + | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ + | hexagon \ + | i370 | i860 | i960 | ia16 | ia64 \ + | ip2k | iq2000 \ + | k1om \ + | le32 | le64 \ + | lm32 \ + | m32c | m32r | m32rle | m68000 | m68k | m88k \ + | maxq | mb | microblaze | microblazeel | mcore | mep | metag \ + | mips | mipsbe | mipseb | mipsel | mipsle \ + | mips16 \ + | mips64 | mips64el \ + | mips64octeon | mips64octeonel \ + | mips64orion | mips64orionel \ + | mips64r5900 | mips64r5900el \ + | mips64vr | mips64vrel \ + | mips64vr4100 | mips64vr4100el \ + | mips64vr4300 | mips64vr4300el \ + | mips64vr5000 | mips64vr5000el \ + | mips64vr5900 | mips64vr5900el \ + | mipsisa32 | mipsisa32el \ + | mipsisa32r2 | mipsisa32r2el \ + | mipsisa32r6 | mipsisa32r6el \ + | mipsisa64 | mipsisa64el \ + | mipsisa64r2 | mipsisa64r2el \ + | mipsisa64r6 | mipsisa64r6el \ + | mipsisa64sb1 | mipsisa64sb1el \ + | mipsisa64sr71k | mipsisa64sr71kel \ + | mipsr5900 | mipsr5900el \ + | mipstx39 | mipstx39el \ + | mn10200 | mn10300 \ + | moxie \ + | mt \ + | msp430 \ + | nds32 | nds32le | nds32be \ + | nios | nios2 | nios2eb | nios2el \ + | ns16k | ns32k \ + | open8 | or1k | or1knd | or32 \ + | pdp10 | pdp11 | pj | pjl \ + | powerpc | powerpc64 | powerpc64le | powerpcle \ + | pru \ + | pyramid \ + | riscv32 | riscv64 \ + | rl78 | rx \ + | score \ + | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[234]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ + | sh64 | sh64le \ + | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ + | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ + | spu \ + | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ + | ubicom32 \ + | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ + | visium \ + | wasm32 \ + | x86 | xc16x | xstormy16 | xtensa \ + | z8k | z80) + basic_machine=$basic_machine-unknown + ;; + c54x) + basic_machine=tic54x-unknown + ;; + c55x) + basic_machine=tic55x-unknown + ;; + c6x) + basic_machine=tic6x-unknown + ;; + leon|leon[3-9]) + basic_machine=sparc-$basic_machine + ;; + m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip) basic_machine=$basic_machine-unknown + os=-none ;; - m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | z8k | v70 | h8500 | w65) + m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) + ;; + ms1) + basic_machine=mt-unknown + ;; + + strongarm | thumb | xscale) + basic_machine=arm-unknown + ;; + xgate) + basic_machine=$basic_machine-unknown + os=-none + ;; + xscaleeb) + basic_machine=armeb-unknown + ;; + + xscaleel) + basic_machine=armel-unknown ;; # We use `pc' rather than `unknown' # because (1) that's what they normally are, and # (2) the word "unknown" tends to confuse beginning users. - i[34567]86) + i*86 | x86_64) basic_machine=$basic_machine-pc ;; # Object if more than one company name word. @@ -191,24 +366,93 @@ case $basic_machine in exit 1 ;; # Recognize the basic CPU types with company name. - vax-* | tahoe-* | i[34567]86-* | i860-* | m32r-* | m68k-* | m68000-* \ - | m88k-* | sparc-* | ns32k-* | fx80-* | arc-* | arm-* | c[123]* \ - | mips-* | pyramid-* | tron-* | a29k-* | romp-* | rs6000-* \ - | power-* | none-* | 580-* | cray2-* | h8300-* | h8500-* | i960-* \ - | xmp-* | ymp-* \ - | hppa-* | hppa1.0-* | hppa1.1-* | hppa2.0-* | hppa2.0w-* | hppa2.0n-* \ - | alpha-* | alphaev[4-7]-* | alphaev56-* | alphapca5[67]-* \ - | we32k-* | cydra-* | ns16k-* | pn-* | np1-* | xps100-* \ - | clipper-* | orion-* \ - | sparclite-* | pdp11-* | sh-* | powerpc-* | powerpcle-* \ - | sparc64-* | sparcv9-* | sparc86x-* | mips16-* | mips64-* | mipsel-* \ - | mips64el-* | mips64orion-* | mips64orionel-* \ - | mips64vr4100-* | mips64vr4100el-* | mips64vr4300-* | mips64vr4300el-* \ - | mipstx39-* | mipstx39el-* \ - | armv[34][lb]-* \ - | f301-* | armv*-* | t3e-* \ - | m88110-* | m680[01234]0-* | m683?2-* | m68360-* | z8k-* | d10v-* \ - | thumb-* | v850-* | d30v-* | tic30-* | c30-* ) + 580-* \ + | a29k-* \ + | aarch64-* | aarch64_be-* \ + | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ + | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ + | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \ + | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ + | avr-* | avr32-* \ + | ba-* \ + | be32-* | be64-* \ + | bfin-* | bs2000-* \ + | c[123]* | c30-* | [cjt]90-* | c4x-* \ + | c8051-* | clipper-* | craynv-* | cydra-* \ + | d10v-* | d30v-* | dlx-* \ + | e2k-* | elxsi-* \ + | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ + | h8300-* | h8500-* \ + | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ + | hexagon-* \ + | i*86-* | i860-* | i960-* | ia16-* | ia64-* \ + | ip2k-* | iq2000-* \ + | k1om-* \ + | le32-* | le64-* \ + | lm32-* \ + | m32c-* | m32r-* | m32rle-* \ + | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ + | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \ + | microblaze-* | microblazeel-* \ + | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ + | mips16-* \ + | mips64-* | mips64el-* \ + | mips64octeon-* | mips64octeonel-* \ + | mips64orion-* | mips64orionel-* \ + | mips64r5900-* | mips64r5900el-* \ + | mips64vr-* | mips64vrel-* \ + | mips64vr4100-* | mips64vr4100el-* \ + | mips64vr4300-* | mips64vr4300el-* \ + | mips64vr5000-* | mips64vr5000el-* \ + | mips64vr5900-* | mips64vr5900el-* \ + | mipsisa32-* | mipsisa32el-* \ + | mipsisa32r2-* | mipsisa32r2el-* \ + | mipsisa32r6-* | mipsisa32r6el-* \ + | mipsisa64-* | mipsisa64el-* \ + | mipsisa64r2-* | mipsisa64r2el-* \ + | mipsisa64r6-* | mipsisa64r6el-* \ + | mipsisa64sb1-* | mipsisa64sb1el-* \ + | mipsisa64sr71k-* | mipsisa64sr71kel-* \ + | mipsr5900-* | mipsr5900el-* \ + | mipstx39-* | mipstx39el-* \ + | mmix-* \ + | mt-* \ + | msp430-* \ + | nds32-* | nds32le-* | nds32be-* \ + | nios-* | nios2-* | nios2eb-* | nios2el-* \ + | none-* | np1-* | ns16k-* | ns32k-* \ + | open8-* \ + | or1k*-* \ + | orion-* \ + | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ + | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ + | pru-* \ + | pyramid-* \ + | riscv32-* | riscv64-* \ + | rl78-* | romp-* | rs6000-* | rx-* \ + | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ + | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ + | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ + | sparclite-* \ + | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx*-* \ + | tahoe-* \ + | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ + | tile*-* \ + | tron-* \ + | ubicom32-* \ + | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ + | vax-* \ + | visium-* \ + | wasm32-* \ + | we32k-* \ + | x86-* | x86_64-* | xc16x-* | xps100-* \ + | xstormy16-* | xtensa*-* \ + | ymp-* \ + | z8k-* | z80-*) + ;; + # Recognize the basic CPU types without company name, with glob match. + xtensa*) + basic_machine=$basic_machine-unknown ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. @@ -226,6 +470,9 @@ case $basic_machine in basic_machine=a29k-amd os=-udi ;; + abacus) + basic_machine=abacus-unknown + ;; adobe68k) basic_machine=m68010-adobe os=-scout @@ -240,19 +487,25 @@ case $basic_machine in basic_machine=a29k-none os=-bsd ;; + amd64) + basic_machine=x86_64-pc + ;; + amd64-*) + basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; amdahl) basic_machine=580-amdahl os=-sysv ;; amiga | amiga-*) - basic_machine=m68k-cbm + basic_machine=m68k-unknown ;; amigaos | amigados) - basic_machine=m68k-cbm + basic_machine=m68k-unknown os=-amigaos ;; amigaunix | amix) - basic_machine=m68k-cbm + basic_machine=m68k-unknown os=-sysv4 ;; apollo68) @@ -263,6 +516,13 @@ case $basic_machine in basic_machine=m68k-apollo os=-bsd ;; + aros) + basic_machine=i386-pc + os=-aros + ;; + asmjs) + basic_machine=asmjs-unknown + ;; aux) basic_machine=m68k-apple os=-aux @@ -271,6 +531,35 @@ case $basic_machine in basic_machine=ns32k-sequent os=-dynix ;; + blackfin) + basic_machine=bfin-unknown + os=-linux + ;; + blackfin-*) + basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + bluegene*) + basic_machine=powerpc-ibm + os=-cnk + ;; + c54x-*) + basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + c55x-*) + basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + c6x-*) + basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + c90) + basic_machine=c90-cray + os=-unicos + ;; + cegcc) + basic_machine=arm-unknown + os=-cegcc + ;; convex-c1) basic_machine=c1-convex os=-bsd @@ -291,27 +580,45 @@ case $basic_machine in basic_machine=c38-convex os=-bsd ;; - cray | ymp) - basic_machine=ymp-cray + cray | j90) + basic_machine=j90-cray os=-unicos ;; - cray2) - basic_machine=cray2-cray - os=-unicos + craynv) + basic_machine=craynv-cray + os=-unicosmp ;; - [ctj]90-cray) - basic_machine=c90-cray - os=-unicos + cr16 | cr16-*) + basic_machine=cr16-unknown + os=-elf ;; crds | unos) basic_machine=m68k-crds ;; + crisv32 | crisv32-* | etraxfs*) + basic_machine=crisv32-axis + ;; + cris | cris-* | etrax*) + basic_machine=cris-axis + ;; + crx) + basic_machine=crx-unknown + os=-elf + ;; da30 | da30-*) basic_machine=m68k-da30 ;; decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) basic_machine=mips-dec ;; + decsystem10* | dec10*) + basic_machine=pdp10-dec + os=-tops10 + ;; + decsystem20* | dec20*) + basic_machine=pdp10-dec + os=-tops20 + ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) basic_machine=m68k-motorola @@ -320,14 +627,30 @@ case $basic_machine in basic_machine=m88k-motorola os=-sysv3 ;; + dicos) + basic_machine=i686-pc + os=-dicos + ;; + djgpp) + basic_machine=i586-pc + os=-msdosdjgpp + ;; dpx20 | dpx20-*) basic_machine=rs6000-bull os=-bosx ;; - dpx2* | dpx2*-bull) + dpx2*) basic_machine=m68k-bull os=-sysv3 ;; + e500v[12]) + basic_machine=powerpc-unknown + os=$os"spe" + ;; + e500v[12]-*) + basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + os=$os"spe" + ;; ebmon29k) basic_machine=a29k-amd os=-ebmon @@ -353,6 +676,10 @@ case $basic_machine in basic_machine=tron-gmicro os=-sysv ;; + go32) + basic_machine=i386-pc + os=-go32 + ;; h3050r* | hiux*) basic_machine=hppa1.1-hitachi os=-hiuxwe2 @@ -426,22 +753,20 @@ case $basic_machine in ;; i370-ibm* | ibm*) basic_machine=i370-ibm - os=-mvs ;; -# I'm not sure what "Sysv32" means. Should this be sysv3.2? - i[34567]86v32) + i*86v32) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv32 ;; - i[34567]86v4*) + i*86v4*) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv4 ;; - i[34567]86v) + i*86v) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv ;; - i[34567]86sol2) + i*86sol2) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-solaris2 ;; @@ -453,14 +778,6 @@ case $basic_machine in basic_machine=i386-unknown os=-vsta ;; - i386-go32 | go32) - basic_machine=i386-unknown - os=-go32 - ;; - i386-mingw32 | mingw32) - basic_machine=i386-unknown - os=-mingw32 - ;; iris | iris4d) basic_machine=mips-sgi case $os in @@ -475,6 +792,17 @@ case $basic_machine in basic_machine=m68k-isi os=-sysv ;; + leon-*|leon[3-9]-*) + basic_machine=sparc-`echo $basic_machine | sed 's/-.*//'` + ;; + m68knommu) + basic_machine=m68k-unknown + os=-linux + ;; + m68knommu-*) + basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; m88k-omron*) basic_machine=m88k-omron ;; @@ -486,21 +814,28 @@ case $basic_machine in basic_machine=ns32k-utek os=-sysv ;; + microblaze*) + basic_machine=microblaze-xilinx + ;; + mingw64) + basic_machine=x86_64-pc + os=-mingw64 + ;; + mingw32) + basic_machine=i686-pc + os=-mingw32 + ;; + mingw32ce) + basic_machine=arm-unknown + os=-mingw32ce + ;; miniframe) basic_machine=m68000-convergent ;; - *mint | *MiNT) + *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) basic_machine=m68k-atari os=-mint ;; - mipsel*-linux*) - basic_machine=mipsel-unknown - os=-linux-gnu - ;; - mips*-linux*) - basic_machine=mips-unknown - os=-linux-gnu - ;; mips3*-*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` ;; @@ -511,10 +846,33 @@ case $basic_machine in basic_machine=m68k-rom68k os=-coff ;; + morphos) + basic_machine=powerpc-unknown + os=-morphos + ;; + moxiebox) + basic_machine=moxie-unknown + os=-moxiebox + ;; msdos) - basic_machine=i386-unknown + basic_machine=i386-pc os=-msdos ;; + ms1-*) + basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` + ;; + msys) + basic_machine=i686-pc + os=-msys + ;; + mvs) + basic_machine=i370-ibm + os=-mvs + ;; + nacl) + basic_machine=le32-unknown + os=-nacl + ;; ncr3000) basic_machine=i486-ncr os=-sysv4 @@ -524,7 +882,7 @@ case $basic_machine in os=-netbsd ;; netwinder) - basic_machine=armv4l-corel + basic_machine=armv4l-rebel os=-linux ;; news | news700 | news800 | news900) @@ -543,7 +901,7 @@ case $basic_machine in basic_machine=v70-nec os=-sysv ;; - next | m*-next ) + next | m*-next) basic_machine=m68k-next case $os in -nextstep* ) @@ -572,13 +930,36 @@ case $basic_machine in basic_machine=i960-intel os=-mon960 ;; + nonstopux) + basic_machine=mips-compaq + os=-nonstopux + ;; np1) basic_machine=np1-gould ;; + neo-tandem) + basic_machine=neo-tandem + ;; + nse-tandem) + basic_machine=nse-tandem + ;; + nsr-tandem) + basic_machine=nsr-tandem + ;; + nsx-tandem) + basic_machine=nsx-tandem + ;; op50n-* | op60c-*) basic_machine=hppa1.1-oki os=-proelf ;; + openrisc | openrisc-*) + basic_machine=or32-unknown + ;; + os400) + basic_machine=powerpc-ibm + os=-os400 + ;; OSE68000 | ose68000) basic_machine=m68000-ericsson os=-ose @@ -595,51 +976,94 @@ case $basic_machine in basic_machine=i860-intel os=-osf ;; + parisc) + basic_machine=hppa-unknown + os=-linux + ;; + parisc-*) + basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; pbd) basic_machine=sparc-tti ;; pbb) basic_machine=m68k-tti ;; - pc532 | pc532-*) + pc532 | pc532-*) basic_machine=ns32k-pc532 ;; - pentium | p5 | k5 | k6 | nexen) + pc98) + basic_machine=i386-pc + ;; + pc98-*) + basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium | p5 | k5 | k6 | nexgen | viac3) basic_machine=i586-pc ;; - pentiumpro | p6 | 6x86) + pentiumpro | p6 | 6x86 | athlon | athlon_*) + basic_machine=i686-pc + ;; + pentiumii | pentium2 | pentiumiii | pentium3) basic_machine=i686-pc ;; - pentiumii | pentium2) + pentium4) basic_machine=i786-pc ;; - pentium-* | p5-* | k5-* | k6-* | nexen-*) + pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` ;; - pentiumpro-* | p6-* | 6x86-*) + pentiumpro-* | p6-* | 6x86-* | athlon-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; - pentiumii-* | pentium2-*) + pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium4-*) basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pn) basic_machine=pn-gould ;; - power) basic_machine=rs6000-ibm + power) basic_machine=power-ibm ;; - ppc) basic_machine=powerpc-unknown - ;; - ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ppc | ppcbe) basic_machine=powerpc-unknown ;; - ppcle | powerpclittle | ppc-le | powerpc-little) + ppc-* | ppcbe-*) + basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppcle | powerpclittle) basic_machine=powerpcle-unknown - ;; + ;; ppcle-* | powerpclittle-*) basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` ;; + ppc64) basic_machine=powerpc64-unknown + ;; + ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64le | powerpc64little) + basic_machine=powerpc64le-unknown + ;; + ppc64le-* | powerpc64little-*) + basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; ps2) basic_machine=i386-ibm ;; + pw32) + basic_machine=i586-unknown + os=-pw32 + ;; + rdos | rdos64) + basic_machine=x86_64-pc + os=-rdos + ;; + rdos32) + basic_machine=i386-pc + os=-rdos + ;; rom68k) basic_machine=m68k-rom68k os=-coff @@ -650,10 +1074,30 @@ case $basic_machine in rtpc | rtpc-*) basic_machine=romp-ibm ;; + s390 | s390-*) + basic_machine=s390-ibm + ;; + s390x | s390x-*) + basic_machine=s390x-ibm + ;; sa29200) basic_machine=a29k-amd os=-udi ;; + sb1) + basic_machine=mipsisa64sb1-unknown + ;; + sb1el) + basic_machine=mipsisa64sb1el-unknown + ;; + sde) + basic_machine=mipsisa32-sde + os=-elf + ;; + sei) + basic_machine=mips-sei + os=-seiux + ;; sequent) basic_machine=i386-sequent ;; @@ -661,7 +1105,13 @@ case $basic_machine in basic_machine=sh-hitachi os=-hms ;; - sparclite-wrs) + sh5el) + basic_machine=sh5le-unknown + ;; + sh64) + basic_machine=sh64-unknown + ;; + sparclite-wrs | simso-wrs) basic_machine=sparclite-wrs os=-vxworks ;; @@ -679,6 +1129,9 @@ case $basic_machine in basic_machine=i860-stratus os=-sysv4 ;; + strongarm-* | thumb-*) + basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; sun2) basic_machine=m68000-sun ;; @@ -719,23 +1172,43 @@ case $basic_machine in sun386 | sun386i | roadrunner) basic_machine=i386-sun ;; + sv1) + basic_machine=sv1-cray + os=-unicos + ;; symmetry) basic_machine=i386-sequent os=-dynix ;; t3e) - basic_machine=t3e-cray + basic_machine=alphaev5-cray + os=-unicos + ;; + t90) + basic_machine=t90-cray os=-unicos ;; + tile*) + basic_machine=$basic_machine-unknown + os=-linux-gnu + ;; tx39) basic_machine=mipstx39-unknown ;; tx39el) basic_machine=mipstx39el-unknown ;; + toad1) + basic_machine=pdp10-xkl + os=-tops20 + ;; tower | tower-32) basic_machine=m68k-ncr ;; + tpf) + basic_machine=s390x-ibm + os=-tpf + ;; udi29k) basic_machine=a29k-amd os=-udi @@ -757,8 +1230,8 @@ case $basic_machine in os=-vms ;; vpp*|vx|vx-*) - basic_machine=f301-fujitsu - ;; + basic_machine=f301-fujitsu + ;; vxworks960) basic_machine=i960-wrs os=-vxworks @@ -771,6 +1244,9 @@ case $basic_machine in basic_machine=a29k-wrs os=-vxworks ;; + wasm32) + basic_machine=wasm32-unknown + ;; w65*) basic_machine=w65-wdc os=-none @@ -779,17 +1255,31 @@ case $basic_machine in basic_machine=hppa1.1-winbond os=-proelf ;; - xmp) - basic_machine=xmp-cray - os=-unicos + x64) + basic_machine=x86_64-pc + ;; + xbox) + basic_machine=i686-pc + os=-mingw32 ;; - xps | xps100) + xps | xps100) basic_machine=xps100-honeywell ;; + xscale-* | xscalee[bl]-*) + basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'` + ;; + ymp) + basic_machine=ymp-cray + os=-unicos + ;; z8k-*-coff) basic_machine=z8k-unknown os=-sim ;; + z80-*-coff) + basic_machine=z80-unknown + os=-sim + ;; none) basic_machine=none-none os=-none @@ -806,32 +1296,35 @@ case $basic_machine in op60c) basic_machine=hppa1.1-oki ;; - mips) - if [ x$os = x-linux-gnu ]; then - basic_machine=mips-unknown - else - basic_machine=mips-mips - fi - ;; romp) basic_machine=romp-ibm ;; + mmix) + basic_machine=mmix-knuth + ;; rs6000) basic_machine=rs6000-ibm ;; vax) basic_machine=vax-dec ;; + pdp10) + # there are many clones, so DEC is not a safe bet + basic_machine=pdp10-unknown + ;; pdp11) basic_machine=pdp11-dec ;; we32k) basic_machine=we32k-att ;; - sparc | sparcv9) + sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) + basic_machine=sh-unknown + ;; + sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) basic_machine=sparc-sun ;; - cydra) + cydra) basic_machine=cydra-cydrome ;; orion) @@ -846,9 +1339,8 @@ case $basic_machine in pmac | pmac-mpw) basic_machine=powerpc-apple ;; - c4x*) - basic_machine=c4x-none - os=-coff + *-unknown) + # Make sure to match an already-canonicalized machine name. ;; *) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 @@ -873,9 +1365,12 @@ esac if [ x"$os" != x"" ] then case $os in - # First match some system type aliases - # that might get confused with valid system types. + # First match some system type aliases that might get confused + # with valid system types. # -solaris* is a basic system type, with this one exception. + -auroraux) + os=-auroraux + ;; -solaris1 | -solaris1.*) os=`echo $os | sed -e 's|solaris1|sunos4|'` ;; @@ -891,35 +1386,63 @@ case $os in -gnu/linux*) os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` ;; - -os2_emx) - ;; - # First accept the basic system types. + # Now accept the basic system types. # The portable systems comes first. - # Each alternative MUST END IN A *, to match a version number. + # Each alternative MUST end in a * to match a version number. # -sysv* is not here because it comes later, after sysvr4. -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ - | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ - | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ + | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ + | -sym* | -kopensolaris* | -plan9* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ - | -aos* \ + | -aos* | -aros* | -cloudabi* | -sortix* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ - | -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \ - | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ + | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ + | -bitrig* | -openbsd* | -solidbsd* | -libertybsd* \ + | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ + | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ - | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ - | -mingw32* | -linux-gnu* | -uxpv* | -beos* | -mpeix* | -udk* \ - | -interix* | -uwin* | -rhapsody* | -openstep* | -oskit*) + | -chorusos* | -chorusrdb* | -cegcc* | -glidix* \ + | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -midipix* | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ + | -linux-newlib* | -linux-musl* | -linux-uclibc* \ + | -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \ + | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ + | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ + | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ + | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ + | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ + | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ + | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* \ + | -onefs* | -tirtos* | -phoenix* | -fuchsia* | -redox* | -bme*) # Remember, each alternative MUST END IN *, to match a version number. ;; + -qnx*) + case $basic_machine in + x86-* | i*86-*) + ;; + *) + os=-nto$os + ;; + esac + ;; + -nto-qnx*) + ;; + -nto*) + os=`echo $os | sed -e 's|nto|nto-qnx|'` + ;; -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ - | -windows* | -osx | -abug | -netware* | -os9* | -beos* \ - | -macos* | -mpw* | -magic* | -mon960* | -lnews*) + | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ + | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) ;; -mac*) os=`echo $os | sed -e 's|mac|macos|'` ;; + -linux-dietlibc) + os=-linux-dietlibc + ;; -linux*) os=`echo $os | sed -e 's|linux|linux-gnu|'` ;; @@ -929,6 +1452,15 @@ case $os in -sunos6*) os=`echo $os | sed -e 's|sunos6|solaris3|'` ;; + -opened*) + os=-openedition + ;; + -os400*) + os=-os400 + ;; + -wince*) + os=-wince + ;; -osfrose*) os=-osfrose ;; @@ -944,14 +1476,26 @@ case $os in -acis*) os=-aos ;; + -atheos*) + os=-atheos + ;; + -syllable*) + os=-syllable + ;; -386bsd) os=-bsd ;; -ctix* | -uts*) os=-sysv ;; - -ns2 ) - os=-nextstep2 + -nova*) + os=-rtmk-nova + ;; + -ns2) + os=-nextstep2 + ;; + -nsk*) + os=-nsk ;; # Preserve the version number of sinix5. -sinix5.*) @@ -960,6 +1504,9 @@ case $os in -sinix*) os=-sysv4 ;; + -tpf*) + os=-tpf + ;; -triton*) os=-sysv3 ;; @@ -987,8 +1534,34 @@ case $os in -xenix) os=-xenix ;; - -*mint | -*MiNT) - os=-mint + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + os=-mint + ;; + -aros*) + os=-aros + ;; + -zvmoe) + os=-zvmoe + ;; + -dicos*) + os=-dicos + ;; + -pikeos*) + # Until real need of OS specific support for + # particular features comes up, bare metal + # configurations are quite functional. + case $basic_machine in + arm*) + os=-eabi + ;; + *) + os=-elf + ;; + esac + ;; + -nacl*) + ;; + -ios) ;; -none) ;; @@ -1012,16 +1585,44 @@ else # system, and we'll never get to this point. case $basic_machine in + score-*) + os=-elf + ;; + spu-*) + os=-elf + ;; *-acorn) os=-riscix1.2 ;; - arm*-corel) + arm*-rebel) os=-linux ;; arm*-semi) os=-aout ;; - pdp11-*) + c4x-* | tic4x-*) + os=-coff + ;; + c8051-*) + os=-elf + ;; + hexagon-*) + os=-elf + ;; + tic54x-*) + os=-coff + ;; + tic55x-*) + os=-coff + ;; + tic6x-*) + os=-coff + ;; + # This must come before the *-dec entry. + pdp10-*) + os=-tops20 + ;; + pdp11-*) os=-none ;; *-dec | vax-*) @@ -1035,31 +1636,43 @@ case $basic_machine in ;; m68000-sun) os=-sunos3 - # This also exists in the configure program, but was not the - # default. - # os=-sunos4 ;; m68*-cisco) os=-aout ;; + mep-*) + os=-elf + ;; mips*-cisco) os=-elf ;; mips*-*) os=-elf ;; + or32-*) + os=-coff + ;; *-tti) # must be before sparc entry or we get the wrong os. os=-sysv3 ;; sparc-* | *-sun) os=-sunos4.1.1 ;; + pru-*) + os=-elf + ;; *-be) os=-beos ;; + *-haiku) + os=-haiku + ;; *-ibm) os=-aix ;; + *-knuth) + os=-mmixware + ;; *-wec) os=-proelf ;; @@ -1093,7 +1706,7 @@ case $basic_machine in m88k-omron*) os=-luna ;; - *-next ) + *-next) os=-nextstep ;; *-sequent) @@ -1111,25 +1724,25 @@ case $basic_machine in *-next) os=-nextstep3 ;; - *-gould) + *-gould) os=-sysv ;; - *-highlevel) + *-highlevel) os=-bsd ;; *-encore) os=-bsd ;; - *-sgi) + *-sgi) os=-irix ;; - *-siemens) + *-siemens) os=-sysv4 ;; *-masscomp) os=-rtu ;; - f301-fujitsu) + f30[01]-fujitsu | f700-fujitsu) os=-uxpv ;; *-rom68k) @@ -1162,7 +1775,7 @@ case $basic_machine in -sunos*) vendor=sun ;; - -aix*) + -cnk*|-aix*) vendor=ibm ;; -beos*) @@ -1189,13 +1802,19 @@ case $basic_machine in -genix*) vendor=ns ;; - -mvs*) + -mvs* | -opened*) + vendor=ibm + ;; + -os400*) vendor=ibm ;; -ptx*) vendor=sequent ;; - -vxsim* | -vxworks*) + -tpf*) + vendor=ibm + ;; + -vxsim* | -vxworks* | -windiss*) vendor=wrs ;; -aux*) @@ -1207,12 +1826,23 @@ case $basic_machine in -mpw* | -macos*) vendor=apple ;; - -*mint | -*MiNT) + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) vendor=atari ;; + -vos*) + vendor=stratus + ;; esac basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` ;; esac echo $basic_machine$os +exit + +# Local variables: +# eval: (add-hook 'write-file-functions 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/build/crypto.m4 b/build/crypto.m4 new file mode 100644 index 00000000000..e972494d719 --- /dev/null +++ b/build/crypto.m4 @@ -0,0 +1,290 @@ +dnl -------------------------------------------------------- -*- autoconf -*- +dnl Copyright 2006 The Apache Software Foundation or its licensors, as +dnl applicable. +dnl +dnl Licensed under the Apache License, Version 2.0 (the "License"); +dnl you may not use this file except in compliance with the License. +dnl You may obtain a copy of the License at +dnl +dnl http://www.apache.org/licenses/LICENSE-2.0 +dnl +dnl Unless required by applicable law or agreed to in writing, software +dnl distributed under the License is distributed on an "AS IS" BASIS, +dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +dnl See the License for the specific language governing permissions and +dnl limitations under the License. + +dnl +dnl Crypto module +dnl + +dnl +dnl APU_CHECK_CRYPTO: look for crypto libraries and headers +dnl +AC_DEFUN([APU_CHECK_CRYPTO], [ + apu_have_crypto=0 + apu_have_openssl=0 + apu_have_nss=0 + apu_have_commoncrypto=0 + + old_libs="$LIBS" + old_cppflags="$CPPFLAGS" + old_ldflags="$LDFLAGS" + + AC_ARG_WITH([crypto], [APR_HELP_STRING([--with-crypto], [enable crypto support])], + [ + cryptolibs="openssl nss commoncrypto" + + if test "$withval" = "yes"; then + + crypto_library_enabled=0 + for cryptolib in $cryptolibs; do + eval v=\$with_$cryptolib + if test "$v" != "" -a "$v" != "no"; then + crypto_library_enabled=1 + fi + done + + if test "$crypto_library_enabled" = "0"; then + for cryptolib in $cryptolibs; do + eval v=\$with_$cryptolib + if test "$v" != "no"; then + eval with_$cryptolib=yes + crypto_library_enabled=1 + fi + done + if test "$crypto_library_enabled" = "1"; then + AC_MSG_NOTICE([Crypto was requested but no crypto library was found; autodetecting possible libraries]) + else + AC_ERROR([Crypto was requested but all possible crypto libraries were disabled.]) + fi + fi + + APU_CHECK_CRYPTO_OPENSSL + APU_CHECK_CRYPTO_NSS + APU_CHECK_CRYPTO_COMMONCRYPTO + dnl add checks for other varieties of ssl here + if test "$apu_have_crypto" = "0"; then + AC_ERROR([Crypto was requested but no crypto library could be enabled; specify the location of a crypto library using --with-openssl, --with-nss, and/or --with-commoncrypto.]) + fi + fi + ], [ + apu_have_crypto=0 + ]) + + AC_SUBST(apu_have_crypto) + +]) +dnl + +AC_DEFUN([APU_CHECK_CRYPTO_OPENSSL], [ + openssl_have_headers=0 + openssl_have_libs=0 + + old_libs="$LIBS" + old_cppflags="$CPPFLAGS" + old_ldflags="$LDFLAGS" + + AC_ARG_WITH([openssl], + [APR_HELP_STRING([--with-openssl=DIR], [specify location of OpenSSL])], + [ + if test "$withval" = "yes"; then + AC_CHECK_HEADERS(openssl/x509.h, [openssl_have_headers=1]) + AC_CHECK_LIB(crypto, EVP_CIPHER_CTX_new, AC_CHECK_LIB(ssl, SSL_accept, [openssl_have_libs=1],,-lcrypto)) + if test "$openssl_have_headers" != "0" && test "$openssl_have_libs" != "0"; then + apu_have_openssl=1 + fi + elif test "$withval" = "no"; then + apu_have_openssl=0 + else + + openssl_CPPFLAGS="-I$withval/include" + openssl_LDFLAGS="-L$withval/lib " + + APR_ADDTO(CPPFLAGS, [$openssl_CPPFLAGS]) + APR_ADDTO(LDFLAGS, [$openssl_LDFLAGS]) + + AC_MSG_NOTICE(checking for openssl in $withval) + AC_CHECK_HEADERS(openssl/x509.h, [openssl_have_headers=1]) + AC_CHECK_LIB(crypto, EVP_CIPHER_CTX_new, AC_CHECK_LIB(ssl, SSL_accept, [openssl_have_libs=1],,-lcrypto)) + if test "$openssl_have_headers" != "0" && test "$openssl_have_libs" != "0"; then + apu_have_openssl=1 + APR_ADDTO(LDFLAGS, [-L$withval/lib]) + APR_ADDTO(INCLUDES, [-I$withval/include]) + fi + + AC_CHECK_DECLS([EVP_PKEY_CTX_new], [], [], + [#include <openssl/evp.h>]) + + fi + ], [ + apu_have_openssl=0 + ]) + + AC_SUBST(apu_have_openssl) + + dnl Since we have already done the AC_CHECK_LIB tests, if we have it, + dnl we know the library is there. + if test "$apu_have_openssl" = "1"; then + APR_ADDTO(LDADD_crypto_openssl, [$openssl_LDFLAGS -lssl -lcrypto]) + apu_have_crypto=1 + + AC_MSG_CHECKING([for const input buffers in OpenSSL]) + AC_TRY_COMPILE([#include <openssl/rsa.h>], + [ const unsigned char * buf; + unsigned char * outbuf; + RSA rsa; + + RSA_private_decrypt(1, + buf, + outbuf, + &rsa, + RSA_PKCS1_PADDING); + + ], + [AC_MSG_RESULT([yes])] + [AC_DEFINE([CRYPTO_OPENSSL_CONST_BUFFERS], 1, [Define that OpenSSL uses const buffers])], + [AC_MSG_RESULT([no])]) + + fi + AC_SUBST(LDADD_crypto_openssl) + AC_SUBST(apu_have_crypto) + + LIBS="$old_libs" + CPPFLAGS="$old_cppflags" + LDFLAGS="$old_ldflags" +]) + +AC_DEFUN([APU_CHECK_CRYPTO_NSS], [ + nss_have_libs=0 + + old_libs="$LIBS" + old_cppflags="$CPPFLAGS" + old_ldflags="$LDFLAGS" + + AC_ARG_WITH([nss], + [APR_HELP_STRING([--with-nss=DIR], [specify location of NSS])], + [ + if test "$withval" = "yes"; then + AC_PATH_TOOL([PKG_CONFIG], [pkg-config]) + if test -n "$PKG_CONFIG"; then + nss_CPPFLAGS=`$PKG_CONFIG --cflags-only-I nss` + nss_LDFLAGS=`$PKG_CONFIG --libs nss` + APR_ADDTO(CPPFLAGS, [$nss_CPPFLAGS]) + APR_ADDTO(LDFLAGS, [$nss_LDFLAGS]) + fi + nss_have_prerrorh=0 + nss_have_nssh=0 + nss_have_pk11pubh=0 + AC_CHECK_HEADERS(prerror.h, [nss_have_prerrorh=1]) + AC_CHECK_HEADERS(nss/nss.h nss.h, [nss_have_nssh=1]) + AC_CHECK_HEADERS(nss/pk11pub.h pk11pub.h, [nss_have_pk11pubh=1]) + nss_have_headers=${nss_have_prerrorh}${nss_have_nssh}${nss_have_pk11pubh} + AC_CHECK_LIB(nspr4, PR_Initialize, AC_CHECK_LIB(nss3, PK11_CreatePBEV2AlgorithmID, [nss_have_libs=1],,-lnspr4)) + if test "$nss_have_headers" = "111" && test "$nss_have_libs" != "0"; then + apu_have_nss=1 + fi + elif test "$withval" = "no"; then + apu_have_nss=0 + elif test "x$withval" != "x"; then + + nss_CPPFLAGS="-I$withval/include/nss -I$withval/include/nss3 -I$withval/include/nspr -I$withval/include/nspr4 -I$withval/include -I$withval/../public" + nss_LDFLAGS="-L$withval/lib " + + APR_ADDTO(CPPFLAGS, [$nss_CPPFLAGS]) + APR_ADDTO(LDFLAGS, [$nss_LDFLAGS]) + + AC_MSG_NOTICE(checking for nss in $withval) + nss_have_prerrorh=0 + nss_have_nssh=0 + nss_have_pk11pubh=0 + AC_CHECK_HEADERS(prerror.h, [nss_have_prerrorh=1]) + AC_CHECK_HEADERS(nss/nss.h nss.h, [nss_have_nssh=1]) + AC_CHECK_HEADERS(nss/pk11pub.h pk11pub.h, [nss_have_pk11pubh=1]) + nss_have_headers=${nss_have_prerrorh}${nss_have_nssh}${nss_have_pk11pubh} + AC_CHECK_LIB(nspr4, PR_Initialize, AC_CHECK_LIB(nss3, PK11_CreatePBEV2AlgorithmID, [nss_have_libs=1],,-lnspr4)) + if test "$nss_have_headers" = "111" && test "$nss_have_libs" != "0"; then + apu_have_nss=1 + fi + + fi + if test "$apu_have_nss" != "0"; then + APR_ADDTO(INCLUDES, [$nss_CPPFLAGS]) + fi + ], [ + apu_have_nss=0 + ]) + + AC_SUBST(apu_have_nss) + + dnl Since we have already done the AC_CHECK_LIB tests, if we have it, + dnl we know the library is there. + if test "$apu_have_nss" = "1"; then + APR_ADDTO(LDADD_crypto_nss, [$nss_LDFLAGS -lnspr4 -lnss3]) + apu_have_crypto=1 + fi + AC_SUBST(LDADD_crypto_nss) + AC_SUBST(apu_have_crypto) + + LIBS="$old_libs" + CPPFLAGS="$old_cppflags" + LDFLAGS="$old_ldflags" +]) + +AC_DEFUN([APU_CHECK_CRYPTO_COMMONCRYPTO], [ + apu_have_commoncrypto=0 + commoncrypto_have_headers=0 + commoncrypto_have_libs=0 + + old_libs="$LIBS" + old_cppflags="$CPPFLAGS" + old_ldflags="$LDFLAGS" + + AC_ARG_WITH([commoncrypto], + [APR_HELP_STRING([--with-commoncrypto=DIR], [specify location of CommonCrypto])], + [ + if test "$withval" = "yes"; then + AC_CHECK_HEADERS(CommonCrypto/CommonKeyDerivation.h, [commoncrypto_have_headers=1]) + AC_CHECK_LIB(System, CCKeyDerivationPBKDF, AC_CHECK_LIB(System, CCCryptorCreate, [commoncrypto_have_libs=1],,-lcrypto)) + if test "$commoncrypto_have_headers" != "0" && test "$commoncrypto_have_libs" != "0"; then + apu_have_commoncrypto=1 + fi + elif test "$withval" = "no"; then + apu_have_commoncrypto=0 + else + + commoncrypto_CPPFLAGS="-I$withval/include" + commoncrypto_LDFLAGS="-L$withval/lib " + + APR_ADDTO(CPPFLAGS, [$commoncrypto_CPPFLAGS]) + APR_ADDTO(LDFLAGS, [$commoncrypto_LDFLAGS]) + + AC_MSG_NOTICE(checking for commoncrypto in $withval) + AC_CHECK_HEADERS(CommonCrypto/CommonKeyDerivation.h, [commoncrypto_have_headers=1]) + AC_CHECK_LIB(System, CCKeyDerivationPBKDF, AC_CHECK_LIB(System, CCCryptorCreate, [commoncrypto_have_libs=1],,-lcrypto)) + if test "$commoncrypto_have_headers" != "0" && test "$commoncrypto_have_libs" != "0"; then + apu_have_commoncrypto=1 + APR_ADDTO(LDFLAGS, [-L$withval/lib]) + APR_ADDTO(INCLUDES, [-I$withval/include]) + fi + + fi + ], [ + apu_have_commoncrypto=0 + ]) + + dnl Since we have already done the AC_CHECK_LIB tests, if we have it, + dnl we know the library is there. + if test "$apu_have_commoncrypto" = "1"; then + apu_have_crypto=1 + fi + AC_SUBST(apu_have_commoncrypto) + AC_SUBST(LDADD_crypto_commoncrypto) + AC_SUBST(apu_have_crypto) + + LIBS="$old_libs" + CPPFLAGS="$old_cppflags" + LDFLAGS="$old_ldflags" +]) + +dnl diff --git a/build/cvtdsp.pl b/build/cvtdsp.pl new file mode 100644 index 00000000000..becb75bd5ed --- /dev/null +++ b/build/cvtdsp.pl @@ -0,0 +1,605 @@ +use IO::File; +use File::Find; + +if ($ARGV[0] eq '-6') { + find(\&tovc6, '.'); +} +elsif ($ARGV[0] eq '-5') { + find(\&tovc5, '.'); +} +elsif ($ARGV[0] eq '-2005') { + find(\&tovc2005, '.'); +} +elsif ($ARGV[0] eq '-w3') { + find(\&tow3, '.'); +} +elsif ($ARGV[0] eq '-w4') { + find(\&tow4, '.'); +} +elsif ($ARGV[0] eq '-ia64') { + find(\&tovc64, '.'); +} +elsif ($ARGV[0] eq '-d') { + find(\&todebugpools, '.'); +} +elsif ($ARGV[0] eq '-b') { + find(\&tobrowse, '.'); +} +elsif ($ARGV[0] eq '-mt') { + find(\&addmt, '.'); +} +elsif ($ARGV[0] eq '-m') { + ## 0 - conapp, 1 - dll lib, 2 - static lib + $dsptype = 2; + $name = "apr"; + onemake(); +} +else { + print "Specify -5 or -6 for Visual Studio 5 or 6 (98) .dsp format\n"; + print "Specify -w3 or -w4 for .dsp build with warning level 3 or 4 (strict)\n\n"; + print "Specify -ia64 for build targeted at Itanium (req's psdk tools)\n\n"; + print "Specify -p for extreme pool debugging\n\n"; + print "Specify -mt to add .manifest embedding\n\n"; + die "Missing argument"; +} + +sub addmt { + my $outpath, $outtype; + + if (m|\.dsp$|) { + $oname = $_; + $tname = '.#' . $_; + $verchg = 0; + $srcfl = new IO::File $oname, "r" || die; + $dstfl = new IO::File $tname, "w" || die; + while ($src = <$srcfl>) { + if ($src =~ m|^# TARGTYPE .+ Application|) { + $outtype = ".exe" + } + if ($src =~ m|^# TARGTYPE .+ Dynamic-Link|) { + $outtype = ".dll" + } + if ($src =~ m|^# PROP Output_Dir "(.+)"|) { + $outdir = $1; + $outpath = $oname; + $outpath =~ s|\.dsp||; + $outpath = ".\\" . $outdir . "\\" . $outpath . $outtype; + } + if ($src =~ m|^# ADD (BASE )?LINK32 .+ /out:"([^"]+)"|) { + $outpath = $2; + $outpath =~ s|/|\\|; + $outpath = ".\\" . $outpath if (!($outpath =~ m|^\.|)); + $src =~ s|/out:"([^"]+)"|/out:"$outpath"|; + } + if (defined($outpath) && ($src =~ m|^# Begin Special Build Tool|)) { + undef $outpath; + } + if (defined($outpath) && defined($outtype) && ($src =~ m|^\s*$|)) { + print $dstfl '# Begin Special Build Tool' . "\n"; + print $dstfl 'TargetPath=' . $outpath . "\n"; + print $dstfl 'SOURCE="$(InputPath)"' . "\n"; + print $dstfl 'PostBuild_Desc=Embed .manifest' . "\n"; + print $dstfl 'PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2' . "\n"; + print $dstfl '# End Special Build Tool' . "\n"; + $verchg = -1; + undef $outpath; + } + print $dstfl $src; + } + undef $outtype if (defined($outtype)); + undef $outpath if (defined($outpath)); + undef $srcfl; + undef $dstfl; + if ($verchg) { + unlink $oname || die; + rename $tname, $oname || die; + print "Added manifest to " . $oname . " in " . $File::Find::dir . "\n"; + } + else { + unlink $tname; + } + } +} +sub tovc5 { + + if (m|\.dsp$|) { + $oname = $_; + $tname = '.#' . $_; + $verchg = 0; + $srcfl = new IO::File $oname, "r" || die; + $dstfl = new IO::File $tname, "w" || die; + while ($src = <$srcfl>) { + if ($src =~ s|Format Version 6\.00|Format Version 5\.00|) { + $verchg = -1; + } + if ($src =~ s|^(# ADD CPP .*)/ZI (.*)|$1/Zi $2|) { + $verchg = -1; + } + if ($src =~ s|^(# ADD BASE CPP .*)/ZI (.*)|$1/Zi $2|) { + $verchg = -1; + } + if ($src =~ s|^(# ADD CPP .*)/EHsc (.*)|$1/GX $2|) { + $verchg = -1; + } + if ($src =~ s|^(# ADD BASE CPP .*)/EHsc (.*)|$1/GX $2|) { + $verchg = -1; + } + while ($src =~ s|^(# ADD RSC .*)/d "([^ ="]+)=([^"]+)"|$1/d $2="$3"|) { + $verchg = -1; + } + if ($src !~ m|^# PROP AllowPerConfigDependencies|) { + print $dstfl $src; } + else { + $verchg = -1; + } + } + undef $srcfl; + undef $dstfl; + if ($verchg) { + unlink $oname || die; + rename $tname, $oname || die; + print "Converted VC6 project " . $oname . " to VC5 in " . $File::Find::dir . "\n"; + } + else { + unlink $tname; + } + } +} + +sub tovc6 { + + if (m|\.dsp$|) { + $oname = $_; + $tname = '.#' . $_; + $verchg = 0; + $srcfl = new IO::File $_, "r" || die; + $dstfl = new IO::File $tname, "w" || die; + while ($src = <$srcfl>) { + if ($src =~ s|Format Version 5\.00|Format Version 6\.00|) { + $verchg = -1; + } + if ($src =~ s|^(!MESSAGE .*)\\\n|$1|) { + $cont = <$srcfl>; + $src = $src . $cont; + $verchg = -1; + } + if ($src =~ s|^(# ADD CPP .*)/GX (.*)|$1/EHsc $2|) { + $verchg = -1; + } + if ($src =~ s|^(# ADD BASE CPP .*)/GX (.*)|$1/EHsc $2|) { + $verchg = -1; + } + while ($src =~ s|^(# ADD RSC .*)/d "([^ ="]+)=([^"]+)"|$1/d $2="$3"|) { + $verchg = -1; + } + print $dstfl $src; + if ($verchg && $src =~ m|^# Begin Project|) { + print $dstfl "# PROP AllowPerConfigDependencies 0\n"; + } + } + undef $srcfl; + undef $dstfl; + if ($verchg) { + unlink $oname || die; + rename $tname, $oname || die; + print "Converted VC5 project " . $oname . " to VC6 in " . $File::Find::dir . "\n"; + } + else { + unlink $tname; + } + } +} + +sub tovc2005 { + + if (m|\.dsp$| || m|\.mak$|) { + $oname = $_; + $tname = '.#' . $_; + $verchg = 0; + $srcfl = new IO::File $_, "r" || die; + $dstfl = new IO::File $tname, "w" || die; + while ($src = <$srcfl>) { + if ($src =~ s|(\bCPP.*) /GX(.*)|$1 /EHsc$2|) { + $verchg = -1; + } + if ($src =~ s|(\bLINK32.*) /machine:I386(.*)|$1$2|) { + $verchg = -1; + } + while ($src =~ s|^(# ADD RSC .*)/d ([^ ="]+)="([^"]+)"|$1/d "$2=$3"|) { + $verchg = -1; + } + print $dstfl $src; + } + undef $srcfl; + undef $dstfl; + if ($verchg) { + unlink $oname || die; + rename $tname, $oname || die; + print "Converted project " . $oname . " to 2005 in " . $File::Find::dir . "\n"; + } + else { + unlink $tname; + } + } +} + +sub tow3 { + + if (m|\.dsp$| || m|\.mak$|) { + $oname = $_; + $tname = '.#' . $_; + $verchg = 0; + $srcfl = new IO::File $_, "r" || die; + $dstfl = new IO::File $tname, "w" || die; + while ($src = <$srcfl>) { + while ($src =~ m|\\\n$|) { + $src = $src . <$srcfl> + } + if ($src =~ s|(\bCPP.*) /W4(.*)|$1 /W3$2|) { + $verchg = -1; + } + print $dstfl $src; + } + undef $srcfl; + undef $dstfl; + if ($verchg) { + unlink $oname || die; + rename $tname, $oname || die; + print "Converted project " . $oname . " to warn:3 in " . $File::Find::dir . "\n"; + } + else { + unlink $tname; + } + } +} + +sub tow4 { + + if (m|\.dsp$| || m|\.mak$|) { + $oname = $_; + $tname = '.#' . $_; + $verchg = 0; + $srcfl = new IO::File $_, "r" || die; + $dstfl = new IO::File $tname, "w" || die; + while ($src = <$srcfl>) { + while ($src =~ m|\\\n$|) { + $src = $src . <$srcfl> + } + if ($src =~ s|(\bCPP.*) /W3(.*)|$1 /W4$2|) { + $verchg = -1; + } + print $dstfl $src; + } + undef $srcfl; + undef $dstfl; + if ($verchg) { + unlink $oname || die; + rename $tname, $oname || die; + print "Converted project " . $oname . " to warn:4 " . $File::Find::dir . "\n"; + } + else { + unlink $tname; + } + } +} + +sub tovc64 { + + if (m|\.dsp$| || m|\.mak$|) { + $oname = $_; + $tname = '.#' . $_; + $verchg = 0; + $srcfl = new IO::File $_, "r" || die; + $dstfl = new IO::File $tname, "w" || die; + while ($src = <$srcfl>) { + while ($src =~ m|\\\n$|) { + $src = $src . <$srcfl> + } + if ($src =~ s|Win32 \(x86\) (Release)|Win32 (IA64) $1|s) { + $verchg = -1; + } + if ($src =~ s|Win32 \(x86\) (Debug)|Win32 (IA64) $1|s) { + $verchg = -1; + } + if ($src =~ s| - Win32 (Release)| - Win32 (IA64) $1|s) { + $verchg = -1; + } + if ($src =~ s| - Win32 (Debug)| - Win32 (IA64) $1|s) { + $verchg = -1; + } + # Cross compilation exceptions + if (!(m|gen[^/]*$| || m|dftables[^/]*$|)) { + if ($src =~ s|(\bCPP.* /W3)(.*) /FD(.*)|$1 /As64 /Wp64$2$3|s) { + $verchg = -1; + } + if ($src =~ s|(\bLINK.*/machine):I386(.*)|$1:IA64$2|s) { + $verchg = -1; + } + } + else { + if ($src =~ s|(\bCPP.* /W3)(.*) /FD(.*)|$1 /As32 /Wp64$2$3|s) { + $verchg = -1; + } + } + print $dstfl $src; + } + undef $srcfl; + undef $dstfl; + if ($verchg) { + unlink $oname || die; + rename $tname, $oname || die; + print "Converted build file " . $oname . " to Win64 in " . $File::Find::dir . "\n"; + } + else { + unlink $tname; + } + } +} + +sub todebugpools { + + if (m|\.dsp$|) { + $oname = $_; + $tname = '.#' . $_; + $verchg = 0; + $srcfl = new IO::File $oname, "r" || die; + $dstfl = new IO::File $tname, "w" || die; + while ($src = <$srcfl>) { + if ($src =~ s|^(# ADD CPP .* /D "_DEBUG" )|$1/D "APR_POOL_DEBUG" |) { + $verchg = -1; + if ($oname =~ /apr\.dsp$/) { + $src =~ s|^(# ADD CPP .* /D "_DEBUG" )|$1/D "POOL_DEBUG" |; + } + } + print $dstfl $src; + } + undef $srcfl; + undef $dstfl; + if ($verchg) { + unlink $oname || die; + rename $tname, $oname || die; + print "Converted project " . $oname . " to debug pools in " . $File::Find::dir . "\n"; + } + else { + unlink $tname; + } + } +} + +sub tobrowsesources { + + if (m|\.dsp$|) { + $oname = $_; + $tname = '.#' . $_; + $verchg = 0; + $srcfl = new IO::File $oname, "r" || die; + $dstfl = new IO::File $tname, "w" || die; + while ($src = <$srcfl>) { + if ($src =~ s|^(# ADD CPP .*)( /Fd)|$1 /Fr "/httpd-2.0/srclib/apr"$2|) { + $verchg = -1; + } + print $dstfl $src; + } + undef $srcfl; + undef $dstfl; + if ($verchg) { + unlink $oname || die; + rename $tname, $oname || die; + print "Converted project " . $oname . " to browse sources in " . $File::Find::dir . "\n"; + } + else { + unlink $tname; + } + } +} + +sub frommakefiles { + + if (m|\.mak\.in$|) { + $oname = $_; + $dname = $_; + $_ =~ s/\.mak\.in/.dsp/; + $verchg = 0; + $srcfl = new IO::File $oname, "r" || die; + $dstfl = new IO::File $tname, "w" || die; + while ($src = <$srcfl>) { + if ($src =~ s|^(# ADD CPP .*)( /Fd)|$1 /Fr "/httpd-2.0/srclib/apr"$2|) { + $verchg = -1; + } + print $dstfl $src; + } + undef $srcfl; + undef $dstfl; + if ($verchg) { + unlink $oname || die; + rename $tname, $oname || die; + print "Converted project " . $oname . " to browse sources in " . $File::Find::dir . "\n"; + } + else { + unlink $tname; + } + } +} + + +sub onemake { + + if ($dsptype == 0) { + $cdefs = qq{/D "WIN32" /D "_CONSOLE"}; + $lmodel = qq{/subsystem:console}; + $targname = "Win32 (x86) Console Application"; + $targid = "0x0103"; + $debpath = "Debug"; $relpath = "Release"; + } elsif ($dsptype == 1) { + $cdefs = qq{/D "WIN32" /D "_WINDOWS"}; + $lmodel = qq{/subsystem:windows /dll}; + $targname = "Win32 (x86) Dynamic-Link Library"; + $targid = "0x0102"; + $debpath = "Debug"; $relpath = "Release"; + } elsif($dsptype == 2) { + $cdefs = qq{/D "WIN32" /D "_CONSOLE"}; + $lmodel = qq{/subsystem:console}; + $targname = "Win32 (x86) Static Library"; + $targid = "0x0104"; + $debpath = "LibD"; $relpath = "LibR"; + } + $file = dspheader(); + + + $second = ""; + + $model = "Release"; + $usedebuglib = "0"; + $debugdef = "NDEBUG"; + $cflags = "/MD /W3 /O2"; + $cincl = qq{/I "./include" /I "./os/win32" /I "./srclib/apr/include" /I "./srclib/apr-util/include"}; + $lflags = qq{/map}; + $file .= dsponemodel(); + + $second = "ELSE"; + $model = "Debug"; + $usedebuglib = "1"; + $debugdef = "_DEBUG"; + $cflags = "/MDd /W3 /GX /Zi /Od"; + $cincl = qq{/I "./include" /I "./os/win32" /I "./srclib/apr/include" /I "./srclib/apr-util/include"}; + $lflags = qq{/incremental:no /debug}; + $file .= dsponemodel(); + + $file .= qq{ +!ENDIF + +# Begin Target + +# Name "$name - Win32 Release" +# Name "$name - Win32 Debug" +}; + + $toroot = "."; + +#HERE IS OUR FOREACH! + $file .= qq{# Begin Source File + +SOURCE=./server/main.c +# End Source File +}; + + if ($dsptype == 0) { + #HERE IS OUR ICON! + $icon="$toroot/build/win32/apache.ico"; + $file .= qq{# Begin Source File + +SOURCE=$icon +# End Source File +}; + $icon = "icon=" . $icon . " "; + } + if ($dsptype == 0 || $dsptype == 1) { + $file .= qq{ +# Begin Source File + +SOURCE=./$name.rc +# End Source File +# Begin Source File + +SOURCE=$toroot/include/ap_release.h +# PROP Ignore_Default_Tool 1 +# Begin Custom Build - Creating Version Resource +InputPath=$toroot/include/ap_release.h $toroot/build/win32/win32ver.awk + +"./$name.rc" : \$(SOURCE) "\$(INTDIR)" "\$(OUTDIR)" + awk -f $toroot/build/win32/win32ver.awk $name "Apache HTTP Server" $toroot/include/ap_release.h $icon> ./Apache.rc + +# End Custom Build +# End Source File +}; + } + $file .= qq{ +# End Target +# End Project +}; + print $file; +} + +sub dspheader { + if ($dsptype == 1) { + $midl = "MTL=midl.exe\n"; + } else { + $midl = "" + } +qq{# Microsoft Developer Studio Project File - Name="$name" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "$targname" $targid + +CFG=$name - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "$name.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "$name.mak" CFG="$name - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "$name - Win32 Release" (based on "$targname") +!MESSAGE "$name - Win32 Debug" (based on "$targname") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +${midl}RSC=rc.exe +}; +} +sub dsponemodel { + if ($model eq "Release") { + $targpath = $relpath; + } else { + $targpath = $debpath; + } + if ($dsptype == 1) { + $midl = +qq{# ADD BASE MTL /nologo /D "$debugdef" /win32 +# ADD MTL /nologo /D "$debugdef" /mktyplib203 /win32 +}; } + if ($dsptype == 2) { + $linkop = qq{LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo +}; + } else { + $linkop = qq{LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib advapi32.lib ws2_32.lib mswsock.lib /nologo $lmodel $lflags /machine:I386 +# ADD LINK32 kernel32.lib user32.lib advapi32.lib ws2_32.lib mswsock.lib /nologo $lmodel $lflags /machine:I386 +}; + } + +qq{ +!${second}IF "\$(CFG)" == "$name - Win32 $model" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries $usedebuglib +# PROP BASE Output_Dir "$targpath" +# PROP BASE Intermediate_Dir "$targpath" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries $usedebuglib +# PROP Output_Dir "$targpath" +# PROP Intermediate_Dir "$targpath" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo $cflags $cincl /D "$debugdef" $cdefs /FD /c +# ADD CPP /nologo $cflags $cincl /D "$debugdef" $cdefs /Fd"$targpath/$name" /FD /c +${midl}# ADD BASE RSC /l 0x409 /d "$debugdef" +# ADD RSC /l 0x409 /d "$debugdef" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +$linkop}; +} \ No newline at end of file diff --git a/build/dbd.m4 b/build/dbd.m4 new file mode 100644 index 00000000000..77e3af10ab8 --- /dev/null +++ b/build/dbd.m4 @@ -0,0 +1,513 @@ +dnl -------------------------------------------------------- -*- autoconf -*- +dnl Licensed to the Apache Software Foundation (ASF) under one or more +dnl contributor license agreements. See the NOTICE file distributed with +dnl this work for additional information regarding copyright ownership. +dnl The ASF licenses this file to You under the Apache License, Version 2.0 +dnl (the "License"); you may not use this file except in compliance with +dnl the License. You may obtain a copy of the License at +dnl +dnl http://www.apache.org/licenses/LICENSE-2.0 +dnl +dnl Unless required by applicable law or agreed to in writing, software +dnl distributed under the License is distributed on an "AS IS" BASIS, +dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +dnl See the License for the specific language governing permissions and +dnl limitations under the License. + +dnl +dnl DBD module +dnl + +dnl +dnl APU_CHECK_DBD: compile backends for apr_dbd. +dnl +AC_DEFUN([APU_CHECK_DBD], [ + apu_have_pgsql=0 + + old_libs="$LIBS" + old_cppflags="$CPPFLAGS" + old_ldflags="$LDFLAGS" + + AC_ARG_WITH([pgsql], APR_HELP_STRING([--with-pgsql=DIR], [specify PostgreSQL location]), + [ + if test "$withval" = "yes"; then + AC_PATH_TOOL([PGSQL_CONFIG],[pg_config]) + if test "x$PGSQL_CONFIG" != 'x'; then + pgsql_CPPFLAGS="-I`$PGSQL_CONFIG --includedir`" + pgsql_LDFLAGS="-L`$PGSQL_CONFIG --libdir`" + + APR_ADDTO(CPPFLAGS, [$pgsql_CPPFLAGS]) + APR_ADDTO(LDFLAGS, [$pgsql_LDFLAGS]) + fi + + AC_CHECK_HEADERS(libpq-fe.h, [ + AC_CHECK_LIB(pq, PQsendQueryPrepared, [apu_have_pgsql=1],[ + if test "x$PGSQL_CONFIG" != 'x'; then + unset ac_cv_lib_pq_PQsendQueryPrepared + pgsql_LIBS="`$PGSQL_CONFIG --libs`" + APR_ADDTO(LIBS, [$pgsql_LIBS]) + AC_CHECK_LIB(pq, PQsendQueryPrepared, [apu_have_pgsql=1]) + fi + ]) + ]) + if test "$apu_have_pgsql" = "0"; then + AC_CHECK_HEADERS(postgresql/libpq-fe.h, [ + AC_CHECK_LIB(pq, PQsendQueryPrepared, [apu_have_pgsql=1],[ + if test "x$PGSQL_CONFIG" != 'x'; then + unset ac_cv_lib_pq_PQsendQueryPrepared + pgsql_LIBS="`$PGSQL_CONFIG --libs`" + APR_ADDTO(LIBS, [$pgsql_LIBS]) + AC_CHECK_LIB(pq, PQsendQueryPrepared, [apu_have_pgsql=1]) + fi + ]) + ]) + fi + if test "$apu_have_pgsql" != "0" && test "x$PGSQL_CONFIG" != 'x'; then + APR_ADDTO(INCLUDES, [$pgsql_CPPFLAGS]) + fi + elif test "$withval" = "no"; then + : + else + AC_PATH_TOOL([PGSQL_CONFIG],[pg_config],,[$withval/bin]) + if test "x$PGSQL_CONFIG" != 'x'; then + pgsql_CPPFLAGS="-I`$PGSQL_CONFIG --includedir`" + pgsql_LDFLAGS="-L`$PGSQL_CONFIG --libdir`" + else + pgsql_CPPFLAGS="-I$withval/include" + pgsql_LDFLAGS="-L$withval/lib " + fi + + APR_ADDTO(CPPFLAGS, [$pgsql_CPPFLAGS]) + APR_ADDTO(LDFLAGS, [$pgsql_LDFLAGS]) + + AC_MSG_NOTICE(checking for pgsql in $withval) + AC_CHECK_HEADERS(libpq-fe.h, [ + AC_CHECK_LIB(pq, PQsendQueryPrepared, [apu_have_pgsql=1],[ + if test "x$PGSQL_CONFIG" != 'x'; then + unset ac_cv_lib_pq_PQsendQueryPrepared + pgsql_LIBS="`$PGSQL_CONFIG --libs`" + APR_ADDTO(LIBS, [$pgsql_LIBS]) + AC_CHECK_LIB(pq, PQsendQueryPrepared, [apu_have_pgsql=1]) + fi + ]) + ]) + if test "$apu_have_pgsql" != "1"; then + AC_CHECK_HEADERS(postgresql/libpq-fe.h, [ + AC_CHECK_LIB(pq, PQsendQueryPrepared, [apu_have_pgsql=1],[ + if test "x$PGSQL_CONFIG" != 'x'; then + unset ac_cv_lib_pq_PQsendQueryPrepared + pgsql_LIBS="`$PGSQL_CONFIG --libs`" + APR_ADDTO(LIBS, [$pgsql_LIBS]) + AC_CHECK_LIB(pq, PQsendQueryPrepared, [apu_have_pgsql=1]) + fi + ]) + ]) + fi + if test "$apu_have_pgsql" != "0"; then + APR_ADDTO(INCLUDES, [$pgsql_CPPFLAGS]) + fi + fi + ], [ + AC_PATH_TOOL([PGSQL_CONFIG],[pg_config]) + if test "x$PGSQL_CONFIG" != 'x'; then + pgsql_CPPFLAGS="-I`$PGSQL_CONFIG --includedir`" + pgsql_LDFLAGS="-L`$PGSQL_CONFIG --libdir`" + + APR_ADDTO(CPPFLAGS, [$pgsql_CPPFLAGS]) + APR_ADDTO(LDFLAGS, [$pgsql_LDFLAGS]) + fi + + AC_CHECK_HEADERS(libpq-fe.h, [ + AC_CHECK_LIB(pq, PQsendQueryPrepared, [apu_have_pgsql=1],[ + if test "x$PGSQL_CONFIG" != 'x'; then + unset ac_cv_lib_pq_PQsendQueryPrepared + pgsql_LIBS="`$PGSQL_CONFIG --libs`" + APR_ADDTO(LIBS, [$pgsql_LIBS]) + AC_CHECK_LIB(pq, PQsendQueryPrepared, [apu_have_pgsql=1]) + fi + ]) + ]) + if test "$apu_have_pgsql" = "0"; then + AC_CHECK_HEADERS(postgresql/libpq-fe.h, [ + AC_CHECK_LIB(pq, PQsendQueryPrepared, [apu_have_pgsql=1],[ + if test "x$PGSQL_CONFIG" != 'x'; then + unset ac_cv_lib_pq_PQsendQueryPrepared + pgsql_LIBS="`$PGSQL_CONFIG --libs`" + APR_ADDTO(LIBS, [$pgsql_LIBS]) + AC_CHECK_LIB(pq, PQsendQueryPrepared, [apu_have_pgsql=1]) + fi + ]) + ]) + fi + if test "$apu_have_pgsql" != "0" && test "x$PGSQL_CONFIG" != 'x'; then + APR_ADDTO(INCLUDES, [$pgsql_CPPFLAGS]) + fi + ]) + AC_SUBST(apu_have_pgsql) + dnl Since we have already done the AC_CHECK_LIB tests, if we have it, + dnl we know the library is there. + if test "$apu_have_pgsql" = "1"; then + APR_ADDTO(LDADD_dbd_pgsql, [$pgsql_LDFLAGS -lpq $pgsql_LIBS]) + fi + AC_SUBST(LDADD_dbd_pgsql) + + LIBS="$old_libs" + CPPFLAGS="$old_cppflags" + LDFLAGS="$old_ldflags" +]) +dnl +AC_DEFUN([APU_CHECK_DBD_MYSQL], [ + apu_have_mysql=0 + + old_libs="$LIBS" + old_cppflags="$CPPFLAGS" + old_ldflags="$LDFLAGS" + + AC_ARG_WITH([mysql], APR_HELP_STRING([--with-mysql=DIR], [enable MySQL DBD driver]), + [ + if test "$withval" = "yes"; then + AC_PATH_TOOL([MYSQL_CONFIG],[mysql_config]) + if test "x$MYSQL_CONFIG" != 'x'; then + mysql_CPPFLAGS="`$MYSQL_CONFIG --include`" + mysql_LDFLAGS="`$MYSQL_CONFIG --libs_r | sed -e 's/-l[[^ ]]\+//g'`" + mysql_LIBS="`$MYSQL_CONFIG --libs_r`" + + APR_ADDTO(CPPFLAGS, [$mysql_CPPFLAGS]) + APR_ADDTO(LIBS, [$mysql_LIBS]) + fi + + AC_CHECK_HEADERS([mysql.h my_global.h my_sys.h], + AC_CHECK_LIB(mysqlclient, mysql_init, [apu_have_mysql=1]), + [apu_have_mysql=0; break], + [#include <my_global.h>]) + if test "$apu_have_mysql" = "0"; then + AC_CHECK_HEADERS([mysql/mysql.h mysql/my_global.h mysql/my_sys.h], + AC_CHECK_LIB(mysqlclient, mysql_init, [apu_have_mysql=1]), + [apu_have_mysql=0; break], + [#include <mysql/my_global.h>]) + fi + if test "$apu_have_mysql" != "0" && test "x$MYSQL_CONFIG" != 'x'; then + APR_ADDTO(INCLUDES, [$mysql_CPPFLAGS]) + fi + elif test "$withval" = "no"; then + : + else + AC_PATH_TOOL([MYSQL_CONFIG],[mysql_config],,[$withval/bin]) + if test "x$MYSQL_CONFIG" != 'x'; then + mysql_CPPFLAGS="`$MYSQL_CONFIG --include`" + mysql_LDFLAGS="`$MYSQL_CONFIG --libs_r | sed -e 's/-l[[^ ]]\+//g'`" + mysql_LIBS="`$MYSQL_CONFIG --libs_r`" + else + mysql_CPPFLAGS="-I$withval/include" + mysql_LDFLAGS="-L$withval/lib " + fi + + APR_ADDTO(CPPFLAGS, [$mysql_CPPFLAGS]) + APR_ADDTO(LDFLAGS, [$mysql_LDFLAGS]) + APR_ADDTO(LIBS, [$mysql_LIBS]) + + AC_MSG_NOTICE(checking for mysql in $withval) + AC_CHECK_HEADERS([mysql.h my_global.h my_sys.h], + AC_CHECK_LIB(mysqlclient, mysql_init, [apu_have_mysql=1]), + [apu_have_mysql=0; break], + [#include <my_global.h>]) + + if test "$apu_have_mysql" != "1"; then + AC_CHECK_HEADERS([mysql/mysql.h mysql/my_global.h mysql/my_sys.h], + AC_CHECK_LIB(mysqlclient, mysql_init, [apu_have_mysql=1]), + [apu_have_mysql=0; break], + [#include <mysql/my_global.h>]) + fi + if test "$apu_have_mysql" != "0"; then + APR_ADDTO(INCLUDES, [$mysql_CPPFLAGS]) + fi + fi + ]) + + AC_SUBST(apu_have_mysql) + + dnl Since we have already done the AC_CHECK_LIB tests, if we have it, + dnl we know the library is there. + if test "$apu_have_mysql" = "1"; then + APR_ADDTO(LDADD_dbd_mysql, [$mysql_LDFLAGS -lmysqlclient $mysql_LIBS]) + fi + AC_SUBST(LDADD_dbd_mysql) + + LIBS="$old_libs" + CPPFLAGS="$old_cppflags" + LDFLAGS="$old_ldflags" +]) +dnl +AC_DEFUN([APU_CHECK_DBD_SQLITE3], [ + apu_have_sqlite3=0 + + old_libs="$LIBS" + old_cppflags="$CPPFLAGS" + old_ldflags="$LDFLAGS" + + AC_ARG_WITH([sqlite3], APR_HELP_STRING([--with-sqlite3=DIR], [enable sqlite3 DBD driver]), + [ + if test "$withval" = "yes"; then + AC_CHECK_HEADERS(sqlite3.h, AC_CHECK_LIB(sqlite3, sqlite3_open, [apu_have_sqlite3=1])) + elif test "$withval" = "no"; then + : + else + sqlite3_CPPFLAGS="-I$withval/include" + sqlite3_LDFLAGS="-L$withval/lib " + + APR_ADDTO(CPPFLAGS, [$sqlite3_CPPFLAGS]) + APR_ADDTO(LDFLAGS, [$sqlite3_LDFLAGS]) + + AC_MSG_NOTICE(checking for sqlite3 in $withval) + AC_CHECK_HEADERS(sqlite3.h, AC_CHECK_LIB(sqlite3, sqlite3_open, [apu_have_sqlite3=1])) + if test "$apu_have_sqlite3" != "0"; then + APR_ADDTO(INCLUDES, [-I$withval/include]) + fi + fi + ], [ + AC_CHECK_HEADERS(sqlite3.h, AC_CHECK_LIB(sqlite3, sqlite3_open, [apu_have_sqlite3=1])) + ]) + + AC_SUBST(apu_have_sqlite3) + + dnl Since we have already done the AC_CHECK_LIB tests, if we have it, + dnl we know the library is there. + if test "$apu_have_sqlite3" = "1"; then + APR_ADDTO(LDADD_dbd_sqlite3, [$sqlite3_LDFLAGS -lsqlite3]) + fi + AC_SUBST(LDADD_dbd_sqlite3) + + LIBS="$old_libs" + CPPFLAGS="$old_cppflags" + LDFLAGS="$old_ldflags" +]) +dnl +AC_DEFUN([APU_CHECK_DBD_SQLITE2], [ + apu_have_sqlite2=0 + + old_libs="$LIBS" + old_cppflags="$CPPFLAGS" + old_ldflags="$LDFLAGS" + + AC_ARG_WITH([sqlite2], APR_HELP_STRING([--with-sqlite2=DIR], [enable sqlite2 DBD driver]), + [ + if test "$withval" = "yes"; then + AC_CHECK_HEADERS(sqlite.h, AC_CHECK_LIB(sqlite, sqlite_open, [apu_have_sqlite2=1])) + elif test "$withval" = "no"; then + : + else + sqlite2_CPPFLAGS="-I$withval/include" + sqlite2_LDFLAGS="-L$withval/lib " + + APR_ADDTO(CPPFLAGS, [$sqlite2_CPPFLAGS]) + APR_ADDTO(LDFLAGS, [$sqlite2_LDFLAGS]) + + AC_MSG_NOTICE(checking for sqlite2 in $withval) + AC_CHECK_HEADERS(sqlite.h, AC_CHECK_LIB(sqlite, sqlite_open, [apu_have_sqlite2=1])) + if test "$apu_have_sqlite2" != "0"; then + APR_ADDTO(INCLUDES, [-I$withval/include]) + fi + fi + ], [ + AC_CHECK_HEADERS(sqlite.h, AC_CHECK_LIB(sqlite, sqlite_open, [apu_have_sqlite2=1])) + ]) + + AC_SUBST(apu_have_sqlite2) + + dnl Since we have already done the AC_CHECK_LIB tests, if we have it, + dnl we know the library is there. + if test "$apu_have_sqlite2" = "1"; then + APR_ADDTO(LDADD_dbd_sqlite2, [$sqlite2_LDFLAGS -lsqlite]) + fi + AC_SUBST(LDADD_dbd_sqlite2) + + LIBS="$old_libs" + CPPFLAGS="$old_cppflags" + LDFLAGS="$old_ldflags" +]) +dnl +AC_DEFUN([APU_CHECK_DBD_ORACLE], [ + apu_have_oracle=0 + + old_libs="$LIBS" + old_cppflags="$CPPFLAGS" + old_ldflags="$LDFLAGS" + + AC_ARG_WITH([oracle-include], + APR_HELP_STRING([--with-oracle-include=DIR], [path to Oracle include files])) + AC_ARG_WITH([oracle], + APR_HELP_STRING([--with-oracle=DIR], [enable Oracle DBD driver; giving ORACLE_HOME as DIR]), + [ + if test "$withval" = "yes"; then + if test -n "$with_oracle_include"; then + oracle_CPPFLAGS="$CPPFLAGS -I$with_oracle_include" + APR_ADDTO(INCLUDES, [-I$with_oracle_include]) + fi + + APR_ADDTO(CPPFLAGS, [$oracle_CPPFLAGS]) + + AC_CHECK_HEADERS(oci.h, AC_CHECK_LIB(clntsh, OCIEnvCreate, [apu_have_oracle=1],[ + unset ac_cv_lib_clntsh_OCIEnvCreate + oracle_LIBS="-lnnz11" + APR_ADDTO(LIBS, [$oracle_LIBS]) + AC_CHECK_LIB(clntsh, OCIEnvCreate, [apu_have_oracle=1],[ + unset ac_cv_lib_clntsh_OCIEnvCreate + APR_REMOVEFROM(LIBS, [$oracle_LIBS]) + oracle_LIBS="-lnnz10" + APR_ADDTO(LIBS, [$oracle_LIBS]) + AC_CHECK_LIB(clntsh, OCIEnvCreate, [apu_have_oracle=1]) + ]) + ])) + elif test "$withval" = "no"; then + : + else + if test -n "$with_oracle_include"; then + oracle_CPPFLAGS="$CPPFLAGS -I$with_oracle_include" + APR_ADDTO(INCLUDES, [-I$with_oracle_include]) + else + oracle_CPPFLAGS="-I$withval/rdbms/demo -I$withval/rdbms/public" + fi + oracle_LDFLAGS="-L$withval/lib " + + APR_ADDTO(CPPFLAGS, [$oracle_CPPFLAGS]) + APR_ADDTO(LDFLAGS, [$oracle_LDFLAGS]) + + AC_MSG_NOTICE(checking for oracle in $withval) + AC_CHECK_HEADERS(oci.h, AC_CHECK_LIB(clntsh, OCIEnvCreate, [apu_have_oracle=1],[ + unset ac_cv_lib_clntsh_OCIEnvCreate + oracle_LIBS="-lnnz11" + APR_ADDTO(LIBS, [$oracle_LIBS]) + AC_CHECK_LIB(clntsh, OCIEnvCreate, [apu_have_oracle=1],[ + unset ac_cv_lib_clntsh_OCIEnvCreate + APR_REMOVEFROM(LIBS, [$oracle_LIBS]) + oracle_LIBS="-lnnz10" + APR_ADDTO(LIBS, [$oracle_LIBS]) + AC_CHECK_LIB(clntsh, OCIEnvCreate, [apu_have_oracle=1]) + ]) + ])) + if test "$apu_have_oracle" != "0"; then + oracle_LDFLAGS="$oracle_LDFLAGS -R$withval/lib" + if test -z "$with_oracle_include"; then + APR_ADDTO(INCLUDES, [-I$withval/rdbms/demo -I$withval/rdbms/public]) + fi + fi + fi + ]) + + AC_SUBST(apu_have_oracle) + + dnl Since we have already done the AC_CHECK_LIB tests, if we have it, + dnl we know the library is there. + if test "$apu_have_oracle" = "1"; then + APR_ADDTO(LDADD_dbd_oracle, [$oracle_LDFLAGS -lclntsh $oracle_LIBS]) + fi + AC_SUBST(LDADD_dbd_oracle) + + LIBS="$old_libs" + CPPFLAGS="$old_cppflags" + LDFLAGS="$old_ldflags" +]) + +dnl + +AC_DEFUN([APU_CHECK_DBD_ODBC], [ + apu_have_odbc=0 + + old_libs="$LIBS" + old_cppflags="$CPPFLAGS" + old_ldflags="$LDFLAGS" + + AC_ARG_WITH([odbc], APR_HELP_STRING([--with-odbc=DIR], [specify ODBC location]), + [ + if test "$withval" = "yes"; then + AC_PATH_TOOL([ODBC_CONFIG],[odbc_config]) + if test "x$ODBC_CONFIG" != 'x'; then + odbc_CPPFLAGS="-I`$ODBC_CONFIG --include-prefix`" + odbc_LDFLAGS="-L`$ODBC_CONFIG --lib-prefix`" + odbc_LIBS="`$ODBC_CONFIG --libs`" + + APR_ADDTO(CPPFLAGS, [$odbc_CPPFLAGS]) + APR_ADDTO(LDFLAGS, [$odbc_LDFLAGS]) + APR_ADDTO(LIBS, [$odbc_LIBS]) + fi + + AC_CHECK_HEADERS(sql.h, AC_CHECK_LIB(odbc, SQLAllocHandle, [apu_have_odbc=1])) + if test "$apu_have_odbc" = "0"; then + AC_CHECK_HEADERS(odbc/sql.h, AC_CHECK_LIB(odbc, SQLAllocHandle, [apu_have_odbc=1])) + fi + if test "$apu_have_odbc" != "0" && test "x$ODBC_CONFIG" != 'x'; then + APR_ADDTO(INCLUDES, [$odbc_CPPFLAGS]) + fi + elif test "$withval" = "no"; then + : + else + AC_PATH_TOOL([ODBC_CONFIG],[odbc_config],,[$withval/bin]) + if test "x$ODBC_CONFIG" != 'x'; then + odbc_CPPFLAGS="-I`$ODBC_CONFIG --include-prefix`" + odbc_LDFLAGS="-L`$ODBC_CONFIG --lib-prefix`" + odbc_LIBS="`$ODBC_CONFIG --libs`" + else + if test -f "$withval" && test -x "$withval"; then + odbc_CPPFLAGS="-I`$withval --include-prefix`" + odbc_LDFLAGS="-L`$withval --lib-prefix`" + odbc_LIBS="`$withval --libs`" + else + odbc_CPPFLAGS="-I$withval/include" + odbc_LDFLAGS="-L$withval/lib " + fi + fi + + APR_ADDTO(CPPFLAGS, [$odbc_CPPFLAGS]) + APR_ADDTO(LDFLAGS, [$odbc_LDFLAGS]) + APR_ADDTO(LIBS, [$odbc_LIBS]) + + AC_MSG_NOTICE(checking for odbc in $withval) + AC_CHECK_HEADERS(sql.h, AC_CHECK_LIB(odbc, SQLAllocHandle, [apu_have_odbc=1])) + if test "$apu_have_odbc" = "0"; then + AC_CHECK_HEADERS(odbc/sql.h, AC_CHECK_LIB(odbc, SQLAllocHandle, [apu_have_odbc=1])) + fi + if test "$apu_have_odbc" != "0" && test "x$ODBC_CONFIG" != 'x'; then + APR_ADDTO(INCLUDES, [$odbc_CPPFLAGS]) + fi + fi + ], [ + AC_PATH_TOOL([ODBC_CONFIG],[odbc_config]) + if test "x$ODBC_CONFIG" != 'x'; then + odbc_CPPFLAGS="-I`$ODBC_CONFIG --include-prefix`" + odbc_LDFLAGS="-L`$ODBC_CONFIG --lib-prefix`" + odbc_LIBS="`$ODBC_CONFIG --libs`" + + APR_ADDTO(CPPFLAGS, [$odbc_CPPFLAGS]) + APR_ADDTO(LDFLAGS, [$odbc_LDFLAGS]) + APR_ADDTO(LIBS, [$odbc_LIBS]) + fi + + AC_CHECK_HEADERS(sql.h, AC_CHECK_LIB(odbc, SQLAllocHandle, [apu_have_odbc=1])) + if test "$apu_have_odbc" = "0"; then + AC_CHECK_HEADERS(odbc/sql.h, AC_CHECK_LIB(odbc, SQLAllocHandle, [apu_have_odbc=1])) + fi + if test "$apu_have_odbc" != "0" && test "x$ODBC_CONFIG" != 'x'; then + APR_ADDTO(INCLUDES, [$odbc_CPPFLAGS]) + fi + ]) + AC_SUBST(apu_have_odbc) + dnl Since we have already done the AC_CHECK_LIB tests, if we have it, + dnl we know the library is there. + if test "$apu_have_odbc" = "1"; then + APR_ADDTO(LDADD_dbd_odbc, [$odbc_LDFLAGS -lodbc $odbc_LIBS]) + fi + AC_SUBST(LDADD_dbd_odbc) + + LIBS="$old_libs" + CPPFLAGS="$old_cppflags" + LDFLAGS="$old_ldflags" + + apu_dbd_tests="" + test $apu_have_oracle = 1 && apu_dbd_tests="$apu_dbd_tests oracle" + test $apu_have_pgsql = 1 && apu_dbd_tests="$apu_dbd_tests pgsql" + test $apu_have_mysql = 1 && apu_dbd_tests="$apu_dbd_tests mysql" + test $apu_have_sqlite2 = 1 && apu_dbd_tests="$apu_dbd_tests sqlite2" + test $apu_have_sqlite3 = 1 && apu_dbd_tests="$apu_dbd_tests sqlite3" + test $apu_have_odbc = 1 && apu_dbd_tests="$apu_dbd_tests odbc" + AC_SUBST(apu_dbd_tests) +]) diff --git a/build/dbm.m4 b/build/dbm.m4 new file mode 100644 index 00000000000..bbe9c863a60 --- /dev/null +++ b/build/dbm.m4 @@ -0,0 +1,745 @@ +dnl -------------------------------------------------------- -*- autoconf -*- +dnl Licensed to the Apache Software Foundation (ASF) under one or more +dnl contributor license agreements. See the NOTICE file distributed with +dnl this work for additional information regarding copyright ownership. +dnl The ASF licenses this file to You under the Apache License, Version 2.0 +dnl (the "License"); you may not use this file except in compliance with +dnl the License. You may obtain a copy of the License at +dnl +dnl http://www.apache.org/licenses/LICENSE-2.0 +dnl +dnl Unless required by applicable law or agreed to in writing, software +dnl distributed under the License is distributed on an "AS IS" BASIS, +dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +dnl See the License for the specific language governing permissions and +dnl limitations under the License. + + +dnl +dnl DBM module +dnl + +dnl APU_LIB_BERKELEY_DB(major, minor, patch, places, headers, libnames) +dnl +dnl Search for a useable version of Berkeley DB in a number of +dnl common places. The installed DB must be no older than the +dnl version given by MAJOR, MINOR, and PATCH. All of these +dnl arguments are allowed to be '-1', indicating we don't care. +dnl PLACES is a list of places to search for a Berkeley DB +dnl installation. HEADERS is a list of headers to try. LIBNAMES +dnl is a list of names of the library to attempt to link against, +dnl typically 'db' and 'db4'. +dnl +dnl If we find a useable version, set CPPFLAGS and LIBS as +dnl appropriate, and set the shell variable `apu_have_db' to +dnl `1', and apu_db_lib to the matching lib name, and apu_db_header +dnl to the header to use. Otherwise, set `apu_have_db' to `0'. +dnl +dnl This macro also checks for the `--with-berkeley-db=PATH' flag; +dnl if given, the macro will use the PATH specified, and the +dnl configuration script will die if it can't find the library. If +dnl the user gives the `--without-berkeley-db' flag, the entire +dnl search is skipped. +dnl +dnl We cache the results of individual searches under particular +dnl prefixes, not the overall result of whether we found Berkeley +dnl DB. That way, the user can re-run the configure script with +dnl different --with-berkeley-db switch values, without interference +dnl from the cache. + + +AC_DEFUN([APU_CHECK_BERKELEY_DB], [ + bdb_version=$1 + if test "$2" != "-1"; then + bdb_version="$bdb_version.$2" + if test "$3" != "-1"; then + bdb_version="$bdb_version.$3" + fi + fi + bdb_places=$4 + bdb_default_search_headers=$5 + bdb_default_search_lib_names=$6 + + apu_have_db=0 + + # Save the original values of the flags we tweak. + apu_check_lib_save_libs="$LIBS" + apu_check_lib_save_ldflags="$LDFLAGS" + apu_check_lib_save_cppflags="$CPPFLAGS" + + # The variable `found' is the prefix under which we've found + # Berkeley DB, or `not' if we haven't found it anywhere yet. + found=not + for bdb_place in $bdb_places; do + + LDFLAGS="$apu_check_lib_save_ldflags" + CPPFLAGS="$apu_check_lib_save_cppflags" + case "$bdb_place" in + "std" ) + description="the standard places" + ;; + *":"* ) + header="`echo $bdb_place | sed -e 's/:.*$//'`" + lib="`echo $bdb_place | sed -e 's/^.*://'`" + CPPFLAGS="$CPPFLAGS -I$header" + LDFLAGS="$LDFLAGS -L$lib" + description="$header and $lib" + ;; + * ) + if test -d $bdb_place; then + LDFLAGS="$LDFLAGS -L$bdb_place/lib" + CPPFLAGS="$CPPFLAGS -I$bdb_place/include" + else + AC_MSG_CHECKING([for Berkeley DB $bdb_version in $bdb_place]) + AC_MSG_RESULT([directory not found]) + continue + fi + description="$bdb_place" + ;; + esac + + # Since there is no AC_MSG_NOTICE in autoconf 2.13, we use this + # trick to display a message instead. + AC_MSG_CHECKING([for Berkeley DB $bdb_version in $description]) + AC_MSG_RESULT() + + for bdb_libname in $bdb_default_search_lib_names; do + for bdb_header in $bdb_default_search_headers; do + # Clear the header cache variable for each location + changequote(,) + cache_id="`echo ac_cv_header_${bdb_header} \ + | sed -e 's/[^a-zA-Z0-9_]/_/g'`" + changequote([,]) + unset $cache_id + AC_CHECK_HEADER([$bdb_header], [ + if test "$1" = "3" -o "$1" = "4" -o "$1" = "5" -o "$1" = "6"; then + # We generate a separate cache variable for each prefix and libname + # we search under. That way, we avoid caching information that + # changes if the user runs `configure' with a different set of + # switches. + changequote(,) + cache_id="`echo apu_cv_check_berkeley_db_$1_$2_$3_${bdb_header}_${bdb_libname}_in_${bdb_place} \ + | sed -e 's/[^a-zA-Z0-9_]/_/g'`" + changequote([,]) + + AC_MSG_CHECKING([for -l$bdb_libname]) + dnl We can't use AC_CACHE_CHECK here, because that won't print out + dnl the value of the computed cache variable properly. + AC_CACHE_VAL($cache_id, + [ + APU_TRY_BERKELEY_DB($1, $2, $3, $bdb_header, $bdb_libname) + eval "$cache_id=$apu_try_berkeley_db" + ]) + result="`eval echo '$'$cache_id`" + AC_MSG_RESULT($result) + elif test "$1" = "1"; then + AC_CHECK_LIB($bdb_libname, + dbopen, + [result=yes], + [result=no] + ) + elif test "$1" = "2"; then + AC_CHECK_LIB($bdb_libname, + db_open, + [result=yes], + [result=no] + ) + fi + ], [result="no"]) + + # If we found it, no need to search any more. + if test "$result" = "yes"; then + found="$bdb_place" + break + fi + done + test "$found" != "not" && break + done + test "$found" != "not" && break + done + + # Restore the original values of the flags we tweak. + LDFLAGS="$apu_check_lib_save_ldflags" + CPPFLAGS="$apu_check_lib_save_cppflags" + + case "$found" in + "not") + apu_have_db=0 + ;; + "std") + apu_db_header=$bdb_header + apu_db_lib=$bdb_libname + apu_have_db=1 + ;; + *":"*) + header="`echo $found | sed -e 's/:.*$//'`" + lib="`echo $found | sed -e 's/^.*://'`" + + APR_ADDTO(INCLUDES, [-I$header]) + APR_ADDTO(LDFLAGS, [-L$lib]) + apu_db_header=$bdb_header + apu_db_lib=$bdb_libname + apu_have_db=1 + ;; + *) + APR_ADDTO(INCLUDES, [-I$found/include]) + APR_ADDTO(LDFLAGS, [-L$found/lib]) + apu_db_header=$bdb_header + apu_db_lib=$bdb_libname + apu_have_db=1 + ;; + esac +]) + + +dnl APU_TRY_BERKELEY_DB(major, minor, patch, header, libname) +dnl +dnl A subroutine of APU_CHECK_BERKELEY_DB. +dnl +dnl Check that a new-enough version of Berkeley DB is installed. +dnl "New enough" means no older than the version given by MAJOR, +dnl MINOR, and PATCH. The result of the test is not cached; no +dnl messages are printed. Use HEADER as the header file to include. +dnl Use LIBNAME as the library to link against. +dnl (e.g. LIBNAME should usually be "db" or "db4".) +dnl +dnl Set the shell variable `apu_try_berkeley_db' to `yes' if we found +dnl an appropriate version installed, or `no' otherwise. +dnl +dnl This macro uses the Berkeley DB library function `db_version' to +dnl find the version. If the library installed doesn't have this +dnl function, then this macro assumes it is too old. + +dnl NOTE: This is pretty messed up. It seems that the FreeBSD port of +dnl Berkeley DB 4 puts the header file in /usr/local/include/db4, but the +dnl database library in /usr/local/lib, as libdb4.[a|so]. There is no +dnl /usr/local/include/db.h. So if you check for /usr/local first, you'll +dnl get the old header file from /usr/include, and the new library from +dnl /usr/local/lib. Disaster. Thus this test compares the version constants +dnl in the db.h header with the ones returned by db_version(). + + +AC_DEFUN([APU_TRY_BERKELEY_DB], + [ + apu_try_berkeley_db_save_libs="$LIBS" + + apu_check_berkeley_db_major=$1 + apu_check_berkeley_db_minor=$2 + apu_check_berkeley_db_patch=$3 + apu_try_berkeley_db_header=$4 + apu_try_berkeley_db_libname=$5 + + LIBS="$LIBS -l$apu_try_berkeley_db_libname" + AC_TRY_RUN( + [ +#include <stdlib.h> +#include <stdio.h> +#include <$apu_try_berkeley_db_header> +main () +{ + int major, minor, patch; + + db_version(&major, &minor, &patch); + + /* Sanity check: ensure that db.h constants actually match the db library */ + if (major != DB_VERSION_MAJOR + || minor != DB_VERSION_MINOR + || patch != DB_VERSION_PATCH) + exit (1); + + /* Run-time check: ensure the library claims to be the correct version. */ + + if ($apu_check_berkeley_db_major != -1) { + if (major < $apu_check_berkeley_db_major) + exit (1); + if (major > $apu_check_berkeley_db_major) + exit (0); + } + + if ($apu_check_berkeley_db_minor != -1) { + if (minor < $apu_check_berkeley_db_minor) + exit (1); + if (minor > $apu_check_berkeley_db_minor) + exit (0); + } + + if ($apu_check_berkeley_db_patch == -1 + || patch >= $apu_check_berkeley_db_patch) + exit (0); + else + exit (1); +} + ], + [apu_try_berkeley_db=yes], + [apu_try_berkeley_db=no], + [apu_try_berkeley_db=yes] + ) + + LIBS="$apu_try_berkeley_db_save_libs" + ] +) + + +dnl +dnl APU_CHECK_DB1: is DB1 present? +dnl +dnl if present: sets apu_db_header, apu_db_lib, and apu_db_version +dnl +AC_DEFUN([APU_CHECK_DB1], [ + places=$1 + if test -z "$places"; then + places="std" + fi + APU_CHECK_BERKELEY_DB(1, 0, 0, + "$places", + "db1/db.h db.h", + "db1" + ) + if test "$apu_have_db" = "1"; then + apu_db_version=1 + fi +]) + + +dnl +dnl APU_CHECK_DB185: is DB1.85 present? +dnl +dnl if present: sets apu_db_header, apu_db_lib, and apu_db_version +dnl +dnl NB: BerkelyDB v2 and above can be compiled in 1.85 mode +dnl which has a libdb not libdb1 or libdb185 +AC_DEFUN([APU_CHECK_DB185], [ + places=$1 + if test -z "$places"; then + places="std" + fi + APU_CHECK_BERKELEY_DB(1, -1, -1, + "$places", + "db_185.h", + "db" + ) + if test "$apu_have_db" = "1"; then + apu_db_version=185 + fi +]) + + +dnl +dnl APU_CHECK_DB2: is DB2 present? +dnl +dnl if present: sets apu_db_header, apu_db_lib, and apu_db_version +dnl +AC_DEFUN([APU_CHECK_DB2], [ + places=$1 + if test -z "$places"; then + places="std" + fi + APU_CHECK_BERKELEY_DB(2, -1, -1, + "$places", + "db2/db.h db.h", + "db2 db" + ) + if test "$apu_have_db" = "1"; then + apu_db_version=2 + fi +]) + + +dnl +dnl APU_CHECK_DB3: is DB3 present? +dnl +dnl if present: sets apu_db_header, apu_db_lib, and apu_db_version +dnl +AC_DEFUN([APU_CHECK_DB3], [ + places=$1 + if test -z "$places"; then + places="std" + fi + APU_CHECK_BERKELEY_DB(3, -1, -1, + "$places", + "db3/db.h db.h", + "db3 db" + ) + if test "$apu_have_db" = "1"; then + apu_db_version=3 + fi +]) + + +dnl +dnl APU_CHECK_DBXY: is DBX.Y present? +dnl +dnl if present: sets apu_db_header, apu_db_lib, and apu_db_version +dnl +AC_DEFUN([APU_CHECK_DBXY], [ + places=$1 + db_major=$2 + db_minor=$3 + if test -z "$places"; then + places="std /usr/local /usr/local/BerkeleyDB.${db_major}.${db_minor} /boot/home/config" + fi + APU_CHECK_BERKELEY_DB("${db_major}", "${db_minor}", "-1", + "$places", + "db${db_major}${db_minor}/db.h db${db_major}/db.h db.h", + "db-${db_major}.${db_minor} db${db_major}-${db_major}.${db_minor} db${db_major}${db_minor} db-${db_major} db${db_major} db" + ) + if test "$apu_have_db" = "1"; then + apu_db_version=${db_major} + fi +]) + + +AC_DEFUN([APU_CHECK_DB], [ + requested=$1 + check_places=$2 + + case "$requested" in + db) + APU_CHECK_DB_ALL("$check_places") + if test "$apu_have_db" = "0"; then + AC_MSG_ERROR(Berkeley db requested, but not found) + fi + ;; + db1) + APU_CHECK_DB1("$check_places") + if test "$apu_db_version" != "1"; then + AC_MSG_ERROR(Berkeley db1 not found) + fi + ;; + db185) + APU_CHECK_DB185("$check_places") + if test "$apu_db_version" != "185"; then + AC_MSG_ERROR(Berkeley db185 not found) + fi + ;; + db2) + APU_CHECK_DB2("$check_places") + if test "$apu_db_version" != "2"; then + AC_MSG_ERROR(Berkeley db2 not found) + fi + ;; + db3) + APU_CHECK_DB3("$check_places") + if test "$apu_db_version" != "3"; then + AC_MSG_ERROR(Berkeley db3 not found) + fi + ;; + db[[456]][[0-9]]) + db_major=`echo "$requested" | sed -e 's/db//' -e 's/.$//'` + db_minor=`echo "$requested" | sed -e 's/db//' -e 's/.//'` + APU_CHECK_DBXY("$check_places", "$db_major", "$db_minor") + if test "$apu_db_version" != "$db_major"; then + AC_MSG_ERROR(Berkeley db$db_major not found) + fi + ;; + db[[456]]) + db_major=`echo "$requested" | sed -e 's/db//'` + # Start version search at version x.9 + db_minor=9 + while [[ $db_minor -ge 0 ]] + do + APU_CHECK_DBXY("$check_places", "$db_major", "$db_minor") + if test "$apu_have_db" = "1"; then + break + fi + db_minor=`expr $db_minor - 1` + done + if test "$apu_db_version" != "$db_major"; then + AC_MSG_ERROR(Berkeley db$db_major not found) + fi + ;; + default) + APU_CHECK_DB_ALL("$check_places") + ;; + esac +]) + +dnl +dnl APU_CHECK_DB_ALL: Try all Berkeley DB versions, from 6.X to 1. +dnl +AC_DEFUN([APU_CHECK_DB_ALL], [ + all_places=$1 + + # Start version search at version 6.9 + db_version=69 + while [[ $db_version -ge 40 ]] + do + db_major=`echo $db_version | sed -e 's/.$//'` + db_minor=`echo $db_version | sed -e 's/.//'` + APU_CHECK_DBXY("$all_places", "$db_major", "$db_minor") + if test "$apu_have_db" = "1"; then + break + fi + db_version=`expr $db_version - 1` + done + if test "$apu_have_db" = "0"; then + APU_CHECK_DB3("$all_places") + fi + if test "$apu_have_db" = "0"; then + APU_CHECK_DB2("$all_places") + fi + if test "$apu_have_db" = "0"; then + APU_CHECK_DB1("$all_places") + fi + if test "$apu_have_db" = "0"; then + APU_CHECK_DB185("$all_places") + fi + AC_MSG_CHECKING(for Berkeley DB) + if test "$apu_have_db" = "1"; then + AC_MSG_RESULT(found db$apu_db_version) + else + AC_MSG_RESULT(not found) + fi +]) + + +dnl +dnl APU_CHECK_DBM: see what kind of DBM backend to use for apr_dbm. +dnl +AC_DEFUN([APU_CHECK_DBM], [ + apu_use_sdbm=0 + apu_use_ndbm=0 + apu_use_gdbm=0 + apu_use_db=0 + dnl it's in our codebase + apu_have_sdbm=1 + apu_have_gdbm=0 + apu_have_ndbm=0 + apu_have_db=0 + + apu_db_header=db.h # default so apu_select_dbm.h is syntactically correct + apu_db_version=0 + + # Maximum supported version announced in help string. + # Although we search for all versions up to 6.9, + # we should only include existing versions in our + # help string. + dbm_list="sdbm, gdbm, ndbm, db, db1, db185, db2, db3, db4" + db_max_version=48 + db_min_version=41 + db_version="$db_min_version" + while [[ $db_version -le $db_max_version ]] + do + dbm_list="$dbm_list, db$db_version" + db_version=`expr $db_version + 1` + done + db_max_version=53 + db_min_version=50 + db_version="$db_min_version" + while [[ $db_version -le $db_max_version ]] + do + dbm_list="$dbm_list, db$db_version" + db_version=`expr $db_version + 1` + done + db_max_version=60 + db_min_version=60 + db_version="$db_min_version" + while [[ $db_version -le $db_max_version ]] + do + dbm_list="$dbm_list, db$db_version" + db_version=`expr $db_version + 1` + done + + AC_ARG_WITH(dbm, [APR_HELP_STRING([--with-dbm=DBM], [choose the DBM type to use. + DBM={sdbm,gdbm,ndbm,db,db1,db185,db2,db3,db4,db4X,db5X,db6X} for some X=0,...,9])], + [ + if test "$withval" = "yes"; then + AC_MSG_ERROR([--with-dbm needs to specify a DBM type to use. + One of: $dbm_list]) + fi + requested="$withval" + ], [ + requested=default + ]) + + dnl We don't pull in GDBM unless the user asks for it, since it's GPL + AC_ARG_WITH([gdbm], [APR_HELP_STRING([--with-gdbm=DIR], [enable GDBM support])], + [ + apu_have_gdbm=0 + if test "$withval" = "yes"; then + AC_CHECK_HEADER(gdbm.h, AC_CHECK_LIB(gdbm, gdbm_open, [apu_have_gdbm=1])) + elif test "$withval" = "no"; then + apu_have_gdbm=0 + else + saved_cppflags="$CPPFLAGS" + saved_ldflags="$LDFLAGS" + CPPFLAGS="$CPPFLAGS -I$withval/include" + LDFLAGS="$LDFLAGS -L$withval/lib " + + AC_MSG_CHECKING(checking for gdbm in $withval) + AC_CHECK_HEADER(gdbm.h, AC_CHECK_LIB(gdbm, gdbm_open, [apu_have_gdbm=1])) + if test "$apu_have_gdbm" != "0"; then + APR_ADDTO(LDFLAGS, [-L$withval/lib]) + APR_ADDTO(INCLUDES, [-I$withval/include]) + fi + CPPFLAGS="$saved_cppflags" + LDFLAGS="$saved_ldflags" + fi + ]) + + AC_ARG_WITH([ndbm], [APR_HELP_STRING([--with-ndbm=PATH], [ + Find the NDBM header and library in `PATH/include' and + `PATH/lib'. If PATH is of the form `HEADER:LIB', then search + for header files in HEADER, and the library in LIB. If you omit + the `=PATH' part completely, the configure script will search + for NDBM in a number of standard places.])], + [ + apu_have_ndbm=0 + if test "$withval" = "yes"; then + AC_MSG_CHECKING(checking for ndbm in the usual places) + apu_want_ndbm=1 + NDBM_INC="" + NDBM_LDFLAGS="" + elif test "$withval" = "no"; then + apu_want_ndbm=0 + else + apu_want_ndbm=1 + case "$withval" in + *":"*) + NDBM_INC="-I`echo $withval |sed -e 's/:.*$//'`" + NDBM_LDFLAGS="-L`echo $withval |sed -e 's/^.*://'`" + AC_MSG_CHECKING(checking for ndbm includes with $NDBM_INC libs with $NDBM_LDFLAGS ) + ;; + *) + NDBM_INC="-I$withval/include" + NDBM_LDFLAGS="-L$withval/lib" + AC_MSG_CHECKING(checking for ndbm includes in $withval) + ;; + esac + fi + + save_cppflags="$CPPFLAGS" + save_ldflags="$LDFLAGS" + CPPFLAGS="$CPPFLAGS $NDBM_INC" + LDFLAGS="$LDFLAGS $NDBM_LDFLAGS" + dnl db_ndbm_open is what sleepcat's compatibility library actually has in it's lib + if test "$apu_want_ndbm" != "0"; then + AC_CHECK_HEADER(ndbm.h, + AC_CHECK_LIB(c, dbm_open, [apu_have_ndbm=1;apu_ndbm_lib=c], + AC_CHECK_LIB(dbm, dbm_open, [apu_have_ndbm=1;apu_ndbm_lib=dbm], + AC_CHECK_LIB(db, dbm_open, [apu_have_ndbm=1;apu_ndbm_lib=db], + AC_CHECK_LIB(db, __db_ndbm_open, [apu_have_ndbm=1;apu_ndbm_lib=db]) + ) + ) + ) + ) + if test "$apu_have_ndbm" != "0"; then + if test "$withval" != "yes"; then + APR_ADDTO(INCLUDES, [$NDBM_INC]) + APR_ADDTO(LDFLAGS, [$NDBM_LDFLAGS]) + fi + elif test "$withval" != "yes"; then + AC_ERROR( NDBM not found in the specified directory) + fi + fi + CPPFLAGS="$save_cppflags" + LDFLAGS="$save_ldflags" + ], [ + dnl don't check it no one has asked us for it + apu_have_ndbm=0 + ]) + + + if test -n "$apu_db_xtra_libs"; then + saveddbxtralibs="$LIBS" + LIBS="$apu_db_xtra_libs $LIBS" + fi + + dnl We're going to try to find the highest version of Berkeley DB supported. + dnl + dnl Note that we only do this if the user requested it, since the Sleepycat + dnl license is viral and requires distribution of source along with programs + dnl that use it. + AC_ARG_WITH([berkeley-db], [APR_HELP_STRING([--with-berkeley-db=PATH], + [Find the Berkeley DB header and library in `PATH/include' and + `PATH/lib'. If PATH is of the form `HEADER:LIB', then search + for header files in HEADER, and the library in LIB. If you omit + the `=PATH' part completely, the configure script will search + for Berkeley DB in a number of standard places.])], + [ + if test "$withval" = "yes"; then + apu_want_db=1 + user_places="" + elif test "$withval" = "no"; then + apu_want_db=0 + else + apu_want_db=1 + user_places="$withval" + fi + + if test "$apu_want_db" != "0"; then + APU_CHECK_DB($requested, $user_places) + if test "$apu_have_db" = "0"; then + AC_ERROR(Berkeley DB not found.) + fi + fi + ]) + + if test -n "$apu_db_xtra_libs"; then + LIBS="$saveddbxtralibs" + fi + + case "$requested" in + sdbm | gdbm | ndbm | db) + eval "apu_use_$requested=1" + apu_default_dbm=$requested + ;; + db185 | db[[123456]]) + apu_use_db=1 + apu_default_dbm=$requested + ;; + db[[456]][[0-9]]) + apu_use_db=1 + apu_default_dbm=`echo $requested | sed -e 's/.$//'` + ;; + default) + dnl ### use more sophisticated DBMs for the default? + apu_default_dbm="sdbm (default)" + apu_use_sdbm=1 + ;; + *) + AC_MSG_ERROR([--with-dbm=$requested is an unknown DBM type. + Use one of: $dbm_list]) + ;; + esac + + dnl Yes, it'd be nice if we could collate the output in an order + dnl so that the AC_MSG_CHECKING would be output before the actual + dnl checks, but it isn't happening now. + AC_MSG_CHECKING(for default DBM) + AC_MSG_RESULT($apu_default_dbm) + + AC_SUBST(apu_use_sdbm) + AC_SUBST(apu_use_gdbm) + AC_SUBST(apu_use_ndbm) + AC_SUBST(apu_use_db) + + AC_SUBST(apu_have_sdbm) + AC_SUBST(apu_have_gdbm) + AC_SUBST(apu_have_ndbm) + AC_SUBST(apu_have_db) + AC_SUBST(apu_db_header) + AC_SUBST(apu_db_version) + + if test "$apu_have_db" = "1"; then + APR_ADDTO(LDADD_dbm_db, [-l$apu_db_lib]) + if test -n "apu_db_xtra_libs"; then + APR_ADDTO(LDADD_dbm_db, [$apu_db_xtra_libs]) + fi + fi + + dnl Since we have already done the AC_CHECK_LIB tests, if we have it, + dnl we know the library is there. + if test "$apu_have_gdbm" = "1"; then + APR_ADDTO(LDADD_dbm_gdbm, [-lgdbm]) + fi + + if test "$apu_have_ndbm" = "1"; then + APR_ADDTO(LDADD_dbm_ndbm, [-l$apu_ndbm_lib]) + fi + + AC_SUBST(LDADD_dbm_db) + AC_SUBST(LDADD_dbm_gdbm) + AC_SUBST(LDADD_dbm_ndbm) +]) + diff --git a/build/dso.m4 b/build/dso.m4 new file mode 100644 index 00000000000..26dd4128119 --- /dev/null +++ b/build/dso.m4 @@ -0,0 +1,98 @@ +dnl -------------------------------------------------------- -*- autoconf -*- +dnl Licensed to the Apache Software Foundation (ASF) under one or more +dnl contributor license agreements. See the NOTICE file distributed with +dnl this work for additional information regarding copyright ownership. +dnl The ASF licenses this file to You under the Apache License, Version 2.0 +dnl (the "License"); you may not use this file except in compliance with +dnl the License. You may obtain a copy of the License at +dnl +dnl http://www.apache.org/licenses/LICENSE-2.0 +dnl +dnl Unless required by applicable law or agreed to in writing, software +dnl distributed under the License is distributed on an "AS IS" BASIS, +dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +dnl See the License for the specific language governing permissions and +dnl limitations under the License. + +dnl +dnl DSO module +dnl + +AC_DEFUN([APR_MODULAR_DSO], [ + + AC_ARG_ENABLE([modular-dso], + APR_HELP_STRING([--disable-modular-dso], + [disable DSO build of modular components])) + + if test "$enable_modular_dso" = "no"; then + apr_modular_dso="0" + else + apr_modular_dso=$aprdso + fi + + if test "$apr_modular_dso" = "0"; then + + # Statically link the drivers: + objs= + test $apu_have_openssl = 1 && objs="$objs crypto/apr_crypto_openssl.lo" + test $apu_have_nss = 1 && objs="$objs crypto/apr_crypto_nss.lo" + test $apu_have_commoncrypto = 1 && objs="$objs crypto/apr_crypto_commoncrypto.lo" + test $apu_have_oracle = 1 && objs="$objs dbd/apr_dbd_oracle.lo" + test $apu_have_pgsql = 1 && objs="$objs dbd/apr_dbd_pgsql.lo" + test $apu_have_mysql = 1 && objs="$objs dbd/apr_dbd_mysql.lo" + test $apu_have_sqlite2 = 1 && objs="$objs dbd/apr_dbd_sqlite2.lo" + test $apu_have_sqlite3 = 1 && objs="$objs dbd/apr_dbd_sqlite3.lo" + test $apu_have_odbc = 1 && objs="$objs dbd/apr_dbd_odbc.lo" + test $apu_have_db = 1 && objs="$objs dbm/apr_dbm_berkeleydb.lo" + test $apu_have_gdbm = 1 && objs="$objs dbm/apr_dbm_gdbm.lo" + test $apu_have_ndbm = 1 && objs="$objs dbm/apr_dbm_ndbm.lo" + EXTRA_OBJECTS="$EXTRA_OBJECTS $objs" + + # Use libtool *.la for mysql if available + if test $apu_have_mysql = 1; then + for flag in $LDADD_dbd_mysql + do + dir=`echo $flag | grep "^-L" | sed s:-L::` + if test "x$dir" != 'x'; then + if test -f "$dir/libmysqlclient_r.la"; then + LDADD_dbd_mysql=$dir/libmysqlclient_r.la + break + fi + fi + done + fi + + LIBS="$LIBS $LDADD_crypto_openssl $LDADD_crypto_nss $LDADD_crypto_commoncrypto" + LIBS="$LIBS $LDADD_dbd_pgsql $LDADD_dbd_sqlite2 $LDADD_dbd_sqlite3 $LDADD_dbd_oracle $LDADD_dbd_mysql $LDADD_dbd_odbc" + LIBS="$LIBS $LDADD_dbm_db $LDADD_dbm_gdbm $LDADD_dbm_ndbm" + APRUTIL_EXPORT_LIBS="$APRUTIL_EXPORT_LIBS $LDADD_crypto_openssl $LDADD_crypto_nss $LDADD_crypto_commoncrypto" + APRUTIL_EXPORT_LIBS="$APRUTIL_EXPORT_LIBS $LDADD_dbd_pgsql $LDADD_dbd_sqlite2 $LDADD_dbd_sqlite3 $LDADD_dbd_oracle $LDADD_dbd_mysql $LDADD_dbd_odbc" + APRUTIL_EXPORT_LIBS="$APRUTIL_EXPORT_LIBS $LDADD_dbm_db $LDADD_dbm_gdbm $LDADD_dbm_ndbm" + + else + + # Build the drivers as loadable modules: + dsos= + test $apu_have_openssl = 1 && dsos="$dsos crypto/apr_crypto_openssl.la" + test $apu_have_nss = 1 && dsos="$dsos crypto/apr_crypto_nss.la" + test $apu_have_commoncrypto = 1 && dsos="$dsos crypto/apr_crypto_commoncrypto.la" + test $apu_have_oracle = 1 && dsos="$dsos dbd/apr_dbd_oracle.la" + test $apu_have_pgsql = 1 && dsos="$dsos dbd/apr_dbd_pgsql.la" + test $apu_have_mysql = 1 && dsos="$dsos dbd/apr_dbd_mysql.la" + test $apu_have_sqlite2 = 1 && dsos="$dsos dbd/apr_dbd_sqlite2.la" + test $apu_have_sqlite3 = 1 && dsos="$dsos dbd/apr_dbd_sqlite3.la" + test $apu_have_odbc = 1 && dsos="$dsos dbd/apr_dbd_odbc.la" + test $apu_have_db = 1 && dsos="$dsos dbm/apr_dbm_db.la" + test $apu_have_gdbm = 1 && dsos="$dsos dbm/apr_dbm_gdbm.la" + test $apu_have_ndbm = 1 && dsos="$dsos dbm/apr_dbm_ndbm.la" + + if test -n "$dsos"; then + APR_DSO_MODULES="$APR_DSO_MODULES $dsos" + fi + + AC_MSG_NOTICE([Using modular DSO build]) + fi + + AC_DEFINE_UNQUOTED([APR_HAVE_MODULAR_DSO], $apr_modular_dso, + [Define to 1 if modular components are built as DSOs]) +]) diff --git a/build/find_apr.m4 b/build/find_apr.m4 new file mode 100644 index 00000000000..925e523f81d --- /dev/null +++ b/build/find_apr.m4 @@ -0,0 +1,202 @@ +dnl -------------------------------------------------------- -*- autoconf -*- +dnl Licensed to the Apache Software Foundation (ASF) under one or more +dnl contributor license agreements. See the NOTICE file distributed with +dnl this work for additional information regarding copyright ownership. +dnl The ASF licenses this file to You under the Apache License, Version 2.0 +dnl (the "License"); you may not use this file except in compliance with +dnl the License. You may obtain a copy of the License at +dnl +dnl http://www.apache.org/licenses/LICENSE-2.0 +dnl +dnl Unless required by applicable law or agreed to in writing, software +dnl distributed under the License is distributed on an "AS IS" BASIS, +dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +dnl See the License for the specific language governing permissions and +dnl limitations under the License. + +dnl +dnl find_apr.m4 : locate the APR include files and libraries +dnl +dnl This macro file can be used by applications to find and use the APR +dnl library. It provides a standardized mechanism for using APR. It supports +dnl embedding APR into the application source, or locating an installed +dnl copy of APR. +dnl +dnl APR_FIND_APR(srcdir, builddir, implicit-install-check, acceptable-majors, +dnl detailed-check) +dnl +dnl where srcdir is the location of the bundled APR source directory, or +dnl empty if source is not bundled. +dnl +dnl where builddir is the location where the bundled APR will will be built, +dnl or empty if the build will occur in the srcdir. +dnl +dnl where implicit-install-check set to 1 indicates if there is no +dnl --with-apr option specified, we will look for installed copies. +dnl +dnl where acceptable-majors is a space separated list of acceptable major +dnl version numbers. Often only a single major version will be acceptable. +dnl If multiple versions are specified, and --with-apr=PREFIX or the +dnl implicit installed search are used, then the first (leftmost) version +dnl in the list that is found will be used. Currently defaults to [0 1]. +dnl +dnl where detailed-check is an M4 macro which sets the apr_acceptable to +dnl either "yes" or "no". The macro will be invoked for each installed +dnl copy of APR found, with the apr_config variable set appropriately. +dnl Only installed copies of APR which are considered acceptable by +dnl this macro will be considered found. If no installed copies are +dnl considered acceptable by this macro, apr_found will be set to either +dnl either "no" or "reconfig". +dnl +dnl Sets the following variables on exit: +dnl +dnl apr_found : "yes", "no", "reconfig" +dnl +dnl apr_config : If the apr-config tool exists, this refers to it. If +dnl apr_found is "reconfig", then the bundled directory +dnl should be reconfigured *before* using apr_config. +dnl +dnl Note: this macro file assumes that apr-config has been installed; it +dnl is normally considered a required part of an APR installation. +dnl +dnl If a bundled source directory is available and needs to be (re)configured, +dnl then apr_found is set to "reconfig". The caller should reconfigure the +dnl (passed-in) source directory, placing the result in the build directory, +dnl as appropriate. +dnl +dnl If apr_found is "yes" or "reconfig", then the caller should use the +dnl value of apr_config to fetch any necessary build/link information. +dnl + +AC_DEFUN([APR_FIND_APR], [ + apr_found="no" + + if test "$target_os" = "os2-emx"; then + # Scripts don't pass test -x on OS/2 + TEST_X="test -f" + else + TEST_X="test -x" + fi + + ifelse([$4], [], [ + ifdef(AC_WARNING,AC_WARNING([$0: missing argument 4 (acceptable-majors): Defaulting to APR 0.x then APR 1.x])) + acceptable_majors="0 1"], + [acceptable_majors="$4"]) + + apr_temp_acceptable_apr_config="" + for apr_temp_major in $acceptable_majors + do + case $apr_temp_major in + 0) + apr_temp_acceptable_apr_config="$apr_temp_acceptable_apr_config apr-config" + ;; + *) + apr_temp_acceptable_apr_config="$apr_temp_acceptable_apr_config apr-$apr_temp_major-config" + ;; + esac + done + + AC_MSG_CHECKING(for APR) + AC_ARG_WITH(apr, + [ --with-apr=PATH prefix for installed APR or the full path to + apr-config], + [ + if test "$withval" = "no" || test "$withval" = "yes"; then + AC_MSG_ERROR([--with-apr requires a directory or file to be provided]) + fi + + for apr_temp_apr_config_file in $apr_temp_acceptable_apr_config + do + for lookdir in "$withval/bin" "$withval" + do + if $TEST_X "$lookdir/$apr_temp_apr_config_file"; then + apr_config="$lookdir/$apr_temp_apr_config_file" + ifelse([$5], [], [], [ + apr_acceptable="yes" + $5 + if test "$apr_acceptable" != "yes"; then + AC_MSG_WARN([Found APR in $apr_config, but we think it is considered unacceptable]) + continue + fi]) + apr_found="yes" + break 2 + fi + done + done + + if test "$apr_found" != "yes" && $TEST_X "$withval" && $withval --help > /dev/null 2>&1 ; then + apr_config="$withval" + ifelse([$5], [], [apr_found="yes"], [ + apr_acceptable="yes" + $5 + if test "$apr_acceptable" = "yes"; then + apr_found="yes" + fi]) + fi + + dnl if --with-apr is used, it is a fatal error for its argument + dnl to be invalid + if test "$apr_found" != "yes"; then + AC_MSG_ERROR([the --with-apr parameter is incorrect. It must specify an install prefix, a build directory, or an apr-config file.]) + fi + ],[ + dnl If we allow installed copies, check those before using bundled copy. + if test -n "$3" && test "$3" = "1"; then + for apr_temp_apr_config_file in $apr_temp_acceptable_apr_config + do + if $apr_temp_apr_config_file --help > /dev/null 2>&1 ; then + apr_config="$apr_temp_apr_config_file" + ifelse([$5], [], [], [ + apr_acceptable="yes" + $5 + if test "$apr_acceptable" != "yes"; then + AC_MSG_WARN([skipped APR at $apr_config, version not acceptable]) + continue + fi]) + apr_found="yes" + break + else + dnl look in some standard places + for lookdir in /usr /usr/local /usr/local/apr /opt/apr; do + if $TEST_X "$lookdir/bin/$apr_temp_apr_config_file"; then + apr_config="$lookdir/bin/$apr_temp_apr_config_file" + ifelse([$5], [], [], [ + apr_acceptable="yes" + $5 + if test "$apr_acceptable" != "yes"; then + AC_MSG_WARN([skipped APR at $apr_config, version not acceptable]) + continue + fi]) + apr_found="yes" + break 2 + fi + done + fi + done + fi + dnl if we have not found anything yet and have bundled source, use that + if test "$apr_found" = "no" && test -d "$1"; then + apr_temp_abs_srcdir="`cd \"$1\" && pwd`" + apr_found="reconfig" + apr_bundled_major="`sed -n '/#define.*APR_MAJOR_VERSION/s/^[^0-9]*\([0-9]*\).*$/\1/p' \"$1/include/apr_version.h\"`" + case $apr_bundled_major in + "") + AC_MSG_ERROR([failed to find major version of bundled APR]) + ;; + 0) + apr_temp_apr_config_file="apr-config" + ;; + *) + apr_temp_apr_config_file="apr-$apr_bundled_major-config" + ;; + esac + if test -n "$2"; then + apr_config="$2/$apr_temp_apr_config_file" + else + apr_config="$1/$apr_temp_apr_config_file" + fi + fi + ]) + + AC_MSG_RESULT($apr_found) +]) diff --git a/build/fixwin32mak.pl b/build/fixwin32mak.pl new file mode 100644 index 00000000000..6f53987ecf8 --- /dev/null +++ b/build/fixwin32mak.pl @@ -0,0 +1,167 @@ +# +# fixwin32mak.pl ::: Apache/Win32 maintanace program +# +# This program, launched from the build/ directory, replaces all nasty absoulute paths +# in the win32 .mak files with the appropriate relative root. +# +# Run this program prior to committing or packaging any newly exported make files. + +use Cwd; +use IO::File; +use File::Find; + +$root = cwd; +# ignore our own direcory (allowing us to move into any parallel tree) +$root =~ s|^.:(.*)?$|cd "$1|; +$root =~ s|/|\\\\|g; +$altroot = $root; +$altroot =~ s| ".:| "|; +print "Stripping " . $root . " and " . $altroot . "\n"; +find(\&fixcwd, '.'); + +# Given this pattern that disregarded the RECURSE flag... +# +# !IF "$(RECURSE)" == "0" +# +# ALL : "$(OUTDIR)\mod_charset_lite.so" +# +# !ELSE +# +# ALL : "libhttpd - Win32 Release" "libaprutil - Win32 Release" "libapr - Win32 Release" "$(OUTDIR)\mod_charset_lite.so" +# +# !ENDIF +#... +# DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep +#... +# ALL : $(DS_POSTBUILD_DEP) +# +# $(DS_POSTBUILD_DEP) : "libhttpd - Win32 Release" "libaprutil - Win32 Release" "libapr - Win32 Release" "$(OUTDIR)\mod_charset_lite.so" +# +# we will axe the final ALL : clause, +# strip all but the final element from $(DS_POSTBUILD_DEP) : clause +# move the DS_POSTBUILD_DEP assignment above the IF (for true ALL : targets) +# and in pass 2, append the $(DS_POSTBUILD_DEP) to the valid ALL : targets + + +sub fixcwd { + if (m|.mak$|) { + $thisroot = $File::Find::dir; + $thisroot =~ s|^./(.*)$|$1|; + $thisroot =~ s|/|\\\\|g; + $thisroot = $root . "\\\\" . $thisroot; + $thisaltroot = $altroot . "\\\\" . $thisroot; + $oname = $_; + $tname = '.#' . $_; + $verchg = 0; + $postdep = 0; + $srcfl = new IO::File $_, "r" || die; + $dstfl = new IO::File $tname, "w" || die; + while ($src = <$srcfl>) { + if ($src =~ m|^DS_POSTBUILD_DEP=.+$|) { + $postdepval = $src; + } + if ($src =~ s|^ALL : \$\(DS_POSTBUILD_DEP\)||) { + $postdep = -1; + $verchg = -1; + $src = <$srcfl>; + $src = <$srcfl> if ($src =~ m|^$|); + } + if ($postdep) { + $src =~ s|^(\$\(DS_POSTBUILD_DEP\)) :.+(\"[^\"]+\")$|"$1" : $2|; + } + if ($src =~ m|^\s*($root[^\"]*)\".*$|) { + $orig = $thisroot; + } elsif ($src =~ m|^\s*($altroot[^\"]*)\".*$|) { + $orig = $thisaltroot; + } + if (defined($orig)) { + $repl = "cd \"."; + while (!($src =~ s|$orig|$repl|)) { + if (!($orig =~ s|^(.*)\\\\[^\\]+$|$1|)) { + break; + } + $repl .= "\\.."; + } + print "Replaced " . $orig . " with " . $repl . "\n"; + $verchg = -1; + undef $orig; + } + # With modern LINK.EXE linkers, there is a different LINK for + # each platform, and it's determined by the file path. Best + # that here, after we compiled the code to the default CPU, + # that we also link here to the default CPU. Omitting the + # /machine spec from the .dsp was not enough, MSVC put it back. + # + if ($src =~ s#^(LINK32_FLAGS=.*) /machine:(x|IX|I3)86 #$1 #i) { + $verchg = -1; + } + print $dstfl $src; + } + undef $srcfl; + undef $dstfl; + if ($verchg) { + if ($postdep) { + $srcfl = new IO::File $tname, "r" || die; + $dstfl = new IO::File $oname, "w" || die; + while ($src = <$srcfl>) { + if ($src =~ m|^INTDIR=|) { + print $dstfl $src; + $src = $postdepval; + } + $src =~ s|^(ALL : .+)$|$1 "\$\(DS_POSTBUILD_DEP\)"|; + print $dstfl $src; + } + undef $srcfl; + undef $dstfl; + unlink $tname || die; + print "Corrected post-dependency within " . $oname . " in " . $File::Find::dir . "\n"; + } + else { + unlink $oname || die; + rename $tname, $oname || die; + print "Corrected absolute paths within " . $oname . " in " . $File::Find::dir . "\n"; + } + } + else { + unlink $tname; + } + $dname = $oname; + $dname =~ s/.mak$/.dsp/; + @dstat = stat($dname); + @ostat = stat($oname); + if ($ostat[9] && $dstat[9] && ($ostat[9] != $dstat[9])) { + @onames = ($oname); + utime $dstat[9], $dstat[9], @onames; + print "Touched datestamp for " . $oname . " in " . $File::Find::dir . "\n"; + } + $oname =~ s/.mak$/.dep/; + $verchg = 0; + $srcfl = new IO::File $oname, "r" || die; + $dstfl = new IO::File $tname, "w" || die; + while ($src = <$srcfl>) { + if (($src =~ m/^\t"(\.\.\\)+(apr|apr-util|apr-iconv)\\.*"\\/) || + ($src =~ m/^\t\{\$\(INCLUDE\)\}".*"\\/)) { + $verchg = -1; + } + else { + print $dstfl $src; + } + } + undef $srcfl; + undef $dstfl; + if ($verchg) { + unlink $oname || die; + rename $tname, $oname || die; + print "Stripped external dependencies from " . $oname . " in " . $File::Find::dir . "\n"; + } + else { + unlink $tname || die; + } + @ostat = stat($oname); + if ($ostat[9] && $dstat[9] && ($ostat[9] != $dstat[9])) { + @onames = ($oname); + utime $dstat[9], $dstat[9], @onames; + print "Touched datestamp for " . $oname . " in " . $File::Find::dir . "\n"; + } + } +} diff --git a/build/gen-build.py b/build/gen-build.py new file mode 100755 index 00000000000..054422abcde --- /dev/null +++ b/build/gen-build.py @@ -0,0 +1,247 @@ +#!/usr/bin/env python +# +# USAGE: gen-build.py TYPE +# +# where TYPE is one of: make, dsp, vcproj +# +# It reads build.conf from the current directory, and produces its output +# into the current directory. +# + + +import os +import ConfigParser +import getopt +import string +import glob +import re + +#import ezt + +# +# legal platforms: aix, beos, netware, os2, os390, unix, win32 +# 'make' users: aix, beos, os2, os390, unix, win32 (mingw) +# +PLATFORMS = [ 'aix', 'beos', 'netware', 'os2', 'os390', 'unix', 'win32' ] +MAKE_PLATFORMS = [ + ('unix', None), + ('aix', 'unix'), + ('beos', 'unix'), + ('os2', 'unix'), + ('os390', 'unix'), + ('win32', 'unix'), + ] +# note: MAKE_PLATFORMS is an ordered set. we want to generate unix symbols +# first, so that the later platforms can reference them. + + +def main(): + parser = ConfigParser.ConfigParser() + parser.read('build.conf') + + if parser.has_option('options', 'dsp'): + dsp_file = parser.get('options', 'dsp') + else: + dsp_file = None + + headers = get_files(parser.get('options', 'headers')) + + # compute the relevant headers, along with the implied includes + legal_deps = { } + for fname in headers: + legal_deps[os.path.basename(fname)] = fname + + h_deps = { } + for fname in headers: + h_deps[os.path.basename(fname)] = extract_deps(fname, legal_deps) + resolve_deps(h_deps) + + f = open('build-outputs.mk', 'w') + f.write('# DO NOT EDIT. AUTOMATICALLY GENERATED.\n\n') + + # write out the platform-independent files + files = get_files(parser.get('options', 'paths')) + objects, dirs = write_objects(f, legal_deps, h_deps, files) + f.write('\nOBJECTS_all = %s\n\n' % string.join(objects)) + + # for each platform and each subdirectory holding platform-specific files, + # write out their compilation rules, and an OBJECT_<subdir>_<plat> symbol. + for platform, parent in MAKE_PLATFORMS: + + # record the object symbols to build for each platform + group = [ '$(OBJECTS_all)' ] + + # If we're doing win32, we're going to look in the libapr.dsp file + # for those files that we have to manually add to our list. + inherit_parent = { } + if platform == 'win32' and dsp_file: + for line in open(dsp_file).readlines(): + if line[:7] != 'SOURCE=': + continue + if line[7:].find('unix') != -1: + # skip the leading .\ and split it out + inherit_files = line[9:].strip().split('\\') + # change the .c to .lo + assert inherit_files[-1][-2:] == '.c' + inherit_files[-1] = inherit_files[-1][:-2] + '.lo' + # replace the \\'s with /'s + inherit_line = '/'.join(inherit_files) + if not inherit_parent.has_key(inherit_files[0]): + inherit_parent[inherit_files[0]] = [] + inherit_parent[inherit_files[0]].append(inherit_line) + + for subdir in string.split(parser.get('options', 'platform_dirs')): + path = '%s/%s' % (subdir, platform) + if not os.path.exists(path): + # this subdir doesn't have a subdir for this platform, so we'll + # use the parent-platform's set of symbols + if parent: + group.append('$(OBJECTS_%s_%s)' % (subdir, parent)) + continue + + # remember that this directory has files/objects + dirs[path] = None + + # write out the compilation lines for this subdir + files = get_files(path + '/*.c') + objects, _unused = write_objects(f, legal_deps, h_deps, files) + + if inherit_parent.has_key(subdir): + objects = objects + inherit_parent[subdir] + + symname = 'OBJECTS_%s_%s' % (subdir, platform) + + objects.sort() + + # and write the symbol for the whole group + f.write('\n%s = %s\n\n' % (symname, string.join(objects))) + + # and include that symbol in the group + group.append('$(%s)' % symname) + + group.sort() + + # write out a symbol which contains the necessary files + f.write('OBJECTS_%s = %s\n\n' % (platform, string.join(group))) + + f.write('HEADERS = $(top_srcdir)/%s\n\n' % string.join(headers, ' $(top_srcdir)/')) + f.write('SOURCE_DIRS = %s $(EXTRA_SOURCE_DIRS)\n\n' % string.join(dirs.keys())) + + if parser.has_option('options', 'modules'): + modules = parser.get('options', 'modules') + + for mod in string.split(modules): + files = get_files(parser.get(mod, 'paths')) + objects, _unused = write_objects(f, legal_deps, h_deps, files) + flat_objects = string.join(objects) + f.write('OBJECTS_%s = %s\n' % (mod, flat_objects)) + + if parser.has_option(mod, 'target'): + target = parser.get(mod, 'target') + f.write('MODULE_%s = %s\n' % (mod, target)) + f.write('%s: %s\n' % (target, flat_objects)) + f.write('\t$(LINK_MODULE) -o $@ $(OBJECTS_%s) $(LDADD_%s)\n' % (mod, mod)) + + f.write('\n') + + if parser.has_option('options', 'libraries'): + libs = parser.get('options', 'libraries') + + for lib in string.split(libs): + files = get_files(parser.get(lib, 'paths')) + objects, _unused = write_objects(f, legal_deps, h_deps, files) + flat_objects = string.join(objects) + f.write('OBJECTS_%s = %s\n' % (lib, flat_objects)) + + if parser.has_option(lib, 'target'): + target = parser.get(lib, 'target') + f.write('MODULE_%s = %s\n' % (lib, target)) + f.write('%s: $(OBJECTS_%s)\n' % (target, lib)) + f.write('\t$(LINK_LIBRARY) -o $@ $(OBJECTS_%s) $(LDADD_%s)\n' % (lib, lib)) + + f.write('\n') + + # Build a list of all necessary directories in build tree + alldirs = { } + for dir in dirs.keys(): + d = dir + while d: + alldirs[d] = None + d = os.path.dirname(d) + + # Sort so 'foo' is before 'foo/bar' + keys = alldirs.keys() + keys.sort() + f.write('BUILD_DIRS = %s\n\n' % string.join(keys)) + + f.write('.make.dirs: $(srcdir)/build-outputs.mk\n' \ + '\t@for d in $(BUILD_DIRS); do test -d $$d || mkdir $$d; done\n' \ + '\t@echo timestamp > $@\n') + + +def write_objects(f, legal_deps, h_deps, files): + dirs = { } + objects = [ ] + + for file in files: + if file[-10:] == '/apr_app.c': + continue + assert file[-2:] == '.c' + obj = file[:-2] + '.lo' + objects.append(obj) + + dirs[os.path.dirname(file)] = None + + # what headers does this file include, along with the implied headers + deps = extract_deps(file, legal_deps) + for hdr in deps.keys(): + deps.update(h_deps.get(hdr, {})) + + vals = deps.values() + vals.sort() + f.write('%s: %s .make.dirs %s\n' % (obj, file, string.join(vals))) + + objects.sort() + + return objects, dirs + + +def extract_deps(fname, legal_deps): + "Extract the headers this file includes." + deps = { } + for line in open(fname).readlines(): + if line[:8] != '#include': + continue + inc = _re_include.match(line).group(1) + if inc in legal_deps.keys(): + deps[inc] = legal_deps[inc] + return deps +_re_include = re.compile('#include *["<](.*)[">]') + + +def resolve_deps(header_deps): + "Alter the provided dictionary to flatten includes-of-includes." + altered = 1 + while altered: + altered = 0 + for hdr, deps in header_deps.items(): + # print hdr, deps + start = len(deps) + for dep in deps.keys(): + deps.update(header_deps.get(dep, {})) + if len(deps) != start: + altered = 1 + +def clean_path(path): + return path.replace("\\", "/") + +def get_files(patterns): + files = [ ] + for pat in string.split(patterns): + files.extend(map(clean_path, glob.glob(pat))) + files.sort() + return files + + +if __name__ == '__main__': + main() diff --git a/build/get-version.sh b/build/get-version.sh new file mode 100755 index 00000000000..fd685b22a8d --- /dev/null +++ b/build/get-version.sh @@ -0,0 +1,37 @@ +#!/bin/sh +# +# extract version numbers from a header file +# +# USAGE: get-version.sh CMD VERSION_HEADER PREFIX +# where CMD is one of: all, major, libtool +# where PREFIX is the prefix to {MAJOR|MINOR|PATCH}_VERSION defines +# +# get-version.sh all returns a dotted version number +# get-version.sh major returns just the major version number +# get-version.sh libtool returns a version "libtool -version-info" format +# + +if test $# != 3; then + echo "USAGE: $0 CMD VERSION_HEADER PREFIX" + echo " where CMD is one of: all, major, libtool" + exit 1 +fi + +major_sed="/#define.*$3_MAJOR_VERSION/s/^[^0-9]*\([0-9]*\).*$/\1/p" +minor_sed="/#define.*$3_MINOR_VERSION/s/^[^0-9]*\([0-9]*\).*$/\1/p" +patch_sed="/#define.*$3_PATCH_VERSION/s/^[^0-9]*\([0-9]*\).*$/\1/p" +major="`sed -n $major_sed $2`" +minor="`sed -n $minor_sed $2`" +patch="`sed -n $patch_sed $2`" + +if test "$1" = "all"; then + echo ${major}.${minor}.${patch} +elif test "$1" = "major"; then + echo ${major} +elif test "$1" = "libtool"; then + # Yes, ${minor}:${patch}:${minor} is correct due to libtool idiocy. + echo ${minor}:${patch}:${minor} +else + echo "ERROR: unknown version CMD ($1)" + exit 1 +fi diff --git a/build/iconv.m4 b/build/iconv.m4 new file mode 100644 index 00000000000..f6eba10e7bb --- /dev/null +++ b/build/iconv.m4 @@ -0,0 +1,119 @@ +dnl -------------------------------------------------------- -*- autoconf -*- +dnl Licensed to the Apache Software Foundation (ASF) under one or more +dnl contributor license agreements. See the NOTICE file distributed with +dnl this work for additional information regarding copyright ownership. +dnl The ASF licenses this file to You under the Apache License, Version 2.0 +dnl (the "License"); you may not use this file except in compliance with +dnl the License. You may obtain a copy of the License at +dnl +dnl http://www.apache.org/licenses/LICENSE-2.0 +dnl +dnl Unless required by applicable law or agreed to in writing, software +dnl distributed under the License is distributed on an "AS IS" BASIS, +dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +dnl See the License for the specific language governing permissions and +dnl limitations under the License. + +dnl +dnl APU_TRY_ICONV[ IF-SUCCESS, IF-FAILURE ]: try to compile for iconv. +dnl +AC_DEFUN([APU_TRY_ICONV], [ + AC_TRY_LINK([ +#include <stdlib.h> +#include <iconv.h> +], +[ + iconv_t cd = iconv_open("", ""); + iconv(cd, NULL, NULL, NULL, NULL); +], [$1], [$2]) +]) + +dnl +dnl APU_FIND_ICONV: find an iconv library +dnl +AC_DEFUN([APU_FIND_ICONV], [ + +apu_iconv_dir="unknown" +want_iconv="1" +AC_ARG_WITH(iconv,[ --with-iconv[=DIR] path to iconv installation], + [ apu_iconv_dir="$withval" + if test "$apu_iconv_dir" = "no"; then + have_iconv="0" + want_iconv="0" + elif test "$apu_iconv_dir" != "yes"; then + if test -f "$apu_iconv_dir/include/iconv.h"; then + have_iconv="1" + APR_ADDTO(CPPFLAGS,[-I$apu_iconv_dir/include]) + APR_ADDTO(LDFLAGS,[-L$apu_iconv_dir/lib]) + fi + fi + ]) + +if test "$want_iconv" = "1"; then + AC_CHECK_HEADER(iconv.h, [ + APU_TRY_ICONV([ have_iconv="1" ], [ + + APR_ADDTO(LIBS,[-liconv]) + + APU_TRY_ICONV([ + APR_ADDTO(LIBS,[-liconv]) + APR_ADDTO(APRUTIL_EXPORT_LIBS,[-liconv]) + have_iconv="1" ], + [ have_iconv="0" ]) + + APR_REMOVEFROM(LIBS,[-liconv]) + + ]) + ], [ have_iconv="0" ]) +fi + +if test "$want_iconv" = "1" -a "$apu_iconv_dir" != "unknown"; then + if test "$have_iconv" != "1"; then + AC_MSG_ERROR([iconv support requested, but not found]) + fi + APR_REMOVEFROM(CPPFLAGS,[-I$apu_iconv_dir/include]) + APR_ADDTO(INCLUDES,[-I$apu_iconv_dir/include]) + APR_ADDTO(LDFLAGS,[-L$apu_iconv_dir/lib]) +fi + +if test "$have_iconv" = "1"; then + APU_CHECK_ICONV_INBUF +fi + +APR_FLAG_HEADERS(iconv.h langinfo.h) +APR_FLAG_FUNCS(nl_langinfo) +APR_CHECK_DEFINE(CODESET, langinfo.h, [CODESET defined in langinfo.h]) + +AC_SUBST(have_iconv) +])dnl + +dnl +dnl APU_CHECK_ICONV_INBUF +dnl +dnl Decide whether or not the inbuf parameter to iconv() is const. +dnl +dnl We try to compile something without const. If it fails to +dnl compile, we assume that the system's iconv() has const. +dnl Unfortunately, we won't realize when there was a compile +dnl warning, so we allow a variable -- apu_iconv_inbuf_const -- to +dnl be set in hints.m4 to specify whether or not iconv() has const +dnl on this parameter. +dnl +AC_DEFUN([APU_CHECK_ICONV_INBUF], [ +AC_MSG_CHECKING(for type of inbuf parameter to iconv) +if test "x$apu_iconv_inbuf_const" = "x"; then + APR_TRY_COMPILE_NO_WARNING([ + #include <stddef.h> + #include <iconv.h> + ],[ + iconv(0,(char **)0,(size_t *)0,(char **)0,(size_t *)0); + ], apu_iconv_inbuf_const="0", apu_iconv_inbuf_const="1") +fi +if test "$apu_iconv_inbuf_const" = "1"; then + AC_DEFINE(APU_ICONV_INBUF_CONST, 1, [Define if the inbuf parm to iconv() is const char **]) + msg="const char **" +else + msg="char **" +fi +AC_MSG_RESULT([$msg]) +])dnl diff --git a/helpers/install.sh b/build/install.sh similarity index 100% rename from helpers/install.sh rename to build/install.sh diff --git a/build/jlibtool.c b/build/jlibtool.c new file mode 100644 index 00000000000..892e26d5653 --- /dev/null +++ b/build/jlibtool.c @@ -0,0 +1,2056 @@ +/* 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 <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <sys/stat.h> +#include <sys/types.h> +#if !defined(__MINGW32__) +#include <sys/wait.h> +#endif +#include <unistd.h> +#include <dirent.h> +#include <errno.h> +#include <assert.h> + +#ifdef __EMX__ +# define SHELL_CMD "sh" +# define GEN_EXPORTS "emxexp" +# define DEF2IMPLIB_CMD "emximp" +# define SHARE_SW "-Zdll -Zmtd" +# define USE_OMF 1 +# define TRUNCATE_DLL_NAME +# define DYNAMIC_LIB_EXT "dll" +# define EXE_EXT ".exe" + +# if USE_OMF + /* OMF is the native format under OS/2 */ +# define STATIC_LIB_EXT "lib" +# define OBJECT_EXT "obj" +# define LIBRARIAN "emxomfar" +# define LIBRARIAN_OPTS "cr" +# else + /* but the alternative, a.out, can fork() which is sometimes necessary */ +# define STATIC_LIB_EXT "a" +# define OBJECT_EXT "o" +# define LIBRARIAN "ar" +# define LIBRARIAN_OPTS "cr" +# endif +#endif + +#if defined(__APPLE__) +# define SHELL_CMD "/bin/sh" +# define DYNAMIC_LIB_EXT "dylib" +# define MODULE_LIB_EXT "bundle" +# define STATIC_LIB_EXT "a" +# define OBJECT_EXT "o" +# define LIBRARIAN "ar" +# define LIBRARIAN_OPTS "cr" +/* man libtool(1) documents ranlib option of -c. */ +# define RANLIB "ranlib" +# define PIC_FLAG "-fPIC -fno-common" +# define SHARED_OPTS "-dynamiclib" +# define MODULE_OPTS "-bundle -dynamic" +# define DYNAMIC_LINK_OPTS "-flat_namespace" +# define DYNAMIC_LINK_UNDEFINED "-undefined suppress" +# define dynamic_link_version_func darwin_dynamic_link_function +# define DYNAMIC_INSTALL_NAME "-install_name" +# define DYNAMIC_LINK_NO_INSTALL "-dylib_file" +# define HAS_REALPATH +/*-install_name /Users/jerenk/apache-2.0-cvs/lib/libapr.0.dylib -compatibility_version 1 -current_version 1.0 */ +# define LD_LIBRARY_PATH "DYLD_LIBRARY_PATH" +#endif + +#if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) +# define SHELL_CMD "/bin/sh" +# define DYNAMIC_LIB_EXT "so" +# define MODULE_LIB_EXT "so" +# define STATIC_LIB_EXT "a" +# define OBJECT_EXT "o" +# define LIBRARIAN "ar" +# define LIBRARIAN_OPTS "cr" +# define RANLIB "ranlib" +# define PIC_FLAG "-fPIC" +# define RPATH "-rpath" +# define SHARED_OPTS "-shared" +# define MODULE_OPTS "-shared" +# define DYNAMIC_LINK_OPTS "-export-dynamic" +# define LINKER_FLAG_PREFIX "-Wl," +# define ADD_MINUS_L +# define LD_RUN_PATH "LD_RUN_PATH" +# define LD_LIBRARY_PATH "LD_LIBRARY_PATH" +#endif + +#if defined(sun) +# define SHELL_CMD "/bin/sh" +# define DYNAMIC_LIB_EXT "so" +# define MODULE_LIB_EXT "so" +# define STATIC_LIB_EXT "a" +# define OBJECT_EXT "o" +# define LIBRARIAN "ar" +# define LIBRARIAN_OPTS "cr" +# define RANLIB "ranlib" +# define PIC_FLAG "-KPIC" +# define RPATH "-R" +# define SHARED_OPTS "-G" +# define MODULE_OPTS "-G" +# define DYNAMIC_LINK_OPTS "" +# define LINKER_FLAG_NO_EQUALS +# define ADD_MINUS_L +# define HAS_REALPATH +# define LD_RUN_PATH "LD_RUN_PATH" +# define LD_LIBRARY_PATH "LD_LIBRARY_PATH" +#endif + +#if defined(_OSD_POSIX) +# define SHELL_CMD "/usr/bin/sh" +# define DYNAMIC_LIB_EXT "so" +# define MODULE_LIB_EXT "so" +# define STATIC_LIB_EXT "a" +# define OBJECT_EXT "o" +# define LIBRARIAN "ar" +# define LIBRARIAN_OPTS "cr" +# define SHARED_OPTS "-G" +# define MODULE_OPTS "-G" +# define LINKER_FLAG_PREFIX "-Wl," +# define NEED_SNPRINTF +#endif + +#if defined(sinix) && defined(mips) && defined(__SNI_TARG_UNIX) +# define SHELL_CMD "/usr/bin/sh" +# define DYNAMIC_LIB_EXT "so" +# define MODULE_LIB_EXT "so" +# define STATIC_LIB_EXT "a" +# define OBJECT_EXT "o" +# define LIBRARIAN "ar" +# define LIBRARIAN_OPTS "cr" +# define RPATH "-Brpath" +# define SHARED_OPTS "-G" +# define MODULE_OPTS "-G" +# define DYNAMIC_LINK_OPTS "-Wl,-Blargedynsym" +# define LINKER_FLAG_PREFIX "-Wl," +# define NEED_SNPRINTF +# define LD_RUN_PATH "LD_RUN_PATH" +# define LD_LIBRARY_PATH "LD_LIBRARY_PATH" +#endif + +#if defined(__MINGW32__) +# define SHELL_CMD "sh" +# define DYNAMIC_LIB_EXT "dll" +# define MODULE_LIB_EXT "dll" +# define STATIC_LIB_EXT "a" +# define OBJECT_EXT "o" +# define LIBRARIAN "ar" +# define LIBRARIAN_OPTS "cr" +# define RANLIB "ranlib" +# define LINKER_FLAG_PREFIX "-Wl," +# define SHARED_OPTS "-shared" +# define MODULE_OPTS "-shared" +# define MKDIR_NO_UMASK +# define EXE_EXT ".exe" +#endif + +#ifndef SHELL_CMD +#error Unsupported platform: Please add defines for SHELL_CMD etc. for your platform. +#endif + +#ifdef NEED_SNPRINTF +#include <stdarg.h> +#endif + +#ifdef __EMX__ +#include <process.h> +#endif + +#ifndef PATH_MAX +#define PATH_MAX 1024 +#endif + + +/* We want to say we are libtool 1.4 for shlibtool compatibility. */ +#define VERSION "1.4" + +enum tool_mode_t { + mUnknown, + mCompile, + mLink, + mInstall, +}; + +enum output_t { + otGeneral, + otObject, + otProgram, + otLibrary, + otStaticLibraryOnly, + otDynamicLibraryOnly, + otModule, +}; + +enum pic_mode_e { + pic_UNKNOWN, + pic_PREFER, + pic_AVOID, +}; + +enum shared_mode_e { + share_UNSET, + share_STATIC, + share_SHARED, +}; + +enum lib_type { + type_UNKNOWN, + type_DYNAMIC_LIB, + type_STATIC_LIB, + type_MODULE_LIB, + type_OBJECT, +}; + +typedef struct { + const char **vals; + int num; +} count_chars; + +typedef struct { + const char *normal; + const char *install; +} library_name; + +typedef struct { + count_chars *normal; + count_chars *install; + count_chars *dependencies; +} library_opts; + +typedef struct { + int silent; + enum shared_mode_e shared; + int export_all; + int dry_run; + enum pic_mode_e pic_mode; + int export_dynamic; + int no_install; +} options_t; + +typedef struct { + enum tool_mode_t mode; + enum output_t output; + options_t options; + + char *output_name; + char *fake_output_name; + char *basename; + + const char *install_path; + const char *compiler; + const char *program; + count_chars *program_opts; + + count_chars *arglist; + count_chars *tmp_dirs; + count_chars *obj_files; + count_chars *dep_rpaths; + count_chars *rpaths; + + library_name static_name; + library_name shared_name; + library_name module_name; + + library_opts static_opts; + library_opts shared_opts; + + const char *version_info; + const char *undefined_flag; +} command_t; + +#ifdef RPATH +void add_rpath(count_chars *cc, const char *path); +#endif + +#if defined(NEED_SNPRINTF) +/* Write at most n characters to the buffer in str, return the + * number of chars written or -1 if the buffer would have been + * overflowed. + * + * This is portable to any POSIX-compliant system has /dev/null + */ +static FILE *f=NULL; +static int vsnprintf( char *str, size_t n, const char *fmt, va_list ap ) +{ + int res; + + if (f == NULL) + f = fopen("/dev/null","w"); + if (f == NULL) + return -1; + + setvbuf( f, str, _IOFBF, n ); + + res = vfprintf( f, fmt, ap ); + + if ( res > 0 && res < n ) { + res = vsprintf( str, fmt, ap ); + } + return res; +} +static int snprintf( char *str, size_t n, const char *fmt, ... ) +{ + va_list ap; + int res; + + va_start( ap, fmt ); + res = vsnprintf( str, n, fmt, ap ); + va_end( ap ); + return res; +} +#endif + +void init_count_chars(count_chars *cc) +{ + cc->vals = (const char**)malloc(PATH_MAX*sizeof(char*)); + cc->num = 0; +} + +void clear_count_chars(count_chars *cc) +{ + int i; + for (i = 0; i < cc->num; i++) { + cc->vals[i] = 0; + } + + cc->num = 0; +} + +void push_count_chars(count_chars *cc, const char *newval) +{ + cc->vals[cc->num++] = newval; +} + +void pop_count_chars(count_chars *cc) +{ + cc->num--; +} + +void insert_count_chars(count_chars *cc, const char *newval, int position) +{ + int i; + + for (i = cc->num; i > position; i--) { + cc->vals[i] = cc->vals[i-1]; + } + + cc->vals[position] = newval; + cc->num++; +} + +void append_count_chars(count_chars *cc, count_chars *cctoadd) +{ + int i; + for (i = 0; i < cctoadd->num; i++) { + if (cctoadd->vals[i]) { + push_count_chars(cc, cctoadd->vals[i]); + } + } +} + +const char *flatten_count_chars(count_chars *cc, int space) +{ + int i, size; + char *newval; + + size = 0; + for (i = 0; i < cc->num; i++) { + if (cc->vals[i]) { + size += strlen(cc->vals[i]) + 1; + if (space) { + size++; + } + } + } + + newval = (char*)malloc(size + 1); + newval[0] = 0; + + for (i = 0; i < cc->num; i++) { + if (cc->vals[i]) { + strcat(newval, cc->vals[i]); + if (space) { + strcat(newval, " "); + } + } + } + + return newval; +} + +char *shell_esc(const char *str) +{ + int in_quote = 0; + char *cmd; + unsigned char *d; + const unsigned char *s; + + cmd = (char *)malloc(2 * strlen(str) + 3); + d = (unsigned char *)cmd; + s = (const unsigned char *)str; + +#ifdef __MINGW32__ + *d++ = '\"'; +#endif + + for (; *s; ++s) { + if (*s == '"') { + *d++ = '\\'; + in_quote++; + } + else if (*s == '\\' || (*s == ' ' && (in_quote % 2))) { + *d++ = '\\'; + } + *d++ = *s; + } + +#ifdef __MINGW32__ + *d++ = '\"'; +#endif + + *d = '\0'; + return cmd; +} + +int external_spawn(command_t *cmd, const char *file, const char **argv) +{ + if (!cmd->options.silent) { + const char **argument = argv; + printf("Executing: "); + while (*argument) { + printf("%s ", *argument); + argument++; + } + puts(""); + } + + if (cmd->options.dry_run) { + return 0; + } +#if defined(__EMX__) || defined(__MINGW32__) + return spawnvp(P_WAIT, argv[0], argv); +#else + { + pid_t pid; + pid = fork(); + if (pid == 0) { + return execvp(argv[0], (char**)argv); + } + else { + int statuscode; + waitpid(pid, &statuscode, 0); + if (WIFEXITED(statuscode)) { + return WEXITSTATUS(statuscode); + } + return 0; + } + } +#endif +} + +int run_command(command_t *cmd_data, count_chars *cc) +{ + char *command; + const char *spawn_args[4]; + count_chars tmpcc; + + init_count_chars(&tmpcc); + + if (cmd_data->program) { + push_count_chars(&tmpcc, cmd_data->program); + } + + append_count_chars(&tmpcc, cmd_data->program_opts); + + append_count_chars(&tmpcc, cc); + + command = shell_esc(flatten_count_chars(&tmpcc, 1)); + + spawn_args[0] = SHELL_CMD; + spawn_args[1] = "-c"; + spawn_args[2] = command; + spawn_args[3] = NULL; + return external_spawn(cmd_data, spawn_args[0], (const char**)spawn_args); +} + +/* + * print configuration + * shlibpath_var is used in configure. + */ +void print_config() +{ +#ifdef LD_RUN_PATH + printf("runpath_var=%s\n", LD_RUN_PATH); +#endif +#ifdef LD_LIBRARY_PATH + printf("shlibpath_var=%s\n", LD_LIBRARY_PATH); +#endif +#ifdef SHELL_CMD + printf("SHELL=\"%s\"\n", SHELL_CMD); +#endif +} +/* + * Add a directory to the runtime library search path. + */ +void add_runtimedirlib(char *arg, command_t *cmd_data) +{ +#ifdef RPATH + add_rpath(cmd_data->shared_opts.dependencies, arg); +#else +#endif +} + +int parse_long_opt(char *arg, command_t *cmd_data) +{ + char *equal_pos = strchr(arg, '='); + char var[50]; + char value[500]; + + if (equal_pos) { + strncpy(var, arg, equal_pos - arg); + var[equal_pos - arg] = 0; + strcpy(value, equal_pos + 1); + } else { + strcpy(var, arg); + } + + if (strcmp(var, "silent") == 0) { + cmd_data->options.silent = 1; + } else if (strcmp(var, "mode") == 0) { + if (strcmp(value, "compile") == 0) { + cmd_data->mode = mCompile; + cmd_data->output = otObject; + } + + if (strcmp(value, "link") == 0) { + cmd_data->mode = mLink; + cmd_data->output = otLibrary; + } + + if (strcmp(value, "install") == 0) { + cmd_data->mode = mInstall; + } + } else if (strcmp(var, "shared") == 0) { + if (cmd_data->mode == mLink) { + cmd_data->output = otDynamicLibraryOnly; + } + cmd_data->options.shared = share_SHARED; + } else if (strcmp(var, "export-all") == 0) { + cmd_data->options.export_all = 1; + } else if (strcmp(var, "dry-run") == 0) { + printf("Dry-run mode on!\n"); + cmd_data->options.dry_run = 1; + } else if (strcmp(var, "version") == 0) { + printf("Version " VERSION "\n"); + } else if (strcmp(var, "help") == 0) { + printf("Sorry. No help available.\n"); + } else if (strcmp(var, "config") == 0) { + print_config(); + } else if (strcmp(var, "tag") == 0) { + if (strcmp(value, "CC") == 0) { + /* Do nothing. */ + } + if (strcmp(value, "CXX") == 0) { + /* Do nothing. */ + } + } else { + return 0; + } + + return 1; +} + +/* Return 1 if we eat it. */ +int parse_short_opt(char *arg, command_t *cmd_data) +{ + if (strcmp(arg, "export-dynamic") == 0) { + cmd_data->options.export_dynamic = 1; + return 1; + } + + if (strcmp(arg, "module") == 0) { + cmd_data->output = otModule; + return 1; + } + + if (strcmp(arg, "shared") == 0) { + if (cmd_data->mode == mLink) { + cmd_data->output = otDynamicLibraryOnly; + } + cmd_data->options.shared = share_SHARED; + return 1; + } + + if (strcmp(arg, "Zexe") == 0) { + return 1; + } + + if (strcmp(arg, "avoid-version") == 0) { + return 1; + } + + if (strcmp(arg, "prefer-pic") == 0) { + cmd_data->options.pic_mode = pic_PREFER; + return 1; + } + + if (strcmp(arg, "prefer-non-pic") == 0) { + cmd_data->options.pic_mode = pic_AVOID; + return 1; + } + + if (strcmp(arg, "static") == 0) { + cmd_data->options.shared = share_STATIC; + return 1; + } + + if (cmd_data->mode == mLink) { + if (strcmp(arg, "no-install") == 0) { + cmd_data->options.no_install = 1; + return 1; + } + if (arg[0] == 'L' || arg[0] == 'l') { + /* Hack... */ + arg--; + push_count_chars(cmd_data->shared_opts.dependencies, arg); + return 1; + } else if (arg[0] == 'R' && arg[1]) { + /* -Rdir Add dir to runtime library search path. */ + add_runtimedirlib(&arg[1], cmd_data); + return 1; + } + } + return 0; +} + +char *truncate_dll_name(char *path) +{ + /* Cut DLL name down to 8 characters after removing any mod_ prefix */ + char *tmppath = strdup(path); + char *newname = strrchr(tmppath, '/') + 1; + char *ext = strrchr(tmppath, '.'); + int len; + + if (ext == NULL) + return tmppath; + + len = ext - newname; + + if (strncmp(newname, "mod_", 4) == 0) { + strcpy(newname, newname + 4); + len -= 4; + } + + if (len > 8) { + strcpy(newname + 8, strchr(newname, '.')); + } + + return tmppath; +} + +long safe_strtol(const char *nptr, const char **endptr, int base) +{ + long rv; + + errno = 0; + + rv = strtol(nptr, (char**)endptr, 10); + + if (errno == ERANGE) { + return 0; + } + + return rv; +} + +void safe_mkdir(const char *path) +{ + mode_t old_umask; + + old_umask = umask(0); + umask(old_umask); + +#ifdef MKDIR_NO_UMASK + mkdir(path); +#else + mkdir(path, ~old_umask); +#endif +} + +/* returns just a file's name without the path */ +const char *jlibtool_basename(const char *fullpath) +{ + const char *name = strrchr(fullpath, '/'); + + if (name == NULL) { + name = strrchr(fullpath, '\\'); + } + + if (name == NULL) { + name = fullpath; + } else { + name++; + } + + return name; +} + +/* returns just a file's name without path or extension */ +const char *nameof(const char *fullpath) +{ + const char *name; + const char *ext; + + name = jlibtool_basename(fullpath); + ext = strrchr(name, '.'); + + if (ext) { + char *trimmed; + trimmed = malloc(ext - name + 1); + strncpy(trimmed, name, ext - name); + trimmed[ext-name] = 0; + return trimmed; + } + + return name; +} + +/* version_info is in the form of MAJOR:MINOR:PATCH */ +const char *darwin_dynamic_link_function(const char *version_info) +{ + char *newarg; + long major, minor, patch; + + major = 0; + minor = 0; + patch = 0; + + if (version_info) { + major = safe_strtol(version_info, &version_info, 10); + + if (version_info) { + if (version_info[0] == ':') { + version_info++; + } + + minor = safe_strtol(version_info, &version_info, 10); + + if (version_info) { + if (version_info[0] == ':') { + version_info++; + } + + patch = safe_strtol(version_info, &version_info, 10); + + } + } + } + + /* Avoid -dylib_compatibility_version must be greater than zero errors. */ + if (major == 0) { + major = 1; + } + newarg = (char*)malloc(100); + snprintf(newarg, 99, + "-compatibility_version %ld -current_version %ld.%ld", + major, major, minor); + + return newarg; +} + +/* genlib values + * 0 - static + * 1 - dynamic + * 2 - module + */ +char *gen_library_name(const char *name, int genlib) +{ + char *newarg, *newext; + + newarg = (char *)malloc(strlen(name) + 11); + strcpy(newarg, ".libs/"); + + if (genlib == 2 && strncmp(name, "lib", 3) == 0) { + name += 3; + } + + if (genlib == 2) { + strcat(newarg, jlibtool_basename(name)); + } + else { + strcat(newarg, name); + } + + newext = strrchr(newarg, '.') + 1; + + switch (genlib) { + case 0: + strcpy(newext, STATIC_LIB_EXT); + break; + case 1: + strcpy(newext, DYNAMIC_LIB_EXT); + break; + case 2: + strcpy(newext, MODULE_LIB_EXT); + break; + } + + return newarg; +} + +/* genlib values + * 0 - static + * 1 - dynamic + * 2 - module + */ +char *gen_install_name(const char *name, int genlib) +{ + struct stat sb; + char *newname; + int rv; + + newname = gen_library_name(name, genlib); + + /* Check if it exists. If not, return NULL. */ + rv = stat(newname, &sb); + + if (rv) { + return NULL; + } + + return newname; +} + +char *check_object_exists(command_t *cmd, const char *arg, int arglen) +{ + char *newarg, *ext; + int pass, rv; + + newarg = (char *)malloc(arglen + 10); + memcpy(newarg, arg, arglen); + newarg[arglen] = 0; + ext = newarg + arglen; + + pass = 0; + + do { + struct stat sb; + + switch (pass) { + case 0: + strcpy(ext, OBJECT_EXT); + break; +/* + case 1: + strcpy(ext, NO_PIC_EXT); + break; +*/ + default: + break; + } + + if (!cmd->options.silent) { + printf("Checking (obj): %s\n", newarg); + } + rv = stat(newarg, &sb); + } + while (rv != 0 && ++pass < 1); + + if (rv == 0) { + if (pass == 1) { + cmd->options.pic_mode = pic_AVOID; + } + return newarg; + } + + return NULL; +} + +/* libdircheck values: + * 0 - no .libs suffix + * 1 - .libs suffix + */ +char *check_library_exists(command_t *cmd, const char *arg, int pathlen, + int libdircheck, enum lib_type *libtype) +{ + char *newarg, *ext; + int pass, rv, newpathlen; + + newarg = (char *)malloc(strlen(arg) + 10); + strcpy(newarg, arg); + newarg[pathlen] = 0; + + newpathlen = pathlen; + if (libdircheck) { + strcat(newarg, ".libs/"); + newpathlen += sizeof(".libs/") - 1; + } + + strcpy(newarg+newpathlen, arg+pathlen); + ext = strrchr(newarg, '.') + 1; + + pass = 0; + + do { + struct stat sb; + + switch (pass) { + case 0: + if (cmd->options.pic_mode != pic_AVOID && + cmd->options.shared != share_STATIC) { + strcpy(ext, DYNAMIC_LIB_EXT); + *libtype = type_DYNAMIC_LIB; + break; + } + pass = 1; + /* Fall through */ + case 1: + strcpy(ext, STATIC_LIB_EXT); + *libtype = type_STATIC_LIB; + break; + case 2: + strcpy(ext, MODULE_LIB_EXT); + *libtype = type_MODULE_LIB; + break; + case 3: + strcpy(ext, OBJECT_EXT); + *libtype = type_OBJECT; + break; + default: + *libtype = type_UNKNOWN; + break; + } + + if (!cmd->options.silent) { + printf("Checking (lib): %s\n", newarg); + } + rv = stat(newarg, &sb); + } + while (rv != 0 && ++pass < 4); + + if (rv == 0) { + return newarg; + } + + return NULL; +} + +char * load_install_path(const char *arg) +{ + FILE *f; + char *path; + + path = malloc(PATH_MAX); + + f = fopen(arg,"r"); + if (f == NULL) { + return NULL; + } + fgets(path, PATH_MAX, f); + fclose(f); + if (path[strlen(path)-1] == '\n') { + path[strlen(path)-1] = '\0'; + } + /* Check that we have an absolute path. + * Otherwise the file could be a GNU libtool file. + */ + if (path[0] != '/') { + return NULL; + } + return path; +} + +char * load_noinstall_path(const char *arg, int pathlen) +{ + char *newarg, *expanded_path; + int newpathlen; + + newarg = (char *)malloc(strlen(arg) + 10); + strcpy(newarg, arg); + newarg[pathlen] = 0; + + newpathlen = pathlen; + strcat(newarg, ".libs"); + newpathlen += sizeof(".libs") - 1; + newarg[newpathlen] = 0; + +#ifdef HAS_REALPATH + expanded_path = malloc(PATH_MAX); + expanded_path = realpath(newarg, expanded_path); + /* Uh, oh. There was an error. Fall back on our first guess. */ + if (!expanded_path) { + expanded_path = newarg; + } +#else + /* We might get ../ or something goofy. Oh, well. */ + expanded_path = newarg; +#endif + + return expanded_path; +} + +void add_dynamic_link_opts(command_t *cmd_data, count_chars *args) +{ +#ifdef DYNAMIC_LINK_OPTS + if (cmd_data->options.pic_mode != pic_AVOID) { + if (!cmd_data->options.silent) { + printf("Adding: %s\n", DYNAMIC_LINK_OPTS); + } + push_count_chars(args, DYNAMIC_LINK_OPTS); + if (cmd_data->undefined_flag) { + push_count_chars(args, "-undefined"); +#if defined(__APPLE__) + /* -undefined dynamic_lookup is used by the bundled Python in + * 10.4, but if we don't set MACOSX_DEPLOYMENT_TARGET to 10.3+, + * we'll get a linker error if we pass this flag. + */ + if (strcasecmp(cmd_data->undefined_flag, + "dynamic_lookup") == 0) { + insert_count_chars(cmd_data->program_opts, + "MACOSX_DEPLOYMENT_TARGET=10.3", 0); + } +#endif + push_count_chars(args, cmd_data->undefined_flag); + } + else { +#ifdef DYNAMIC_LINK_UNDEFINED + if (!cmd_data->options.silent) { + printf("Adding: %s\n", DYNAMIC_LINK_UNDEFINED); + } + push_count_chars(args, DYNAMIC_LINK_UNDEFINED); +#endif + } + } +#endif +} + +/* Read the final install location and add it to runtime library search path. */ +#ifdef RPATH +void add_rpath(count_chars *cc, const char *path) +{ + int size = 0; + char *tmp; + +#ifdef LINKER_FLAG_PREFIX + size = strlen(LINKER_FLAG_PREFIX); +#endif + size = size + strlen(path) + strlen(RPATH) + 2; + tmp = malloc(size); + if (tmp == NULL) { + return; + } +#ifdef LINKER_FLAG_PREFIX + strcpy(tmp, LINKER_FLAG_PREFIX); + strcat(tmp, RPATH); +#else + strcpy(tmp, RPATH); +#endif +#ifndef LINKER_FLAG_NO_EQUALS + strcat(tmp, "="); +#endif + strcat(tmp, path); + + push_count_chars(cc, tmp); +} + +void add_rpath_file(count_chars *cc, const char *arg) +{ + const char *path; + + path = load_install_path(arg); + if (path) { + add_rpath(cc, path); + } +} + +void add_rpath_noinstall(count_chars *cc, const char *arg, int pathlen) +{ + const char *path; + + path = load_noinstall_path(arg, pathlen); + if (path) { + add_rpath(cc, path); + } +} +#endif + +#ifdef DYNAMIC_LINK_NO_INSTALL +void add_dylink_noinstall(count_chars *cc, const char *arg, int pathlen, + int extlen) +{ + const char *install_path, *current_path, *name; + char *exp_argument; + int i_p_len, c_p_len, name_len, dyext_len, cur_len; + + install_path = load_install_path(arg); + current_path = load_noinstall_path(arg, pathlen); + + if (!install_path || !current_path) { + return; + } + + push_count_chars(cc, DYNAMIC_LINK_NO_INSTALL); + + i_p_len = strlen(install_path); + c_p_len = strlen(current_path); + + name = arg+pathlen; + name_len = extlen-pathlen; + dyext_len = sizeof(DYNAMIC_LIB_EXT) - 1; + + /* No, we need to replace the extension. */ + exp_argument = (char *)malloc(i_p_len + c_p_len + (name_len*2) + + (dyext_len*2) + 2); + + cur_len = 0; + strcpy(exp_argument, install_path); + cur_len += i_p_len; + exp_argument[cur_len++] = '/'; + strncpy(exp_argument+cur_len, name, extlen-pathlen); + cur_len += name_len; + strcpy(exp_argument+cur_len, DYNAMIC_LIB_EXT); + cur_len += dyext_len; + exp_argument[cur_len++] = ':'; + strcpy(exp_argument+cur_len, current_path); + cur_len += c_p_len; + exp_argument[cur_len++] = '/'; + strncpy(exp_argument+cur_len, name, extlen-pathlen); + cur_len += name_len; + strcpy(exp_argument+cur_len, DYNAMIC_LIB_EXT); + cur_len += dyext_len; + + push_count_chars(cc, exp_argument); +} +#endif + +/* use -L -llibname to allow to use installed libraries */ +void add_minus_l(count_chars *cc, const char *arg) +{ + char *newarg; + char *name = strrchr(arg, '/'); + char *file = strrchr(arg, '.'); + char *lib = strstr(name, "lib"); + + if (name !=NULL && file != NULL && lib == name+1) { + *name = '\0'; + *file = '\0'; + file = name; + file = file+4; + push_count_chars(cc, "-L"); + push_count_chars(cc, arg); + /* we need one argument like -lapr-1 */ + newarg = malloc(strlen(file) + 3); + strcpy(newarg, "-l"); + strcat(newarg, file); + push_count_chars(cc, newarg); + } else { + push_count_chars(cc, arg); + } +} + +void add_linker_flag_prefix(count_chars *cc, const char *arg) +{ +#ifndef LINKER_FLAG_PREFIX + push_count_chars(cc, arg); +#else + char *newarg; + newarg = (char*)malloc(strlen(arg) + sizeof(LINKER_FLAG_PREFIX) + 1); + strcpy(newarg, LINKER_FLAG_PREFIX); + strcat(newarg, arg); + push_count_chars(cc, newarg); +#endif +} + +int explode_static_lib(command_t *cmd_data, const char *lib) +{ + count_chars tmpdir_cc, libname_cc; + const char *tmpdir, *libname; + char savewd[PATH_MAX]; + const char *name; + DIR *dir; + struct dirent *entry; + const char *lib_args[4]; + + /* Bah! */ + if (cmd_data->options.dry_run) { + return 0; + } + + name = jlibtool_basename(lib); + + init_count_chars(&tmpdir_cc); + push_count_chars(&tmpdir_cc, ".libs/"); + push_count_chars(&tmpdir_cc, name); + push_count_chars(&tmpdir_cc, ".exploded/"); + tmpdir = flatten_count_chars(&tmpdir_cc, 0); + + if (!cmd_data->options.silent) { + printf("Making: %s\n", tmpdir); + } + safe_mkdir(tmpdir); + + push_count_chars(cmd_data->tmp_dirs, tmpdir); + + getcwd(savewd, sizeof(savewd)); + + if (chdir(tmpdir) != 0) { + if (!cmd_data->options.silent) { + printf("Warning: could not explode %s\n", lib); + } + return 1; + } + + if (lib[0] == '/') { + libname = lib; + } + else { + init_count_chars(&libname_cc); + push_count_chars(&libname_cc, "../../"); + push_count_chars(&libname_cc, lib); + libname = flatten_count_chars(&libname_cc, 0); + } + + lib_args[0] = LIBRARIAN; + lib_args[1] = "x"; + lib_args[2] = libname; + lib_args[3] = NULL; + + external_spawn(cmd_data, LIBRARIAN, lib_args); + + chdir(savewd); + dir = opendir(tmpdir); + + while ((entry = readdir(dir)) != NULL) { +#if defined(__APPLE__) && defined(RANLIB) + /* Apple inserts __.SYMDEF which isn't needed. + * Leopard (10.5+) can also add '__.SYMDEF SORTED' which isn't + * much fun either. Just skip them. + */ + if (strstr(entry->d_name, "__.SYMDEF") != NULL) { + continue; + } +#endif + if (entry->d_name[0] != '.') { + push_count_chars(&tmpdir_cc, entry->d_name); + name = flatten_count_chars(&tmpdir_cc, 0); + if (!cmd_data->options.silent) { + printf("Adding: %s\n", name); + } + push_count_chars(cmd_data->obj_files, name); + pop_count_chars(&tmpdir_cc); + } + } + + closedir(dir); + return 0; +} + +int parse_input_file_name(char *arg, command_t *cmd_data) +{ + char *ext = strrchr(arg, '.'); + char *name = strrchr(arg, '/'); + int pathlen; + enum lib_type libtype; + char *newarg; + + if (!ext) { + return 0; + } + + ext++; + + if (name == NULL) { + name = strrchr(arg, '\\'); + + if (name == NULL) { + name = arg; + } else { + name++; + } + } else { + name++; + } + + pathlen = name - arg; + + if (strcmp(ext, "lo") == 0) { + newarg = check_object_exists(cmd_data, arg, ext - arg); + if (!newarg) { + printf("Can not find suitable object file for %s\n", arg); + exit(1); + } + if (cmd_data->mode != mLink) { + push_count_chars(cmd_data->arglist, newarg); + } + else { + push_count_chars(cmd_data->obj_files, newarg); + } + return 1; + } + + if (strcmp(ext, "la") == 0) { + switch (cmd_data->mode) { + case mLink: + /* Try the .libs dir first! */ + newarg = check_library_exists(cmd_data, arg, pathlen, 1, &libtype); + if (!newarg) { + /* Try the normal dir next. */ + newarg = check_library_exists(cmd_data, arg, pathlen, 0, &libtype); + if (!newarg) { + printf("Can not find suitable library for %s\n", arg); + exit(1); + } + } + + /* It is not ok to just add the file: a library may added with: + 1 - -L path library_name. (For *.so in Linux). + 2 - library_name. + */ +#ifdef ADD_MINUS_L + if (libtype == type_DYNAMIC_LIB) { + add_minus_l(cmd_data->shared_opts.dependencies, newarg); + } else if (cmd_data->output == otLibrary && + libtype == type_STATIC_LIB) { + explode_static_lib(cmd_data, newarg); + } else { + push_count_chars(cmd_data->shared_opts.dependencies, newarg); + } +#else + if (cmd_data->output == otLibrary && libtype == type_STATIC_LIB) { + explode_static_lib(cmd_data, newarg); + } + else { + push_count_chars(cmd_data->shared_opts.dependencies, newarg); + } +#endif + if (libtype == type_DYNAMIC_LIB) { + if (cmd_data->options.no_install) { +#ifdef RPATH + add_rpath_noinstall(cmd_data->shared_opts.dependencies, + arg, pathlen); +#endif +#ifdef DYNAMIC_LINK_NO_INSTALL + /* + * This doesn't work as Darwin's linker has no way to + * override at link-time the search paths for a + * non-installed library. + */ + /* + add_dylink_noinstall(cmd_data->shared_opts.dependencies, + arg, pathlen, ext - arg); + */ +#endif + } + else { +#ifdef RPATH + add_rpath_file(cmd_data->shared_opts.dependencies, arg); +#endif + } + } + break; + case mInstall: + /* If we've already recorded a library to install, we're most + * likely getting the .la file that we want to install as. + * The problem is that we need to add it as the directory, + * not the .la file itself. Otherwise, we'll do odd things. + */ + if (cmd_data->output == otLibrary) { + arg[pathlen] = '\0'; + push_count_chars(cmd_data->arglist, arg); + } + else { + cmd_data->output = otLibrary; + cmd_data->output_name = arg; + cmd_data->static_name.install = gen_install_name(arg, 0); + cmd_data->shared_name.install = gen_install_name(arg, 1); + cmd_data->module_name.install = gen_install_name(arg, 2); + } + break; + default: + break; + } + return 1; + } + + if (strcmp(ext, "c") == 0) { + /* If we don't already have an idea what our output name will be. */ + if (cmd_data->basename == NULL) { + cmd_data->basename = (char *)malloc(strlen(arg) + 4); + strcpy(cmd_data->basename, arg); + strcpy(strrchr(cmd_data->basename, '.') + 1, "lo"); + + cmd_data->fake_output_name = strrchr(cmd_data->basename, '/'); + if (cmd_data->fake_output_name) { + cmd_data->fake_output_name++; + } + else { + cmd_data->fake_output_name = cmd_data->basename; + } + } + } + + return 0; +} + +int parse_output_file_name(char *arg, command_t *cmd_data) +{ + char *name = strrchr(arg, '/'); + char *ext = strrchr(arg, '.'); + char *newarg = NULL; + int pathlen; + + cmd_data->fake_output_name = arg; + + if (name) { + name++; + } + else { + name = strrchr(arg, '\\'); + + if (name == NULL) { + name = arg; + } + else { + name++; + } + } + +#ifdef EXE_EXT + if (!ext || strcmp(ext, EXE_EXT) == 0) { +#else + if (!ext) { +#endif + cmd_data->basename = arg; + cmd_data->output = otProgram; +#if defined(_OSD_POSIX) + cmd_data->options.pic_mode = pic_AVOID; +#endif + newarg = (char *)malloc(strlen(arg) + 5); + strcpy(newarg, arg); +#ifdef EXE_EXT + if (!ext) { + strcat(newarg, EXE_EXT); + } +#endif + cmd_data->output_name = newarg; + return 1; + } + + ext++; + pathlen = name - arg; + + if (strcmp(ext, "la") == 0) { + assert(cmd_data->mode == mLink); + + cmd_data->basename = arg; + cmd_data->static_name.normal = gen_library_name(arg, 0); + cmd_data->shared_name.normal = gen_library_name(arg, 1); + cmd_data->module_name.normal = gen_library_name(arg, 2); + cmd_data->static_name.install = gen_install_name(arg, 0); + cmd_data->shared_name.install = gen_install_name(arg, 1); + cmd_data->module_name.install = gen_install_name(arg, 2); + +#ifdef TRUNCATE_DLL_NAME + if (shared) { + arg = truncate_dll_name(arg); + } +#endif + + cmd_data->output_name = arg; + return 1; + } + + if (strcmp(ext, "lo") == 0) { + cmd_data->basename = arg; + cmd_data->output = otObject; + newarg = (char *)malloc(strlen(arg) + 2); + strcpy(newarg, arg); + ext = strrchr(newarg, '.') + 1; + strcpy(ext, OBJECT_EXT); + cmd_data->output_name = newarg; + return 1; + } + + return 0; +} + +void parse_args(int argc, char *argv[], command_t *cmd_data) +{ + int a; + char *arg; + int argused; + + for (a = 1; a < argc; a++) { + arg = argv[a]; + argused = 1; + + if (arg[0] == '-') { + if (arg[1] == '-') { + argused = parse_long_opt(arg + 2, cmd_data); + } + else { + argused = parse_short_opt(arg + 1, cmd_data); + } + + /* We haven't done anything with it yet, try some of the + * more complicated short opts... */ + if (argused == 0 && a + 1 < argc) { + if (arg[1] == 'o' && !arg[2]) { + arg = argv[++a]; + argused = parse_output_file_name(arg, cmd_data); + } else if (strcmp(arg+1, "MT") == 0) { + if (!cmd_data->options.silent) { + printf("Adding: %s\n", arg); + } + push_count_chars(cmd_data->arglist, arg); + arg = argv[++a]; + if (!cmd_data->options.silent) { + printf(" %s\n", arg); + } + push_count_chars(cmd_data->arglist, arg); + argused = 1; + } else if (strcmp(arg+1, "rpath") == 0) { + /* Aha, we should try to link both! */ + cmd_data->install_path = argv[++a]; + argused = 1; + } else if (strcmp(arg+1, "release") == 0) { + /* Store for later deciphering */ + cmd_data->version_info = argv[++a]; + argused = 1; + } else if (strcmp(arg+1, "version-info") == 0) { + /* Store for later deciphering */ + cmd_data->version_info = argv[++a]; + argused = 1; + } else if (strcmp(arg+1, "export-symbols-regex") == 0) { + /* Skip the argument. */ + ++a; + argused = 1; + } else if (strcmp(arg+1, "release") == 0) { + /* Skip the argument. */ + ++a; + argused = 1; + } else if (strcmp(arg+1, "undefined") == 0) { + cmd_data->undefined_flag = argv[++a]; + argused = 1; + } else if (arg[1] == 'R' && !arg[2]) { + /* -R dir Add dir to runtime library search path. */ + add_runtimedirlib(argv[++a], cmd_data); + argused = 1; + } + } + } else { + argused = parse_input_file_name(arg, cmd_data); + } + + if (!argused) { + if (!cmd_data->options.silent) { + printf("Adding: %s\n", arg); + } + push_count_chars(cmd_data->arglist, arg); + } + } + +} + +#ifdef GEN_EXPORTS +void generate_def_file(command_t *cmd_data) +{ + char def_file[1024]; + char implib_file[1024]; + char *ext; + FILE *hDef; + char *export_args[1024]; + int num_export_args = 0; + char *cmd; + int cmd_size = 0; + int a; + + if (cmd_data->output_name) { + strcpy(def_file, cmd_data->output_name); + strcat(def_file, ".def"); + hDef = fopen(def_file, "w"); + + if (hDef != NULL) { + fprintf(hDef, "LIBRARY '%s' INITINSTANCE\n", nameof(cmd_data->output_name)); + fprintf(hDef, "DATA NONSHARED\n"); + fprintf(hDef, "EXPORTS\n"); + fclose(hDef); + + for (a = 0; a < cmd_data->num_obj_files; a++) { + cmd_size += strlen(cmd_data->obj_files[a]) + 1; + } + + cmd_size += strlen(GEN_EXPORTS) + strlen(def_file) + 3; + cmd = (char *)malloc(cmd_size); + strcpy(cmd, GEN_EXPORTS); + + for (a=0; a < cmd_data->num_obj_files; a++) { + strcat(cmd, " "); + strcat(cmd, cmd_data->obj_files[a] ); + } + + strcat(cmd, ">>"); + strcat(cmd, def_file); + puts(cmd); + export_args[num_export_args++] = SHELL_CMD; + export_args[num_export_args++] = "-c"; + export_args[num_export_args++] = cmd; + export_args[num_export_args++] = NULL; + external_spawn(cmd_data, export_args[0], (const char**)export_args); + cmd_data->arglist[cmd_data->num_args++] = strdup(def_file); + + /* Now make an import library for the dll */ + num_export_args = 0; + export_args[num_export_args++] = DEF2IMPLIB_CMD; + export_args[num_export_args++] = "-o"; + + strcpy(implib_file, ".libs/"); + strcat(implib_file, cmd_data->basename); + ext = strrchr(implib_file, '.'); + + if (ext) + *ext = 0; + + strcat(implib_file, "."); + strcat(implib_file, STATIC_LIB_EXT); + + export_args[num_export_args++] = implib_file; + export_args[num_export_args++] = def_file; + export_args[num_export_args++] = NULL; + external_spawn(cmd_data, export_args[0], (const char**)export_args); + + } + } +} +#endif + +const char* expand_path(const char *relpath) +{ + char foo[PATH_MAX], *newpath; + + getcwd(foo, PATH_MAX-1); + newpath = (char*)malloc(strlen(foo)+strlen(relpath)+2); + strcpy(newpath, foo); + strcat(newpath, "/"); + strcat(newpath, relpath); + return newpath; +} + +void link_fixup(command_t *c) +{ + /* If we were passed an -rpath directive, we need to build + * shared objects too. Otherwise, we should only create static + * libraries. + */ + if (!c->install_path && (c->output == otDynamicLibraryOnly || + c->output == otModule || c->output == otLibrary)) { + c->output = otStaticLibraryOnly; + } + + if (c->output == otDynamicLibraryOnly || + c->output == otModule || + c->output == otLibrary) { + + push_count_chars(c->shared_opts.normal, "-o"); + if (c->output == otModule) { + push_count_chars(c->shared_opts.normal, c->module_name.normal); + } + else { + char *tmp; + push_count_chars(c->shared_opts.normal, c->shared_name.normal); +#ifdef DYNAMIC_INSTALL_NAME + push_count_chars(c->shared_opts.normal, DYNAMIC_INSTALL_NAME); + + tmp = (char*)malloc(PATH_MAX); + strcpy(tmp, c->install_path); + strcat(tmp, strrchr(c->shared_name.normal, '/')); + push_count_chars(c->shared_opts.normal, tmp); +#endif + } + + append_count_chars(c->shared_opts.normal, c->obj_files); + append_count_chars(c->shared_opts.normal, c->shared_opts.dependencies); + + if (c->options.export_all) { +#ifdef GEN_EXPORTS + generate_def_file(c); +#endif + } + } + + if (c->output == otLibrary || c->output == otStaticLibraryOnly) { + push_count_chars(c->static_opts.normal, "-o"); + push_count_chars(c->static_opts.normal, c->output_name); + } + + if (c->output == otProgram) { + if (c->output_name) { + push_count_chars(c->arglist, "-o"); + push_count_chars(c->arglist, c->output_name); + append_count_chars(c->arglist, c->obj_files); + append_count_chars(c->arglist, c->shared_opts.dependencies); + add_dynamic_link_opts(c, c->arglist); + } + } +} + +void post_parse_fixup(command_t *cmd_data) +{ + switch (cmd_data->mode) + { + case mCompile: +#ifdef PIC_FLAG + if (cmd_data->options.pic_mode != pic_AVOID) { + push_count_chars(cmd_data->arglist, PIC_FLAG); + } +#endif + if (cmd_data->output_name) { + push_count_chars(cmd_data->arglist, "-o"); + push_count_chars(cmd_data->arglist, cmd_data->output_name); + } + break; + case mLink: + link_fixup(cmd_data); + break; + case mInstall: + if (cmd_data->output == otLibrary) { + link_fixup(cmd_data); + } + default: + break; + } + +#if USE_OMF + if (cmd_data->output == otObject || + cmd_data->output == otProgram || + cmd_data->output == otLibrary || + cmd_data->output == otDynamicLibraryOnly) { + push_count_chars(cmd_data->arglist, "-Zomf"); + } +#endif + + if (cmd_data->options.shared && + (cmd_data->output == otObject || + cmd_data->output == otLibrary || + cmd_data->output == otDynamicLibraryOnly)) { +#ifdef SHARE_SW + push_count_chars(cmd_data->arglist, SHARE_SW); +#endif + } +} + +int run_mode(command_t *cmd_data) +{ + int rv; + count_chars *cctemp; + + cctemp = (count_chars*)malloc(sizeof(count_chars)); + init_count_chars(cctemp); + + switch (cmd_data->mode) + { + case mCompile: + rv = run_command(cmd_data, cmd_data->arglist); + if (rv) { + return rv; + } + break; + case mInstall: + /* Well, we'll assume it's a file going to a directory... */ + /* For brain-dead install-sh based scripts, we have to repeat + * the command N-times. install-sh should die. + */ + if (!cmd_data->output_name) { + rv = run_command(cmd_data, cmd_data->arglist); + if (rv) { + return rv; + } + } + if (cmd_data->output_name) { + append_count_chars(cctemp, cmd_data->arglist); + insert_count_chars(cctemp, + cmd_data->output_name, + cctemp->num - 1); + rv = run_command(cmd_data, cctemp); + if (rv) { + return rv; + } + clear_count_chars(cctemp); + } + if (cmd_data->static_name.install) { + append_count_chars(cctemp, cmd_data->arglist); + insert_count_chars(cctemp, + cmd_data->static_name.install, + cctemp->num - 1); + rv = run_command(cmd_data, cctemp); + if (rv) { + return rv; + } +#if defined(__APPLE__) && defined(RANLIB) + /* From the Apple libtool(1) manpage on Tiger/10.4: + * ---- + * With the way libraries used to be created, errors were possible + * if the library was modified with ar(1) and the table of + * contents was not updated by rerunning ranlib(1). Thus the + * link editor, ld, warns when the modification date of a library + * is more recent than the creation date of its table of + * contents. Unfortunately, this means that you get the warning + * even if you only copy the library. + * ---- + * + * This means that when we install the static archive, we need to + * rerun ranlib afterwards. + */ + const char *lib_args[3], *static_lib_name; + char *tmp; + size_t len1, len2; + len1 = strlen(cmd_data->arglist->vals[cmd_data->arglist->num - 1]); + + static_lib_name = jlibtool_basename(cmd_data->static_name.install); + len2 = strlen(static_lib_name); + + tmp = malloc(len1 + len2 + 2); + + snprintf(tmp, len1 + len2 + 2, "%s/%s", + cmd_data->arglist->vals[cmd_data->arglist->num - 1], + static_lib_name); + + lib_args[0] = RANLIB; + lib_args[1] = tmp; + lib_args[2] = NULL; + external_spawn(cmd_data, RANLIB, lib_args); + free(tmp); +#endif + clear_count_chars(cctemp); + } + if (cmd_data->shared_name.install) { + append_count_chars(cctemp, cmd_data->arglist); + insert_count_chars(cctemp, + cmd_data->shared_name.install, + cctemp->num - 1); + rv = run_command(cmd_data, cctemp); + if (rv) { + return rv; + } + clear_count_chars(cctemp); + } + if (cmd_data->module_name.install) { + append_count_chars(cctemp, cmd_data->arglist); + insert_count_chars(cctemp, + cmd_data->module_name.install, + cctemp->num - 1); + rv = run_command(cmd_data, cctemp); + if (rv) { + return rv; + } + clear_count_chars(cctemp); + } + break; + case mLink: + if (!cmd_data->options.dry_run) { + /* Check first to see if the dir already exists! */ + safe_mkdir(".libs"); + } + + if (cmd_data->output == otStaticLibraryOnly || + cmd_data->output == otLibrary) { +#ifdef RANLIB + const char *lib_args[3]; +#endif + /* Removes compiler! */ + cmd_data->program = LIBRARIAN; + push_count_chars(cmd_data->program_opts, LIBRARIAN_OPTS); + push_count_chars(cmd_data->program_opts, + cmd_data->static_name.normal); + + rv = run_command(cmd_data, cmd_data->obj_files); + if (rv) { + return rv; + } + +#ifdef RANLIB + lib_args[0] = RANLIB; + lib_args[1] = cmd_data->static_name.normal; + lib_args[2] = NULL; + external_spawn(cmd_data, RANLIB, lib_args); +#endif + } + + if (cmd_data->output == otDynamicLibraryOnly || + cmd_data->output == otModule || + cmd_data->output == otLibrary) { + cmd_data->program = NULL; + clear_count_chars(cmd_data->program_opts); + + append_count_chars(cmd_data->program_opts, cmd_data->arglist); + if (cmd_data->output == otModule) { +#ifdef MODULE_OPTS + push_count_chars(cmd_data->program_opts, MODULE_OPTS); +#endif + } else { +#ifdef SHARED_OPTS + push_count_chars(cmd_data->program_opts, SHARED_OPTS); +#endif +#ifdef dynamic_link_version_func + push_count_chars(cmd_data->program_opts, + dynamic_link_version_func(cmd_data->version_info)); +#endif + } + add_dynamic_link_opts(cmd_data, cmd_data->program_opts); + + rv = run_command(cmd_data, cmd_data->shared_opts.normal); + if (rv) { + return rv; + } + } + if (cmd_data->output == otProgram) { + rv = run_command(cmd_data, cmd_data->arglist); + if (rv) { + return rv; + } + } + break; + default: + break; + } + + return 0; +} + +void cleanup_tmp_dir(const char *dirname) +{ + DIR *dir; + struct dirent *entry; + char fullname[1024]; + + dir = opendir(dirname); + + if (dir == NULL) + return; + + while ((entry = readdir(dir)) != NULL) { + if (entry->d_name[0] != '.') { + strcpy(fullname, dirname); + strcat(fullname, "/"); + strcat(fullname, entry->d_name); + remove(fullname); + } + } + + rmdir(dirname); +} + +void cleanup_tmp_dirs(command_t *cmd_data) +{ + int d; + + for (d = 0; d < cmd_data->tmp_dirs->num; d++) { + cleanup_tmp_dir(cmd_data->tmp_dirs->vals[d]); + } +} + +int ensure_fake_uptodate(command_t *cmd_data) +{ + /* FIXME: could do the stat/touch here, but nah... */ + const char *touch_args[3]; + + if (cmd_data->mode == mInstall) { + return 0; + } + if (!cmd_data->fake_output_name) { + return 0; + } + + touch_args[0] = "touch"; + touch_args[1] = cmd_data->fake_output_name; + touch_args[2] = NULL; + return external_spawn(cmd_data, "touch", touch_args); +} + +/* Store the install path in the *.la file */ +int add_for_runtime(command_t *cmd_data) +{ + if (cmd_data->mode == mInstall) { + return 0; + } + if (cmd_data->output == otDynamicLibraryOnly || + cmd_data->output == otLibrary) { + FILE *f=fopen(cmd_data->fake_output_name,"w"); + if (f == NULL) { + return -1; + } + fprintf(f,"%s\n", cmd_data->install_path); + fclose(f); + return(0); + } else { + return(ensure_fake_uptodate(cmd_data)); + } +} + +int main(int argc, char *argv[]) +{ + int rc; + command_t cmd_data; + + memset(&cmd_data, 0, sizeof(cmd_data)); + + cmd_data.options.pic_mode = pic_UNKNOWN; + + cmd_data.program_opts = (count_chars*)malloc(sizeof(count_chars)); + init_count_chars(cmd_data.program_opts); + cmd_data.arglist = (count_chars*)malloc(sizeof(count_chars)); + init_count_chars(cmd_data.arglist); + cmd_data.tmp_dirs = (count_chars*)malloc(sizeof(count_chars)); + init_count_chars(cmd_data.tmp_dirs); + cmd_data.obj_files = (count_chars*)malloc(sizeof(count_chars)); + init_count_chars(cmd_data.obj_files); + cmd_data.dep_rpaths = (count_chars*)malloc(sizeof(count_chars)); + init_count_chars(cmd_data.dep_rpaths); + cmd_data.rpaths = (count_chars*)malloc(sizeof(count_chars)); + init_count_chars(cmd_data.rpaths); + cmd_data.static_opts.normal = (count_chars*)malloc(sizeof(count_chars)); + init_count_chars(cmd_data.static_opts.normal); + cmd_data.shared_opts.normal = (count_chars*)malloc(sizeof(count_chars)); + init_count_chars(cmd_data.shared_opts.normal); + cmd_data.shared_opts.dependencies = (count_chars*)malloc(sizeof(count_chars)); + init_count_chars(cmd_data.shared_opts.dependencies); + + cmd_data.mode = mUnknown; + cmd_data.output = otGeneral; + + parse_args(argc, argv, &cmd_data); + post_parse_fixup(&cmd_data); + + if (cmd_data.mode == mUnknown) { + exit(0); + } + + rc = run_mode(&cmd_data); + + if (!rc) { + add_for_runtime(&cmd_data); + } + + cleanup_tmp_dirs(&cmd_data); + return rc; +} diff --git a/build/libaprapp.dsp b/build/libaprapp.dsp new file mode 100644 index 00000000000..2e3d2001331 --- /dev/null +++ b/build/libaprapp.dsp @@ -0,0 +1,144 @@ +# Microsoft Developer Studio Project File - Name="libaprapp" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=libaprapp - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "libaprapp.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "libaprapp.mak" CFG="libaprapp - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "libaprapp - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "libaprapp - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "libaprapp - x64 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "libaprapp - x64 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "libaprapp - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "..\Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c +# ADD CPP /nologo /MD /W3 /O2 /Oy- /Zi /I "../include" /I "../include/arch" /I "../include/arch/win32" /I "../include/arch/unix" /D "NDEBUG" /D "WINNT" /D "WIN32" /D "_WINDOWS" /D "APR_APP" /Fo"$(INTDIR)\" /Fd"$(OUTDIR)\libaprapp-2" /FD /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"..\Release\libaprapp-2.lib" + +!ELSEIF "$(CFG)" == "libaprapp - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "..\Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /EHsc /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /c +# ADD CPP /nologo /MDd /W3 /EHsc /Zi /Od /I "../include" /I "../include/arch" /I "../include/arch/win32" /I "../include/arch/unix" /D "_DEBUG" /D "WINNT" /D "WIN32" /D "_WINDOWS" /D "APR_APP" /Fo"$(INTDIR)\" /Fd"$(OUTDIR)\libaprapp-2" /FD /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"..\Debug\libaprapp-2.lib" + +!ELSEIF "$(CFG)" == "libaprapp - x64 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "..\x64\Release" +# PROP BASE Intermediate_Dir "x64\Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\x64\Release" +# PROP Intermediate_Dir "x64\Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c +# ADD CPP /nologo /MD /W3 /O2 /Oy- /Zi /I "../include" /I "../include/arch" /I "../include/arch/win32" /I "../include/arch/unix" /D "NDEBUG" /D "WINNT" /D "WIN32" /D "_WINDOWS" /D "APR_APP" /Fo"$(INTDIR)\" /Fd"$(OUTDIR)\libaprapp-2" /FD /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"..\x64\Release\libaprapp-2.lib" + +!ELSEIF "$(CFG)" == "libaprapp - x64 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "..\x64\Debug" +# PROP BASE Intermediate_Dir "x64\Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\x64\Debug" +# PROP Intermediate_Dir "x64\Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /EHsc /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /c +# ADD CPP /nologo /MDd /W3 /EHsc /Zi /Od /I "../include" /I "../include/arch" /I "../include/arch/win32" /I "../include/arch/unix" /D "_DEBUG" /D "WINNT" /D "WIN32" /D "_WINDOWS" /D "APR_APP" /Fo"$(INTDIR)\" /Fd"$(OUTDIR)\libaprapp-2" /FD /c +# ADD BASE RSC /l 0x409 +# ADD RSC /l 0x409 +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"..\x64\Debug\libaprapp-2.lib" + +!ENDIF + +# Begin Target + +# Name "libaprapp - Win32 Release" +# Name "libaprapp - Win32 Debug" +# Name "libaprapp - x64 Release" +# Name "libaprapp - x64 Debug" +# Begin Source File + +SOURCE=..\misc\win32\apr_app.c +# End Source File +# Begin Source File + +SOURCE=..\misc\win32\internal.c +# End Source File +# End Target +# End Project diff --git a/build/lineends.pl b/build/lineends.pl new file mode 100644 index 00000000000..8aa735cc827 --- /dev/null +++ b/build/lineends.pl @@ -0,0 +1,150 @@ +#!/usr/local/bin/perl +# +# Heuristically converts line endings to the current OS's preferred format +# +# All existing line endings must be identical (e.g. lf's only, or even +# the accidental cr.cr.lf sequence.) If some lines end lf, and others as +# cr.lf, the file is presumed binary. If the cr character appears anywhere +# except prefixed to an lf, the file is presumed binary. If there is no +# change in the resulting file size, or the file is binary, the conversion +# is discarded. +# +# Todo: Handle NULL stdin characters gracefully. +# + +use IO::File; +use File::Find; + +# The ignore list is '-' seperated, with this leading hyphen and +# trailing hyphens in ever concatinated list below. +$ignore = "-"; + +# Image formats +$ignore .= "gif-jpg-jpeg-png-ico-bmp-"; + +# Archive formats +$ignore .= "tar-gz-z-zip-jar-war-bz2-tgz-"; + +# Many document formats +$ignore .= "eps-psd-pdf-chm-ai-"; + +# Some encodings +$ignore .= "ucs2-ucs4-"; + +# Some binary objects +$ignore .= "class-so-dll-exe-obj-lib-a-o-lo-slo-sl-dylib-"; + +# Some build env files +$ignore .= "mcp-xdc-ncb-opt-pdb-ilk-exp-res-pch-idb-sbr-"; + +$preservedate = 1; + +$forceending = 0; + +$givenpaths = 0; + +$notnative = 0; + +while (defined @ARGV[0]) { + if (@ARGV[0] eq '--touch') { + $preservedate = 0; + } + elsif (@ARGV[0] eq '--nocr') { + $notnative = -1; + } + elsif (@ARGV[0] eq '--cr') { + $notnative = 1; + } + elsif (@ARGV[0] eq '--force') { + $forceending = 1; + } + elsif (@ARGV[0] eq '--FORCE') { + $forceending = 2; + } + elsif (@ARGV[0] =~ m/^-/) { + die "What is " . @ARGV[0] . " supposed to mean?\n\n" + . "Syntax:\t$0 [option()s] [path(s)]\n\n" . <<'OUTCH' +Where: paths specifies the top level directory to convert (default of '.') + options are; + + --cr keep/add one ^M + --nocr remove ^M's + --touch the datestamp (default: keeps date/attribs) + --force mismatched corrections (unbalanced ^M's) + --FORCE all files regardless of file name! + +OUTCH + } + else { + find(\&totxt, @ARGV[0]); + print "scanned " . @ARGV[0] . "\n"; + $givenpaths = 1; + } + shift @ARGV; +} + +if (!$givenpaths) { + find(\&totxt, '.'); + print "did .\n"; +} + +sub totxt { + $oname = $_; + $tname = '.#' . $_; + if (!-f) { + return; + } + @exts = split /\./; + if ($forceending < 2) { + while ($#exts && ($ext = pop(@exts))) { + if ($ignore =~ m|-$ext-|i) { + return; + } + } + } + return if ($File::Find::dir =~ m|^(.+/)?.svn(/.+)?$|); + @ostat = stat($oname); + $srcfl = new IO::File $oname, "r" or die; + $dstfl = new IO::File $tname, "w" or die; + binmode $srcfl; + if ($notnative) { + binmode $dstfl; + } + undef $t; + while (<$srcfl>) { + if (s/(\r*)\n$/\n/) { + $n = length $1; + if (!defined $t) { + $t = $n; + } + if (!$forceending && (($n != $t) || m/\r/)) { + print "mismatch in " .$oname. ":" .$n. " expected " .$t. "\n"; + undef $t; + last; + } + elsif ($notnative > 0) { + s/\n$/\r\n/; + } + } + print $dstfl $_; + } + if (defined $t && (tell $srcfl == tell $dstfl)) { + undef $t; + } + undef $srcfl; + undef $dstfl; + if (defined $t) { + unlink $oname or die; + rename $tname, $oname or die; + @anames = ($oname); + if ($preservedate) { + utime $ostat[9], $ostat[9], @anames; + } + chmod $ostat[2] & 07777, @anames; + chown $ostat[5], $ostat[6], @anames; + print "Converted file " . $oname . " to text in " . $File::Find::dir . "\n"; + } + else { + unlink $tname or die; + } +} diff --git a/build/make_exports.awk b/build/make_exports.awk new file mode 100644 index 00000000000..1d12fc65abe --- /dev/null +++ b/build/make_exports.awk @@ -0,0 +1,150 @@ + +BEGIN { + printf("/*\n") + printf(" * THIS FILE WAS AUTOGENERATED BY make_exports.awk\n") + printf(" *\n") + printf(" * This is an ugly hack that needs to be here, so\n") + printf(" * that libtool will link all of the APR functions\n") + printf(" * into server regardless of whether the base server\n") + printf(" * uses them.\n") + printf(" */\n") + printf("\n") + printf("#define CORE_PRIVATE\n") + printf("\n") + + for (i = 1; i < ARGC; i++) { + file = ARGV[i] + sub("([^/]*[/])*", "", file) + printf("#include \"%s\"\n", file) + } + + printf("\n") + printf("const void *ap_ugly_hack = NULL;\n") + printf("\n") + + TYPE_NORMAL = 0 + TYPE_HEADER = 1 + + stackptr = 0 +} + +function push(line) { + stack[stackptr] = line + stackptr++ +} + +function do_output() { + printf("/*\n") + printf(" * %s\n", FILENAME) + printf(" */\n") + + for (i = 0; i < stackptr; i++) { + printf("%s\n", stack[i]) + } + + stackptr = 0 + + printf("\n"); +} + +function enter_scope(type) { + scope++ + scope_type[scope] = type + scope_stack[scope] = stackptr + delete scope_used[scope] +} + +function leave_scope() { + used = scope_used[scope] + + if (!used) + stackptr = scope_stack[scope] + + scope-- + if (used) { + scope_used[scope] = 1 + + if (!scope) + do_output() + } +} + +function add_symbol(symbol) { + if (!index(symbol, "#")) { + push("const void *ap_hack_" symbol " = (const void *)" symbol ";") + scope_used[scope] = 1 + } +} + +/^[ \t]*AP[RUI]?_(CORE_)?DECLARE[^(]*[(][^)]*[)]([^ ]* )*[^(]+[(]/ { + sub("[ \t]*AP[RUI]?_(CORE_)?DECLARE[^(]*[(][^)]*[)][ \t]*", "") + sub("[(].*", "") + sub("([^ ]* (^([ \t]*[(])))+", "") + + add_symbol($0) + next +} + +/^[ \t]*AP_DECLARE_HOOK[^(]*[(][^)]*/ { + split($0, args, ",") + symbol = args[2] + sub("^[ \t]+", "", symbol) + sub("[ \t]+$", "", symbol) + + add_symbol("ap_hook_" symbol) + add_symbol("ap_hook_get_" symbol) + add_symbol("ap_run_" symbol) + next +} + +/^[ \t]*APR_POOL_DECLARE_ACCESSOR[^(]*[(][^)]*[)]/ { + sub("[ \t]*APR_POOL_DECLARE_ACCESSOR[^(]*[(]", "", $0) + sub("[)].*$", "", $0) + add_symbol("apr_" $0 "_pool_get") + next +} + +/^[ \t]*APR_DECLARE_INHERIT_SET[^(]*[(][^)]*[)]/ { + sub("[ \t]*APR_DECLARE_INHERIT_SET[^(]*[(]", "", $0) + sub("[)].*$", "", $0) + add_symbol("apr_" $0 "_inherit_set") + next +} + +/^[ \t]*APR_DECLARE_INHERIT_UNSET[^(]*[(][^)]*[)]/ { + sub("[ \t]*APR_DECLARE_INHERIT_UNSET[^(]*[(]", "", $0) + sub("[)].*$", "", $0) + add_symbol("apr_" $0 "_inherit_unset") + next +} + +/^#[ \t]*if(ndef| !defined[(])([^_]*_)*H/ { + enter_scope(TYPE_HEADER) + next +} + +/^#[ \t]*if([n]?def)? / { + enter_scope(TYPE_NORMAL) + push($0) + next +} + +/^#[ \t]*endif/ { + if (scope_type[scope] == TYPE_NORMAL) + push($0) + + leave_scope() + next +} + +/^#[ \t]*else/ { + push($0) + next +} + +/^#[ \t]*elif/ { + push($0) + next +} + + diff --git a/build/make_nw_export.awk b/build/make_nw_export.awk new file mode 100644 index 00000000000..14f60ffdbb1 --- /dev/null +++ b/build/make_nw_export.awk @@ -0,0 +1,115 @@ +# 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. +# +# Based on apr's make_export.awk, which is +# based on Ryan Bloom's make_export.pl +# + +BEGIN { + add_symbol("apr_wait_for_io_or_timeout") +} + +function add_symbol(sym_name) { + sub(" ", "", sym_name) + exports[++idx] = sym_name +} + +# List of functions that we don't support, yet?? +#/apr_##name##_set_inherit/{next} +#/apr_##name##_unset_inherit/{next} +#/apr_##name##_perms_set/{next} +/apr_socket_perms_set/{next} + +/^[ \t]*AP[RUI]?_DECLARE[^(]*[(][^)]*[)]([^ ]* )*[^(]+[(]/ { + sub("[ \t]*AP[RUI]?_DECLARE[^(]*[(][^)]*[)][ \t]*", "") + sub("[(].*", "") + sub("([^ ]* (^([ \t]*[(])))+", "") + add_symbol($0) + next +} + +/^[ \t]*AP_DECLARE_HOOK[^(]*[(][^)]*/ { + split($0, args, ",") + symbol = args[2] + sub("^[ \t]+", "", symbol) + sub("[ \t]+$", "", symbol) + add_symbol("ap_hook_" symbol) + add_symbol("ap_hook_get_" symbol) + add_symbol("ap_run_" symbol) + next +} + +/^[ \t]*APR_POOL_DECLARE_ACCESSOR[^(]*[(][^)]*[)]/ { + sub("[ \t]*APR_POOL_DECLARE_ACCESSOR[^(]*[(]", "", $0) + sub("[)].*$", "", $0) + add_symbol("apr_" $0 "_pool_get") + next +} + +/^[ \t]*APR_DECLARE_INHERIT_SET[^(]*[(][^)]*[)]/ { + sub("[ \t]*APR_DECLARE_INHERIT_SET[^(]*[(]", "", $0) + sub("[)].*$", "", $0) + add_symbol("apr_" $0 "_inherit_set") + next +} + +/^[ \t]*APR_DECLARE_INHERIT_UNSET[^(]*[(][^)]*[)]/ { + sub("[ \t]*APR_DECLARE_INHERIT_UNSET[^(]*[(]", "", $0) + sub("[)].*$", "", $0) + add_symbol("apr_" $0 "_inherit_unset") + next +} + +#/^[ \t]*APR_PERMS_SET_IMPLEMENT[^(]*[(][^)]*[)]/ { +# sub("[ \t]*APR_PERMS_SET_IMPLEMENT[^(]*[(]", "", $0) +# sub("[)].*$", "", $0) +# add_symbol("apr_" $0 "_perms_set") +# next +#} + +/^[ \t]*AP[RUI]?_DECLARE_DATA .*;/ { + gsub(/[*;\n\r]/, "", $NF) + gsub(/\[.*\]/, "", $NF) + add_symbol($NF) +} + + +END { + printf("Added %d symbols to export list.\n", idx) > "/dev/stderr" + # sort symbols with shell sort + increment = int(idx / 2) + while (increment > 0) { + for (i = increment+1; i <= idx; i++) { + j = i + temp = exports[i] + while ((j >= increment+1) && (exports[j-increment] > temp)) { + exports[j] = exports[j-increment] + j -= increment + } + exports[j] = temp + } + if (increment == 2) + increment = 1 + else + increment = int(increment*5/11) + } + # print the array + printf(" (%s)\n", EXPPREFIX) + while (x < idx - 1) { + printf(" %s,\n", exports[++x]) + } + printf(" %s\n", exports[++x]) +} + diff --git a/build/make_var_export.awk b/build/make_var_export.awk new file mode 100644 index 00000000000..59922758d58 --- /dev/null +++ b/build/make_var_export.awk @@ -0,0 +1,59 @@ +# Based on apr's make_export.awk, which is +# based on Ryan Bloom's make_export.pl + +/^#[ \t]*if(def)? (AP[RUI]?_|!?defined).*/ { + if (old_filename != FILENAME) { + if (old_filename != "") printf("%s", line) + macro_no = 0 + found = 0 + count = 0 + old_filename = FILENAME + line = "" + } + macro_stack[macro_no++] = macro + macro = substr($0, length($1)+2) + count++ + line = line "#ifdef " macro "\n" + next +} + +/^#[ \t]*endif/ { + if (count > 0) { + count-- + line = line "#endif /* " macro " */\n" + macro = macro_stack[--macro_no] + } + if (count == 0) { + if (found != 0) { + printf("%s", line) + } + line = "" + } + next +} + +function add_symbol (sym_name) { + if (count) { + found++ + } + for (i = 0; i < count; i++) { + line = line "\t" + } + line = line sym_name "\n" + + if (count == 0) { + printf("%s", line) + line = "" + } +} + +/^[ \t]*(extern[ \t]+)?AP[RUI]?_DECLARE_DATA .*;$/ { + varname = $NF; + gsub( /[*;]/, "", varname); + gsub( /\[.*\]/, "", varname); + add_symbol(varname); +} + +END { + printf("%s", line) +} diff --git a/helpers/mkdir.sh b/build/mkdir.sh similarity index 69% rename from helpers/mkdir.sh rename to build/mkdir.sh index 4cd33c5671c..c59f03e181b 100755 --- a/helpers/mkdir.sh +++ b/build/mkdir.sh @@ -23,10 +23,18 @@ for file in ${1+"$@"} ; do pathcomp="$pathcomp$d" case "$pathcomp" in -* ) pathcomp=./$pathcomp ;; + ?: ) pathcomp="$pathcomp/" + continue ;; esac if test ! -d "$pathcomp"; then echo "mkdir $pathcomp" 1>&2 - mkdir "$pathcomp" || errstatus=$? + thiserrstatus=0 + mkdir "$pathcomp" || thiserrstatus=$? + # ignore errors due to races if a parallel mkdir.sh already + # created the dir + if test $thiserrstatus != 0 && test ! -d "$pathcomp" ; then + errstatus=$thiserrstatus + fi fi pathcomp="$pathcomp/" done diff --git a/build/nw_export.h b/build/nw_export.h new file mode 100644 index 00000000000..c69442e8c3e --- /dev/null +++ b/build/nw_export.h @@ -0,0 +1,75 @@ +/* Must include apr.h / apu.h first so that we can undefine +** the standard prototypes macros after it messes with them. +*/ +#include "apr.h" + +#undef APR_DECLARE +#undef APR_DECLARE_NONSTD +#undef APR_DECLARE_HOOK +#undef APR_POOL_DECLARE_ACCESSOR +#undef APR_DECLARE_DATA + +/* Preprocess all of the standard APR headers. */ +#include "apr_allocator.h" +#include "apr_anylock.h" +#include "apr_atomic.h" +#include "apr_base64.h" +#include "apr_buckets.h" +#include "apr_date.h" +#include "apr_dbd.h" +#include "apr_dbm.h" +#include "apr_dbm_private.h" +#include "apr_dso.h" +#include "apr_env.h" +#include "apr_errno.h" +#include "apr_escape.h" +#include "apr_file_info.h" +#include "apr_file_io.h" +#include "apr_fnmatch.h" +#include "apr_general.h" +#include "apr_getopt.h" +#include "apr_global_mutex.h" +#include "apr_hash.h" +#include "apr_hooks.h" +#include "apr_inherit.h" +#include "apr_lib.h" +#include "apr_md4.h" +#include "apr_md5.h" +#include "apr_memcache.h" +#include "apr_mmap.h" +#include "apr_network_io.h" +#include "apr_optional.h" +#include "apr_optional_hooks.h" +#include "apr_poll.h" +#include "apr_pools.h" +#include "apr_portable.h" +#include "apr_proc_mutex.h" +#include "apr_queue.h" +#include "apr_random.h" +#include "apr_reslist.h" +#include "apr_ring.h" +#include "apr_rmm.h" +#include "apr_sdbm.h" +#include "apr_sha1.h" +#include "apr_shm.h" +#include "apr_signal.h" +#include "apr_siphash.h" +#include "apr_skiplist.h" +#include "apr_strings.h" +#include "apr_strmatch.h" +#include "apr_support.h" +#include "apr_tables.h" +#include "apr_thread_cond.h" +#include "apr_thread_mutex.h" +#include "apr_thread_pool.h" +#include "apr_thread_proc.h" +#include "apr_thread_rwlock.h" +#include "apr_time.h" +#include "apr_uri.h" +#include "apr_user.h" +#include "apr_uuid.h" +#include "apr_version.h" +#include "apr_want.h" +#include "apr_xlate.h" +#include "apr_xml.h" +#include "apu_want.h" diff --git a/build/nw_ver.awk b/build/nw_ver.awk new file mode 100644 index 00000000000..0285e990022 --- /dev/null +++ b/build/nw_ver.awk @@ -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. + +BEGIN { + + # fetch APR version numbers from input file and write them to STDOUT + + while ((getline < ARGV[1]) > 0) { + if (match ($0, /^#define AP._MAJOR_VERSION/)) { + ver_major = $3; + } + else if (match ($0, /^#define AP._MINOR_VERSION/)) { + ver_minor = $3; + } + else if (match ($0, /^#define AP._PATCH_VERSION/)) { + ver_patch = $3; + } + else if (match ($0, /^#define AP._IS_DEV_VERSION/)) { + ver_devbuild = 1; + } + } + if (ver_devbuild) { + ver_dev = "-dev" + if (ARGV[2]) { + while ((getline < ARGV[2]) > 0) { + if (match ($0, /^\/repos\/asf\/!svn\/ver\/[0-9]+\/apr\/(apr|apr-util)\/(trunk|branches\/[0-9]\.[0-9]\.x)$/)) { + gsub(/^\/repos\/asf\/!svn\/ver\/|\/apr\/(apr|apr-util)\/(trunk|branches\/[0-9]\.[0-9]\.x)$/, "", $0); + ver_dev = svn_rev = "-r" $0; + } + } + } + } + + if (WANTED) { + ver_num = ver_major * 1000000 + ver_minor * 1000 + ver_patch; + if (ver_num < WANTED) { + print "ERROR: APR version " ver_str " does NOT match!"; + exit 1; + } else if (ver_num > (WANTED + 1000)) { + print "WARNING: APR version " ver_str " higher than expected!"; + exit 0; + } else { + print "OK: APR version " ver_str ""; + exit 0; + } + } else { + ver_nlm = ver_major "," ver_minor "," ver_patch; + ver_str = ver_major "." ver_minor "." ver_patch ver_dev; + print "VERSION = " ver_nlm ""; + print "VERSION_STR = " ver_str ""; + print "VERSION_MAJMIN = " ver_major ver_minor ""; + # print "COPYRIGHT_STR = " copyright_str ""; + print "SVN_REVISION = " svn_rev ""; + } + +} + + diff --git a/build/pkg/README b/build/pkg/README new file mode 100644 index 00000000000..ce1c9b73a95 --- /dev/null +++ b/build/pkg/README @@ -0,0 +1,20 @@ +The script in this directory will attempt to build a Solaris package +out of a source tree for APR. + +To build a package, make sure you are in the root of the source tree, +and run: + +build/pkg/buildpkg.sh + +A Solaris package called apr-<version>-<architecture>-local.gz will be +created in the root of the source tree. + +By default, if you attempt to build packages for apr-util, it will +search for the sources for apr in: + +../apr + +You may override the location of apr like so: + +build/pkg/buildpkg.sh --with-apr=some/other/path + diff --git a/build/pkg/buildpkg.sh b/build/pkg/buildpkg.sh new file mode 100755 index 00000000000..073e89d746f --- /dev/null +++ b/build/pkg/buildpkg.sh @@ -0,0 +1,72 @@ +#!/bin/sh +# 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. +# +# + +# buildpkg.sh: This script builds a Solaris PKG from the source tree +# provided. + +PREFIX=/usr/local +TEMPDIR=/var/tmp/$USER/apr-root +rm -rf $TEMPDIR + +apr_src_dir=. + +while test $# -gt 0 +do + # Normalize + case "$1" in + -*=*) optarg=`echo "$1" | sed 's/[-_a-zA-Z0-9]*=//'` ;; + *) optarg= ;; + esac + + case "$1" in + --with-apr=*) + apr_src_dir=$optarg + ;; + esac + + shift +done + +if [ -f "$apr_src_dir/configure.in" ]; then + cd $apr_src_dir +else + echo "The apr source could not be found within $apr_src_dir" + echo "Usage: buildpkg [--with-apr=dir]" + exit 1 +fi + +./configure --prefix=$PREFIX +make +make install DESTDIR=$TEMPDIR +rm $TEMPDIR$PREFIX/lib/apr.exp +. build/pkg/pkginfo +cp build/pkg/pkginfo $TEMPDIR$PREFIX + +current=`pwd` +cd $TEMPDIR$PREFIX +echo "i pkginfo=./pkginfo" > prototype +find . -print | grep -v ./prototype | grep -v ./pkginfo | pkgproto | awk '{print $1" "$2" "$3" "$4" root bin"}' >> prototype +mkdir $TEMPDIR/pkg +pkgmk -r $TEMPDIR$PREFIX -d $TEMPDIR/pkg + +cd $current +pkgtrans -s $TEMPDIR/pkg $current/$NAME-$VERSION-$ARCH-local +gzip $current/$NAME-$VERSION-$ARCH-local + +rm -rf $TEMPDIR + diff --git a/build/pkg/pkginfo.in b/build/pkg/pkginfo.in new file mode 100644 index 00000000000..f389b26901a --- /dev/null +++ b/build/pkg/pkginfo.in @@ -0,0 +1,11 @@ +PKG="ASFapr-1" +NAME="apr" +ARCH="@target_cpu@" +VERSION="@APR_DOTTED_VERSION@" +CATEGORY="application" +VENDOR="Apache Software Foundation" +EMAIL="dev@apr.apache.org" +PSTAMP="dev@apr.apache.org" +BASEDIR="@prefix@" +CLASSES="none" + diff --git a/build/preaprapp.dsp b/build/preaprapp.dsp new file mode 100644 index 00000000000..b17aa7b0786 --- /dev/null +++ b/build/preaprapp.dsp @@ -0,0 +1,131 @@ +# Microsoft Developer Studio Project File - Name="preaprapp" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) External Target" 0x0106 + +CFG=preaprapp - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "preaprapp.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "preaprapp.mak" CFG="preaprapp - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "preaprapp - Win32 Release" (based on "Win32 (x86) External Target") +!MESSAGE "preaprapp - Win32 Debug" (based on "Win32 (x86) External Target") +!MESSAGE "preaprapp - x64 Release" (based on "Win32 (x86) External Target") +!MESSAGE "preaprapp - x64 Debug" (based on "Win32 (x86) External Target") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" + +!IF "$(CFG)" == "preaprapp - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "" +# PROP BASE Intermediate_Dir "" +# PROP BASE Cmd_Line "NMAKE /nologo /f NUL" +# PROP BASE Rebuild_Opt "/a" +# PROP BASE Target_File "preaprapp.exe" +# PROP BASE Bsc_Name "preaprapp.bsc" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "" +# PROP Intermediate_Dir "" +# PROP Cmd_Line "NMAKE /nologo /f NUL" +# PROP Rebuild_Opt "/a" +# PROP Bsc_Name "" +# PROP Target_Dir "" + +!ELSEIF "$(CFG)" == "preaprapp - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "" +# PROP BASE Intermediate_Dir "" +# PROP BASE Cmd_Line "NMAKE /nologo /f NUL" +# PROP BASE Rebuild_Opt "/a" +# PROP BASE Target_File "preaprapp.exe" +# PROP BASE Bsc_Name "preaprapp.bsc" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "" +# PROP Intermediate_Dir "" +# PROP Cmd_Line "NMAKE /nologo /f NUL" +# PROP Rebuild_Opt "/a" +# PROP Bsc_Name "" +# PROP Target_Dir "" + +!ELSEIF "$(CFG)" == "preaprapp - x64 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "" +# PROP BASE Intermediate_Dir "" +# PROP BASE Cmd_Line "NMAKE /nologo /f NUL" +# PROP BASE Rebuild_Opt "/a" +# PROP BASE Target_File "preaprapp.exe" +# PROP BASE Bsc_Name "preaprapp.bsc" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "" +# PROP Intermediate_Dir "" +# PROP Cmd_Line "NMAKE /nologo /f NUL" +# PROP Rebuild_Opt "/a" +# PROP Bsc_Name "" +# PROP Target_Dir "" + +!ELSEIF "$(CFG)" == "preaprapp - x64 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "" +# PROP BASE Intermediate_Dir "" +# PROP BASE Cmd_Line "NMAKE /nologo /f NUL" +# PROP BASE Rebuild_Opt "/a" +# PROP BASE Target_File "preaprapp.exe" +# PROP BASE Bsc_Name "preaprapp.bsc" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "" +# PROP Intermediate_Dir "" +# PROP Cmd_Line "NMAKE /nologo /f NUL" +# PROP Rebuild_Opt "/a" +# PROP Bsc_Name "" +# PROP Target_Dir "" + +!ENDIF + +# Begin Target + +# Name "preaprapp - Win32 Release" +# Name "preaprapp - Win32 Debug" +# Name "preaprapp - x64 Release" +# Name "preaprapp - x64 Debug" + +!IF "$(CFG)" == "preaprapp - Win32 Release" + +!ELSEIF "$(CFG)" == "preaprapp - Win32 Debug" + +!ELSEIF "$(CFG)" == "preaprapp - x64 Release" + +!ELSEIF "$(CFG)" == "preaprapp - x64 Debug" + +!ENDIF + +# End Target +# End Project diff --git a/build/prelibaprapp.dsp b/build/prelibaprapp.dsp new file mode 100644 index 00000000000..b370a14f34e --- /dev/null +++ b/build/prelibaprapp.dsp @@ -0,0 +1,131 @@ +# Microsoft Developer Studio Project File - Name="prelibaprapp" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) External Target" 0x0106 + +CFG=prelibaprapp - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "prelibaprapp.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "prelibaprapp.mak" CFG="prelibaprapp - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "prelibaprapp - Win32 Release" (based on "Win32 (x86) External Target") +!MESSAGE "prelibaprapp - Win32 Debug" (based on "Win32 (x86) External Target") +!MESSAGE "prelibaprapp - x64 Release" (based on "Win32 (x86) External Target") +!MESSAGE "prelibaprapp - x64 Debug" (based on "Win32 (x86) External Target") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" + +!IF "$(CFG)" == "prelibaprapp - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "" +# PROP BASE Intermediate_Dir "" +# PROP BASE Cmd_Line "NMAKE /nologo /f NUL" +# PROP BASE Rebuild_Opt "/a" +# PROP BASE Target_File "prelibaprapp.exe" +# PROP BASE Bsc_Name "prelibaprapp.bsc" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "" +# PROP Intermediate_Dir "" +# PROP Cmd_Line "NMAKE /nologo /f NUL" +# PROP Rebuild_Opt "/a" +# PROP Bsc_Name "" +# PROP Target_Dir "" + +!ELSEIF "$(CFG)" == "prelibaprapp - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "" +# PROP BASE Intermediate_Dir "" +# PROP BASE Cmd_Line "NMAKE /nologo /f NUL" +# PROP BASE Rebuild_Opt "/a" +# PROP BASE Target_File "prelibaprapp.exe" +# PROP BASE Bsc_Name "prelibaprapp.bsc" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "" +# PROP Intermediate_Dir "" +# PROP Cmd_Line "NMAKE /nologo /f NUL" +# PROP Rebuild_Opt "/a" +# PROP Bsc_Name "" +# PROP Target_Dir "" + +!ELSEIF "$(CFG)" == "prelibaprapp - x64 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "" +# PROP BASE Intermediate_Dir "" +# PROP BASE Cmd_Line "NMAKE /nologo /f NUL" +# PROP BASE Rebuild_Opt "/a" +# PROP BASE Target_File "prelibaprapp.exe" +# PROP BASE Bsc_Name "prelibaprapp.bsc" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "" +# PROP Intermediate_Dir "" +# PROP Cmd_Line "NMAKE /nologo /f NUL" +# PROP Rebuild_Opt "/a" +# PROP Bsc_Name "" +# PROP Target_Dir "" + +!ELSEIF "$(CFG)" == "prelibaprapp - x64 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "" +# PROP BASE Intermediate_Dir "" +# PROP BASE Cmd_Line "NMAKE /nologo /f NUL" +# PROP BASE Rebuild_Opt "/a" +# PROP BASE Target_File "prelibaprapp.exe" +# PROP BASE Bsc_Name "prelibaprapp.bsc" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "" +# PROP Intermediate_Dir "" +# PROP Cmd_Line "NMAKE /nologo /f NUL" +# PROP Rebuild_Opt "/a" +# PROP Bsc_Name "" +# PROP Target_Dir "" + +!ENDIF + +# Begin Target + +# Name "prelibaprapp - Win32 Release" +# Name "prelibaprapp - Win32 Debug" +# Name "prelibaprapp - x64 Release" +# Name "prelibaprapp - x64 Debug" + +!IF "$(CFG)" == "prelibaprapp - Win32 Release" + +!ELSEIF "$(CFG)" == "prelibaprapp - Win32 Debug" + +!ELSEIF "$(CFG)" == "prelibaprapp - x64 Release" + +!ELSEIF "$(CFG)" == "prelibaprapp - x64 Debug" + +!ENDIF + +# End Target +# End Project diff --git a/build/rpm/apr.spec.in b/build/rpm/apr.spec.in new file mode 100644 index 00000000000..4a2645527b6 --- /dev/null +++ b/build/rpm/apr.spec.in @@ -0,0 +1,201 @@ + +%define aprver 2 + +Summary: Apache Portable Runtime library +Name: apr +Version: APR_VERSION +Release: APR_RELEASE +License: Apache Software License +Group: System Environment/Libraries +URL: http://apr.apache.org/ +Source0: http://www.apache.org/dist/apr/%{name}-%{version}.tar.bz2 +BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-buildroot +BuildRequires: autoconf, libtool, doxygen, libuuid-devel, python + +%description +The mission of the Apache Portable Runtime (APR) is to provide a +free library of C data structures and routines, forming a system +portability layer to as many operating systems as possible, +including Unices, MS Win32, BeOS and OS/2. + +%package devel +Group: Development/Libraries +Summary: APR library development kit +Requires: apr = %{version} + +%description devel +This package provides the support files which can be used to +build applications using the APR library. The mission of the +Apache Portable Runtime (APR) is to provide a free library of +C data structures and routines. + +%package dbm +Group: Development/Libraries +Summary: APR utility library DBM driver +BuildRequires: db4-devel +Requires: apr-util = %{version}-%{release} + +%description dbm +This package provides the DBM driver for the apr-util. + +%package pgsql +Group: Development/Libraries +Summary: APR utility library PostgreSQL DBD driver +BuildRequires: postgresql-devel +Requires: apr-util = %{version}-%{release} + +%description pgsql +This package provides the PostgreSQL driver for the apr-util +DBD (database abstraction) interface. + +%package mysql +Group: Development/Libraries +Summary: APR utility library MySQL DBD driver +BuildRequires: mysql-devel +Requires: apr-util = %{version}-%{release} + +%description mysql +This package provides the MySQL driver for the apr-util DBD +(database abstraction) interface. + +%package sqlite +Group: Development/Libraries +Summary: APR utility library SQLite DBD driver +BuildRequires: sqlite-devel >= 3.0.0 +Requires: apr-util = %{version}-%{release} + +%description sqlite +This package provides the SQLite driver for the apr-util DBD +(database abstraction) interface. + +%package odbc +Group: Development/Libraries +Summary: APR utility library ODBC DBD driver +BuildRequires: unixODBC-devel +Requires: apr-util = %{version}-%{release} + +%description odbc +This package provides the ODBC driver for the apr-util DBD +(database abstraction) interface. + +%package openssl +Group: Development/Libraries +Summary: APR utility library OpenSSL crypto support +BuildRequires: openssl-devel +Requires: apr-util = %{version}-%{release} + +%description openssl +This package provides crypto support for apr-util based on OpenSSL. + +%package nss +Group: Development/Libraries +Summary: APR utility library NSS crypto support +BuildRequires: nss-devel +Requires: apr-util = %{version}-%{release} + +%description nss +This package provides crypto support for apr-util based on Mozilla NSS. + +%prep +%setup -q + +%build +# regenerate configure script etc. +./buildconf +%configure \ + --prefix=/usr \ + --includedir=%{_includedir}/apr-%{aprver} \ + --with-installbuilddir=%{_libdir}/apr/build-%{aprver} \ + --with-devrandom=/dev/urandom \ + --without-gdbm \ + --with-sqlite3 --with-pgsql --with-mysql --with-odbc \ + --with-berkeley-db \ + --with-crypto --with-openssl --with-nss \ + --without-sqlite2 + CC=gcc CXX=g++ +make %{?_smp_mflags} && make dox + +%check +# Run non-interactive tests +pushd test +make %{?_smp_mflags} all CFLAGS=-fno-strict-aliasing +make check || exit 1 +popd + +%install +rm -rf $RPM_BUILD_ROOT +make install DESTDIR=$RPM_BUILD_ROOT + +# Move docs to more convenient location +mv docs/dox/html html + +# Unpackaged files: +rm -f $RPM_BUILD_ROOT%{_libdir}/apr.exp + +%clean +rm -rf $RPM_BUILD_ROOT + +%post -p /sbin/ldconfig + +%postun -p /sbin/ldconfig + +%files +%defattr(-,root,root,-) +%doc CHANGES LICENSE NOTICE +%{_libdir}/libapr-%{aprver}.so.* +%dir %{_libdir}/apr-%{aprver} + +%files dbm +%defattr(-,root,root,-) +%{_libdir}/apr-%{aprver}/apr_dbm_db* + +%files pgsql +%defattr(-,root,root,-) +%{_libdir}/apr-%{aprver}/apr_dbd_pgsql* + +%files mysql +%defattr(-,root,root,-) +%{_libdir}/apr-%{aprver}/apr_dbd_mysql* + +%files sqlite +%defattr(-,root,root,-) +%{_libdir}/apr-%{aprver}/apr_dbd_sqlite* + +%files odbc +%defattr(-,root,root,-) +%{_libdir}/apr-%{aprver}/apr_dbd_odbc* + +%files openssl +%defattr(-,root,root,-) +%{_libdir}/apr-%{aprver}/apr_crypto_openssl* + +%files nss +%defattr(-,root,root,-) +%{_libdir}/apr-%{aprver}/apr_crypto_nss* + +%files devel +%defattr(-,root,root,-) +%doc docs/APRDesign.html docs/canonical_filenames.html +%doc docs/incomplete_types docs/non_apr_programs +%doc html +%{_bindir}/apr*config +%{_libdir}/libapr-%{aprver}.*a +%{_libdir}/libapr-%{aprver}.so +%dir %{_libdir}/apr +%dir %{_libdir}/apr/build-%{aprver} +%{_libdir}/apr/build-%{aprver}/* +%{_libdir}/pkgconfig/apr-%{aprver}.pc +%dir %{_includedir}/apr-%{aprver} +%{_includedir}/apr-%{aprver}/*.h + +%changelog +* Sat Aug 30 2008 Graham Leggett <minfrin@sharp.fm> 1.3.3 +- update to depend on the bzip2 binary +- build depends on python + +* Tue Jun 22 2004 Graham Leggett <minfrin@sharp.fm> 1.0.0-1 +- update to support v1.0.0 of APR + +* Tue Jun 22 2004 Graham Leggett <minfrin@sharp.fm> 1.0.0-1 +- derived from Fedora Core apr.spec + diff --git a/build/run-gcov.sh b/build/run-gcov.sh new file mode 100755 index 00000000000..98f911fc89a --- /dev/null +++ b/build/run-gcov.sh @@ -0,0 +1,130 @@ +#!/bin/sh + +if [ ! -d coverage ]; then + mkdir coverage +fi +cd coverage + +# It would be really nice to find a better way to do this than copying the +# HTML into this script. But, I am being lazy right now. +cat > index.html << EOF +<!-- This is a generated file, do not edit --> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" +"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"/> + <meta name="author" content="APR Developers" /><meta name="email" content="dev@apr.apache.org" /> + <title>Test Coverage</title> + </head> + <body bgcolor="#ffffff" text="#000000" link="#525D76"> +<p><a href="/"><img src="./images/apr_logo_wide.png" alt="The Apache Portable Runtime Project" border="0"/></a></p> + <table border="0" width="100%" cellspacing="4"> + <tr> + <!-- LEFT SIDE NAVIGATION --> + <td valign="top" nowrap="nowrap"> + <a href="http://apachecon.com/" + ><img src="http://www.apache.org/images/ac2003-150.gif" height="86" + width="150" border="0" alt="ApacheCon" /></a> + <p><b>Get Involved</b></p> + <menu compact="compact"> + <li><a href="/anoncvs.txt">CVS</a></li> + <li><a href="/mailing-lists.html">Mailing Lists</a></li> + <li><a href="http://cvs.apache.org/snapshots/apr/">Snapshots</a></li> + <li><a href="/compiling_win32.html">Build on Win32</a></li> + <li><a href="/compiling_unix.html">Build on Unix</a></li> + </menu> + <p><b>Download!</b></p> + <menu compact="compact"> + <li><a href="http://www.apache.org/dyn/closer.cgi/apr/">from a mirror</a></li> + </menu> + <p><b>Docs</b></p> + <menu compact="compact"> + <li><a href="/docs/apr/">APR</a></li> + <li><a href="/docs/apr-util/">APR-util</a></li> + <li>APR-iconv</li> + </menu> + <p><b>Guidelines</b></p> + <menu compact="compact"> + <li><a href="/guidelines.html">Project Guidelines</a></li> + <li><a href="/patches.html">Contributing</a></li> + <li><a href="/versioning.html">Version Numbers</a></li> + </menu> + <p><b><a href="/info/">Miscellaneous</a></b></p> + <menu compact="compact"> + <li><a href="http://www.apache.org/LICENSE.txt">License</a></li> + <li><a href="/projects.html">Projects using APR</a></li> + </menu> + </td> + <!-- RIGHT SIDE INFORMATION --> + <td align="left" valign="top"> + <table border="0" cellspacing="0" cellpadding="2" width="100%"> + <tr><td bgcolor="#525D76"> + <font color="#ffffff" face="arial,helvetica,sanserif"> + <strong>APR Test Coverage</strong> + </font> + </td></tr> + <tr><td> + <blockquote> +<p>This should give us some idea of how well our tests actually stress our +code. To generate this data, do the following:</p> +<menu compact="compact"> + <li>./buildconf</li> + <li>CFLAGS="-fprofile-arcs -ftest-coverage ./configure</li> + <li>make</li> + <li>cd test</li> + <li>make</li> + <li>./testall</li> + <li>cd ..</li> + <li>make gcov</li> +</menu> +<p>Note that this will only generate test coverage data for the testall script, +but all tests should be moving to the unified framework, so this is correct.</p> + </blockquote> + + <table border="0" width="100%" cellspacing="0"> +EOF + +for i in `find .. -name "*.bb" -maxdepth 1 | sort`; do + percent=`gcov $i -o .. | grep "%" | awk -F'%' {'print $1'}` + name=`echo $i | awk -F'/' {'print $2'}` + basename=`echo $name | awk -F'.' {'print $1'}` + + if [ "x$percent" = "x" ]; then + echo "<tr>" >> index.html + echo "<td bgcolor=#ffffff> Error generating data for $basename<br>" >> index.html + continue; + fi + intpercent=`echo "$percent/1" | bc` + if [ $intpercent -lt 33 ]; then + color="#ffaaaa" + else if [ $intpercent -lt 66 ]; then + color="#ffff77" + else + color="#aaffaa" + fi + fi + + echo "<tr>" >> index.html + echo "<td bgcolor=$color><a href=\"$basename.c.gcov\">$basename</a><br>" >> index.html + echo "<td bgcolor=$color>$percent% tested" >> index.html +done + +echo "</table><p>Last generated `date`</p>" >> index.html + +cat >> index.html << EOF +</td></tr> +</table> + <!-- FOOTER --> + <tr><td colspan="2"><hr noshade="noshade" size="1"/></td></tr> + <tr><td colspan="2" align="center"> + <font size="-1"> + <em>Copyright © 1999-2004, The Apache Software Foundation</em> + </font> + </td> + </tr> + </table> + </body> +</html> + +EOF diff --git a/build/subst.py b/build/subst.py new file mode 100644 index 00000000000..042035a8d8d --- /dev/null +++ b/build/subst.py @@ -0,0 +1,68 @@ +# +# +# Ported from <http://www.scons.org/wiki/SubstInFileBuilder> +# """ This code is freely available for your use. """ +# + +import re +from SCons.Script import * + +def do_subst_in_file(targetfile, sourcefile, dict): + """Replace all instances of the keys of dict with their values. + For example, if dict is {'%VERSION%': '1.2345', '%BASE%': 'MyProg'}, + then all instances of %VERSION% in the file will be replaced with 1.2345 etc. + """ + try: + f = open(sourcefile, 'rb') + contents = f.read() + f.close() + except: + raise SCons.Errors.UserError, "Can't read source file %s"%sourcefile + for (k,v) in dict.items(): + contents = re.sub(k, v, contents) + try: + f = open(targetfile, 'wb') + f.write(contents) + f.close() + except: + raise SCons.Errors.UserError, "Can't write target file %s"%targetfile + return 0 # success + +def subst_in_file(target, source, env): + if not env.has_key('SUBST_DICT'): + raise SCons.Errors.UserError, "SubstFile requires SUBST_DICT to be set." + d = dict(env['SUBST_DICT']) # copy it + for (k,v) in d.items(): + if callable(v): + d[k] = env.subst(v()) + elif SCons.Util.is_String(v): + d[k]=env.subst(v) + else: + d[k] = SCons.Util.to_String(v) + for (t,s) in zip(target, source): + return do_subst_in_file(str(t), str(s), d) + +def subst_in_file_string(target, source, env): + """This is what gets printed on the console.""" + return '\n'.join(['Substituting vars from %s into %s'%(str(s), str(t)) + for (t,s) in zip(target, source)]) + +def subst_emitter(target, source, env): + """Add dependency from substituted SUBST_DICT to target. + Returns original target, source tuple unchanged. + """ + d = env['SUBST_DICT'].copy() # copy it + for (k,v) in d.items(): + if callable(v): + d[k] = env.subst(v()) + elif SCons.Util.is_String(v): + d[k] = env.subst(v) + Depends(target, SCons.Node.Python.Value(d)) + return target, source + +def generate(env): + subst_action=SCons.Action.Action(subst_in_file, subst_in_file_string) + env['BUILDERS']['SubstFile'] = Builder(action=subst_action, emitter=subst_emitter) + +def exists(env): + return 1 diff --git a/build/win32ver.awk b/build/win32ver.awk new file mode 100644 index 00000000000..11be08072d0 --- /dev/null +++ b/build/win32ver.awk @@ -0,0 +1,124 @@ +BEGIN { + + # ff bits: 1(debug), 2(prerelease), 4(patched), 8(vendor) and 32(special) + # debug is summed based on the /Define _DEBUG + # prerelease is based on the -dev extension, + # patched is based on a non-standard "-ver" extension, + # special and vendor are toggled by their args. + # + ff = 0; + + file=ARGV[1]; + desc=ARGV[2]; + rel_h=ARGV[3]; + + filename = file; + if (match(file, /\./)) { + sub(/\.[^\.]*$/, "", file); + } + + i = 4; + while (length(ARGV[i])) { + if (match(ARGV[i], /icon=/)) { + icon = substr(ARGV[i], 6); + } + if (match(ARGV[i], /vendor=/)) { + vendor = substr(ARGV[i], 8); + ff = ff + 8; + } + if (match(ARGV[i], /special=/)) { + special = substr(ARGV[i], 9); + ff = ff + 32; + } + i = i + 1 + } + + i = i - 1; + while (i) { + delete ARGV[i]; + i = i - 1; + } + + while ((getline < rel_h) > 0) { + if (match ($0, /^#define AP._MAJOR_VERSION/)) { + ver_major = $3; + } + if (match ($0, /^#define AP._MINOR_VERSION/)) { + ver_minor = $3; + } + if (match ($0, /^#define AP._PATCH_VERSION/)) { + ver_patch = $3; + } + if (match ($0, /^#define AP._IS_DEV_VERSION/)) { + ver_suffix = "-dev"; + ver_build = "0"; + } + if (match ($0, /^#undef AP._IS_DEV_VERSION/)) { + ver_build = "100"; + } + if (match ($0, /^.*Copyright /)) { + copyright = substr($0, RLENGTH + 1); + } + } + ver = ver_major "." ver_minor "." ver_patch ver_suffix; + verc = ver_major "," ver_minor "," ver_patch "," ver_build; + + if (length(vendor)) { + ff = ff + 8; + } + + if (length(icon)) { + print "1 ICON DISCARDABLE \"" icon "\""; + } + print "1 VERSIONINFO"; + print " FILEVERSION " verc ""; + print " PRODUCTVERSION " verc ""; + print " FILEFLAGSMASK 0x3fL"; + print "#if defined(_DEBUG)" + print " FILEFLAGS 0x" sprintf("%02x", ff + 1) "L"; + print "#else" + print " FILEFLAGS 0x" sprintf("%02x", ff) "L"; + print "#endif" + print " FILEOS 0x40004L"; + print " FILETYPE 0x1L"; + print " FILESUBTYPE 0x0L"; + print "BEGIN"; + print " BLOCK \"StringFileInfo\""; + print " BEGIN"; + print " BLOCK \"040904b0\""; + print " BEGIN"; + print " VALUE \"Comments\", "\ + "\"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\\r\\n\\r\\n" \ + "http://www.apache.org/licenses/LICENSE-2.0\\r\\n\\r\\n" \ + "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.\\0\""; + print " VALUE \"CompanyName\", \"Apache Software Foundation\\0\""; + print " VALUE \"FileDescription\", \"" desc "\\0\""; + print " VALUE \"FileVersion\", \"" ver "\\0\""; + print " VALUE \"InternalName\", \"" file "\\0\""; + print " VALUE \"LegalCopyright\", \"Copyright " copyright "\\0\""; + print " VALUE \"OriginalFilename\", \"" filename "\\0\""; + if (vendor) { + print " VALUE \"PrivateBuild\", \"" vendor "\\0\""; + } + if (special) { + print " VALUE \"SpecialBuild\", \"" vendor "\\0\""; + } + print " VALUE \"ProductName\", \"Apache Portable Runtime\\0\""; + print " VALUE \"ProductVersion\", \"" ver "\\0\""; + print " END"; + print " END"; + print " BLOCK \"VarFileInfo\""; + print " BEGIN"; + print " VALUE \"Translation\", 0x409, 1200"; + print " END"; + print "END"; +} diff --git a/build/xml.m4 b/build/xml.m4 new file mode 100644 index 00000000000..3c31ea995a0 --- /dev/null +++ b/build/xml.m4 @@ -0,0 +1,211 @@ +dnl -------------------------------------------------------- -*- autoconf -*- +dnl Licensed to the Apache Software Foundation (ASF) under one or more +dnl contributor license agreements. See the NOTICE file distributed with +dnl this work for additional information regarding copyright ownership. +dnl The ASF licenses this file to You under the Apache License, Version 2.0 +dnl (the "License"); you may not use this file except in compliance with +dnl the License. You may obtain a copy of the License at +dnl +dnl http://www.apache.org/licenses/LICENSE-2.0 +dnl +dnl Unless required by applicable law or agreed to in writing, software +dnl distributed under the License is distributed on an "AS IS" BASIS, +dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +dnl See the License for the specific language governing permissions and +dnl limitations under the License. + + +dnl +dnl APU_TRY_EXPAT_LINK( +dnl test-message, cache-var-name, hdrs, libs, +dnl [actions-on-success], [actions-on-failure]) +dnl +dnl Tests linking against expat with libraries 'libs' and includes +dnl 'hdrs', passing message + cache-var-name to AC_CACHE_CHECK. +dnl On success, sets $expat_libs to libs, sets $apu_has_expat to 1, +dnl and runs actions-on-success; on failure runs actions-on-failure. +dnl +AC_DEFUN([APU_TRY_EXPAT_LINK], [ +AC_CACHE_CHECK([$1], [$2], [ + apu_expat_LIBS=$LIBS + apu_expat_CPPFLAGS=$CPPFLAGS + LIBS="$LIBS $4" + CPPFLAGS="$CPPFLAGS $INCLUDES" + AC_TRY_LINK([#include <stdlib.h> +#include <$3>], [XML_ParserCreate(NULL);], + [$2=yes], [$2=no]) + LIBS=$apu_expat_LIBS + CPPFLAGS=$apu_expat_CPPFLAGS +]) + +if test $[$2] = yes; then + AC_DEFINE([HAVE_]translit([$3], [a-z./], [A-Z__]), 1, + [Define if $3 is available]) + apu_expat_libs="$4" + apu_has_expat=1 + $5 + AC_SUBST(apu_has_expat) +else + apu_has_expat=0 + $6 +fi +]) + +dnl +dnl APU_SYSTEM_EXPAT: tests for a system expat installation +dnl If present, sets $apu_has_expat to 1 and adjusts LDFLAGS/CPPFLAGS +dnl appropriately. This is mostly for compatibility with existing +dnl expat releases; all but the first APU_TRY_EXPAT_LINK call could +dnl be dropped later. +dnl +AC_DEFUN([APU_SYSTEM_EXPAT], [ + + APU_TRY_EXPAT_LINK([Expat 1.95.x], apu_cv_expat_system, + [expat.h], [-lexpat]) + + if test $apu_has_expat = 0; then + APU_TRY_EXPAT_LINK([old Debian-packaged expat], apu_cv_expat_debian, + [xmltok/xmlparse.h], [-lxmlparse -lxmltok]) + fi + + if test $apu_has_expat = 0; then + APU_TRY_EXPAT_LINK([old FreeBSD-packaged expat], apu_cv_expat_freebsd, + [xml/xmlparse.h], [-lexpat]) + fi + + if test $apu_has_expat = 0; then + APU_TRY_EXPAT_LINK([Expat 1.0/1.1], apu_cv_expat_1011, + [xmlparse/xmlparse.h], [-lexpat]) + fi + + if test $apu_has_expat = 0; then + APR_ADDTO(LDFLAGS, [-L/usr/local/lib]) + APR_ADDTO(INCLUDES, [-I/usr/local/include]) + + APU_TRY_EXPAT_LINK([Expat 1.95.x in /usr/local], + apu_cv_expat_usrlocal, [expat.h], [-lexpat], [], [ + APR_REMOVEFROM(LDFLAGS, [-L/usr/local/lib]) + APR_REMOVEFROM(INCLUDES, [-I/usr/local/include]) + ]) + fi +]) + + +dnl +dnl APU_FIND_EXPAT: figure out where EXPAT is located (or use bundled) +dnl +AC_DEFUN([APU_FIND_EXPAT], [ + +save_cppflags="$CPPFLAGS" + +apu_has_expat=0 + +AC_ARG_WITH([expat], +[ --with-expat=DIR specify Expat location], [ + if test "$withval" = "yes"; then + AC_MSG_ERROR([a directory must be specified for --with-expat]) + elif test "$withval" = "no"; then + if test "$apu_has_libxml2" != "1"; then + AC_MSG_ERROR([An XML parser is required! If you disable expat, you must select --with-libxml2]) + fi + else + # Add given path to standard search paths if appropriate: + if test "$apu_has_libxml2" = "1"; then + AC_MSG_ERROR(Cannot build with both expat and libxml2 - please select one) + fi + if test "$withval" != "/usr"; then + APR_ADDTO(INCLUDES, [-I$withval/include]) + APR_ADDTO(LDFLAGS, [-L$withval/lib]) + fi + fi +]) + +if test "$apu_has_libxml2" != "1"; then + APU_SYSTEM_EXPAT + + APR_ADDTO(APRUTIL_EXPORT_LIBS, [$apu_expat_libs]) + APR_ADDTO(LIBS, [$apu_expat_libs]) + + APR_XML_DIR=$bundled_subdir + AC_SUBST(APR_XML_DIR) +fi + +CPPFLAGS=$save_cppflags +]) + + +dnl +dnl APU_FIND_LIBXML2: figure out where LIBXML2 is located (or use bundled) +dnl +AC_DEFUN([APU_FIND_LIBXML2], [ + +save_cppflags="$CPPFLAGS" + +apu_has_libxml2=0 +apu_try_libxml2=0 + +AC_ARG_WITH([libxml2], +[ --with-libxml2=DIR specify libxml2 location], [ + if test "$withval" = "yes"; then + apu_try_libxml2=1 + APR_ADDTO(INCLUDES, [-I/usr/include/libxml2]) + elif test "$withval" != "no"; then + apu_try_libxml2=1 + APR_ADDTO(INCLUDES, [-I$withval/include/libxml2]) + if test "$withval" != "/usr"; then + APR_ADDTO(LDFLAGS, [-L$withval/lib]) + fi + fi + if test ${apu_try_libxml2} = "1" ; then + + #test for libxml2 + AC_CACHE_CHECK([libxml2], [apu_cv_libxml2], [ + apu_libxml2_CPPFLAGS=$CPPFLAGS + apu_libxml2_LIBS="$LIBS -lxml2" + CPPFLAGS="$CPPFLAGS $INCLUDES" + LIBS="$LIBS -lxml2" + AC_TRY_LINK( + [#include <libxml/parser.h>], + [xmlSAXHandler sax; xmlCreatePushParserCtxt(&sax, NULL, NULL, 0, NULL);], + [apu_cv_libxml2=yes], + [apu_cv_libxml2=no], + ) + CPPFLAGS=$apu_libxml2_CPPFLAGS + LIBS=$apu_libxml2_LIBS + ]) + if test $apu_cv_libxml2 = yes ; then + AC_DEFINE([HAVE_LIBXML2_H], 1, [libxml2 found]) + apu_has_libxml2=1 + else + apu_has_libxml2=0 + fi + fi +]) +AC_SUBST(apu_has_libxml2) + +if test ${apu_has_libxml2} = "1" ; then + APR_ADDTO(APRUTIL_EXPORT_LIBS, [-lxml2]) + APR_ADDTO(LIBS, [-lxml2]) +fi + +CPPFLAGS=$save_cppflags +]) + +dnl +dnl APU_FIND_XML: Find an XML library +dnl +dnl Logic: we need exactly one but not both XML libraries +dnl Make expat the default for back-compatibility. +dnl Use libxml2 if a --with-libxml2 is specified (and works), +dnl otherwise expat. +dnl +AC_DEFUN([APU_FIND_XML], [ +APU_FIND_LIBXML2 +APU_FIND_EXPAT + +if test ${apu_has_expat} = "1" && test ${apu_has_libxml2} = "1" ; then + AC_MSG_ERROR(Cannot build with both expat and libxml2 - please select one) +elif test ${apu_has_expat} != "1" && test ${apu_has_libxml2} != "1" ; then + AC_MSG_ERROR(No XML parser found! Please specify --with-expat or --with-libxml2) +fi +]) diff --git a/buildconf b/buildconf new file mode 100755 index 00000000000..113c3c7f620 --- /dev/null +++ b/buildconf @@ -0,0 +1,143 @@ +#!/bin/sh +# 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. +# +# + +# buildconf: Build the support scripts needed to compile from a +# checked-out version of the source code. + +if [ "$1" = "--verbose" -o "$1" = "-v" ]; then + verbose="--verbose" + shift +fi + +# Verify that the builder has the right config tools installed +# +build/buildcheck.sh $verbose || exit 1 + +libtoolize=`build/PrintPath glibtoolize1 glibtoolize libtoolize15 libtoolize14 libtoolize` +if [ "x$libtoolize" = "x" ]; then + echo "libtoolize not found in path" + exit 1 +fi + +# Create the libtool helper files +# +# Note: we copy (rather than link) them to simplify distribution. +# Note: APR supplies its own config.guess and config.sub -- we do not +# rely on libtool's versions +# +echo "buildconf: copying libtool helper files using $libtoolize" + +# Remove any libtool files so one can switch between libtool versions +# by simply rerunning the buildconf script. +rm -f aclocal.m4 libtool.m4 +(cd build ; rm -f ltconfig ltmain.sh argz.m4 libtool.m4 ltoptions.m4 ltsugar.m4 ltversion.m4 lt~obsolete.m4) + +# Determine libtool version, because --copy behaves differently +# w.r.t. copying libtool.m4 +lt_pversion=`$libtoolize --version 2>/dev/null|sed -e 's/([^)]*)//g;s/^[^0-9]*//;s/[- ].*//g;q'` +lt_version=`echo $lt_pversion|sed -e 's/\([a-z]*\)$/.\1/'` +IFS=.; set $lt_version; IFS=' ' + +# libtool 1 +if test "$1" = "1"; then + $libtoolize --copy --automake + # Unlikely, maybe for old versions the file exists + if [ -f libtool.m4 ]; then + ltfile=`pwd`/libtool.m4 + else + + # Extract all lines setting variables from libtoolize up until + # libtool_m4 gets set + ltfindcmd="`sed -n \"/=[^\\\`]/p;/libtool_m4=/{s/.*=/echo /p;q;}\" \ + < $libtoolize`" + + # Get path to libtool.m4 either from LIBTOOL_M4 env var or our libtoolize based script + ltfile=${LIBTOOL_M4-`eval "$ltfindcmd"`} + + # Expecting the code above to be very portable, but just in case... + if [ -z "$ltfile" -o ! -f "$ltfile" ]; then + ltpath=`dirname $libtoolize` + ltfile=`cd $ltpath/../share/aclocal ; pwd`/libtool.m4 + fi + fi + if [ ! -f $ltfile ]; then + echo "$ltfile not found" + exit 1 + fi + # Do we need this anymore? + echo "buildconf: Using libtool.m4 at ${ltfile}." + rm -f build/libtool.m4 + cp -p $ltfile build/libtool.m4 + +# libtool 2 +elif test "$1" = "2"; then + $libtoolize --copy --quiet $verbose +fi + +# Replace top_builddir by apr_builddir. +# Wouldn't it just be better to define top_builddir?? +# Not sure, would it interfere with httpd top_builddir when bundled? +mv build/libtool.m4 build/libtool.m4.$$ +sed -e 's/\(LIBTOOL=.*\)top_build/\1apr_build/' < build/libtool.m4.$$ > build/libtool.m4 +rm -f build/libtool.m4.$$ + +# Clean up any leftovers +rm -f aclocal.m4 libtool.m4 + +# +# Generate the autoconf header and ./configure +# +echo "buildconf: creating include/arch/unix/apr_private.h.in ..." +${AUTOHEADER:-autoheader} $verbose + +echo "buildconf: creating configure ..." +### do some work to toss config.cache? +${AUTOCONF:-autoconf} $verbose + +# Remove autoconf 2.5x's cache directory +rm -rf autom4te*.cache + +echo "buildconf: generating 'make' outputs ..." +build/gen-build.py $verbose make + +# Create RPM Spec file +if [ -f `which cut` ]; then + echo "buildconf: rebuilding rpm spec file" + ( REVISION=`build/get-version.sh all include/apr_version.h APR` + VERSION=`echo $REVISION | cut -d- -s -f1` + RELEASE=`echo $REVISION | cut -d- -s -f2` + if [ "x$VERSION" = "x" ]; then + VERSION=$REVISION + RELEASE=1 + fi + cat ./build/rpm/apr.spec.in | \ + sed -e "s/APR_VERSION/$VERSION/" \ + -e "s/APR_RELEASE/$RELEASE/" \ + > apr.spec ) +fi + +# Verify the tree was clean, notify user if not (normal in development) +# +if [ -f "include/apr.h" -o -f "include/arch/unix/apr_private.h" -o \ + -f "include/apu_want.h" -o -f "include/private/apu_select_dbm.h" ]; then + echo "" + echo "Generated include files already exist, the tree is not clean." + echo "The resulting build-outputs.mk file is incorrect" +fi + +exit 0 diff --git a/config.guess b/config.guess deleted file mode 100755 index 19b0a0a7182..00000000000 --- a/config.guess +++ /dev/null @@ -1,1091 +0,0 @@ -#! /bin/sh -# Attempt to guess a canonical system name. -# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999 -# Free Software Foundation, Inc. -# -# This file is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# -# As a special exception to the GNU General Public License, if you -# distribute this file as part of a program that contains a -# configuration script generated by Autoconf, you may include it under -# the same distribution terms that you use for the rest of that program. - -# Written by Per Bothner <bothner@cygnus.com>. -# The master version of this file is at the FSF in /home/gd/gnu/lib. -# Please send patches to the Autoconf mailing list <autoconf@gnu.org>. -# -# This script attempts to guess a canonical system name similar to -# config.sub. If it succeeds, it prints the system name on stdout, and -# exits with 0. Otherwise, it exits with 1. -# -# The plan is that this can be called by configure scripts if you -# don't specify an explicit system type (host/target name). -# -# Only a few systems have been added to this list; please add others -# (but try to keep the structure clean). -# - -# Use $HOST_CC if defined. $CC may point to a cross-compiler -if test x"$CC_FOR_BUILD" = x; then - if test x"$HOST_CC" != x; then - CC_FOR_BUILD="$HOST_CC" - else - if test x"$CC" != x; then - CC_FOR_BUILD="$CC" - else - CC_FOR_BUILD=cc - fi - fi -fi - - -# This is needed to find uname on a Pyramid OSx when run in the BSD universe. -# (ghazi@noc.rutgers.edu 8/24/94.) -if (test -f /.attbin/uname) >/dev/null 2>&1 ; then - PATH=$PATH:/.attbin ; export PATH -fi - -UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown -UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown -UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown -UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown - -dummy=dummy-$$ -trap 'rm -f $dummy.c $dummy.o $dummy; exit 1' 1 2 15 - -# Note: order is significant - the case branches are not exclusive. - -case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in - alpha:OSF1:*:*) - if test $UNAME_RELEASE = "V4.0"; then - UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` - fi - # A Vn.n version is a released version. - # A Tn.n version is a released field test version. - # A Xn.n version is an unreleased experimental baselevel. - # 1.2 uses "1.2" for uname -r. - cat <<EOF >$dummy.s - .globl main - .ent main -main: - .frame \$30,0,\$26,0 - .prologue 0 - .long 0x47e03d80 # implver $0 - lda \$2,259 - .long 0x47e20c21 # amask $2,$1 - srl \$1,8,\$2 - sll \$2,2,\$2 - sll \$0,3,\$0 - addl \$1,\$0,\$0 - addl \$2,\$0,\$0 - ret \$31,(\$26),1 - .end main -EOF - $CC_FOR_BUILD $dummy.s -o $dummy 2>/dev/null - if test "$?" = 0 ; then - ./$dummy - case "$?" in - 7) - UNAME_MACHINE="alpha" - ;; - 15) - UNAME_MACHINE="alphaev5" - ;; - 14) - UNAME_MACHINE="alphaev56" - ;; - 10) - UNAME_MACHINE="alphapca56" - ;; - 16) - UNAME_MACHINE="alphaev6" - ;; - esac - fi - rm -f $dummy.s $dummy - echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` - exit 0 ;; - Alpha\ *:Windows_NT*:*) - # How do we know it's Interix rather than the generic POSIX subsystem? - # Should we change UNAME_MACHINE based on the output of uname instead - # of the specific Alpha model? - echo alpha-pc-interix - exit 0 ;; - 21064:Windows_NT:50:3) - echo alpha-dec-winnt3.5 - exit 0 ;; - Amiga*:UNIX_System_V:4.0:*) - echo m68k-cbm-sysv4 - exit 0;; - amiga:NetBSD:*:*) - echo m68k-cbm-netbsd${UNAME_RELEASE} - exit 0 ;; - amiga:OpenBSD:*:*) - echo m68k-unknown-openbsd${UNAME_RELEASE} - exit 0 ;; - *:[Aa]miga[Oo][Ss]:*:*) - echo ${UNAME_MACHINE}-unknown-amigaos - exit 0 ;; - arc64:OpenBSD:*:*) - echo mips64el-unknown-openbsd${UNAME_RELEASE} - exit 0 ;; - arc:OpenBSD:*:*) - echo mipsel-unknown-openbsd${UNAME_RELEASE} - exit 0 ;; - hkmips:OpenBSD:*:*) - echo mips-unknown-openbsd${UNAME_RELEASE} - exit 0 ;; - pmax:OpenBSD:*:*) - echo mipsel-unknown-openbsd${UNAME_RELEASE} - exit 0 ;; - sgi:OpenBSD:*:*) - echo mips-unknown-openbsd${UNAME_RELEASE} - exit 0 ;; - wgrisc:OpenBSD:*:*) - echo mipsel-unknown-openbsd${UNAME_RELEASE} - exit 0 ;; - arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) - echo arm-acorn-riscix${UNAME_RELEASE} - exit 0;; - arm32:NetBSD:*:*) - echo arm-unknown-netbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` - exit 0 ;; - SR2?01:HI-UX/MPP:*:*) - echo hppa1.1-hitachi-hiuxmpp - exit 0;; - Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) - # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. - if test "`(/bin/universe) 2>/dev/null`" = att ; then - echo pyramid-pyramid-sysv3 - else - echo pyramid-pyramid-bsd - fi - exit 0 ;; - NILE*:*:*:dcosx) - echo pyramid-pyramid-svr4 - exit 0 ;; - sun4H:SunOS:5.*:*) - echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` - exit 0 ;; - sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) - echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` - exit 0 ;; - i86pc:SunOS:5.*:*) - echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` - exit 0 ;; - sun4*:SunOS:6*:*) - # According to config.sub, this is the proper way to canonicalize - # SunOS6. Hard to guess exactly what SunOS6 will be like, but - # it's likely to be more like Solaris than SunOS4. - echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` - exit 0 ;; - sun4*:SunOS:*:*) - case "`/usr/bin/arch -k`" in - Series*|S4*) - UNAME_RELEASE=`uname -v` - ;; - esac - # Japanese Language versions have a version number like `4.1.3-JL'. - echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` - exit 0 ;; - sun3*:SunOS:*:*) - echo m68k-sun-sunos${UNAME_RELEASE} - exit 0 ;; - sun*:*:4.2BSD:*) - UNAME_RELEASE=`(head -1 /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` - test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 - case "`/bin/arch`" in - sun3) - echo m68k-sun-sunos${UNAME_RELEASE} - ;; - sun4) - echo sparc-sun-sunos${UNAME_RELEASE} - ;; - esac - exit 0 ;; - aushp:SunOS:*:*) - echo sparc-auspex-sunos${UNAME_RELEASE} - exit 0 ;; - atari*:NetBSD:*:*) - echo m68k-atari-netbsd${UNAME_RELEASE} - exit 0 ;; - atari*:OpenBSD:*:*) - echo m68k-unknown-openbsd${UNAME_RELEASE} - exit 0 ;; - # The situation for MiNT is a little confusing. The machine name - # can be virtually everything (everything which is not - # "atarist" or "atariste" at least should have a processor - # > m68000). The system name ranges from "MiNT" over "FreeMiNT" - # to the lowercase version "mint" (or "freemint"). Finally - # the system name "TOS" denotes a system which is actually not - # MiNT. But MiNT is downward compatible to TOS, so this should - # be no problem. - atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) - echo m68k-atari-mint${UNAME_RELEASE} - exit 0 ;; - atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) - echo m68k-atari-mint${UNAME_RELEASE} - exit 0 ;; - *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) - echo m68k-atari-mint${UNAME_RELEASE} - exit 0 ;; - milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) - echo m68k-milan-mint${UNAME_RELEASE} - exit 0 ;; - hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) - echo m68k-hades-mint${UNAME_RELEASE} - exit 0 ;; - *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) - echo m68k-unknown-mint${UNAME_RELEASE} - exit 0 ;; - sun3*:NetBSD:*:*) - echo m68k-sun-netbsd${UNAME_RELEASE} - exit 0 ;; - sun3*:OpenBSD:*:*) - echo m68k-unknown-openbsd${UNAME_RELEASE} - exit 0 ;; - mac68k:NetBSD:*:*) - echo m68k-apple-netbsd${UNAME_RELEASE} - exit 0 ;; - mac68k:OpenBSD:*:*) - echo m68k-unknown-openbsd${UNAME_RELEASE} - exit 0 ;; - mvme68k:OpenBSD:*:*) - echo m68k-unknown-openbsd${UNAME_RELEASE} - exit 0 ;; - mvme88k:OpenBSD:*:*) - echo m88k-unknown-openbsd${UNAME_RELEASE} - exit 0 ;; - powerpc:machten:*:*) - echo powerpc-apple-machten${UNAME_RELEASE} - exit 0 ;; - macppc:NetBSD:*:*) - echo powerpc-apple-netbsd${UNAME_RELEASE} - exit 0 ;; - RISC*:Mach:*:*) - echo mips-dec-mach_bsd4.3 - exit 0 ;; - RISC*:ULTRIX:*:*) - echo mips-dec-ultrix${UNAME_RELEASE} - exit 0 ;; - VAX*:ULTRIX*:*:*) - echo vax-dec-ultrix${UNAME_RELEASE} - exit 0 ;; - 2020:CLIX:*:* | 2430:CLIX:*:*) - echo clipper-intergraph-clix${UNAME_RELEASE} - exit 0 ;; - mips:*:*:UMIPS | mips:*:*:RISCos) - sed 's/^ //' << EOF >$dummy.c -#ifdef __cplusplus - int main (int argc, char *argv[]) { -#else - int main (argc, argv) int argc; char *argv[]; { -#endif - #if defined (host_mips) && defined (MIPSEB) - #if defined (SYSTYPE_SYSV) - printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); - #endif - #if defined (SYSTYPE_SVR4) - printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); - #endif - #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) - printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); - #endif - #endif - exit (-1); - } -EOF - $CC_FOR_BUILD $dummy.c -o $dummy \ - && ./$dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \ - && rm $dummy.c $dummy && exit 0 - rm -f $dummy.c $dummy - echo mips-mips-riscos${UNAME_RELEASE} - exit 0 ;; - Night_Hawk:Power_UNIX:*:*) - echo powerpc-harris-powerunix - exit 0 ;; - m88k:CX/UX:7*:*) - echo m88k-harris-cxux7 - exit 0 ;; - m88k:*:4*:R4*) - echo m88k-motorola-sysv4 - exit 0 ;; - m88k:*:3*:R3*) - echo m88k-motorola-sysv3 - exit 0 ;; - AViiON:dgux:*:*) - # DG/UX returns AViiON for all architectures - UNAME_PROCESSOR=`/usr/bin/uname -p` - if [ $UNAME_PROCESSOR = mc88100 -o $UNAME_PROCESSOR = mc88110 ] ; then - if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx \ - -o ${TARGET_BINARY_INTERFACE}x = x ] ; then - echo m88k-dg-dgux${UNAME_RELEASE} - else - echo m88k-dg-dguxbcs${UNAME_RELEASE} - fi - else echo i586-dg-dgux${UNAME_RELEASE} - fi - exit 0 ;; - M88*:DolphinOS:*:*) # DolphinOS (SVR3) - echo m88k-dolphin-sysv3 - exit 0 ;; - M88*:*:R3*:*) - # Delta 88k system running SVR3 - echo m88k-motorola-sysv3 - exit 0 ;; - XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) - echo m88k-tektronix-sysv3 - exit 0 ;; - Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) - echo m68k-tektronix-bsd - exit 0 ;; - *:IRIX*:*:*) - echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` - exit 0 ;; - ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. - echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id - exit 0 ;; # Note that: echo "'`uname -s`'" gives 'AIX ' - i?86:AIX:*:*) - echo i386-ibm-aix - exit 0 ;; - *:AIX:2:3) - if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then - sed 's/^ //' << EOF >$dummy.c - #include <sys/systemcfg.h> - - main() - { - if (!__power_pc()) - exit(1); - puts("powerpc-ibm-aix3.2.5"); - exit(0); - } -EOF - $CC_FOR_BUILD $dummy.c -o $dummy && ./$dummy && rm $dummy.c $dummy && exit 0 - rm -f $dummy.c $dummy - echo rs6000-ibm-aix3.2.5 - elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then - echo rs6000-ibm-aix3.2.4 - else - echo rs6000-ibm-aix3.2 - fi - exit 0 ;; - *:AIX:*:4) - IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | head -1 | awk '{ print $1 }'` - if /usr/sbin/lsattr -EHl ${IBM_CPU_ID} | grep POWER >/dev/null 2>&1; then - IBM_ARCH=rs6000 - else - IBM_ARCH=powerpc - fi - if [ -x /usr/bin/oslevel ] ; then - IBM_REV=`/usr/bin/oslevel` - else - IBM_REV=4.${UNAME_RELEASE} - fi - echo ${IBM_ARCH}-ibm-aix${IBM_REV} - exit 0 ;; - *:AIX:*:*) - echo rs6000-ibm-aix - exit 0 ;; - ibmrt:4.4BSD:*|romp-ibm:BSD:*) - echo romp-ibm-bsd4.4 - exit 0 ;; - ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC NetBSD and - echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to - exit 0 ;; # report: romp-ibm BSD 4.3 - *:BOSX:*:*) - echo rs6000-bull-bosx - exit 0 ;; - DPX/2?00:B.O.S.:*:*) - echo m68k-bull-sysv3 - exit 0 ;; - 9000/[34]??:4.3bsd:1.*:*) - echo m68k-hp-bsd - exit 0 ;; - hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) - echo m68k-hp-bsd4.4 - exit 0 ;; - 9000/[34678]??:HP-UX:*:*) - case "${UNAME_MACHINE}" in - 9000/31? ) HP_ARCH=m68000 ;; - 9000/[34]?? ) HP_ARCH=m68k ;; - 9000/[678][0-9][0-9]) - sed 's/^ //' << EOF >$dummy.c - #include <stdlib.h> - #include <unistd.h> - - int main () - { - #if defined(_SC_KERNEL_BITS) - long bits = sysconf(_SC_KERNEL_BITS); - #endif - long cpu = sysconf (_SC_CPU_VERSION); - - switch (cpu) - { - case CPU_PA_RISC1_0: puts ("hppa1.0"); break; - case CPU_PA_RISC1_1: puts ("hppa1.1"); break; - case CPU_PA_RISC2_0: - #if defined(_SC_KERNEL_BITS) - switch (bits) - { - case 64: puts ("hppa2.0w"); break; - case 32: puts ("hppa2.0n"); break; - default: puts ("hppa2.0"); break; - } break; - #else /* !defined(_SC_KERNEL_BITS) */ - puts ("hppa2.0"); break; - #endif - default: puts ("hppa1.0"); break; - } - exit (0); - } -EOF - ($CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null ) && HP_ARCH=`./$dummy` - rm -f $dummy.c $dummy - esac - HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` - echo ${HP_ARCH}-hp-hpux${HPUX_REV} - exit 0 ;; - 3050*:HI-UX:*:*) - sed 's/^ //' << EOF >$dummy.c - #include <unistd.h> - int - main () - { - long cpu = sysconf (_SC_CPU_VERSION); - /* The order matters, because CPU_IS_HP_MC68K erroneously returns - true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct - results, however. */ - if (CPU_IS_PA_RISC (cpu)) - { - switch (cpu) - { - case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; - case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; - case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; - default: puts ("hppa-hitachi-hiuxwe2"); break; - } - } - else if (CPU_IS_HP_MC68K (cpu)) - puts ("m68k-hitachi-hiuxwe2"); - else puts ("unknown-hitachi-hiuxwe2"); - exit (0); - } -EOF - $CC_FOR_BUILD $dummy.c -o $dummy && ./$dummy && rm $dummy.c $dummy && exit 0 - rm -f $dummy.c $dummy - echo unknown-hitachi-hiuxwe2 - exit 0 ;; - 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) - echo hppa1.1-hp-bsd - exit 0 ;; - 9000/8??:4.3bsd:*:*) - echo hppa1.0-hp-bsd - exit 0 ;; - *9??*:MPE/iX:*:*) - echo hppa1.0-hp-mpeix - exit 0 ;; - hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) - echo hppa1.1-hp-osf - exit 0 ;; - hp8??:OSF1:*:*) - echo hppa1.0-hp-osf - exit 0 ;; - i?86:OSF1:*:*) - if [ -x /usr/sbin/sysversion ] ; then - echo ${UNAME_MACHINE}-unknown-osf1mk - else - echo ${UNAME_MACHINE}-unknown-osf1 - fi - exit 0 ;; - parisc*:Lites*:*:*) - echo hppa1.1-hp-lites - exit 0 ;; - hppa*:OpenBSD:*:*) - echo hppa-unknown-openbsd - exit 0 ;; - C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) - echo c1-convex-bsd - exit 0 ;; - C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) - if getsysinfo -f scalar_acc - then echo c32-convex-bsd - else echo c2-convex-bsd - fi - exit 0 ;; - C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) - echo c34-convex-bsd - exit 0 ;; - C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) - echo c38-convex-bsd - exit 0 ;; - C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) - echo c4-convex-bsd - exit 0 ;; - CRAY*X-MP:*:*:*) - echo xmp-cray-unicos - exit 0 ;; - CRAY*Y-MP:*:*:*) - echo ymp-cray-unicos${UNAME_RELEASE} - exit 0 ;; - CRAY*[A-Z]90:*:*:*) - echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ - | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ - -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ - exit 0 ;; - CRAY*TS:*:*:*) - echo t90-cray-unicos${UNAME_RELEASE} - exit 0 ;; - CRAY*T3E:*:*:*) - echo t3e-cray-unicosmk${UNAME_RELEASE} - exit 0 ;; - CRAY-2:*:*:*) - echo cray2-cray-unicos - exit 0 ;; - F300:UNIX_System_V:*:*) - FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` - FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` - echo "f300-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" - exit 0 ;; - F301:UNIX_System_V:*:*) - echo f301-fujitsu-uxpv`echo $UNAME_RELEASE | sed 's/ .*//'` - exit 0 ;; - hp3[0-9][05]:NetBSD:*:*) - echo m68k-hp-netbsd${UNAME_RELEASE} - exit 0 ;; - hp300:OpenBSD:*:*) - echo m68k-unknown-openbsd${UNAME_RELEASE} - exit 0 ;; - i?86:BSD/386:*:* | i?86:BSD/OS:*:*) - echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} - exit 0 ;; - sparc*:BSD/OS:*:*) - echo sparc-unknown-bsdi${UNAME_RELEASE} - exit 0 ;; - *:BSD/OS:*:*) - echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} - exit 0 ;; - *:FreeBSD:*:*) - if test -x /usr/bin/objformat; then - if test "elf" = "`/usr/bin/objformat`"; then - echo ${UNAME_MACHINE}-unknown-freebsdelf`echo ${UNAME_RELEASE}|sed -e 's/[-_].*//'` - exit 0 - fi - fi - echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` - exit 0 ;; - *:NetBSD:*:*) - echo ${UNAME_MACHINE}-unknown-netbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` - exit 0 ;; - *:OpenBSD:*:*) - echo ${UNAME_MACHINE}-unknown-openbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` - exit 0 ;; - i*:CYGWIN*:*) - echo ${UNAME_MACHINE}-pc-cygwin - exit 0 ;; - i*:MINGW*:*) - echo ${UNAME_MACHINE}-pc-mingw32 - exit 0 ;; - i*:Windows_NT*:* | Pentium*:Windows_NT*:*) - # How do we know it's Interix rather than the generic POSIX subsystem? - # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we - # UNAME_MACHINE based on the output of uname instead of i386? - echo i386-pc-interix - exit 0 ;; - i*:UWIN*:*) - echo ${UNAME_MACHINE}-pc-uwin - exit 0 ;; - p*:CYGWIN*:*) - echo powerpcle-unknown-cygwin - exit 0 ;; - prep*:SunOS:5.*:*) - echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` - exit 0 ;; - *:GNU:*:*) - echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` - exit 0 ;; - *:Linux:*:*) -# # uname on the ARM produces all sorts of strangeness, and we need to -# # filter it out. -# case "$UNAME_MACHINE" in -# armv*) UNAME_MACHINE=$UNAME_MACHINE ;; -# arm* | sa110*) UNAME_MACHINE="arm" ;; -# esac - - # The BFD linker knows what the default object file format is, so - # first see if it will tell us. cd to the root directory to prevent - # problems with other programs or directories called `ld' in the path. - ld_help_string=`cd /; ld --help 2>&1` - ld_supported_emulations=`echo $ld_help_string \ - | sed -ne '/supported emulations:/!d - s/[ ][ ]*/ /g - s/.*supported emulations: *// - s/ .*// - p'` - case "$ld_supported_emulations" in - i?86linux) echo "${UNAME_MACHINE}-pc-linux-gnuaout" ; exit 0 ;; - i?86coff) echo "${UNAME_MACHINE}-pc-linux-gnucoff" ; exit 0 ;; - sparclinux) echo "${UNAME_MACHINE}-unknown-linux-gnuaout" ; exit 0 ;; - armlinux) echo "${UNAME_MACHINE}-unknown-linux-gnuaout" ; exit 0 ;; - m68klinux) echo "${UNAME_MACHINE}-unknown-linux-gnuaout" ; exit 0 ;; - elf32arm) echo "${UNAME_MACHINE}-unknown-linux-gnu" ; exit 0 ;; - elf32ppc) - # Determine Lib Version - cat >$dummy.c <<EOF -#include <features.h> -#if defined(__GLIBC__) -extern char __libc_version[]; -extern char __libc_release[]; -#endif -main(argc, argv) - int argc; - char *argv[]; -{ -#if defined(__GLIBC__) - printf("%s %s\n", __libc_version, __libc_release); -#else - printf("unkown\n"); -#endif - return 0; -} -EOF - LIBC="" - $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null - if test "$?" = 0 ; then - ./$dummy | grep 1\.99 > /dev/null - if test "$?" = 0 ; then - LIBC="libc1" - fi - fi - rm -f $dummy.c $dummy - echo powerpc-unknown-linux-gnu${LIBC} ; exit 0 ;; - esac - - if test "${UNAME_MACHINE}" = "alpha" ; then - sed 's/^ //' <<EOF >$dummy.s - .globl main - .ent main - main: - .frame \$30,0,\$26,0 - .prologue 0 - .long 0x47e03d80 # implver $0 - lda \$2,259 - .long 0x47e20c21 # amask $2,$1 - srl \$1,8,\$2 - sll \$2,2,\$2 - sll \$0,3,\$0 - addl \$1,\$0,\$0 - addl \$2,\$0,\$0 - ret \$31,(\$26),1 - .end main -EOF - LIBC="" - $CC_FOR_BUILD $dummy.s -o $dummy 2>/dev/null - if test "$?" = 0 ; then - ./$dummy - case "$?" in - 7) - UNAME_MACHINE="alpha" - ;; - 15) - UNAME_MACHINE="alphaev5" - ;; - 14) - UNAME_MACHINE="alphaev56" - ;; - 10) - UNAME_MACHINE="alphapca56" - ;; - 16) - UNAME_MACHINE="alphaev6" - ;; - esac - - objdump --private-headers $dummy | \ - grep ld.so.1 > /dev/null - if test "$?" = 0 ; then - LIBC="libc1" - fi - fi - rm -f $dummy.s $dummy - echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} ; exit 0 - elif test "${UNAME_MACHINE}" = "mips" ; then - cat >$dummy.c <<EOF -#ifdef __cplusplus - int main (int argc, char *argv[]) { -#else - int main (argc, argv) int argc; char *argv[]; { -#endif -#ifdef __MIPSEB__ - printf ("%s-unknown-linux-gnu\n", argv[1]); -#endif -#ifdef __MIPSEL__ - printf ("%sel-unknown-linux-gnu\n", argv[1]); -#endif - return 0; -} -EOF - $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy "${UNAME_MACHINE}" && rm $dummy.c $dummy && exit 0 - rm -f $dummy.c $dummy - else - # Either a pre-BFD a.out linker (linux-gnuoldld) - # or one that does not give us useful --help. - # GCC wants to distinguish between linux-gnuoldld and linux-gnuaout. - # If ld does not provide *any* "supported emulations:" - # that means it is gnuoldld. - echo "$ld_help_string" | grep >/dev/null 2>&1 "supported emulations:" - test $? != 0 && echo "${UNAME_MACHINE}-pc-linux-gnuoldld" && exit 0 - - case "${UNAME_MACHINE}" in - i?86) - VENDOR=pc; - ;; - *) - VENDOR=unknown; - ;; - esac - # Determine whether the default compiler is a.out or elf - cat >$dummy.c <<EOF -#include <features.h> -#ifdef __cplusplus - int main (int argc, char *argv[]) { -#else - int main (argc, argv) int argc; char *argv[]; { -#endif -#ifdef __ELF__ -# ifdef __GLIBC__ -# if __GLIBC__ >= 2 - printf ("%s-${VENDOR}-linux-gnu\n", argv[1]); -# else - printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]); -# endif -# else - printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]); -# endif -#else - printf ("%s-${VENDOR}-linux-gnuaout\n", argv[1]); -#endif - return 0; -} -EOF - $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy "${UNAME_MACHINE}" && rm $dummy.c $dummy && exit 0 - rm -f $dummy.c $dummy - fi ;; -# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. earlier versions -# are messed up and put the nodename in both sysname and nodename. - i?86:DYNIX/ptx:4*:*) - echo i386-sequent-sysv4 - exit 0 ;; - i?86:UNIX_SV:4.2MP:2.*) - # Unixware is an offshoot of SVR4, but it has its own version - # number series starting with 2... - # I am not positive that other SVR4 systems won't match this, - # I just have to hope. -- rms. - # Use sysv4.2uw... so that sysv4* matches it. - echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} - exit 0 ;; - i?86:*:4.*:* | i?86:SYSTEM_V:4.*:*) - if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then - echo ${UNAME_MACHINE}-univel-sysv${UNAME_RELEASE} - else - echo ${UNAME_MACHINE}-pc-sysv${UNAME_RELEASE} - fi - exit 0 ;; - i?86:*:5:7*) - UNAME_REL=`(/bin/uname -X|egrep Release|sed -e 's/.*= //')` - (/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486 - (/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) && UNAME_MACHINE=i586 - (/bin/uname -X|egrep '^Machine.*Pent.*II' >/dev/null) && UNAME_MACHINE=i686 - (/bin/uname -X|egrep '^Machine.*Pentium Pro' >/dev/null) && UNAME_MACHINE=i585 - echo ${UNAME_MACHINE}-${UNAME_SYSTEM}${UNAME_VERSION}-sysv${UNAME_RELEASE} - exit 0 ;; - i?86:*:3.2:*) - if test -f /usr/options/cb.name; then - UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name` - echo ${UNAME_MACHINE}-pc-isc$UNAME_REL - elif /bin/uname -X 2>/dev/null >/dev/null ; then - UNAME_REL=`(/bin/uname -X|egrep Release|sed -e 's/.*= //')` - (/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486 - (/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) \ - && UNAME_MACHINE=i586 - (/bin/uname -X|egrep '^Machine.*Pent ?II' >/dev/null) \ - && UNAME_MACHINE=i686 - (/bin/uname -X|egrep '^Machine.*Pentium Pro' >/dev/null) \ - && UNAME_MACHINE=i686 - echo ${UNAME_MACHINE}-pc-sco$UNAME_REL - else - echo ${UNAME_MACHINE}-pc-sysv32 - fi - exit 0 ;; - pc:*:*:*) - # uname -m prints for DJGPP always 'pc', but it prints nothing about - # the processor, so we play safe by assuming i386. - echo i386-pc-msdosdjgpp - exit 0 ;; - Intel:Mach:3*:*) - echo i386-pc-mach3 - exit 0 ;; - paragon:*:*:*) - echo i860-intel-osf1 - exit 0 ;; - i860:*:4.*:*) # i860-SVR4 - if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then - echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 - else # Add other i860-SVR4 vendors below as they are discovered. - echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 - fi - exit 0 ;; - mini*:CTIX:SYS*5:*) - # "miniframe" - echo m68010-convergent-sysv - exit 0 ;; - M68*:*:R3V[567]*:*) - test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;; - 3[34]??:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 4850:*:4.0:3.0) - OS_REL='' - test -r /etc/.relid \ - && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` - /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ - && echo i486-ncr-sysv4.3${OS_REL} && exit 0 - /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ - && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;; - 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) - /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ - && echo i486-ncr-sysv4 && exit 0 ;; - m68*:LynxOS:2.*:*) - echo m68k-unknown-lynxos${UNAME_RELEASE} - exit 0 ;; - mc68030:UNIX_System_V:4.*:*) - echo m68k-atari-sysv4 - exit 0 ;; - i?86:LynxOS:2.*:* | i?86:LynxOS:3.[01]*:*) - echo i386-unknown-lynxos${UNAME_RELEASE} - exit 0 ;; - TSUNAMI:LynxOS:2.*:*) - echo sparc-unknown-lynxos${UNAME_RELEASE} - exit 0 ;; - rs6000:LynxOS:2.*:* | PowerPC:LynxOS:2.*:*) - echo rs6000-unknown-lynxos${UNAME_RELEASE} - exit 0 ;; - SM[BE]S:UNIX_SV:*:*) - echo mips-dde-sysv${UNAME_RELEASE} - exit 0 ;; - RM*:ReliantUNIX-*:*:*) - echo mips-sni-sysv4 - exit 0 ;; - RM*:SINIX-*:*:*) - echo mips-sni-sysv4 - exit 0 ;; - *:SINIX-*:*:*) - if uname -p 2>/dev/null >/dev/null ; then - UNAME_MACHINE=`(uname -p) 2>/dev/null` - echo ${UNAME_MACHINE}-sni-sysv4 - else - echo ns32k-sni-sysv - fi - exit 0 ;; - PENTIUM:CPunix:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort - # says <Richard.M.Bartel@ccMail.Census.GOV> - echo i586-unisys-sysv4 - exit 0 ;; - *:UNIX_System_V:4*:FTX*) - # From Gerald Hewes <hewes@openmarket.com>. - # How about differentiating between stratus architectures? -djm - echo hppa1.1-stratus-sysv4 - exit 0 ;; - *:*:*:FTX*) - # From seanf@swdc.stratus.com. - echo i860-stratus-sysv4 - exit 0 ;; - mc68*:A/UX:*:*) - echo m68k-apple-aux${UNAME_RELEASE} - exit 0 ;; - news*:NEWS-OS:*:6*) - echo mips-sony-newsos6 - exit 0 ;; - R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) - if [ -d /usr/nec ]; then - echo mips-nec-sysv${UNAME_RELEASE} - else - echo mips-unknown-sysv${UNAME_RELEASE} - fi - exit 0 ;; - BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. - echo powerpc-be-beos - exit 0 ;; - BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. - echo powerpc-apple-beos - exit 0 ;; - BePC:BeOS:*:*) # BeOS running on Intel PC compatible. - echo i586-pc-beos - exit 0 ;; - SX-4:SUPER-UX:*:*) - echo sx4-nec-superux${UNAME_RELEASE} - exit 0 ;; - SX-5:SUPER-UX:*:*) - echo sx5-nec-superux${UNAME_RELEASE} - exit 0 ;; - Power*:Rhapsody:*:*) - echo powerpc-apple-rhapsody${UNAME_RELEASE} - exit 0 ;; - *:Rhapsody:*:*) - echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} - exit 0 ;; - *:OS/2:*:*) - echo "i386-pc-os2_emx" - exit 0;; -esac - -#echo '(No uname command or uname output not recognized.)' 1>&2 -#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 - -cat >$dummy.c <<EOF -#ifdef _SEQUENT_ -# include <sys/types.h> -# include <sys/utsname.h> -#endif -main () -{ -#if defined (sony) -#if defined (MIPSEB) - /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, - I don't know.... */ - printf ("mips-sony-bsd\n"); exit (0); -#else -#include <sys/param.h> - printf ("m68k-sony-newsos%s\n", -#ifdef NEWSOS4 - "4" -#else - "" -#endif - ); exit (0); -#endif -#endif - -#if defined (__arm) && defined (__acorn) && defined (__unix) - printf ("arm-acorn-riscix"); exit (0); -#endif - -#if defined (hp300) && !defined (hpux) - printf ("m68k-hp-bsd\n"); exit (0); -#endif - -#if defined (NeXT) -#if !defined (__ARCHITECTURE__) -#define __ARCHITECTURE__ "m68k" -#endif - int version; - version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; - if (version < 4) - printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); - else - printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); - exit (0); -#endif - -#if defined (MULTIMAX) || defined (n16) -#if defined (UMAXV) - printf ("ns32k-encore-sysv\n"); exit (0); -#else -#if defined (CMU) - printf ("ns32k-encore-mach\n"); exit (0); -#else - printf ("ns32k-encore-bsd\n"); exit (0); -#endif -#endif -#endif - -#if defined (__386BSD__) - printf ("i386-pc-bsd\n"); exit (0); -#endif - -#if defined (sequent) -#if defined (i386) - printf ("i386-sequent-dynix\n"); exit (0); -#endif -#if defined (ns32000) - printf ("ns32k-sequent-dynix\n"); exit (0); -#endif -#endif - -#if defined (_SEQUENT_) - struct utsname un; - - uname(&un); - - if (strncmp(un.version, "V2", 2) == 0) { - printf ("i386-sequent-ptx2\n"); exit (0); - } - if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ - printf ("i386-sequent-ptx1\n"); exit (0); - } - printf ("i386-sequent-ptx\n"); exit (0); - -#endif - -#if defined (vax) -#if !defined (ultrix) - printf ("vax-dec-bsd\n"); exit (0); -#else - printf ("vax-dec-ultrix\n"); exit (0); -#endif -#endif - -#if defined (alliant) && defined (i860) - printf ("i860-alliant-bsd\n"); exit (0); -#endif - - exit (1); -} -EOF - -$CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy && rm $dummy.c $dummy && exit 0 -rm -f $dummy.c $dummy - -# Apollos put the system type in the environment. - -test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; } - -# Convex versions that predate uname can use getsysinfo(1) - -if [ -x /usr/convex/getsysinfo ] -then - case `getsysinfo -f cpu_type` in - c1*) - echo c1-convex-bsd - exit 0 ;; - c2*) - if getsysinfo -f scalar_acc - then echo c32-convex-bsd - else echo c2-convex-bsd - fi - exit 0 ;; - c34*) - echo c34-convex-bsd - exit 0 ;; - c38*) - echo c38-convex-bsd - exit 0 ;; - c4*) - echo c4-convex-bsd - exit 0 ;; - esac -fi - -#echo '(Unable to guess system type)' 1>&2 - -exit 1 diff --git a/config.layout b/config.layout new file mode 100644 index 00000000000..0f42e84e273 --- /dev/null +++ b/config.layout @@ -0,0 +1,231 @@ +## +## config.layout -- Pre-defined Installation Path Layouts +## +## Hints: +## - layouts can be loaded with configure's --enable-layout=ID option +## - when no --enable-layout option is given, the default layout is `apr' +## - a trailing plus character (`+') on paths is replaced with a +## `/<target>' suffix where <target> is currently hardcoded to 'apr'. +## (This may become a configurable parameter at some point.) +## + +# Classical APR path layout designed for parallel installs. +<Layout apr> + prefix: /usr/local/apr + exec_prefix: ${prefix} + bindir: ${exec_prefix}/bin + sbindir: ${exec_prefix}/bin + libdir: ${exec_prefix}/lib + libexecdir: ${exec_prefix}/modules + mandir: ${prefix}/man + sysconfdir: ${prefix}/conf + datadir: ${prefix} + installbuilddir: ${datadir}/build-${APR_MAJOR_VERSION} + includedir: ${prefix}/include/apr-${APR_MAJOR_VERSION} + localstatedir: ${prefix} + libsuffix: -${APR_MAJOR_VERSION} +</Layout> + +# Classical single-installation APR path layout. +<Layout classic> + prefix: /usr/local/apr + exec_prefix: ${prefix} + bindir: ${exec_prefix}/bin + sbindir: ${exec_prefix}/bin + libdir: ${exec_prefix}/lib + libexecdir: ${exec_prefix}/modules + mandir: ${prefix}/man + sysconfdir: ${prefix}/conf + datadir: ${prefix} + installbuilddir: ${datadir}/build + includedir: ${prefix}/include + localstatedir: ${prefix} +</Layout> + +# GNU standards conforming path layout. +# See FSF's GNU project `make-stds' document for details. +<Layout GNU> + prefix: /usr/local + exec_prefix: ${prefix} + bindir: ${exec_prefix}/bin + sbindir: ${exec_prefix}/sbin + libdir: ${exec_prefix}/lib + libexecdir: ${exec_prefix}/libexec + mandir: ${prefix}/man + sysconfdir: ${prefix}/etc+ + datadir: ${prefix}/share+ + installbuilddir: ${datadir}/build + includedir: ${prefix}/include+ + localstatedir: ${prefix}/var+ + runtimedir: ${localstatedir}/run +</Layout> + +# Mac OS X Server (Rhapsody) +<Layout Mac OS X Server> + prefix: /Local/Library/WebServer + exec_prefix: /usr + bindir: ${exec_prefix}/bin + sbindir: ${exec_prefix}/sbin + libdir: ${exec_prefix}/lib + libexecdir: /System/Library/apr/Modules + mandir: ${exec_prefix}/share/man + sysconfdir: ${prefix}/Configuration + datadir: ${prefix} + installbuilddir: /System/Library/apr/Build + includedir: /System/Library/Frameworks/apr.framework/Versions/2.0/Headers + localstatedir: /var + runtimedir: ${prefix}/Logs +</Layout> + +# Darwin/Mac OS Layout +<Layout Darwin> + prefix: /usr + exec_prefix: ${prefix} + bindir: ${exec_prefix}/bin + sbindir: ${exec_prefix}/sbin + libdir: ${exec_prefix}/lib + libexecdir: ${exec_prefix}/libexec+ + mandir: ${prefix}/share/man + datadir: /Library/WebServer + sysconfdir: /etc+ + installbuilddir: ${prefix}/share/httpd/build + includedir: ${prefix}/include+ + localstatedir: /var + runtimedir: ${localstatedir}/run +</Layout> + +# Red Hat Linux 7.x layout +<Layout RedHat> + prefix: /usr + exec_prefix: ${prefix} + bindir: ${prefix}/bin + sbindir: ${prefix}/sbin + libdir: ${prefix}/lib + libexecdir: ${prefix}/lib/apr + mandir: ${prefix}/man + sysconfdir: /etc/httpd/conf + datadir: /var/www + installbuilddir: ${datadir}/build + includedir: ${prefix}/include/apr + localstatedir: /var + runtimedir: ${localstatedir}/run +</Layout> + +# According to the /opt filesystem conventions +<Layout opt> + prefix: /opt/apr + exec_prefix: ${prefix} + bindir: ${exec_prefix}/bin + sbindir: ${exec_prefix}/sbin + libdir: ${exec_prefix}/lib + libexecdir: ${exec_prefix}/libexec + mandir: ${prefix}/man + sysconfdir: /etc${prefix} + datadir: ${prefix}/share + installbuilddir: ${datadir}/build + includedir: ${prefix}/include + localstatedir: /var${prefix} + runtimedir: ${localstatedir}/run +</Layout> + +# BeOS layout... +<Layout beos> + prefix: /boot/home/apr + exec_prefix: ${prefix} + bindir: ${exec_prefix}/bin + sbindir: ${exec_prefix}/bin + libdir: ${exec_prefix}/lib + libexecdir: ${exec_prefix}/libexec + mandir: ${prefix}/man + sysconfdir: ${prefix}/conf + datadir: ${prefix} + installbuilddir: ${datadir}/build + includedir: ${prefix}/include + localstatedir: ${prefix} + runtimedir: ${localstatedir}/logs +</Layout> + +# SuSE 6.x layout +<Layout SuSE> + prefix: /usr + exec_prefix: ${prefix} + bindir: ${prefix}/bin + sbindir: ${prefix}/sbin + libdir: ${prefix}/lib + libexecdir: ${prefix}/lib/apr + mandir: ${prefix}/share/man + sysconfdir: /etc/httpd + datadir: /usr/local/httpd + installbuilddir: ${datadir}/build + includedir: ${prefix}/include/apr + localstatedir: /var/lib/httpd + runtimedir: /var/run +</Layout> + +# BSD/OS layout +<Layout BSDI> + prefix: /var/www + exec_prefix: /usr/contrib + bindir: ${exec_prefix}/bin + sbindir: ${exec_prefix}/bin + libdir: ${exec_prefix}/lib + libexecdir: ${exec_prefix}/libexec/apr + mandir: ${exec_prefix}/man + sysconfdir: ${prefix}/conf + datadir: ${prefix} + installbuilddir: ${datadir}/build + includedir: ${exec_prefix}/include/apr + localstatedir: /var + runtimedir: ${localstatedir}/run +</Layout> + +# Solaris 8 Layout +<Layout Solaris> + prefix: /usr/apr + exec_prefix: ${prefix} + bindir: ${exec_prefix}/bin + sbindir: ${exec_prefix}/bin + libdir: ${exec_prefix}/lib + libexecdir: ${exec_prefix}/libexec + mandir: ${exec_prefix}/man + sysconfdir: /etc/apr + datadir: /var/apr + installbuilddir: ${datadir}/build + includedir: ${exec_prefix}/include + localstatedir: ${prefix} + runtimedir: /var/run +</Layout> + +# OpenBSD Layout +<Layout OpenBSD> + prefix: /var/www + exec_prefix: /usr + bindir: ${exec_prefix}/bin + sbindir: ${exec_prefix}/sbin + libdir: ${exec_prefix}/lib + libexecdir: ${exec_prefix}/lib/apr/modules + mandir: ${exec_prefix}/share/man + sysconfdir: ${prefix}/conf + datadir: ${prefix} + installbuilddir: ${prefix}/build + includedir: ${exec_prefix}/lib/apr/include + localstatedir: ${prefix} + runtimedir: ${prefix}/logs +</Layout> + +# Debian layout +<Layout Debian> + prefix: + exec_prefix: ${prefix}/usr + bindir: ${exec_prefix}/bin + sbindir: ${exec_prefix}/sbin + libdir: ${exec_prefix}/lib + libexecdir: ${exec_prefix}/lib/apr/modules + mandir: ${exec_prefix}/share/man + datadir: ${exec_prefix}/share/apr + includedir: ${exec_prefix}/include/apr-${APR_MAJOR_VERSION} + localstatedir: ${prefix}/var/run + runtimedir: ${prefix}/var/run + infodir: ${exec_prefix}/share/info + libsuffix: -${APR_MAJOR_VERSION} +</Layout> diff --git a/configure.in b/configure.in index 0817ac7f37f..b9d537cdb56 100644 --- a/configure.in +++ b/configure.in @@ -1,214 +1,1568 @@ -dnl ## -dnl ## Autoconf configuration file for APR -dnl ## +dnl +dnl Autoconf configuration file for APR +dnl +dnl Process this file with autoconf to produce a configure script. +dnl Use ./buildconf to prepare build files and run autoconf for APR. +AC_PREREQ(2.59) -AC_CONFIG_AUX_DIR(./helpers) -echo "Configuring APR library" -OS=`./config.guess` -OS=`./config.sub $OS` -echo "Platform: ${OS}" +AC_INIT(build/apr_common.m4) +AC_CONFIG_HEADER(include/arch/unix/apr_private.h) +AC_CONFIG_AUX_DIR(build) +AC_CONFIG_MACRO_DIR(build) -dnl # Some initial steps for configuration. We setup the default directory -dnl # and which files are to be configured. +dnl +dnl Include our own M4 macros along with those for libtool +dnl +sinclude(build/apr_common.m4) +sinclude(build/apr_network.m4) +sinclude(build/apr_threads.m4) +sinclude(build/apr_win32.m4) +sinclude(build/apr_hints.m4) +sinclude(build/libtool.m4) +sinclude(build/ltsugar.m4) +sinclude(build/argz.m4) +sinclude(build/ltoptions.m4) +sinclude(build/ltversion.m4) +sinclude(build/lt~obsolete.m4) -# These added to allow default directories to be used... -DEFAULT_OSDIR="unix" -echo "(Default will be ${DEFAULT_OSDIR})" -MODULES="file_io network_io threadproc misc locks time mmap shmem dso i18n" +sinclude(build/apu-conf.m4) +sinclude(build/xml.m4) +sinclude(build/apu-hints.m4) +sinclude(build/crypto.m4) +sinclude(build/dbm.m4) +sinclude(build/dbd.m4) +sinclude(build/dso.m4) +sinclude(build/iconv.m4) -dnl Process this file with autoconf to produce a configure script. -AC_INIT(configure.in) -AC_CONFIG_HEADER(include/apr_private.h) +dnl Hard-coded top of apr_private.h: +AH_TOP([ +#ifndef APR_PRIVATE_H +#define APR_PRIVATE_H + +/* Pick up publicly advertised headers and symbols before the + * APR internal private headers and symbols + */ +#include <apr.h> +]) + +dnl Hard-coded inclusion at the tail end of apr_private.h: +AH_BOTTOM([ +/* switch this on if we have a BeOS version below BONE */ +#if defined(BEOS) && !defined(HAVE_BONE_VERSION) +#define BEOS_R5 1 +#else +#define BEOS_BONE 1 +#endif + +/* + * Darwin 10's default compiler (gcc42) builds for both 64 and + * 32 bit architectures unless specifically told not to. + * In those cases, we need to override types depending on how + * we're being built at compile time. + * NOTE: This is an ugly work-around for Darwin's + * concept of universal binaries, a single package + * (executable, lib, etc...) which contains both 32 + * and 64 bit versions. The issue is that if APR is + * built universally, if something else is compiled + * against it, some bit sizes will depend on whether + * it is 32 or 64 bit. This is determined by the __LP64__ + * flag. Since we need to support both, we have to + * handle OS X unqiuely. + */ +#ifdef DARWIN_10 + +#undef APR_OFF_T_STRFN +#undef APR_INT64_STRFN +#undef SIZEOF_LONG +#undef SIZEOF_SIZE_T +#undef SIZEOF_SSIZE_T +#undef SIZEOF_VOIDP +#undef SIZEOF_STRUCT_IOVEC + +#ifdef __LP64__ + #define APR_INT64_STRFN strtol + #define SIZEOF_LONG 8 + #define SIZEOF_SIZE_T 8 + #define SIZEOF_SSIZE_T 8 + #define SIZEOF_VOIDP 8 + #define SIZEOF_STRUCT_IOVEC 16 +#else + #define APR_INT64_STRFN strtoll + #define SIZEOF_LONG 4 + #define SIZEOF_SIZE_T 4 + #define SIZEOF_SSIZE_T 4 + #define SIZEOF_VOIDP 4 + #define SIZEOF_STRUCT_IOVEC 8 +#endif + +#undef APR_OFF_T_STRFN +#define APR_OFF_T_STRFN APR_INT64_STRFN + + +#undef SETPGRP_VOID +#ifdef __DARWIN_UNIX03 + #define SETPGRP_VOID 1 +#else +/* #undef SETPGRP_VOID */ +#endif + +#endif /* DARWIN_10 */ + +#endif /* APR_PRIVATE_H */ +]) + +dnl Save user-defined environment settings for later restoration +dnl +APR_SAVE_THE_ENVIRONMENT(CPPFLAGS) +APR_SAVE_THE_ENVIRONMENT(CFLAGS) +APR_SAVE_THE_ENVIRONMENT(LDFLAGS) +APR_SAVE_THE_ENVIRONMENT(LIBS) +APR_SAVE_THE_ENVIRONMENT(INCLUDES) + +dnl Generate ./config.nice for reproducing runs of configure +dnl +APR_CONFIG_NICE(config.nice) + +AC_CANONICAL_SYSTEM +AC_MSG_NOTICE([Configuring APR library]) +AC_MSG_NOTICE([Platform: $host]) + +dnl Some initial steps for configuration. We setup the default directory +dnl and which files are to be configured. + +dnl Setup the directory macros now + +# Absolute source/build directory +apr_srcdir=`(cd $srcdir && pwd)` +apr_builddir=`pwd` +AC_SUBST(apr_srcdir) +AC_SUBST(apr_builddir) + +if test "$apr_builddir" != "$apr_srcdir"; then + USE_VPATH=1 + APR_CONFIG_LOCATION=build +else + APR_CONFIG_LOCATION=source +fi -# Most platforms use a prefix of 'lib' on their library files. -LIBPREFIX='lib' +AC_SUBST(APR_CONFIG_LOCATION) -dnl # Checks for programs. +# Libtool might need this symbol -- it must point to the location of +# the generated libtool script (not necessarily the "top" build dir). +# +top_builddir="$apr_builddir" +AC_SUBST(top_builddir) + +# Directory containing apr build macros, helpers, and make rules +# NOTE: make rules (apr_rules.mk) will be in the builddir for vpath +# +apr_buildout=$apr_builddir/build +apr_builders=$apr_srcdir/build +AC_SUBST(apr_builders) + +MKDIR=$apr_builders/mkdir.sh + +dnl Initialize mkdir -p functionality. +APR_MKDIR_P_CHECK($apr_builders/mkdir.sh) + +# get our version information +get_version="$apr_builders/get-version.sh" +version_hdr="$apr_srcdir/include/apr_version.h" +APR_MAJOR_VERSION="`$get_version major $version_hdr APR`" +APR_DOTTED_VERSION="`$get_version all $version_hdr APR`" + +AC_SUBST(APR_DOTTED_VERSION) +AC_SUBST(APR_MAJOR_VERSION) + +AC_MSG_NOTICE([APR Version: ${APR_DOTTED_VERSION}]) + +dnl Enable the layout handling code, then reparse the prefix-style +dnl arguments due to autoconf being a PITA. +APR_ENABLE_LAYOUT(apr) +dnl This must be synchronized to the prefix of the apr layout, to make +dnl configure --help print the correct default. +AC_PREFIX_DEFAULT([/usr/local/apr]) +APR_PARSE_ARGUMENTS + +dnl Set optional CC hints here in case autoconf makes an inappropriate choice. +dnl This allows us to suggest what the compiler should be, but still +dnl allows the user to override CC externally. +APR_CC_HINTS + +dnl Do the various CC checks *before* preloading values. The preload code +dnl may need to use compiler characteristics to make decisions. This macro +dnl can only be used once within a configure script, so this prevents a +dnl preload section from invoking the macro to get compiler info. AC_PROG_CC -AC_PROG_RANLIB_NC + +dnl AC_PROG_SED is only avaliable in recent autoconf versions. +dnl Use AC_CHECK_PROG instead if AC_PROG_SED is not present. +ifdef([AC_PROG_SED], + [AC_PROG_SED], + [AC_CHECK_PROG(SED, sed, sed)]) + +dnl Preload +APR_PRELOAD + +dnl These added to allow default directories to be used... +DEFAULT_OSDIR="unix" +AC_MSG_NOTICE([(Default will be ${DEFAULT_OSDIR})]) + +apr_modules="file_io network_io threadproc misc locks time mmap shmem user memory atomic poll support random" + +dnl Checks for programs. AC_PROG_MAKE_SET +AC_PROG_CPP +AC_PROG_AWK +AC_PROG_LN_S +AC_PROG_RANLIB +AC_PROG_INSTALL AC_CHECK_PROG(RM, rm, rm) -AC_CHECK_PROG(AR, ar, ar) +AC_CHECK_TOOL(AS, as, as) +AC_CHECK_TOOL(ASCPP, cpp, cpp) +AC_CHECK_TOOL(AR, ar, ar) -# This macro needs to be here in case we are on an AIX box. +dnl Various OS checks that apparently set required flags +ifdef([AC_USE_SYSTEM_EXTENSIONS], [ +AC_USE_SYSTEM_EXTENSIONS +], [ AC_AIX +AC_MINIX +]) + +AC_ISC_POSIX +APR_EBCDIC + +dnl this is our library name +APR_LIBNAME="apr${libsuffix}" +AC_SUBST(APR_LIBNAME) + +dnl prep libtool +dnl +AC_MSG_NOTICE([performing libtool configuration...]) + +AC_ARG_ENABLE(experimental-libtool,[ --enable-experimental-libtool Use experimental custom libtool], + [experimental_libtool=$enableval],[experimental_libtool=no]) + +dnl Workarounds for busted Libtool 2.x when we don't call AC_PROG_LIBTOOL +if test "x$Xsed" = "x"; then + Xsed="$SED -e 1s/^X//" +fi -# Use /bin/sh if it exists, otherwise go looking for sh in the path -if test ".$SH" = . -a -f /bin/sh; then - SH="/bin/sh" +case $host in +*-os2*) + # Use a custom-made libtool replacement + AC_MSG_NOTICE([using aplibtool]) + LIBTOOL="$apr_builddir/build/aplibtool" + LIBTOOL_SRC="$apr_srcdir/build/aplibtool.c" + $CC $CFLAGS $CPPFLAGS -o $LIBTOOL.exe $LIBTOOL_SRC + ;; +*) + if test "x$LTFLAGS" = "x"; then + LTFLAGS='--silent' + fi + if test "$experimental_libtool" = "yes"; then + # Use a custom-made libtool replacement + AC_MSG_NOTICE([using jlibtool]) + LIBTOOL="$apr_builddir/libtool" + LIBTOOL_SRC="$apr_srcdir/build/jlibtool.c" + $CC $CFLAGS $CPPFLAGS -o $LIBTOOL $LIBTOOL_SRC + eval `$apr_builddir/libtool --config | grep "^shlibpath_var=[[A-Z_]]*$"` + if test "x$shlibpath_var" = "x"; then + shlibpath_var=REPLACE_WITH_YOUR_SHLIBPATH_VAR + fi + else + dnl libtoolize requires that the following not be indented + dnl should become LT_INIT(win32-dll) +AC_LIBTOOL_WIN32_DLL +AC_PROG_LIBTOOL + # get libtool's setting of shlibpath_var + eval `grep "^shlibpath_var=[[A-Z_]]*$" $apr_builddir/libtool` + if test "x$shlibpath_var" = "x"; then + shlibpath_var=REPLACE_WITH_YOUR_SHLIBPATH_VAR + fi + fi + ;; +esac + +AC_ARG_WITH(installbuilddir, [ --with-installbuilddir=DIR location to store APR build files (defaults to '${datadir}/build')], + [ installbuilddir=$withval ], [ installbuilddir="${datadir}/build-${APR_MAJOR_VERSION}" ] ) +AC_SUBST(installbuilddir) + +AC_ARG_WITH(libtool, [ --without-libtool avoid using libtool to link the library], + [ use_libtool=$withval ], [ use_libtool="yes" ] ) + +if test "x$use_libtool" = "xyes"; then + lt_compile='$(LIBTOOL) $(LTFLAGS) --mode=compile $(COMPILE) -o $@ -c $< && touch $@' + LT_VERSION="-version-info `$get_version libtool $version_hdr APR`" + link="\$(LIBTOOL) \$(LTFLAGS) --mode=link \$(COMPILE) \$(LT_LDFLAGS) \$(LT_VERSION) \$(ALL_LDFLAGS) -o \$@" + so_ext='lo' + lib_target='-rpath $(libdir) $(OBJECTS)' + export_lib_target='-rpath \$(libdir) \$(OBJECTS)' +else + lt_compile='$(COMPILE) -o $@ -c $<' + link='$(AR) cr $(TARGET_LIB) $(OBJECTS); $(RANLIB) $(TARGET_LIB)' + so_ext='o' + lib_target='' + export_lib_target='' fi -AC_CHECK_PROG(SH, sh, sh) -dnl #----------------------------- Checks for compiler flags +case $host in + *-solaris2*) + apr_platform_runtime_link_flag="-R" + ;; + *-mingw* | *-cygwin*) + LT_LDFLAGS="$LT_LDFLAGS -no-undefined" + ;; + *) + ;; +esac + +AC_SUBST(lt_compile) +AC_SUBST(link) +AC_SUBST(so_ext) +AC_SUBST(lib_target) +AC_SUBST(export_lib_target) +AC_SUBST(shlibpath_var) +AC_SUBST(LTFLAGS) +AC_SUBST(LT_LDFLAGS) +AC_SUBST(LT_VERSION) + +dnl ----------------------------- Checks for compiler flags nl=' ' -echo $ac_n "${nl}Check for compiler flags..." -AC_ARG_WITH(optim,[ --with-optim="FLAGS" compiler optimisation flags], - [OPTIM="$withval"]) - -AC_ARG_WITH(debug,[ --with-debug Turn on debugging and compile tim -e warnings], - [if test "$GCC" = "yes"; then CFLAGS="$CFLAGS -g -Wall"; else CFLAGS="$CFLAGS -g"; fi]) - -dnl # this is the place to put specific options for platform/compiler -dnl # combinations -case "$OS:$CC" in - *-hp-hpux*:cc ) CFLAGS="$CFLAGS -Ae +DAportable" ;; +AC_MSG_NOTICE([]) +AC_MSG_NOTICE([Check for compiler flags...]) + +dnl AC_PROG_CC sets -g in CFLAGS (and -O2 for gcc) by default. +dnl On OS/390 this causes the compiler to insert extra debugger +dnl hook instructions. That's fine for debug/maintainer builds, not fine +dnl otherwise. + +case $host in + *os390) + if test "$ac_test_CFLAGS" != set; then + APR_REMOVEFROM(CFLAGS,-g) + fi + ;; +esac + +AC_ARG_ENABLE(debug,[ --enable-debug Turn on debugging and compile time warnings], + [APR_ADDTO(CFLAGS,-g) + if test "$GCC" = "yes"; then + APR_ADDTO(CFLAGS,-Wall) + elif test "$AIX_XLC" = "yes"; then + APR_ADDTO(CFLAGS,-qfullpath) + fi +])dnl + +AC_ARG_ENABLE(maintainer-mode,[ --enable-maintainer-mode Turn on debugging and compile time warnings], + [APR_ADDTO(CFLAGS,-g) + if test "$GCC" = "yes"; then + APR_ADDTO(CFLAGS,[-Wall -Wmissing-prototypes -Wstrict-prototypes -Wmissing-declarations]) + case `($CC --version) 2>/dev/null` in + *clang-900* | *"clang version 5.0.0"*) + APR_ADDTO(CFLAGS,[-Wno-error=strict-prototypes]) + ;; + esac + elif test "$AIX_XLC" = "yes"; then + APR_ADDTO(CFLAGS,-qfullpath -qinitauto=FE -qcheck=all -qinfo=pro) + fi +])dnl + +AC_ARG_ENABLE(profile,[ --enable-profile Turn on profiling for the build (GCC)], + if test "$GCC" = "yes"; then + APR_ADDTO(CFLAGS, -pg) + APR_REMOVEFROM(CFLAGS, -g) + if test "$host" = "i586-pc-beos"; then + APR_REMOVEFROM(CFLAGS, -O2) + APR_ADDTO(CFLAGS, -O1) + APR_ADDTO(LDFLAGS, -p) + fi + fi +)dnl + +AC_ARG_ENABLE(pool-debug, + [ --enable-pool-debug[[=yes|no|verbose|verbose-alloc|lifetime|owner|all]] Turn on pools debugging], + [ if test -z "$enableval"; then + APR_ADDTO(CPPFLAGS, -DAPR_POOL_DEBUG=1) + elif test ! "$enableval" = "no"; then + apr_pool_debug=1 + + for i in $enableval + do + flag=0 + + case $i in + yes) + flag=1 + ;; + verbose) + flag=2 + ;; + lifetime) + flag=4 + ;; + owner) + flag=8 + ;; + verbose-alloc) + flag=16 + ;; + all) + apr_pool_debug=31 + ;; + *) + ;; + esac + + if test $flag -gt 0; then + apr_pool_debug=`expr '(' $apr_pool_debug - $apr_pool_debug % \ + '(' $flag '*' 2 ')' ')' + $flag + $apr_pool_debug % $flag` + fi + done + + APR_ADDTO(CPPFLAGS, -DAPR_POOL_DEBUG=$apr_pool_debug) + fi + ]) + +if test "$host" = "i586-pc-beos"; then + AC_ARG_ENABLE(malloc-debug,[ --enable-malloc-debug Switch on malloc_debug for BeOS], + APR_REMOVEFROM(CFLAGS, -O2) + APR_ADDTO(CPPFLAGS, -fcheck-memory-usage -D_KERNEL_MODE) + ) dnl +fi + +# this is the place to put specific options for platform/compiler +# combinations +case "$host:$CC" in + *-hp-hpux*:cc ) + APR_ADDTO(CFLAGS,[-Ae +Z]) + case $host in + ia64-* ) + ;; + * ) + if echo "$CFLAGS " | grep '+DA' >/dev/null; then : + else + APR_ADDTO(CFLAGS,[+DAportable]) + fi + ;; + esac + ;; powerpc-*-beos:mwcc* ) - CPP="mwcc -E" - CC="mwcc" - AR="ar" + APR_SETVAR(CPP,[mwcc -E]) + APR_SETVAR(CC,mwcc) + APR_SETVAR(AR,ar) + ;; + + dnl If building static APR, both the APR build and the app build + dnl need -DAPR_DECLARE_STATIC to generate the right linkage from + dnl APR_DECLARE et al. + dnl If building dynamic APR, the APR build needs APR_DECLARE_EXPORT + dnl and the app build should have neither define. + *-mingw* | *-cygwin*) + if test "$enable_shared" = "yes"; then + APR_ADDTO(INTERNAL_CPPFLAGS, -DAPR_DECLARE_EXPORT) + else + APR_ADDTO(CPPFLAGS, -DAPR_DECLARE_STATIC) + fi + ;; +esac + +AC_CACHE_CHECK([whether the compiler provides atomic builtins], [ap_cv_atomic_builtins], +[AC_TRY_RUN([ +int main() +{ + unsigned long val = 1010, tmp, *mem = &val; + + if (__sync_fetch_and_add(&val, 1010) != 1010 || val != 2020) + return 1; + + tmp = val; + + if (__sync_fetch_and_sub(mem, 1010) != tmp || val != 1010) + return 1; + + if (__sync_sub_and_fetch(&val, 1010) != 0 || val != 0) + return 1; + + tmp = 3030; + + if (__sync_val_compare_and_swap(mem, 0, tmp) != 0 || val != tmp) + return 1; + + if (__sync_lock_test_and_set(&val, 4040) != 3030) + return 1; + + mem = &tmp; + + if (__sync_val_compare_and_swap(&mem, &tmp, &val) != &tmp) + return 1; + + __sync_synchronize(); + + if (mem != &val) + return 1; + + return 0; +}], [ap_cv_atomic_builtins=yes], [ap_cv_atomic_builtins=no], [ap_cv_atomic_builtins=no])]) + +if test "$ap_cv_atomic_builtins" = "yes"; then + AC_DEFINE(HAVE_ATOMIC_BUILTINS, 1, [Define if compiler provides atomic builtins]) +fi + +AC_CACHE_CHECK([whether the compiler handles weak symbols], [ap_cv_weak_symbols], +[AC_TRY_RUN([ +__attribute__ ((weak)) +int weak_noop(void) +{ + return 0; +} +int main() +{ + return weak_noop(); +}], [ap_cv_weak_symbols=yes], [ap_cv_weak_symbols=no], [ap_cv_weak_symbols=no])]) + +if test "$ap_cv_weak_symbols" = "yes"; then + AC_DEFINE(HAVE_WEAK_SYMBOLS, 1, [Define if compiler handles weak symbols]) +fi + +case $host in + powerpc-405-*) + # The IBM ppc405cr processor has a bugged stwcx instruction. + AC_DEFINE(PPC405_ERRATA, 1, [Define on PowerPC 405 where errata 77 applies]) + ;; + *) ;; esac -case "$OS" in +dnl Check the depend program we can use +APR_CHECK_DEPEND + +proc_mutex_is_global=0 + +config_subdirs="none" +INSTALL_SUBDIRS="none" +OBJECTS_PLATFORM='$(OBJECTS_unix)' + +case $host in + i386-ibm-aix* | *-ibm-aix[[1-2]].* | *-ibm-aix3.* | *-ibm-aix4.1 | *-ibm-aix4.1.* | *-ibm-aix4.2 | *-ibm-aix4.2.*) + OSDIR="aix" + APR_ADDTO(LDFLAGS,-lld) + eolstr="\\n" + OBJECTS_PLATFORM='$(OBJECTS_aix)' + ;; *-os2*) - CFLAGS="$CFLAGS -DOS2 -Zmt" + APR_ADDTO(CPPFLAGS,-DOS2) + APR_ADDTO(CFLAGS,-Zmt) + AC_CHECK_LIB(bsd, random) OSDIR="os2" - LIBPREFIX="" - enable_apr_threads="system_threads" + enable_threads="system_threads" + eolstr="\\r\\n" + file_as_socket="0" + proc_mutex_is_global=1 + OBJECTS_PLATFORM='$(OBJECTS_os2)' ;; *beos*) OSDIR="beos" - CFLAGS="$CFLAGS -DBEOS" - enable_apr_threads="system_threads" - config_subdirs="shmem/unix/mm" + APR_ADDTO(CPPFLAGS,-DBEOS) + enable_threads="system_threads" + native_mmap_emul="1" + APR_CHECK_DEFINE(BONE_VERSION, sys/socket.h) + eolstr="\\n" + osver=`uname -r` + proc_mutex_is_global=1 + OBJECTS_PLATFORM='$(OBJECTS_beos)' + case $osver in + 5.0.4) + file_as_socket="1" + ;; + *) + file_as_socket="0" + ;; + esac + ;; + *apple-darwin*) + ac_cv_func_fdatasync="no" # Mac OS X wrongly reports it has fdatasync() + OSDIR="unix" + eolstr="\\n" + ;; + *os390) + OSDIR="os390" + OBJECTS_PLATFORM='$(OBJECTS_os390)' + eolstr="\\n" + ;; + *os400) + OSDIR="as400" + eolstr="\\n" + ;; + *mingw*) + OSDIR="win32" + enable_threads="system_threads" + eolstr="\\r\\n" + file_as_socket=0 + proc_mutex_is_global=1 + OBJECTS_PLATFORM='$(OBJECTS_win32)' + ;; + *cygwin*) + OSDIR="unix" + enable_threads="no" + eolstr="\\n" + ;; + *hpux10* ) + enable_threads="no" + OSDIR="unix" + eolstr="\\n" ;; *) OSDIR="unix" - config_subdirs="shmem/unix/mm" + eolstr="\\n" + ;; +esac + +AC_SUBST(OBJECTS_PLATFORM) + +# Check whether LFS has explicitly been disabled +AC_ARG_ENABLE(lfs,[ --disable-lfs Disable large file support on 32-bit platforms], +[apr_lfs_choice=$enableval], [apr_lfs_choice=yes]) + +if test "$apr_lfs_choice" = "yes"; then + # Check whether the transitional LFS API is sufficient + AC_CACHE_CHECK([whether to enable -D_LARGEFILE64_SOURCE], [apr_cv_use_lfs64], [ + apr_save_CPPFLAGS=$CPPFLAGS + CPPFLAGS="$CPPFLAGS -D_LARGEFILE64_SOURCE" + AC_TRY_RUN([ +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> + +void main(void) +{ + int fd, ret = 0; + struct stat64 st; + off64_t off = 4242; + + if (sizeof(off64_t) != 8 || sizeof(off_t) != 4) + exit(1); + if ((fd = open("conftest.lfs", O_LARGEFILE|O_CREAT|O_WRONLY, 0644)) < 0) + exit(2); + if (ftruncate64(fd, off) != 0) + ret = 3; + else if (fstat64(fd, &st) != 0 || st.st_size != off) + ret = 4; + else if (lseek64(fd, off, SEEK_SET) != off) + ret = 5; + else if (close(fd) != 0) + ret = 6; + else if (lstat64("conftest.lfs", &st) != 0 || st.st_size != off) + ret = 7; + else if (stat64("conftest.lfs", &st) != 0 || st.st_size != off) + ret = 8; + unlink("conftest.lfs"); + + exit(ret); +}], [apr_cv_use_lfs64=yes], [apr_cv_use_lfs64=no], [apr_cv_use_lfs64=no]) + CPPFLAGS=$apr_save_CPPFLAGS]) + if test "$apr_cv_use_lfs64" = "yes"; then + APR_ADDTO(CPPFLAGS, [-D_LARGEFILE64_SOURCE]) + fi +fi + +AC_ARG_ENABLE(nonportable-atomics, +[ --enable-nonportable-atomics Use optimized atomic code which may produce nonportable binaries], +[if test $enableval = yes; then + force_generic_atomics=no + else + force_generic_atomics=yes + fi +], +[case $host_cpu in + i[[456]]86) force_generic_atomics=yes ;; + *) force_generic_atomics=no + case $host in + *solaris2.10*) + AC_TRY_COMPILE( + [#include <atomic.h>], + [void *ptr = NULL; atomic_cas_ptr(&ptr, NULL, NULL);],, + [force_generic_atomics=yes] + ) + if test $force_generic_atomics = yes; then + AC_MSG_NOTICE([nonportable atomic support disabled, system needs Patch-ID 118884 or 118885]) + fi + ;; + esac + ;; +esac +]) + +if test $force_generic_atomics = yes; then + AC_DEFINE([USE_ATOMICS_GENERIC], 1, + [Define if use of generic atomics is requested]) +fi + +AC_SUBST(proc_mutex_is_global) +AC_SUBST(eolstr) +AC_SUBST(INSTALL_SUBDIRS) + +# For some platforms we need a version string which allows easy numeric +# comparisons. +case $host in + *freebsd*) + if test -x /sbin/sysctl; then + os_version=`/sbin/sysctl -n kern.osreldate` + else + os_version=000000 + fi + ;; + *linux*) + os_major=[`uname -r | sed -e 's/\([1-9][0-9]*\)\..*/\1/'`] + os_minor=[`uname -r | sed -e 's/[1-9][0-9]*\.\([0-9]\+\)\..*/\1/'`] + if test $os_major -lt 2 -o \( $os_major -eq 2 -a $os_minor -lt 4 \); then + AC_MSG_WARN([Configured for pre-2.4 Linux $os_major.$os_minor]) + os_pre24linux=1 + else + os_pre24linux=0 + AC_MSG_NOTICE([Configured for Linux $os_major.$os_minor]) + fi + ;; + *os390) + os_version=`uname -r | sed -e 's/\.//g'` + ;; + *) + os_version=OS_VERSION_IS_NOT_SET + ;; +esac + +AC_MSG_NOTICE([]) +AC_MSG_NOTICE([Checking for libraries...]) + +dnl ----------------------------- Checks for Any required Libraries +dnl Note: Autoconf will always append LIBS with an extra " " in AC_CHECK_LIB. +dnl It should check for LIBS being empty and set LIBS equal to the new value +dnl without the extra " " in that case, but they didn't do that. So, we +dnl end up LIBS="-lm -lcrypt -lnsl -ldl" which is an annoyance. +case $host in + *-mingw*) + APR_ADDTO(LIBS,[-lshell32 -ladvapi32 -lws2_32 -lrpcrt4 -lmswsock]) + ac_cv_func_CreateFileMapping=yes + ;; + *) + AC_SEARCH_LIBS(gethostbyname, nsl) + AC_SEARCH_LIBS(gethostname, nsl) + AC_SEARCH_LIBS(socket, socket) + AC_SEARCH_LIBS(crypt, crypt ufc) + AC_CHECK_LIB(truerand, main) + AC_SEARCH_LIBS(modf, m) ;; esac -if test ".$SYS_SW" = ".AIX"; then - CFLAGS="$CFLAGS -U__STR__" - case "$SYS_KV" in - [12]*) - AC_DEFINE(USEBCOPY) - OSDIR="aix" +dnl ----------------------------- Checking for Threads +AC_MSG_NOTICE([${nl}Checking for Threads...]) + +if test -z "$enable_threads"; then + AC_ARG_ENABLE(threads, + [ --enable-threads Enable threading support in APR.], + [ enable_threads=$enableval] , + [ APR_CHECK_PTHREADS_H([ enable_threads="pthread" ] , + [ enable_threads="no" ] ) ] ) +fi + +if test "$enable_threads" = "no"; then + threads="0" + pthreadh="0" + pthreadser="0" +else + if test "$enable_threads" = "pthread"; then +# We have specified pthreads for our threading library, just make sure +# that we have everything we need + APR_PTHREADS_CHECK_SAVE + APR_PTHREADS_CHECK + APR_CHECK_PTHREADS_H([ + threads="1" + pthreadh="1" + pthreadser="1" ], [ + threads="0" + pthreadh="0" + pthreadser="0" + APR_PTHREADS_CHECK_RESTORE ] ) + elif test "$enable_threads" = "system_threads"; then + threads="1" + pthreadh="0" + pthreadser="0" + else +# We basically specified that we wanted threads, but not how to implement +# them. In this case, just look for pthreads. In the future, we can check +# for other threading libraries as well. + APR_PTHREADS_CHECK_SAVE + APR_PTHREADS_CHECK + APR_CHECK_PTHREADS_H([ + threads="1" + pthreadh="1" + pthreadser="1" ], [ + threads="0" + pthreadser="0" + pthreadh="0" + APR_PTHREADS_CHECK_RESTORE ] ) + fi + if test "$pthreadh" = "1"; then + APR_CHECK_PTHREAD_GETSPECIFIC_TWO_ARGS + APR_CHECK_PTHREAD_ATTR_GETDETACHSTATE_ONE_ARG + APR_CHECK_PTHREAD_RECURSIVE_MUTEX + AC_CHECK_FUNCS([pthread_key_delete pthread_rwlock_init \ + pthread_attr_setguardsize pthread_yield]) + + if test "$ac_cv_func_pthread_rwlock_init" = "yes"; then + dnl ----------------------------- Checking for pthread_rwlock_t + AC_CACHE_CHECK([for pthread_rwlock_t], [apr_cv_type_rwlock_t], + AC_TRY_COMPILE([#include <sys/types.h> +#include <pthread.h>], [pthread_rwlock_t *rwlock;], + [apr_cv_type_rwlock_t=yes], [apr_cv_type_rwlock_t=no], + [apr_cv_type_rwlock_t=no])) + if test "$apr_cv_type_rwlock_t" = "yes"; then + AC_DEFINE(HAVE_PTHREAD_RWLOCKS, 1, [Define if pthread rwlocks are available]) + fi + fi + + if test "$ac_cv_func_pthread_yield" = "no"; then + dnl ----------------------------- Checking for sched_yield + AC_CHECK_HEADERS([sched.h]) + AC_CHECK_FUNCS([sched_yield]) + fi + fi +fi + +ac_cv_define_READDIR_IS_THREAD_SAFE=no +ac_cv_define_GETHOSTBYNAME_IS_THREAD_SAFE=no +ac_cv_define_GETHOSTBYADDR_IS_THREAD_SAFE=no +ac_cv_define_GETSERVBYNAME_IS_THREAD_SAFE=no +if test "$threads" = "1"; then + AC_MSG_NOTICE([APR will use threads]) + AC_CHECK_LIB(c_r, readdir, + AC_DEFINE(READDIR_IS_THREAD_SAFE, 1, + [Define if readdir is thread safe])) + if test "x$apr_gethostbyname_is_thread_safe" = "x"; then + AC_CHECK_LIB(c_r, gethostbyname, apr_gethostbyname_is_thread_safe=yes) + fi + if test "$apr_gethostbyname_is_thread_safe" = "yes"; then + AC_DEFINE(GETHOSTBYNAME_IS_THREAD_SAFE, 1, + [Define if gethostbyname is thread safe]) + fi + if test "x$apr_gethostbyaddr_is_thread_safe" = "x"; then + AC_CHECK_LIB(c_r, gethostbyaddr, apr_gethostbyaddr_is_thread_safe=yes) + fi + if test "$apr_gethostbyaddr_is_thread_safe" = "yes"; then + AC_DEFINE(GETHOSTBYADDR_IS_THREAD_SAFE, 1, + [Define if gethostbyaddr is thread safe]) + fi + if test "x$apr_getservbyname_is_thread_safe" = "x"; then + AC_CHECK_LIB(c_r, getservbyname, apr_getservbyname_is_thread_safe=yes) + fi + if test "$apr_getservbyname_is_thread_safe" = "yes"; then + AC_DEFINE(GETSERVBYNAME_IS_THREAD_SAFE, 1, + [Define if getservbyname is thread safe]) + fi + AC_CHECK_FUNCS(gethostbyname_r gethostbyaddr_r getservbyname_r) +else + AC_MSG_NOTICE([APR will be non-threaded]) +fi + +dnl Electric Fence malloc checker. +dnl --with-efence specifies the path to Electric Fence. +dnl This test should remain after the threads checks since libefence +dnl may depend on libpthread. +AC_ARG_WITH(efence, + [ --with-efence[[=DIR]] path to Electric Fence installation], + [ apr_efence_dir="$withval" + if test "$apr_efence_dir" != "yes"; then + APR_ADDTO(LDFLAGS,[-L$apr_efence_dir/lib]) + if test "x$apr_platform_runtime_link_flag" != "x"; then + APR_ADDTO(LDFLAGS, + [$apr_platform_runtime_link_flag$apr_efence_dir/lib]) + fi + fi + AC_CHECK_LIB(efence, malloc, + [ APR_ADDTO(LIBS,-lefence) ], + [ AC_MSG_ERROR(Electric Fence requested but not detected) ]) + ]) + +AC_ARG_WITH(valgrind, + [ --with-valgrind[[=DIR]] Enable code to teach valgrind about apr pools + (optionally: set path to valgrind headers) ], + [ if test "$withval" != no; then + if test "$withval" = yes; then + withval=/usr/include/valgrind + fi + APR_ADDTO(CPPFLAGS, -I$withval) + AC_CHECK_HEADERS(valgrind.h memcheck.h) + APR_IFALLYES(header:valgrind.h header:memcheck.h, + [AC_DEFINE(HAVE_VALGRIND, 1, [Compile in valgrind support]) ], + [AC_MSG_ERROR(valgrind headers not found) ] + ) + fi ] +) + +AC_CHECK_FUNCS(sigsuspend, [ have_sigsuspend="1" ], [ have_sigsuspend="0" ]) +AC_CHECK_FUNCS(sigwait, [ have_sigwait="1" ], [ have_sigwait="0" ]) +dnl AC_CHECK_FUNCS doesn't work for this on Tru64 since the function +dnl is renamed in signal.h. Todo: Autodetect +case $host in + *alpha*-dec-osf* ) + have_sigwait="1" + ;; +esac + +AC_SUBST(threads) +AC_SUBST(have_sigsuspend) +AC_SUBST(have_sigwait) + +AC_CHECK_FUNCS(poll kqueue port_create) + +# Check for the Linux epoll interface; epoll* may be available in libc +# but return ENOSYS on a pre-2.6 kernel, so do a run-time check. +AC_CACHE_CHECK([for epoll support], [apr_cv_epoll], +[AC_TRY_RUN([ +#include <sys/epoll.h> +#include <unistd.h> + +int main() +{ + return epoll_create(5) == -1; +}], [apr_cv_epoll=yes], [apr_cv_epoll=no], [apr_cv_epoll=no])]) + +if test "$apr_cv_epoll" = "yes"; then + AC_DEFINE([HAVE_EPOLL], 1, [Define if the epoll interface is supported]) +fi + +dnl ----------------------------- Checking for extended file descriptor handling +# test for epoll_create1 +AC_CACHE_CHECK([for epoll_create1 support], [apr_cv_epoll_create1], +[AC_TRY_RUN([ +#include <sys/epoll.h> +#include <unistd.h> + +int main() +{ + return epoll_create1(0) == -1; +}], [apr_cv_epoll_create1=yes], [apr_cv_epoll_create1=no], [apr_cv_epoll_create1=no])]) + +if test "$apr_cv_epoll_create1" = "yes"; then + AC_DEFINE([HAVE_EPOLL_CREATE1], 1, [Define if epoll_create1 function is supported]) +fi + +# Check for z/OS async i/o support. +AC_CACHE_CHECK([for asio -> message queue support], [apr_cv_aio_msgq], +[AC_TRY_RUN([ +#define _AIO_OS390 +#include <aio.h> + +int main() +{ + struct aiocb a; + + a.aio_notifytype = AIO_MSGQ; /* use IPC message queue for notification */ + + return aio_cancel(2, NULL) == -1; +}], [apr_cv_aio_msgq=yes], [apr_cv_aio_msgq=no], [apr_cv_aio_msgq=no])]) + +if test "$apr_cv_aio_msgq" = "yes"; then + AC_DEFINE([HAVE_AIO_MSGQ], 1, [Define if async i/o supports message q's]) +fi + +# test for dup3 +AC_CACHE_CHECK([for dup3 support], [apr_cv_dup3], +[AC_TRY_RUN([ +#include <unistd.h> + +int main() +{ + return dup3(STDOUT_FILENO, STDERR_FILENO, 0) == -1; +}], [apr_cv_dup3=yes], [apr_cv_dup3=no], [apr_cv_dup3=no])]) + +if test "$apr_cv_dup3" = "yes"; then + AC_DEFINE([HAVE_DUP3], 1, [Define if dup3 function is supported]) +fi + +# Test for accept4(). Create a non-blocking socket, bind it to +# an unspecified port & address (kernel picks), and attempt to +# call accept4() on it. If the syscall is wired up (i.e. the +# kernel is new enough), it should return EAGAIN. +AC_CACHE_CHECK([for accept4 support], [apr_cv_accept4], +[AC_TRY_RUN([ +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/wait.h> +#include <netinet/in.h> +#include <netinet/tcp.h> +#include <errno.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> + +int main(int argc, char **argv) +{ + int fd, flags; + struct sockaddr_in sin; + + if ((fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) + return 1; + flags = fcntl(fd, F_GETFL); + if (flags == -1 || fcntl(fd, F_SETFL, flags|O_NONBLOCK) == -1) + return 5; + + memset(&sin, 0, sizeof sin); + sin.sin_family = AF_INET; + + if (bind(fd, (struct sockaddr *) &sin, sizeof sin) == -1) + return 2; + + if (listen(fd, 5) == -1) + return 3; + + if (accept4(fd, NULL, 0, SOCK_NONBLOCK) == 0 + || errno == EAGAIN || errno == EWOULDBLOCK) + return 0; + + return 4; +}], [apr_cv_accept4=yes], [apr_cv_accept4=no], [apr_cv_accept4=no])]) + +if test "$apr_cv_accept4" = "yes"; then + AC_DEFINE([HAVE_ACCEPT4], 1, [Define if accept4 function is supported]) +fi + +AC_CACHE_CHECK([for SOCK_CLOEXEC support], [apr_cv_sock_cloexec], +[AC_TRY_RUN([ +#include <sys/types.h> +#include <sys/socket.h> + +int main() +{ + return socket(AF_INET, SOCK_STREAM|SOCK_CLOEXEC, 0) == -1; +}], [apr_cv_sock_cloexec=yes], [apr_cv_sock_cloexec=no], [apr_cv_sock_cloexec=no])]) + +if test "$apr_cv_sock_cloexec" = "yes"; then + AC_DEFINE([HAVE_SOCK_CLOEXEC], 1, [Define if the SOCK_CLOEXEC flag is supported]) +fi + +dnl ----------------------------- Checking for fdatasync: OS X doesn't have it +AC_CHECK_FUNCS(fdatasync) + +dnl ----------------------------- Checking for missing POSIX thread functions +AC_CHECK_FUNCS([getpwnam_r getpwuid_r getgrnam_r getgrgid_r]) + +dnl ----------------------------- Checking for Shared Memory Support +AC_MSG_NOTICE([]) +AC_MSG_NOTICE([Checking for Shared Memory Support...]) + +# The real-time POSIX extensions (e.g. shm_*, sem_*) may only +# be available if linking against librt. +AC_SEARCH_LIBS(shm_open, rt) + +case $host in + *-sysv*) + ac_includes_default="$ac_includes_default +#if HAVE_SYS_MUTEX_H /* needed to define lock_t for sys/shm.h */ +# include <sys/mutex.h> +#endif";; +esac + +AC_CHECK_HEADERS([sys/types.h sys/mman.h sys/ipc.h sys/mutex.h \ + sys/shm.h sys/file.h kernel/OS.h os2.h windows.h \ + net/if.h]) +AC_CHECK_FUNCS([mmap munmap shm_open shm_unlink shmget shmat shmdt shmctl \ + create_area mprotect]) + +APR_CHECK_DEFINE(MAP_ANON, sys/mman.h) +AC_CHECK_FILE(/dev/zero) + +# Not all systems can mmap /dev/zero (such as HP-UX). Check for that. +if test "$ac_cv_func_mmap" = "yes" && + test "$ac_cv_file__dev_zero" = "yes"; then + AC_MSG_CHECKING(for mmap that can map /dev/zero) + AC_TRY_RUN([ +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#ifdef HAVE_SYS_MMAN_H +#include <sys/mman.h> +#endif + int main() + { + int fd; + void *m; + fd = open("/dev/zero", O_RDWR); + if (fd < 0) { + return 1; + } + m = mmap(0, sizeof(void*), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); + if (m == (void *)-1) { /* aka MAP_FAILED */ + return 2; + } + if (munmap(m, sizeof(void*)) < 0) { + return 3; + } + return 0; + }], [], [ac_cv_file__dev_zero=no], [ac_cv_file__dev_zero=no]) + + AC_MSG_RESULT($ac_cv_file__dev_zero) +fi + +# Now we determine which one is our anonymous shmem preference. +haveshmgetanon="0" +havemmapzero="0" +havemmapanon="0" +APR_BEGIN_DECISION([anonymous shared memory allocation method]) +APR_IFALLYES(header:sys/ipc.h header:sys/shm.h header:sys/file.h dnl + func:shmget func:shmat func:shmdt func:shmctl, + [haveshmgetanon="1" + APR_DECIDE(USE_SHMEM_SHMGET_ANON, [SysV IPC shmget()])]) +APR_IFALLYES(header:sys/mman.h func:mmap func:munmap file:/dev/zero, + [havemmapzero="1" + APR_DECIDE(USE_SHMEM_MMAP_ZERO, + [SVR4-style mmap() on /dev/zero])]) +APR_IFALLYES(header:sys/mman.h func:mmap func:munmap define:MAP_ANON, + [havemmapanon="1" + APR_DECIDE(USE_SHMEM_MMAP_ANON, + [4.4BSD-style mmap() via MAP_ANON])]) +APR_IFALLYES(header:os2.h, + [haveos2shm="1" + APR_DECIDE(USE_SHMEM_OS2_ANON, [OS/2 DosAllocSharedMem()])]) +APR_IFALLYES(header:kernel/OS.h func:create_area, + [havebeosshm="1" + APR_DECIDE(USE_SHMEM_BEOS_ANON, + [BeOS areas])]) +APR_IFALLYES(header:windows.h func:CreateFileMapping, + [havewin32shm="1" + APR_DECIDE(USE_SHMEM_WIN32_ANON, + [Windows CreateFileMapping()])]) +case $host in + *linux* ) + # Linux has problems with MM_SHMT_MMANON even though it reports + # that it has it. + # FIXME - find exact 2.3 version that MMANON was fixed in. It is + # confirmed fixed in 2.4 series. + if test $os_pre24linux -eq 1; then + AC_MSG_WARN([Disabling anon mmap() support for Linux pre-2.4]) + APR_DECISION_OVERRIDE(USE_SHMEM_MMAP_ZERO USE_SHMEM_SHMGET_ANON) + fi + ;; + *hpux11* ) + APR_DECISION_OVERRIDE(USE_SHMEM_SHMGET_ANON) + ;; +esac +APR_END_DECISION +AC_DEFINE_UNQUOTED($ac_decision) + +useshmgetanon="0" +usemmapzero="0" +usemmapanon="0" + +case $ac_decision in + USE_SHMEM_SHMGET_ANON ) + useshmgetanon="1" + ;; + USE_SHMEM_MMAP_ZERO ) + usemmapzero="1" + ;; + USE_SHMEM_MMAP_ANON ) + usemmapanon="1" + ;; +esac + +AC_SUBST(useshmgetanon) +AC_SUBST(usemmapzero) +AC_SUBST(usemmapanon) +AC_SUBST(haveshmgetanon) +AC_SUBST(havemmapzero) +AC_SUBST(havemmapanon) + +# Now we determine which one is our name-based shmem preference. +havemmaptmp="0" +havemmapshm="0" +haveshmget="0" +havebeosarea="0" +haveos2shm="0" +havewin32shm="0" +APR_BEGIN_DECISION([namebased memory allocation method]) +APR_IFALLYES(header:sys/mman.h func:mmap func:munmap, + [havemmaptmp="1" + APR_DECIDE(USE_SHMEM_MMAP_TMP, + [Classical mmap() on temporary file])]) +APR_IFALLYES(header:sys/mman.h func:mmap func:munmap func:shm_open dnl + func:shm_unlink, + [havemmapshm="1" + APR_DECIDE(USE_SHMEM_MMAP_SHM, + [mmap() via POSIX.1 shm_open() on temporary file])]) +APR_IFALLYES(header:sys/ipc.h header:sys/shm.h header:sys/file.h dnl + func:shmget func:shmat func:shmdt func:shmctl, + [haveshmget="1" + APR_DECIDE(USE_SHMEM_SHMGET, [SysV IPC shmget()])]) +APR_IFALLYES(header:kernel/OS.h func:create_area, + [havebeosshm="1" + APR_DECIDE(USE_SHMEM_BEOS, [BeOS areas])]) +APR_IFALLYES(header:os2.h, + [haveos2shm="1" + APR_DECIDE(USE_SHMEM_OS2, [OS/2 DosAllocSharedMem()])]) +APR_IFALLYES(header:windows.h, + [havewin32shm="1" + APR_DECIDE(USE_SHMEM_WIN32, [Windows shared memory])]) +AC_ARG_ENABLE(posix-shm, +[ --enable-posix-shm Use POSIX shared memory (shm_open) if available], +[ +if test "$havemmapshm" = "1"; then + APR_DECISION_OVERRIDE(USE_SHMEM_MMAP_SHM) +fi +]) +case $host in + *linux* ) + # Linux pre-2.4 had problems with MM_SHMT_MMANON even though + # it reports that it has it. + if test $os_pre24linux -eq 1; then + APR_DECISION_OVERRIDE(USE_SHMEM_MMAP_TMP USE_SHMEM_MMAP_SHM dnl + USE_SHMEM_SHMGET) + fi + ;; +esac +APR_END_DECISION +AC_DEFINE_UNQUOTED($ac_decision) + +usemmaptmp="0" +usemmapshm="0" +useshmget="0" +usebeosarea="0" +useos2shm="0" +usewin32shm="0" + +case $ac_decision in + USE_SHMEM_MMAP_TMP ) + usemmaptmp="1" + ;; + USE_SHMEM_MMAP_SHM ) + usemmapshm="1" + ;; + USE_SHMEM_SHMGET ) + useshmget="1" + ;; + USE_SHMEM_BEOS ) + usebeosarea="1" + ;; + USE_SHMEM_OS2 ) + useos2shm="1" + ;; + USE_SHMEM_WIN32 ) + usewin32shm="1" + ;; +esac + +# Do we have any shared memory support? +if test "$usemmaptmp$usemmapshm$usemmapzero$useshmget$usemmapanon$usebeosarea$useos2shm$usewin32shm" = "00000000"; then + sharedmem="0" +else + sharedmem="1" +fi + +AC_SUBST(usemmaptmp) +AC_SUBST(usemmapshm) +AC_SUBST(useshmget) +AC_SUBST(usebeosarea) +AC_SUBST(useos2shm) +AC_SUBST(usewin32shm) +AC_SUBST(havemmaptmp) +AC_SUBST(havemmapshm) +AC_SUBST(haveshmget) +AC_SUBST(havebeosarea) +AC_SUBST(haveos2shm) +AC_SUBST(havewin32shm) +AC_SUBST(sharedmem) + +dnl ----------------------------- Checks for Any required Functions +dnl Checks for library functions. (N.B. poll is further down) + +AC_FUNC_ALLOCA + +AC_CHECK_FUNCS([calloc setsid isinf isnan \ + getenv putenv setenv unsetenv \ + writev getifaddrs utime utimes]) +AC_CHECK_FUNCS(setrlimit, [ have_setrlimit="1" ], [ have_setrlimit="0" ]) +AC_CHECK_FUNCS(getrlimit, [ have_getrlimit="1" ], [ have_getrlimit="0" ]) +sendfile="0" +AC_CHECK_LIB(sendfile, sendfilev) +AC_CHECK_FUNCS(sendfile send_file sendfilev, [ sendfile="1" ]) + +dnl THIS MUST COME AFTER THE THREAD TESTS - FreeBSD doesn't always have a +dnl threaded poll() and we don't want to use sendfile on early FreeBSD +dnl systems if we are also using threads. + +AC_ARG_WITH(sendfile, [ --with-sendfile Override decision to use sendfile], + [ if test "$withval" = "yes"; then + sendfile="1" + else + sendfile="0" + fi ], [ + orig_sendfile=$sendfile + case $host in + *freebsd*) + # FreeBSD < 4.2 has issues with threads+sendfile + if test $os_version -le "401999"; then + if test "$threads" = "1"; then + sendfile="0" + fi + fi ;; - 3*) - AC_DEFINE(NEED_RLIM_T) - OSDIR="aix" + *alpha*-dec-osf* ) + sendfile="0" ;; - 41*) - AC_DEFINE(NEED_RLIM_T) - OSDIR="aix" + s390-*-linux-gnu) + # disable sendfile support for 2.2 on S/390 + if test $os_pre24linux -eq 1; then + AC_MSG_WARN([Disabled sendfile support for Linux 2.2 on S/390]) + sendfile="0" + fi ;; - 42*) - OSDIR="aix" + *aix*) + # compiler-independent check for 64-bit build + AC_CHECK_SIZEOF(void*, 4) + if test "x$ac_cv_sizeof_voidp" = "x8"; then + # sendfile not working for 64-bit build + sendfile="0" + fi ;; - esac -fi - -dnl #----------------------------- Checks for Any required Libraries -AC_CHECK_LIB(dl, dlopen) -AC_CHECK_LIB(nsl,gethostbyname) -AC_CHECK_LIB(nsl,gethostname) -AC_CHECK_LIB(socket,socket) -AC_CHECK_LIB(crypt,crypt) -AC_CHECK_LIB(ufc,crypt) -AC_CHECK_LIB(truerand,main) + esac + if test "$orig_sendfile" != "$sendfile"; then + AC_MSG_NOTICE([sendfile support disabled to avoid system problem]) + fi ] ) +AC_SUBST(sendfile) -dnl #----------------------------- Checks for Any required Functions -dnl Checks for library functions. -AC_CHECK_FUNCS(pthread_sigmask) -AC_CHECK_FUNCS(strcasecmp stricmp poll setsid) AC_CHECK_FUNCS(sigaction, [ have_sigaction="1" ], [ have_sigaction="0" ]) -AC_CHECK_FUNCS(writev) -AC_CHECK_FUNCS(sendfile, [ sendfile="1" ], [ sendfile="0" ]) +AC_DECL_SYS_SIGLIST + AC_CHECK_FUNCS(fork, [ fork="1" ], [ fork="0" ]) -AC_CHECK_FUNCS(getpass) -AC_CHECK_FUNC(inet_addr, [ inet_addr="1" ], [ inet_addr="0" ]) -AC_CHECK_FUNC(inet_network, [ inet_network="1" ], [ inet_network="0" ]) +APR_CHECK_INET_ADDR +APR_CHECK_INET_NETWORK +AC_SUBST(apr_inaddr_none) AC_CHECK_FUNC(_getch) -AC_CHECK_FUNCS(gmtime_r localtime_r) -AC_CHECK_FUNCS(iconv, [ iconv="1" ], [ iconv="0" ]) -AC_SUBST(sendfile) +AC_CHECK_FUNCS(strerror_r, [ strerror_r="1" ], [ strerror_r="0" ]) +if test "$strerror_r" = "1"; then + APR_CHECK_STRERROR_R_RC +fi +AC_CHECK_FUNCS(mmap, [ mmap="1" ], [ mmap="0" ]) +if test "$native_mmap_emul" = "1"; then + mmap="1" +fi +AC_CHECK_FUNCS(memmove, [ have_memmove="1" ], [have_memmove="0" ]) +AC_CHECK_FUNCS([getpass getpassphrase gmtime_r localtime_r]) +case $host in + *-hp-hpux*) + dnl mkstemp is limited to 26 temporary files (a-z); use APR replacement + ;; + *) + AC_CHECK_FUNCS(mkstemp mkostemp) + ;; +esac + AC_SUBST(fork) -AC_SUBST(inet_addr) -AC_SUBST(inet_network) +AC_SUBST(have_inet_addr) +AC_SUBST(tcp_nodelay_inherited) +AC_SUBST(o_nonblock_inherited) +AC_SUBST(have_inet_network) AC_SUBST(have_sigaction) -AC_SUBST(iconv) +AC_SUBST(have_setrlimit) +AC_SUBST(have_getrlimit) +AC_SUBST(mmap) +AC_SUBST(have_memmove) +APR_CHECK_SIGWAIT_ONE_ARG -dnl #----------------------------- Checks for Any required Headers +dnl ----------------------------- Checks for Any required Headers AC_HEADER_STDC -AC_CHECK_HEADERS(conio.h) -AC_CHECK_HEADERS(crypt.h) -AC_CHECK_HEADERS(ctype.h) -AC_CHECK_HEADERS(dir.h) -AC_CHECK_HEADERS(dirent.h, direnth="1", dirent="0") -AC_CHECK_HEADERS(errno.h, errnoh="1", errnoh="0") -AC_CHECK_HEADERS(net/errno.h) -AC_CHECK_HEADERS(fcntl.h, fcntlh="1", fcntl="0") -AC_CHECK_HEADERS(features.h) -AC_CHECK_HEADERS(grp.h) -AC_CHECK_HEADERS(io.h) -AC_CHECK_HEADERS(limits.h) -AC_CHECK_HEADERS(malloc.h) -AC_CHECK_HEADERS(math.h) -AC_CHECK_HEADERS(memory.h) -AC_CHECK_HEADERS(netdb.h) -AC_CHECK_HEADERS(osreldate.h) -AC_CHECK_HEADERS(process.h) -AC_CHECK_HEADERS(pwd.h) -AC_CHECK_HEADERS(sys/sem.h) -AC_CHECK_HEADERS(setjmp.h) -AC_CHECK_HEADERS(signal.h, signalh="1", signalh="0") -AC_CHECK_HEADERS(stdarg.h, stdargh="1", stdargh="0") -AC_CHECK_HEADERS(stddef.h) -AC_CHECK_HEADERS(stdio.h, stdioh="1", stdioh"0") -AC_CHECK_HEADERS(stdlib.h) -AC_CHECK_HEADERS(string.h) -AC_CHECK_HEADERS(sysapi.h) -AC_CHECK_HEADERS(sysgtime.h) -AC_CHECK_HEADERS(termios.h) -AC_CHECK_HEADERS(time.h) -AC_CHECK_HEADERS(sys/time.h) -AC_CHECK_HEADERS(sys/times.h) -AC_CHECK_HEADERS(tpfeq.h) -AC_CHECK_HEADERS(tpfio.h) -AC_CHECK_HEADERS(sys/uio.h, sys_uioh="1", sys_uioh="0") -AC_CHECK_HEADERS(unistd.h) -AC_CHECK_HEADERS(poll.h) -AC_CHECK_HEADERS(unix.h) -AC_CHECK_HEADERS(arpa/inet.h) -AC_CHECK_HEADERS(netinet/in.h, netinet_inh="1", netinet_inh="0") -AC_CHECK_HEADERS(netinet/tcp.h) -AC_CHECK_HEADERS(iconv.h) - -AC_CHECK_HEADERS(sys/file.h) -AC_CHECK_HEADERS(sys/ioctl.h) -AC_CHECK_HEADERS(sys/mman.h) -AC_CHECK_HEADERS(sys/param.h) -AC_CHECK_HEADERS(sys/resource.h) -AC_CHECK_HEADERS(sys/select.h) -AC_CHECK_HEADERS(sys/sendfile.h) -AC_CHECK_HEADERS(sys/signal.h) -AC_CHECK_HEADERS(sys/socket.h) -AC_CHECK_HEADERS(sys/stat.h) -AC_CHECK_HEADERS(sys/types.h, sys_typesh="1", sys_typesh="0") -AC_CHECK_HEADERS(sys/wait.h) -AC_CHECK_HEADERS(dlfcn.h) -AC_CHECK_HEADERS(dl.h) - -AC_CHECK_HEADERS(kernel/OS.h) +APR_FLAG_HEADERS( + aio.h \ + ByteOrder.h \ + conio.h \ + crypt.h \ + ctype.h \ + dir.h \ + dirent.h \ + dl.h \ + dlfcn.h \ + errno.h \ + fcntl.h \ + grp.h \ + ifaddrs.h \ + io.h \ + limits.h \ + mach-o/dyld.h \ + malloc.h \ + memory.h \ + netdb.h \ + osreldate.h \ + poll.h \ + process.h \ + pwd.h \ + semaphore.h \ + signal.h \ + stdarg.h \ + stddef.h \ + stdio.h \ + stdlib.h \ + string.h \ + strings.h \ + sysapi.h \ + sysgtime.h \ + termios.h \ + time.h \ + tpfeq.h \ + tpfio.h \ + unistd.h \ + unix.h \ + windows.h \ + winsock2.h \ + ws2tcpip.h \ + arpa/inet.h \ + kernel/OS.h \ + net/errno.h \ + netinet/in.h \ + netinet/sctp.h \ + netinet/sctp_uio.h \ + sys/file.h \ + sys/ioctl.h \ + sys/mman.h \ + sys/param.h \ + sys/poll.h \ + sys/resource.h \ + sys/select.h \ + sys/sem.h \ + sys/sendfile.h \ + sys/signal.h \ + sys/socket.h \ + sys/sockio.h \ + sys/stat.h \ + sys/sysctl.h \ + sys/syslimits.h \ + sys/time.h \ + sys/types.h \ + sys/uio.h \ + sys/un.h \ + sys/wait.h) +# Windows' <mswsock.h> requires <windows.h> first +AC_CACHE_CHECK([for mswsock.h], [apr_cv_hdr_mswsock_h], +[AC_TRY_CPP( +[#include <windows.h> +#include <mswsock.h> +], [apr_cv_hdr_mswsock_h=yes], [apr_cv_hdr_mswsock_h=no])]) +if test "$apr_cv_hdr_mswsock_h" = "yes"; then + mswsockh=1 +else + mswsockh=0 +fi + +# IRIX 6.5 has a problem in <netinet/tcp.h> which prevents it from +# being included by itself. Check for <netinet/tcp.h> manually, +# including another header file first. +AC_CACHE_CHECK([for netinet/tcp.h], [apr_cv_hdr_netinet_tcp_h], +[AC_TRY_CPP( +[#ifdef HAVE_NETINET_IN_H +#include <netinet/in.h> +#endif +#include <netinet/tcp.h> +], [apr_cv_hdr_netinet_tcp_h=yes], [apr_cv_hdr_netinet_tcp_h=no])]) +if test "$apr_cv_hdr_netinet_tcp_h" = "yes"; then + netinet_tcph=1 + AC_DEFINE([HAVE_NETINET_TCP_H], 1, [Defined if netinet/tcp.h is present]) +else + netinet_tcph=0 +fi + +AC_SUBST(aioh) +AC_SUBST(arpa_ineth) +AC_SUBST(conioh) +AC_SUBST(ctypeh) +AC_SUBST(crypth) AC_SUBST(errnoh) AC_SUBST(direnth) AC_SUBST(fcntlh) +AC_SUBST(ioh) +AC_SUBST(ifaddrsh) +AC_SUBST(limitsh) +AC_SUBST(mswsockh) +AC_SUBST(netdbh) AC_SUBST(netinet_inh) +AC_SUBST(netinet_sctph) +AC_SUBST(netinet_sctp_uioh) +AC_SUBST(netinet_tcph) AC_SUBST(stdargh) +AC_SUBST(stddefh) AC_SUBST(stdioh) +AC_SUBST(stdlibh) +AC_SUBST(stringh) +AC_SUBST(stringsh) +AC_SUBST(sys_ioctlh) +AC_SUBST(sys_sendfileh) +AC_SUBST(sys_signalh) +AC_SUBST(sys_socketh) +AC_SUBST(sys_sockioh) +AC_SUBST(sys_syslimitsh) AC_SUBST(sys_typesh) +AC_SUBST(sys_timeh) AC_SUBST(sys_uioh) +AC_SUBST(sys_unh) +AC_SUBST(timeh) +AC_SUBST(unistdh) AC_SUBST(signalh) +AC_SUBST(sys_waith) +AC_SUBST(processh) AC_SUBST(pthreadh) +AC_SUBST(semaphoreh) +AC_SUBST(windowsh) +AC_SUBST(winsock2h) +AC_SUBST(ws2tcpiph) + +# Checking for h_errno in <netdb.h> +if test "$netdbh" = "1"; then + APR_CHECK_H_ERRNO_FLAG + if test "$ac_cv_h_errno_cflags" = "no"; then + AC_MSG_ERROR([can not find h_errno in netdb.h]) + fi +fi + +AC_ARG_ENABLE(allocator-uses-mmap, + [ --enable-allocator-uses-mmap Use mmap in apr_allocator instead of malloc ], + [ if test "$enableval" = "yes"; then + APR_IFALLYES(header:sys/mman.h func:mmap func:munmap define:MAP_ANON, + [AC_DEFINE(APR_ALLOCATOR_USES_MMAP, 1, + [Define if apr_allocator should use mmap]) ], + [AC_MSG_ERROR([mmap()/MAP_ANON not supported]) ] + ) + fi ] +) -dnl #----------------------------- Checks for standard typedefs +AC_ARG_ENABLE(allocator-guard-pages, + [ --enable-allocator-guard-pages Use guard pages in apr_allocator + (implies --enable-allocator-uses-mmap) ] , + [ if test "$enableval" = "yes"; then + APR_IFALLYES(header:sys/mman.h func:mmap func:munmap func:mprotect define:MAP_ANON, + [AC_DEFINE(APR_ALLOCATOR_GUARD_PAGES, 1, + [Define if apr_allocator should use guard pages]) ], + [AC_MSG_ERROR([mmap()/MAP_ANON/mprotect() not supported]) ] + ) + fi ] +) + + +AC_ARG_ENABLE(pool-concurrency-check, + [ --enable-pool-concurrency-check Check for concurrent usage of memory pools], + [ if test "$enableval" = "yes"; then + AC_DEFINE(APR_POOL_CONCURRENCY_CHECK, 1, + [Define if pool functions should abort if concurrent usage is detected]) + fi ] +) + +dnl ----------------------------- Checks for standard typedefs AC_TYPE_OFF_T AC_TYPE_PID_T AC_TYPE_SIZE_T @@ -216,17 +1570,24 @@ AC_TYPE_UID_T AC_CHECK_TYPE(ssize_t, int) AC_C_INLINE AC_C_CONST -AC_TYPE_SIZE_T AC_FUNC_SETPGRP APR_CHECK_SOCKLEN_T -dnl # Checks for integer size +dnl Checks for pointer size +AC_CHECK_SIZEOF(void*, 4) + +if test "x$ac_cv_sizeof_voidp" != "x"; then + voidp_size=$ac_cv_sizeof_voidp +else + AC_ERROR([Cannot determine size of void*]) +fi + +dnl Checks for integer size AC_CHECK_SIZEOF(char, 1) AC_CHECK_SIZEOF(int, 4) AC_CHECK_SIZEOF(long, 4) AC_CHECK_SIZEOF(short, 2) -AC_CHECK_SIZEOF(long double, 12) AC_CHECK_SIZEOF(long long, 8) if test "$ac_cv_sizeof_short" = "2"; then @@ -235,134 +1596,605 @@ fi if test "$ac_cv_sizeof_int" = "4"; then int_value=int fi -if test "$ac_cv_sizeof_long" = "8"; then +# Now we need to find what apr_int64_t (sizeof == 8) will be. +# The first match is our preference. +if test "$ac_cv_sizeof_int" = "8"; then + int64_literal='#define APR_INT64_C(val) (val)' + uint64_literal='#define APR_UINT64_C(val) (val##U)' + int64_t_fmt='#define APR_INT64_T_FMT "d"' + uint64_t_fmt='#define APR_UINT64_T_FMT "u"' + uint64_t_hex_fmt='#define APR_UINT64_T_HEX_FMT "x"' + int64_value="int" + long_value=int + int64_strfn="strtoi" +elif test "$ac_cv_sizeof_long" = "8"; then + int64_literal='#define APR_INT64_C(val) (val##L)' + uint64_literal='#define APR_UINT64_C(val) (val##UL)' + int64_t_fmt='#define APR_INT64_T_FMT "ld"' + uint64_t_fmt='#define APR_UINT64_T_FMT "lu"' + uint64_t_hex_fmt='#define APR_UINT64_T_HEX_FMT "lx"' + int64_value="long" long_value=long -fi -if test "$ac_cv_sizeof_long_double" = "8"; then - long_value="long double" -fi -if test "$ac_cv_sizeof_long_long" = "8"; then + int64_strfn="strtol" +elif test "$ac_cv_sizeof_long_long" = "8"; then + int64_literal='#define APR_INT64_C(val) (val##LL)' + uint64_literal='#define APR_UINT64_C(val) (val##ULL)' + # Linux, Solaris, FreeBSD all support ll with printf. + # BSD 4.4 originated 'q'. Solaris is more popular and + # doesn't support 'q'. Solaris wins. Exceptions can + # go to the OS-dependent section. + int64_t_fmt='#define APR_INT64_T_FMT "lld"' + uint64_t_fmt='#define APR_UINT64_T_FMT "llu"' + uint64_t_hex_fmt='#define APR_UINT64_T_HEX_FMT "llx"' + int64_value="long long" long_value="long long" -fi -if test "$ac_cv_sizeof_longlong" = "8"; then + int64_strfn="strtoll" +elif test "$ac_cv_sizeof_longlong" = "8"; then + int64_literal='#define APR_INT64_C(val) (val##LL)' + uint64_literal='#define APR_UINT64_C(val) (val##ULL)' + int64_t_fmt='#define APR_INT64_T_FMT "qd"' + uint64_t_fmt='#define APR_UINT64_T_FMT "qu"' + uint64_t_hex_fmt='#define APR_UINT64_T_HEX_FMT "qx"' + int64_value="__int64" long_value="__int64" + int64_strfn="strtoll" +else + # int64_literal may be overriden if your compiler thinks you have + # a 64-bit value but APR does not agree. + AC_ERROR([could not detect a 64-bit integer type]) fi -if test "$ac_cv_type_off_t" = "yes"; then - off_t_value="off_t" +# If present, allow the C99 macro INT64_C to override our conversion. +# +# HP-UX's ANSI C compiler provides this without any includes, so we +# will first look for INT64_C without adding stdint.h +AC_CACHE_CHECK([for INT64_C], [apr_cv_define_INT64_C], [ +AC_EGREP_CPP(YES_IS_DEFINED, +[#ifdef INT64_C +YES_IS_DEFINED +#endif], [apr_cv_define_INT64_C=yes], [ + # Now check for INT64_C in stdint.h + AC_EGREP_CPP(YES_IS_DEFINED, [#include <stdint.h> +#ifdef INT64_C +YES_IS_DEFINED +#endif], [apr_cv_define_INT64_C=yes], [apr_cv_define_INT64_C=no])])]) + +if test "$apr_cv_define_INT64_C" = "yes"; then + int64_literal='#define APR_INT64_C(val) INT64_C(val)' + uint64_literal='#define APR_UINT64_C(val) UINT64_C(val)' + stdint=1 else - off_t_value="ap_int32_t" + stdint=0 fi + if test "$ac_cv_type_size_t" = "yes"; then size_t_value="size_t" else - size_t_value="ap_int32_t" + size_t_value="apr_int32_t" fi if test "$ac_cv_type_ssize_t" = "yes"; then ssize_t_value="ssize_t" else - ssize_t_value="ap_int32_t" + ssize_t_value="apr_int32_t" +fi +if test "$ac_cv_socklen_t" = "yes"; then + socklen_t_value="socklen_t" + case $host in + *-hp-hpux*) + if test "$ac_cv_sizeof_long" = "8"; then + # 64-bit HP-UX requires 32-bit socklens in + # kernel, but user-space declarations say + # 64-bit (socklen_t == size_t == long). + # This will result in many compile warnings, + # but we're functionally busted otherwise. + socklen_t_value="int" + fi + ;; + esac +else + socklen_t_value="int" +fi + +APR_CHECK_SIZEOF_EXTENDED([#include <sys/types.h>], pid_t, 8) + +if test "$ac_cv_sizeof_pid_t" = "$ac_cv_sizeof_short"; then + pid_t_fmt='#define APR_PID_T_FMT "hd"' +elif test "$ac_cv_sizeof_pid_t" = "$ac_cv_sizeof_int"; then + pid_t_fmt='#define APR_PID_T_FMT "d"' +elif test "$ac_cv_sizeof_pid_t" = "$ac_cv_sizeof_long"; then + pid_t_fmt='#define APR_PID_T_FMT "ld"' +elif test "$ac_cv_sizeof_pid_t" = "$ac_cv_sizeof_long_long"; then + pid_t_fmt='#define APR_PID_T_FMT APR_INT64_T_FMT' +else + pid_t_fmt='#error Can not determine the proper size for pid_t' +fi + +# Basically, we have tried to figure out the correct format strings +# for APR types which vary between platforms, but we don't always get +# it right. +case $host in + s390*linux*) + # uniquely, the 31-bit Linux/s390 uses "unsigned long int" + # for size_t rather than "unsigned int": + size_t_fmt="lu" + ssize_t_fmt="ld" + ;; + *-os2*) + size_t_fmt="lu" + ;; + *-solaris*) + if test "$ac_cv_sizeof_long" = "8"; then + pid_t_fmt='#define APR_PID_T_FMT "d"' + else + pid_t_fmt='#define APR_PID_T_FMT "ld"' + fi + ;; + *aix4*|*aix5*) + ssize_t_fmt="ld" + size_t_fmt="lu" + ;; + *beos*) + ssize_t_fmt="ld" + size_t_fmt="ld" + ;; + *apple-darwin*) + osver=`uname -r` + case $osver in + [[0-7]].*) + ssize_t_fmt="d" + ;; + *) + ssize_t_fmt="ld" + ;; + esac + size_t_fmt="lu" + ;; + *-mingw*) + int64_t_fmt='#define APR_INT64_T_FMT "I64d"' + uint64_t_fmt='#define APR_UINT64_T_FMT "I64u"' + uint64_t_hex_fmt='#define APR_UINT64_T_HEX_FMT "I64x"' + int64_value="__int64" + long_value="__int64" + int64_strfn="_strtoi64" + ;; +esac + +APR_CHECK_TYPES_COMPATIBLE(ssize_t, int, [ssize_t_fmt="d"]) +APR_CHECK_TYPES_COMPATIBLE(ssize_t, long, [ssize_t_fmt="ld"]) +APR_CHECK_TYPES_COMPATIBLE(size_t, unsigned int, [size_t_fmt="u"]) +APR_CHECK_TYPES_COMPATIBLE(size_t, unsigned long, [size_t_fmt="lu"]) + +APR_CHECK_SIZEOF_EXTENDED([#include <sys/types.h>], ssize_t, 8) + +AC_MSG_CHECKING([which format to use for apr_ssize_t]) +if test -n "$ssize_t_fmt"; then + AC_MSG_RESULT(%$ssize_t_fmt) +elif test "$ac_cv_sizeof_ssize_t" = "$ac_cv_sizeof_int"; then + ssize_t_fmt="d" + AC_MSG_RESULT(%d) +elif test "$ac_cv_sizeof_ssize_t" = "$ac_cv_sizeof_long"; then + ssize_t_fmt="ld" + AC_MSG_RESULT(%ld) +else + AC_ERROR([could not determine the proper format for apr_ssize_t]) +fi + +ssize_t_fmt="#define APR_SSIZE_T_FMT \"$ssize_t_fmt\"" + +APR_CHECK_SIZEOF_EXTENDED([#include <stddef.h>], size_t, 8) + +AC_MSG_CHECKING([which format to use for apr_size_t]) +if test -n "$size_t_fmt"; then + AC_MSG_RESULT(%$size_t_fmt) +elif test "$ac_cv_sizeof_size_t" = "$ac_cv_sizeof_int"; then + size_t_fmt="d" + AC_MSG_RESULT(%d) +elif test "$ac_cv_sizeof_size_t" = "$ac_cv_sizeof_long"; then + size_t_fmt="ld" + AC_MSG_RESULT(%ld) +else + AC_ERROR([could not determine the proper format for apr_size_t]) +fi + +size_t_fmt="#define APR_SIZE_T_FMT \"$size_t_fmt\"" + +APR_CHECK_SIZEOF_EXTENDED([#include <sys/types.h>], off_t, 8) + +if test "${ac_cv_sizeof_off_t}${apr_cv_use_lfs64}" = "4yes"; then + # Enable LFS + aprlfs=1 + AC_CHECK_FUNCS([mmap64 sendfile64 sendfilev64 readdir64_r]) + case $host in + *-hp-hpux*) + dnl mkstemp64 is limited to 26 temporary files (a-z); use APR replacement + ;; + *) + AC_CHECK_FUNCS(mkstemp64 mkostemp64) + ;; + esac +elif test "${ac_cv_sizeof_off_t}" != "${ac_cv_sizeof_size_t}"; then + # unsure of using -gt above is as portable, can can't forsee where + # off_t can legitimately be smaller than size_t + aprlfs=1 +else + aprlfs=0 +fi + +AC_MSG_CHECKING([which type to use for apr_off_t]) +if test "${ac_cv_sizeof_off_t}${apr_cv_use_lfs64}" = "4yes"; then + # LFS is go! + off_t_fmt='#define APR_OFF_T_FMT APR_INT64_T_FMT' + off_t_value='off64_t' + off_t_strfn='apr_strtoi64' +elif test "${ac_cv_sizeof_off_t}x${ac_cv_sizeof_long}" = "4x4"; then + # Special case: off_t may change size with _FILE_OFFSET_BITS + # on 32-bit systems with LFS support. To avoid compatibility + # issues when other packages do define _FILE_OFFSET_BITS, + # hard-code apr_off_t to long. + off_t_value=long + off_t_fmt='#define APR_OFF_T_FMT "ld"' + off_t_strfn='strtol' +elif test "$ac_cv_type_off_t" = "yes"; then + off_t_value=off_t + # off_t is more commonly a long than an int; prefer that case + # where int and long are the same size. + if test "$ac_cv_sizeof_off_t" = "$ac_cv_sizeof_long"; then + off_t_fmt='#define APR_OFF_T_FMT "ld"' + off_t_strfn='strtol' + elif test "$ac_cv_sizeof_off_t" = "$ac_cv_sizeof_int"; then + off_t_fmt='#define APR_OFF_T_FMT "d"' + off_t_strfn='strtoi' + elif test "$ac_cv_sizeof_off_t" = "$ac_cv_sizeof_long_long"; then + off_t_fmt='#define APR_OFF_T_FMT APR_INT64_T_FMT' + off_t_strfn='apr_strtoi64' + else + AC_ERROR([could not determine the size of off_t]) + fi + # Per OS tuning... + case $host in + *-mingw*) + off_t_value=apr_int64_t + off_t_fmt='#define APR_OFF_T_FMT "I64d"' + off_t_strfn='_strtoi64' + ;; + esac +else + # Fallback on int + off_t_value=apr_int64_t + off_t_fmt='#define APR_OFF_T_FMT "d"' + off_t_strfn='strtoi' fi +AC_MSG_RESULT($off_t_value) -AC_CHECK_SIZEOF_EXTENDED([#include <sys/types.h>], ssize_t, 8) +# Regardless of whether _LARGEFILE64_SOURCE is used, on some +# platforms _FILE_OFFSET_BITS will affect the size of ino_t and hence +# the build-time ABI may be different from the apparent ABI when using +# APR with another package which *does* define _FILE_OFFSET_BITS. +# (Exactly as per the case above with off_t where LFS is *not* used) +# +# To be safe, hard-code apr_ino_t as 'unsigned long' or 'unsigned int' +# iff that is exactly the size of ino_t here; otherwise use ino_t as existing +# releases did. To be correct, apr_ino_t should have been made an +# ino64_t as apr_off_t is off64_t, but this can't be done now without +# breaking ABI. -if test "$ac_cv_sizeof_ssize_t" = "$ac_cv_sizeof_int"; then - ssize_t_fmt='#define APR_SSIZE_T_FMT "d"' -elif test "$ac_cv_sizeof_ssize_t" = "$ac_cv_sizeof_long"; then - ssize_t_fmt='#define APR_SSIZE_T_FMT "ld"' +# Per OS tuning... +case $host in +*mingw*) + ino_t_value=apr_int64_t + ;; +*) + ino_t_value=ino_t + APR_CHECK_SIZEOF_EXTENDED(AC_INCLUDES_DEFAULT, ino_t, $ac_cv_sizeof_long) + if test $ac_cv_sizeof_ino_t = 4; then + if test $ac_cv_sizeof_long = 4; then + ino_t_value="unsigned long" + else + ino_t_value="unsigned int" + fi + fi + ;; +esac +AC_MSG_NOTICE([using $ino_t_value for ino_t]) + +# Checks for endianness +AC_C_BIGENDIAN +if test $ac_cv_c_bigendian = yes; then + bigendian=1 else - ssize_t_fmt='#error Can not determine the proper size for ssize_t' + bigendian=0 fi -AC_CHECK_SIZEOF_EXTENDED([#include <sys/types.h>], off_t, 8) - -if test "$ac_cv_sizeof_off_t" = "$ac_cv_sizeof_int"; then - off_t_fmt='#define APR_OFF_T_FMT "d"' -elif test "$ac_cv_sizeof_off_t" = "$ac_cv_sizeof_long"; then - off_t_fmt='#define APR_OFF_T_FMT "ld"' -elif test "$ac_cv_sizeof_off_t" = "$ac_cv_sizeof_long_long"; then - off_t_fmt='#define APR_OFF_T_FMT "qd"' +APR_CHECK_SIZEOF_EXTENDED([#include <sys/types.h> +#include <sys/uio.h>],struct iovec,0) +if test "$ac_cv_sizeof_struct_iovec" = "0"; then + have_iovec=0 else - off_t_fmt='#error Can not determine the proper size for off_t' + have_iovec=1 fi +AC_SUBST(voidp_size) AC_SUBST(short_value) AC_SUBST(int_value) AC_SUBST(long_value) +AC_SUBST(int64_value) AC_SUBST(off_t_value) AC_SUBST(size_t_value) AC_SUBST(ssize_t_value) +AC_SUBST(socklen_t_value) +AC_SUBST(int64_t_fmt) +AC_SUBST(uint64_t_fmt) +AC_SUBST(uint64_t_hex_fmt) AC_SUBST(ssize_t_fmt) +AC_SUBST(size_t_fmt) AC_SUBST(off_t_fmt) +AC_SUBST(pid_t_fmt) +AC_SUBST(int64_literal) +AC_SUBST(uint64_literal) +AC_SUBST(stdint) +AC_SUBST(bigendian) +AC_SUBST(aprlfs) +AC_SUBST(have_iovec) +AC_SUBST(ino_t_value) -dnl #----------------------------- Checking for Threads -echo $ac_n "${nl}Checking for Threads...${nl}" -AC_CACHE_CHECK([for threads], ac_cv_enable_threads, - [ AC_ARG_ENABLE(threads, - [ --enable-threads Enable threading support in APR.], - [ ac_cv_enable_threads=$enableval] , - [ AC_CHECK_HEADERS(pthread.h, - [ ac_cv_enable_threads="pthread" ] , - [ ac_cv_enable_threads="no" ] ) ] ) ] ) - -if test "$ac_cv_enable_threads" = "no"; then - threads="0" - pthreadh="0" -else - REENTRANCY_FLAGS - if test "$ac_cv_enable_threads" = "pthread"; then -# We have specified pthreads for our threading library, just make sure -# that we have everything we need - PTHREADS_CHECK - AC_CHECK_HEADERS(pthread.h, [ - threads="1" - pthreadh="1" - AC_DEFINE(USE_THREADS) ], [ - threads="0" - pthreadh="0" ] ) - elif test "$enable_apr_threads" = "system_threads"; then - threads="1" - pthreadh="0" - else -# We basically specified that we wanted threads, but not how to implement -# them. In this case, just look for pthreads. In the future, we can check -# for other threading libraries as well. - PTHREADS_CHECK - AC_CHECK_HEADERS(pthread.h, [ - threads="1" - pthreadh="1" - AC_DEFINE(USE_THREADS) ], [ - threads="0" - pthreadh="0" ] ) - fi +dnl ----------------------------- Checking for string functions +AC_CHECK_FUNCS(strnicmp, have_strnicmp="1", have_strnicmp="0") +AC_CHECK_FUNCS(strncasecmp, have_strncasecmp="1", have_strncasecmp="0") +AC_CHECK_FUNCS(stricmp, have_stricmp="1", have_stricmp="0") +AC_CHECK_FUNCS(strcasecmp, have_strcasecmp="1", have_strcasecmp="0") +AC_CHECK_FUNCS(strdup, have_strdup="1", have_strdup="0") +AC_CHECK_FUNCS(strstr, have_strstr="1", have_strstr="0") +AC_CHECK_FUNCS(memchr, have_memchr="1", have_memchr="0") +AC_CHECK_FUNC($int64_strfn, have_int64_strfn="1", have_int64_strfn="0") + +dnl ----------------------------- We have a fallback position +if test "$have_int64_strfn" = "0" && test "$int64_strfn" = "strtoll"; then + int64_strfn="strtoq" + AC_CHECK_FUNC(strtoq, [have_int64_strfn=1], [have_int64_strfn=0]) fi -ac_cv_define_READDIR_IS_THREAD_SAFE=no -AC_CHECK_LIB(c_r, readdir, AC_DEFINE(READDIR_IS_THREAD_SAFE)) +if test "$have_int64_strfn" = "1"; then + AC_DEFINE_UNQUOTED(APR_INT64_STRFN, [$int64_strfn], + [Define as function which can be used for conversion of strings to apr_int64_t]) +fi -if test "$threads" = "1"; then - echo "APR will use threads" -else - echo "APR will be non-threaded" +AC_SUBST(have_strnicmp) +AC_SUBST(have_strncasecmp) +AC_SUBST(have_stricmp) +AC_SUBST(have_strcasecmp) +AC_SUBST(have_strdup) +AC_SUBST(have_strstr) +AC_SUBST(have_memchr) + +AC_CACHE_CHECK([for memset_s support], [apr_cv_memset_s], +[AC_TRY_RUN([ +#ifdef HAVE_STRING_H +#define __STDC_WANT_LIB_EXT1__ 1 +#include <string.h> +#endif + +int main(int argc, const char **argv) +{ + char buf[1] = {1}; + return memset_s(buf, sizeof buf, 0, sizeof buf) != 0 || *buf != '\0'; +}], [apr_cv_memset_s=yes], [apr_cv_memset_s=no], [apr_cv_memset_s=no])]) + +if test "$apr_cv_memset_s" = "yes"; then + AC_DEFINE([HAVE_MEMSET_S], 1, [Define if memset_s function is supported]) fi -AC_SUBST(threads) +AC_CACHE_CHECK([for explicit_bzero support], [apr_cv_explicit_bzero], +[AC_TRY_RUN([ +#ifdef HAVE_STRING_H +#include <string.h> +#endif +#ifdef HAVE_STRINGS_H +#include <strings.h> +#endif -dnl #----------------------------- Checking for MMAP -echo $ac_n "${nl}Checking for MMAP...${nl}" -AC_FUNC_MMAP -if test "$ac_cv_func_mmap_fixed_mapped" = "yes"; then - mmap="1" +int main(int argc, const char **argv) +{ + char buf[1] = {1}; + explicit_bzero(buf, sizeof buf); + return *buf != '\0'; +}], [apr_cv_explicit_bzero=yes], [apr_cv_explicit_bzero=no], [apr_cv_explicit_bzero=no])]) + +if test "$apr_cv_explicit_bzero" = "yes"; then + AC_DEFINE([HAVE_EXPLICIT_BZERO], 1, [Define if explicit_bzero function is supported]) +fi + +if test "$off_t_strfn" = "apr_strtoi64" && test "$have_int64_strfn" = "1"; then + off_t_strfn=$int64_strfn +fi +AC_DEFINE_UNQUOTED(APR_OFF_T_STRFN, [$off_t_strfn], + [Define as function used for conversion of strings to apr_off_t]) + +dnl ----------------------------- Checking for DSO support +AC_MSG_NOTICE([]) +AC_MSG_NOTICE([Checking for DSO...]) + +AC_ARG_ENABLE(dso, + [ --disable-dso Disable DSO support ], + [if test "x$enableval" = "xyes"; then + dsotype=any + else + dsotype=$enableval + fi + ], [dsotype=any]) + +if test "$dsotype" = "any"; then + if test "$dsotype" = "any"; then + case $host in + *darwin[[0-8]]\.*) + # Original Darwin, not for 9.0!: + AC_CHECK_FUNC(NSLinkModule, [dsotype=dyld]);; + hppa*-hpux[[1-9]]\.*|hppa*-hpux1[[01]]*) + # shl is specific to parisc hpux SOM binaries, not used for 64 bit + AC_CHECK_LIB(dld, shl_load, [have_shl=1]) + if test "$ac_cv_sizeof_voidp$have_shl" = "41"; then + dsotype=shl; APR_ADDTO(LIBS,-ldld) + fi;; + *-mingw*|*-os2*) + # several 'other's below probably belong up here. If they always + # use a platform implementation and shouldn't test the dlopen/dlfcn + # features, then bring them up here. + # But if they -should- optionally use dlfcn, and/or need the config + # detection of dlopen/dlsym, do not move them up. + dsotype=other ;; + esac + fi + # Normal POSIX: + if test "$dsotype" = "any"; then + AC_CHECK_FUNC(dlopen, [dsotype=dlfcn]) + fi + if test "$dsotype" = "any"; then + AC_CHECK_LIB(dl, dlopen, [dsotype=dlfcn; APR_ADDTO(LIBS,-ldl)]) + fi + if test "$dsotype" = "dlfcn"; then + # ReliantUnix has dlopen() in libc but dlsym() in libdl :( + AC_CHECK_FUNC(dlsym, [], + [AC_CHECK_LIB(dl, dlsym, + [APR_ADDTO(LIBS, -ldl)], + [dsotype=any + AC_MSG_WARN([Weird: dlopen() was found but dlsym() was not found!])])]) + fi + if test "$dsotype" = "any"; then + # BeOS: + AC_CHECK_LIB(root, load_image, [dsotype=other]) + fi + # Everything else: + if test "$dsotype" = "any"; then + case $host in + *os390|*os400|*-aix*) + # Some -aix5 will use dl, no hassles. Keep that pattern here. + dsotype=other ;; + *-hpux*) + if test "$have_shl" = "1"; then + dsotype=shl; APR_ADDTO(LIBS,-ldld) + fi;; + esac + fi +fi + +if test "$dsotype" = "any"; then + AC_MSG_ERROR([Could not detect suitable DSO implementation]) +elif test "$dsotype" = "no"; then + aprdso="0" else - mmap="0" + case "$dsotype" in + dlfcn) AC_DEFINE(DSO_USE_DLFCN, 1, [Define if DSO support uses dlfcn.h]);; + shl) AC_DEFINE(DSO_USE_SHL, 1, [Define if DSO support uses shl_load]);; + dyld) AC_DEFINE(DSO_USE_DYLD, 1, [Define if DSO support uses dyld.h]);; + other) ;; # Use whatever is in dso/OSDIR + *) AC_MSG_ERROR([Unknown DSO implementation "$dsotype"]);; + esac + aprdso="1" + apr_modules="$apr_modules dso" +fi + +AC_SUBST(aprdso) + +dnl ----------------------------- Checking for Processes +AC_MSG_NOTICE([]) +AC_MSG_NOTICE([Checking for Processes...]) + +AC_CHECK_FUNCS(waitpid) + +AC_ARG_ENABLE(other-child, + [ --enable-other-child Enable reliable child processes ], + [ if test "$enableval" = "yes"; then + oc="1" + else + oc="0" + fi ], + [ oc=1 ] ) + +AC_SUBST(oc) + +if test -z "$have_proc_invoked"; then + have_proc_invoked="0" +fi + +AC_SUBST(have_proc_invoked) + +AC_MSG_CHECKING(for Variable Length Arrays) +APR_TRY_COMPILE_NO_WARNING([], +[ + int foo[argc]; + foo[0] = 0; +], vla_msg=yes, vla_msg=no ) +AC_MSG_RESULT([$vla_msg]) +if test "$vla_msg" = "yes"; then + AC_DEFINE(HAVE_VLA, 1, [Define if C compiler supports VLA]) fi -AC_SUBST(mmap) -dnl #----------------------------- Checking for Locking Characteristics -echo $ac_n "${nl}Checking for Locking..." +AC_CACHE_CHECK(struct rlimit,ac_cv_struct_rlimit,[ +AC_TRY_RUN([ +#include <sys/types.h> +#include <sys/time.h> +#include <sys/resource.h> +main() +{ + struct rlimit limit; + limit.rlim_cur = 0; + limit.rlim_max = 0; + exit(0); +}], [ + ac_cv_struct_rlimit=yes ], [ + ac_cv_struct_rlimit=no ], [ + ac_cv_struct_rlimit=no ] ) ] ) +struct_rlimit=0 +test "x$ac_cv_struct_rlimit" = xyes && struct_rlimit=1 +AC_SUBST(struct_rlimit) + +dnl ----------------------------- Checking for Locking Characteristics +AC_MSG_NOTICE([]) +AC_MSG_NOTICE([Checking for Locking...]) + +AC_CHECK_FUNCS(semget semctl semop semtimedop flock) +APR_IFALLYES(func:semtimedop, have_semtimedop="1", have_semtimedop="0") + +AC_CHECK_HEADERS(semaphore.h) +AC_SEARCH_LIBS(sem_open, rt) +AC_CHECK_FUNCS(sem_close sem_unlink sem_post sem_wait sem_timedwait) +APR_IFALLYES(func:sem_timedwait, have_sem_timedwait="1", have_sem_timedwait="0") + +AC_CHECK_HEADERS(OS.h) +AC_CHECK_FUNCS(create_sem acquire_sem acquire_sem_etc) +APR_IFALLYES(header:OS.h func:acquire_sem_etc, have_acquire_sem_etc="1", have_acquire_sem_etc="0") + +# Some systems return ENOSYS from sem_open. +AC_CACHE_CHECK(for working sem_open,ac_cv_func_sem_open,[ +AC_TRY_RUN([ +#include <errno.h> +#include <stdlib.h> +#include <fcntl.h> +#include <semaphore.h> +#ifndef SEM_FAILED +#define SEM_FAILED (-1) +#endif +main() +{ + sem_t *psem; + const char *sem_name = "/apr_autoconf"; + + psem = sem_open(sem_name, O_CREAT, 0644, 1); + if (psem == (sem_t *)SEM_FAILED) { + exit(1); + } + sem_close(psem); + psem = sem_open(sem_name, O_CREAT | O_EXCL, 0644, 1); + if (psem != (sem_t *)SEM_FAILED) { + sem_close(psem); + exit(1); + } + sem_unlink(sem_name); + exit(0); +}], [ac_cv_func_sem_open=yes], [ac_cv_func_sem_open=no], +[ac_cv_func_sem_open=no])]) # It's stupid, but not all platforms have union semun, even those that need it. -AC_MSG_CHECKING(looking for union semun in sys/sem.h) +AC_MSG_CHECKING(for union semun in sys/sem.h) AC_TRY_COMPILE([ #include <sys/types.h> #include <sys/ipc.h> @@ -378,167 +2210,799 @@ AC_MSG_RESULT([$msg]) AC_SUBST(have_union_semun) dnl Checks for libraries. -AC_CHECK_DEFINE(LOCK_EX, sys/file.h) -AC_CHECK_DEFINE(F_SETLK, fcntl.h) +APR_CHECK_DEFINE(LOCK_EX, sys/file.h) +APR_CHECK_DEFINE(F_SETLK, fcntl.h) +APR_CHECK_DEFINE(SEM_UNDO, sys/sem.h) + +# We are assuming that if the platform doesn't have POLLIN, it doesn't have +# any POLL definitions. +APR_CHECK_DEFINE_FILES(POLLIN, poll.h sys/poll.h) -pthreadser="0" if test "$threads" = "1"; then - AC_CHECK_DEFINE(PTHREAD_PROCESS_SHARED, pthread.h) - AC_CHECK_FUNC(pthread_mutex_init, [ - AC_DEFINE(USE_PTHREAD_SERIALIZE) - pthreadser="1" ]) -fi -AC_BEGIN_DECISION([lock implementation method]) -AC_IFALLYES(custom:union_semun, - AC_DECIDE(USE_SYSVSEM_SERIALIZE, [SysV IPC semget()])) -AC_IFALLYES(header:sys/file.h define:LOCK_EX, - AC_DECIDE(USE_FLOCK_SERIALIZE, [4.2BSD-style flock()])) -AC_IFALLYES(header:fcntl.h define:F_SETLK, - AC_DECIDE(USE_FCNTL_SERIALIZE, [SVR4-style fcntl()])) -AC_IFALLYES(header:pthread.h define:PTHREAD_PROCESS_SHARED dnl - custom:with_pthread_cross, - AC_DECIDE(USE_PROC_PTHREAD_SERIALIZE, [pthread mutex])) -dnl AC_DECISION_FORCE(USE_FCNTL_SERIALIZE) -AC_END_DECISION + APR_CHECK_DEFINE(PTHREAD_PROCESS_SHARED, pthread.h) + AC_CHECK_FUNCS(pthread_mutex_timedlock pthread_mutexattr_setpshared) + APR_IFALLYES(header:pthread.h func:pthread_mutex_timedlock, + have_pthread_mutex_timedlock="1", have_pthread_mutex_timedlock="0") + AC_SUBST(have_pthread_mutex_timedlock) + # Some systems have setpshared and define PROCESS_SHARED, but don't + # really support PROCESS_SHARED locks. So, we must validate that we + # can go through the steps without receiving some sort of system error. + # Linux and older versions of AIX have this problem. + APR_IFALLYES(header:pthread.h define:PTHREAD_PROCESS_SHARED func:pthread_mutexattr_setpshared, [ + AC_CACHE_CHECK([for working PROCESS_SHARED locks], apr_cv_process_shared_works, [ + AC_TRY_RUN([ +#include <sys/types.h> +#include <pthread.h> + int main() + { + pthread_mutex_t mutex; + pthread_mutexattr_t attr; + if (pthread_mutexattr_init(&attr)) + exit(1); + if (pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED)) + exit(2); + if (pthread_mutex_init(&mutex, &attr)) + exit(3); + if (pthread_mutexattr_destroy(&attr)) + exit(4); + if (pthread_mutex_destroy(&mutex)) + exit(5); + exit(0); + }], [apr_cv_process_shared_works=yes], [apr_cv_process_shared_works=no])]) + # Override detection of pthread_mutexattr_setpshared + ac_cv_func_pthread_mutexattr_setpshared=$apr_cv_process_shared_works]) + + if test "$ac_cv_func_pthread_mutexattr_setpshared" = "yes"; then + APR_CHECK_PTHREAD_ROBUST_SHARED_MUTEX + fi +fi + +# See which lock mechanisms we can support on this system. +APR_IFALLYES(header:semaphore.h func:sem_open func:sem_close dnl + func:sem_unlink func:sem_post func:sem_wait, + hasposixser="1", hasposixser="0") +APR_IFALLYES(func:semget func:semctl func:semop define:SEM_UNDO, + hassysvser="1", hassysvser="0") +APR_IFALLYES(func:flock define:LOCK_EX, hasflockser="1", hasflockser="0") +APR_IFALLYES(header:fcntl.h define:F_SETLK, hasfcntlser="1", hasfcntlser="0") +# note: the current APR use of shared mutex requires /dev/zero +APR_IFALLYES(header:pthread.h define:PTHREAD_PROCESS_SHARED dnl + func:pthread_mutexattr_setpshared dnl + file:/dev/zero, + hasprocpthreadser="1", hasprocpthreadser="0") +APR_IFALLYES(header:OS.h func:create_sem, hasbeossem="1", hasbeossem="0") + +AC_CHECK_FUNCS(pthread_condattr_setpshared) +APR_IFALLYES(header:pthread.h func:pthread_condattr_setpshared, + have_pthread_condattr_setpshared="1", have_pthread_condattr_setpshared="0") +AC_SUBST(have_pthread_condattr_setpshared) + +# See which lock mechanism we'll select by default on this system. +# The last APR_DECIDE to execute sets the default. +# At this stage, we match the ordering in Apache 1.3 +# which is (highest to lowest): sysvsem -> fcntl -> flock. +# POSIX semaphores and cross-process pthread mutexes are not +# used by default since they have less desirable behaviour when +# e.g. a process holding the mutex segfaults. +# The BEOSSEM decision doesn't require any substitutions but is +# included here to prevent the fcntl() branch being selected +# from the decision making. +APR_BEGIN_DECISION([apr_lock implementation method]) +APR_IFALLYES(func:flock define:LOCK_EX, + APR_DECIDE(USE_FLOCK_SERIALIZE, [4.2BSD-style flock()])) +APR_IFALLYES(header:fcntl.h define:F_SETLK, + APR_DECIDE(USE_FCNTL_SERIALIZE, [SVR4-style fcntl()])) +APR_IFALLYES(func:semget func:semctl func:semop define:SEM_UNDO, + APR_DECIDE(USE_SYSVSEM_SERIALIZE, [SysV IPC semget()])) +APR_IFALLYES(header:OS.h func:create_sem func:acquire_sem func:acquire_sem_etc, + APR_DECIDE(USE_BEOSSEM, [BeOS Semaphores])) +if test "x$apr_lock_method" != "x"; then + APR_DECISION_FORCE($apr_lock_method) +fi +APR_END_DECISION AC_DEFINE_UNQUOTED($ac_decision) flockser="0" sysvser="0" +posixser="0" procpthreadser="0" fcntlser="0" case $ac_decision in USE_FLOCK_SERIALIZE ) flockser="1" ;; + USE_FCNTL_SERIALIZE ) + fcntlser="1" + ;; USE_SYSVSEM_SERIALIZE ) sysvser="1" ;; - USE_FCNTL_SERIALIZE ) - fcntlser="1" + USE_POSIXSEM_SERIALIZE ) + posixser="1" ;; USE_PROC_PTHREAD_SERIALIZE ) procpthreadser="1" ;; + USE_BEOSSEM ) + beossem="1" + ;; esac +if test $hasfcntlser = "1"; then +AC_MSG_CHECKING(if fcntl returns EACCES when F_SETLK is already held) +AC_TRY_RUN([ +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif +#ifdef HAVE_SYS_WAIT_H +#include <sys/wait.h> +#endif +#if defined(HAVE_UNISTD_H) +#include <unistd.h> +#endif +#include <fcntl.h> +#include <errno.h> + +int fd; +struct flock proc_mutex_lock_it = {0}; +const char *fname = "conftest.fcntl"; + +int main() +{ + int rc, status;; + proc_mutex_lock_it.l_whence = SEEK_SET; /* from current point */ + proc_mutex_lock_it.l_type = F_WRLCK; /* set exclusive/write lock */ + + fd = creat(fname, S_IRWXU); + unlink(fname); + + if (rc = lockit()) { + exit(-1); + } + + if (fork()) { + wait(&status); + } + else { + return(lockit()); + } + + close(fd); + exit(WEXITSTATUS(status) != EACCES); +} + +int lockit() { + int rc; + do { + rc = fcntl(fd, F_SETLK, &proc_mutex_lock_it); + } while ( rc < 0 && errno == EINTR); + + return (rc < 0) ? errno : 0; +}], [apr_fcntl_tryacquire_eacces=1], [apr_fcntl_tryacquire_eacces=0], [apr_fcntl_tryacquire_eacces=0]) +fi + +if test "$apr_fcntl_tryacquire_eacces" = "1"; then + AC_DEFINE(FCNTL_TRYACQUIRE_EACCES, 1, [Define if fcntl returns EACCES when F_SETLK is already held]) + AC_MSG_RESULT(yes) +else + AC_MSG_RESULT(no) +fi + + +AC_SUBST(hasflockser) +AC_SUBST(hassysvser) +AC_SUBST(hasposixser) +AC_SUBST(hasfcntlser) +AC_SUBST(hasprocpthreadser) AC_SUBST(flockser) AC_SUBST(sysvser) +AC_SUBST(posixser) AC_SUBST(fcntlser) AC_SUBST(procpthreadser) AC_SUBST(pthreadser) -dnl #----------------------------- Checking for Shared Memory Support -echo $ac_n "${nl}Checking for Shared Memory Support...${nl}" - -# run the MM config script regardless of whether we are going to use -# it or not. When we have a much better idea of who is using MM, we can -# run this on a more conditional basis. -AC_CONFIG_SUBDIRS($config_subdirs) - -AC_MSG_CHECKING(Checking for Shared memory support) -AC_ARG_ENABLE(shmem, - [ --enable-shmem Enable shared memory support in APR. ], - [ ], - ac_cv_enable_shmem="mm" ) - -sharedmem="0" -anonymous_shm="0" -filebased_shm="0" -keybased_shm="0" -if test "$ac_cv_enable_shmem" = "mm"; then - sharedmem="1" - anonymous_shm="1" - AC_MSG_RESULT(anonymous) -elif test "$ac_cv_enable_shmem" = "file"; then - sharedmem="1" - filebased_shm="1" - AC_MSG_RESULT(file based) -elif test "$ac_cv_enable_shmem" = "key"; then - sharedmem="1" - keybased_shm="1" - AC_MSG_RESULT(key based) +AC_MSG_CHECKING(if all interprocess locks affect threads) +if test "x$apr_process_lock_is_global" = "xyes"; then + proclockglobal="1" + AC_MSG_RESULT(yes) +else + proclockglobal="0" + AC_MSG_RESULT(no) +fi + +AC_SUBST(proclockglobal) + +AC_MSG_CHECKING(if POSIX sems affect threads in the same process) +if test "x$apr_posixsem_is_global" = "xyes"; then + AC_DEFINE(POSIXSEM_IS_GLOBAL, 1, + [Define if POSIX semaphores affect threads within the process]) + AC_MSG_RESULT(yes) else AC_MSG_RESULT(no) fi -AC_SUBST(sharedmem) -AC_SUBST(anonymous_shm) -AC_SUBST(filebased_shm) -AC_SUBST(keybased_shm) - -dnl #----------------------------- Checking for /dev/random -AC_MSG_CHECKING(for /dev/random) -if test -r "/dev/random"; then - AC_DEFINE(DEV_RANDOM, [/dev/random]) - AC_MSG_RESULT(/dev/random) +AC_MSG_CHECKING(if SysV sems affect threads in the same process) +if test "x$apr_sysvsem_is_global" = "xyes"; then + AC_DEFINE(SYSVSEM_IS_GLOBAL, 1, + [Define if SysV semaphores affect threads within the process]) + AC_MSG_RESULT(yes) +else + AC_MSG_RESULT(no) +fi + +AC_MSG_CHECKING(if fcntl locks affect threads in the same process) +if test "x$apr_fcntl_is_global" = "xyes"; then + AC_DEFINE(FCNTL_IS_GLOBAL, 1, + [Define if fcntl locks affect threads within the process]) + AC_MSG_RESULT(yes) +else + AC_MSG_RESULT(no) +fi + +AC_MSG_CHECKING(if flock locks affect threads in the same process) +if test "x$apr_flock_is_global" = "xyes"; then + AC_DEFINE(FLOCK_IS_GLOBAL, 1, + [Define if flock locks affect threads within the process]) + AC_MSG_RESULT(yes) +else + AC_MSG_RESULT(no) +fi + +dnl ----------------------------- Checking for /dev/random +AC_CHECK_HEADERS(sys/random.h) +AC_CHECK_FUNCS(getrandom) + +AC_CHECK_HEADERS(sys/syscall.h) +AC_CHECK_HEADERS(linux/random.h) +AC_CHECK_DECLS([SYS_getrandom], [], [], [#include <sys/syscall.h>]) + +AC_CHECK_FUNCS(arc4random_buf) + +AC_MSG_CHECKING(for entropy source) + +why_no_rand="" + +AC_ARG_WITH(egd, + [ --with-egd[[=DIR]] use EGD-compatible socket], + [ AC_DEFINE(HAVE_EGD, 1, [Define if EGD is supported]) + if test "$withval" = "yes"; then + AC_DEFINE_UNQUOTED(EGD_DEFAULT_SOCKET, ["/var/run/egd-pool","/dev/egd-pool","/etc/egd-pool","/etc/entropy"], + [Define to list of paths to EGD sockets]) + else + AC_DEFINE_UNQUOTED(EGD_DEFAULT_SOCKET, ["$withval"]) + fi + AC_MSG_RESULT(EGD-compatible daemon) rand="1" -elif test -f "/dev/urandom"; then - AC_DEFINE(DEV_RANDOM, [/dev/urandom]) - AC_MSG_RESULT(/dev/urandom) + ]) + +if test "$rand" != "1"; then + if test "$ac_cv_func_getrandom" = yes; then + AC_MSG_RESULT(getrandom) rand="1" -else - AC_MSG_RESULT(not found); - if test "$ac_cv_lib_truerand_main" = "yes"; then - rand="1" + elif test "$ac_cv_have_decl_SYS_getrandom" = yes; then + AC_MSG_RESULT(SYS_getrandom) + rand="1" + fi +fi + +if test "$rand" != "1"; then + if test "$ac_cv_func_arc4random_buf" = yes; then + AC_MSG_RESULT(arc4random) + rand="1" + fi +fi + +if test "$rand" != "1"; then + AC_ARG_WITH(devrandom, + [ --with-devrandom[[=DEV]] use /dev/random or compatible [[searches by default]]], + [ apr_devrandom="$withval" ], [ apr_devrandom="yes" ]) + + if test "$apr_devrandom" = "yes"; then + # /dev/random on OpenBSD doesn't provide random data, so + # prefer /dev/arandom, which does; see random(4). + for f in /dev/arandom /dev/urandom /dev/random; do + if test -r $f; then + apr_devrandom=$f + rand=1 + break + fi + done + elif test "$apr_devrandom" != "no"; then + if test -r "$apr_devrandom"; then + rand="1" else - rand="0" + AC_ERROR([$apr_devrandom not found or unreadable.]) fi + fi + + if test "$rand" = "1"; then + case $host in + *os390) + if test $os_version -lt 1700; then + rand="0" + why_no_rand=" ($apr_devrandom unusable on z/OS before V1R7)" + fi + ;; + esac + fi + + if test "$rand" = "1"; then + AC_DEFINE_UNQUOTED(DEV_RANDOM, ["$apr_devrandom"], [Define to path of random device]) + AC_MSG_RESULT([$apr_devrandom]) + fi +fi + +if test "$rand" != "1"; then + case $host in + # we have built in support for OS/2 + *-os2*) + AC_MSG_RESULT([Using OS/2 builtin random]) + rand="1" + ;; + *) + if test "$rand" != "1"; then + if test "$ac_cv_lib_truerand_main" = "yes"; then + AC_DEFINE(HAVE_TRUERAND, 1, [Define if truerand is supported]) + AC_MSG_RESULT(truerand) + rand="1" + else + AC_MSG_RESULT(not found$why_no_rand) + rand="0" + fi + fi + ;; + esac fi AC_SUBST(rand) -dnl #----------------------------- Checking for Time Support -echo $ac_n "${nl}Checking for Time Support...${nl}" -AC_CACHE_CHECK([for tm_gmtoff in struct tm], ac_cv_struct_tm_gmtoff, -[AC_TRY_COMPILE([#include <sys/types.h> -#include <$ac_cv_struct_tm>], [struct tm tm; tm.tm_gmtoff;], - ac_cv_struct_tm_gmtoff=yes, ac_cv_struct_tm_gmtoff=no)]) -if test "$ac_cv_struct_tm_gmtoff" = "yes"; then - AC_DEFINE(HAVE_GMTOFF) +dnl ----------------------------- Checking for File Info Support +AC_MSG_NOTICE([]) +AC_MSG_NOTICE([Checking for File Info Support...]) +AC_CHECK_MEMBERS([struct stat.st_blocks, struct stat.st_atimensec, +struct stat.st_ctimensec, struct stat.st_mtimensec, struct stat.st_atim.tv_nsec, +struct stat.st_ctim.tv_nsec, struct stat.st_mtim.tv_nsec, +struct stat.st_atime_n, struct stat.st_ctime_n, struct stat.st_mtime_n],,,[ +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif]) + +APR_CHECK_DIRENT_INODE +APR_CHECK_DIRENT_TYPE + +dnl ----------------------------- Checking for UUID Support +AC_MSG_NOTICE([]) +AC_MSG_NOTICE([Checking for OS UUID Support...]) + +AC_CHECK_HEADERS(uuid.h uuid/uuid.h sys/uuid.h, break) + +apr_revert_save_LIBS=$LIBS + +# Prefer the flavor(s) that live in libc; +AC_SEARCH_LIBS(uuid_create, uuid) +AC_SEARCH_LIBS(uuid_generate, uuid) +if test "$ac_cv_search_uuid_create" = "none required" -o \ + "$ac_cv_search_uuid_generate" = "none required"; then + LIBS=$apr_revert_save_LIBS fi -dnl #----------------------------- Checking for Networking Support -echo $ac_n "${nl}Checking for Networking support..." -AC_MSG_CHECKING(looking for in_addr in netinet/in.h) -AC_TRY_COMPILE([ -#include <netinet/in.h> -],[ -struct in_addr arg; -arg.s_addr = htonl(INADDR_ANY); -], [ have_in_addr="1" -msg=yes ] , [ have_in_addr="0" -msg=no ]) -AC_MSG_RESULT([$msg]) +AC_CHECK_FUNCS(uuid_create uuid_generate) + +AC_CACHE_CHECK([for os uuid usability], [apr_cv_osuuid], [ +# Ensure this test closely mirrors misc/unix/rand.c! +uuid_includes=" +#if defined(HAVE_SYS_TYPES_H) +#include <sys/types.h> +#endif +#if defined(HAVE_UNISTD_H) +#include <unistd.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 +" + apr_cv_osuuid=no + if test $ac_cv_func_uuid_create = yes; then + AC_TRY_LINK([$uuid_includes], [ + uuid_t g; + uint32_t s; + uuid_create(&g, &s); + if (s == uuid_s_ok) s = 0; + ], [apr_cv_osuuid=yes], [apr_cv_func_uuid_create=no]) + fi + if test $ac_cv_func_uuid_generate = yes; then + AC_TRY_LINK([$uuid_includes], [ + uuid_t g; + uuid_generate(g); + ], [apr_cv_osuuid=yes], [apr_cv_func_uuid_generate=no]) + fi +]) + +if test $apr_cv_osuuid = yes; then + osuuid="1" +else + osuuid="0" + LIBS=$apr_revert_save_LIBS +fi +AC_SUBST(osuuid) + + +dnl ----------------------------- Checking for Time Support +AC_MSG_NOTICE([]) +AC_MSG_NOTICE([Checking for Time Support...]) + +AC_CHECK_MEMBERS([struct tm.tm_gmtoff, struct tm.__tm_gmtoff],,,[ +#include <sys/types.h> +#include <time.h>]) + +dnl ----------------------------- Checking for Networking Support +AC_MSG_NOTICE([]) +AC_MSG_NOTICE([Checking for Networking support...]) +APR_TYPE_IN_ADDR +if test "$ac_cv_type_in_addr" = "yes"; then + have_in_addr="1" +else + have_in_addr="0" +fi + +AC_MSG_CHECKING([if fd == socket on this platform]) +if test "x$file_as_socket" != "x0" ; then + file_as_socket="1"; + AC_MSG_RESULT([yes]) +else + AC_MSG_RESULT([no]) +fi AC_SUBST(have_in_addr) +AC_SUBST(file_as_socket) + +if test "$ac_cv_func_poll $file_as_socket" = "yes 1"; then + AC_DEFINE(WAITIO_USES_POLL, 1, + [Define if apr_wait_for_io_or_timeout() uses poll(2)]) +fi + +# Check the types only if we have gethostbyname_r +if test "$ac_cv_func_gethostbyname_r" = "yes"; then + APR_CHECK_GETHOSTBYNAME_R_STYLE +fi + +# Check the types only if we have getservbyname_r +if test "$ac_cv_func_getservbyname_r" = "yes"; then + APR_CHECK_GETSERVBYNAME_R_STYLE +fi + +APR_CHECK_TCP_NODELAY_INHERITED +APR_CHECK_O_NONBLOCK_INHERITED +APR_CHECK_TCP_NODELAY_WITH_CORK + +# Look for a way of corking TCP... +APR_CHECK_DEFINE(TCP_CORK, netinet/tcp.h) +APR_CHECK_DEFINE(TCP_NOPUSH, netinet/tcp.h) +apr_tcp_nopush_flag="0" +have_corkable_tcp="0" +if test "x$ac_cv_define_TCP_CORK" = "xyes"; then + apr_tcp_nopush_flag="TCP_CORK" + have_corkable_tcp="1" +else + case $host in + *linux*) + AC_EGREP_CPP(yes,[ +#include <linux/socket.h> +#ifdef TCP_CORK +yes +#endif + ],[ + apr_tcp_nopush_flag="3" + have_corkable_tcp="1" + ]) + ;; + *) + ;; + esac +fi +if test "x$ac_cv_define_TCP_NOPUSH" = "xyes"; then + apr_tcp_nopush_flag="TCP_NOPUSH" + have_corkable_tcp="1" +fi + +APR_CHECK_DEFINE(SO_ACCEPTFILTER, sys/socket.h) +if test "x$ac_cv_define_SO_ACCEPTFILTER" = "xyes"; then + acceptfilter="1" +else + acceptfilter="0" +fi + +APR_CHECK_SCTP +APR_CHECK_MCAST + +AC_SUBST(apr_tcp_nopush_flag) +AC_SUBST(have_corkable_tcp) +AC_SUBST(acceptfilter) +AC_SUBST(have_sctp) -dnl #----------------------------- Construct the files +AC_CHECK_FUNCS(set_h_errno) + +AC_MSG_NOTICE([]) +AC_MSG_NOTICE([Checking for IPv6 Networking support...]) +dnl Start of checking for IPv6 support... + +AC_ARG_ENABLE(ipv6, + [ --disable-ipv6 Disable IPv6 support in APR.], + [ if test "$enableval" = "no"; then + user_disabled_ipv6=1 + fi ], + [ user_disabled_ipv6=0 ] ) + +case $host in + *) + broken_ipv6=0 +esac + +AC_SEARCH_LIBS(getaddrinfo, socket inet6) +AC_SEARCH_LIBS(gai_strerror, socket inet6) +AC_SEARCH_LIBS(getnameinfo, socket inet6) +AC_CHECK_FUNCS(gai_strerror if_nametoindex if_indextoname) +APR_CHECK_WORKING_GETADDRINFO +APR_CHECK_NEGATIVE_EAI +APR_CHECK_WORKING_GETNAMEINFO +APR_CHECK_SOCKADDR_IN6 +APR_CHECK_SOCKADDR_STORAGE +APR_CHECK_SOCKADDR_UN + +have_ipv6="0" +if test "$user_disabled_ipv6" = 1; then + ipv6_result="no -- disabled by user" +else + if test "x$broken_ipv6" = "x0"; then + if test "x$have_sockaddr_in6" = "x1"; then + if test "x$ac_cv_working_getaddrinfo" = "xyes"; then + if test "x$ac_cv_working_getnameinfo" = "xyes"; then + APR_CHECK_GETADDRINFO_ADDRCONFIG + have_ipv6="1" + ipv6_result="yes" + else + ipv6_result="no -- no getnameinfo" + fi + else + ipv6_result="no -- no working getaddrinfo" + fi + else + ipv6_result="no -- no sockaddr_in6" + fi + else + ipv6_result="no -- the platform has known problems supporting IPv6" + fi +fi + +AC_MSG_CHECKING(if APR supports IPv6) +AC_MSG_RESULT($ipv6_result) + +AC_SUBST(have_ipv6) + +# hstrerror is only needed if IPv6 is not enabled, +# so getaddrinfo/gai_strerror are not used. +if test $have_ipv6 = 0; then + AC_SEARCH_LIBS(hstrerror, resolv, + [AC_DEFINE(HAVE_HSTRERROR, 1, [Define if hstrerror is present])]) +fi + +dnl Check for langinfo support + +AC_CHECK_HEADERS(langinfo.h) +AC_CHECK_FUNCS(nl_langinfo) + +dnl ------------------------------ Defaults for some platform nuances + +dnl Do we have a Win32-centric Unicode FS? +APR_SETIFNULL(have_unicode_fs, [0]) +AC_SUBST(have_unicode_fs) + +APR_SETIFNULL(apr_has_xthread_files, [0]) +AC_SUBST(apr_has_xthread_files) + +APR_SETIFNULL(apr_procattr_user_set_requires_password, [0]) +AC_SUBST(apr_procattr_user_set_requires_password) + +APR_SETIFNULL(apr_thread_func, []) +AC_SUBST(apr_thread_func) + +APR_SETIFNULL(apr_has_user, [1]) +AC_SUBST(apr_has_user) + +dnl ------------------------------ APR-util stuff + +APU_PRELOAD + +dnl Find crypto libraries +APU_CHECK_CRYPTO + +dnl Find DBM and DBD backends to use. +APU_CHECK_DBM +APU_CHECK_DBD +APU_CHECK_DBD_MYSQL +APU_CHECK_DBD_SQLITE3 +APU_CHECK_DBD_SQLITE2 +APU_CHECK_DBD_ORACLE +APU_CHECK_DBD_ODBC + +dnl select an XML parser +APU_FIND_XML + +dnl Find iconv implementations +APU_FIND_ICONV + +dnl Enable DSO build; must be last: +APR_MODULAR_DSO + +AC_SEARCH_LIBS(crypt, crypt ufc) +AC_MSG_CHECKING(if system crypt() function is threadsafe) +if test "x$apu_crypt_threadsafe" = "x1"; then + AC_DEFINE(APU_CRYPT_THREADSAFE, 1, [Define if the system crypt() function is threadsafe]) + msg="yes" +else + msg="no" +fi +AC_MSG_RESULT([$msg]) + +AC_CHECK_FUNCS(crypt_r, [ crypt_r="1" ], [ crypt_r="0" ]) +if test "$crypt_r" = "1"; then + APU_CHECK_CRYPT_R_STYLE +fi + +APRUTIL_LIBNAME="aprutil${libsuffix}" +AC_SUBST(APRUTIL_LIBNAME) + +# Set up destination directory for DSOs. +APR_DSO_LIBDIR="\${libdir}/apr-${APR_MAJOR_VERSION}" +# Set APU_HAVE_MODULES appropriately for the Makefile +if test -n "$APR_DSO_MODULES"; then + APR_HAVE_MODULES=yes +else + APR_HAVE_MODULES=no +fi +APR_EXPAND_VAR(abs_dso_libdir, $APR_DSO_LIBDIR) +AC_DEFINE_UNQUOTED([APR_DSO_LIBDIR], ["$abs_dso_libdir"], + [Define to be absolute path to DSO directory]) +AC_SUBST(APR_HAVE_MODULES) +AC_SUBST(APR_DSO_LIBDIR) +AC_SUBST(APR_DSO_MODULES) +AC_SUBST(EXTRA_OBJECTS) + +dnl XXX FIXME; used for -lexpat, -liconv etc? +AC_SUBST(APRUTIL_EXPORT_LIBS) + +dnl +dnl Prep all the flags and stuff for compilation and export to other builds +dnl +APR_ADDTO(LIBS, [$APRUTIL_LIBS]) + +AC_SUBST(LDFLAGS) + + + +dnl ----------------------------- Finalize the variables + +AC_MSG_NOTICE([]) +AC_MSG_NOTICE([Restore user-defined environment settings...]) + +APR_RESTORE_THE_ENVIRONMENT(CPPFLAGS, EXTRA_) +APR_RESTORE_THE_ENVIRONMENT(CFLAGS, EXTRA_) +APR_RESTORE_THE_ENVIRONMENT(LDFLAGS, EXTRA_) +APR_RESTORE_THE_ENVIRONMENT(LIBS, EXTRA_) +APR_RESTORE_THE_ENVIRONMENT(INCLUDES, EXTRA_) +AC_SUBST(NOTEST_CPPFLAGS) +AC_SUBST(NOTEST_CFLAGS) +AC_SUBST(NOTEST_LDFLAGS) +AC_SUBST(NOTEST_LIBS) +AC_SUBST(NOTEST_INCLUDES) + +dnl ----------------------------- Construct the files + +AC_SUBST(INTERNAL_CPPFLAGS) AC_SUBST(LDLIBS) -AC_SUBST(OPTIM) -AC_SUBST(RANLIB) +AC_SUBST(INCLUDES) AC_SUBST(AR) AC_SUBST(RM) AC_SUBST(OSDIR) AC_SUBST(DEFAULT_OSDIR) -AC_SUBST(LIBPREFIX) AC_SUBST(EXEEXT) +AC_SUBST(LIBTOOL_LIBS) + +# Use -no-install or -no-fast-install to link the test +# programs on all platforms but Darwin, where it would cause +# the programs to be linked against installed versions of +# libapr instead of those just built. +case $host in + *-apple-darwin*) + LT_NO_INSTALL="" + ;; + *-mingw*) + LT_NO_INSTALL="-no-fast-install" + ;; + *) + LT_NO_INSTALL="-no-install" + ;; +esac +AC_SUBST(LT_NO_INSTALL) -echo "Construct Makefiles and header files." -MAKEFILE1="Makefile lib/Makefile " -SUBDIRS="lib " -for dir in $MODULES -do - if test -f $dir/$OSDIR/Makefile.in; then - MAKEFILE2="$MAKEFILE2 $dir/$OSDIR/Makefile " - SUBDIRS="$SUBDIRS $dir/$OSDIR " +# +# BSD/OS (BSDi) needs to use a different include syntax in the Makefiles +# +case $host in +*bsdi*) + # Check whether they've installed GNU make + if make --version > /dev/null 2>&1; then + INCLUDE_RULES="include $apr_buildout/apr_rules.mk" + INCLUDE_OUTPUTS="include $apr_srcdir/build-outputs.mk" else - MAKEFILE2="$MAKEFILE2 $dir/$DEFAULT_OSDIR/Makefile " - SUBDIRS="$SUBDIRS $dir/$DEFAULT_OSDIR " + # BSDi make + INCLUDE_RULES=".include \"$apr_buildout/apr_rules.mk\"" + INCLUDE_OUTPUTS=".include \"$apr_srcdir/build-outputs.mk\"" fi + ;; +*) + INCLUDE_RULES="include $apr_buildout/apr_rules.mk" + INCLUDE_OUTPUTS="include $apr_srcdir/build-outputs.mk" + ;; +esac +AC_SUBST(INCLUDE_RULES) +AC_SUBST(INCLUDE_OUTPUTS) + +AC_CONFIG_FILES([Makefile + include/apr.h + build/apr_rules.mk + build/pkg/pkginfo + apr-$APR_MAJOR_VERSION-config:apr-config.in + apr.pc]) + +if test -d $srcdir/test; then + AC_CONFIG_FILES([test/Makefile test/internal/Makefile]) +fi + +AC_CONFIG_FILES([include/private/apu_select_dbm.h + include/apu_want.h]) + +dir=include/arch/unix +test -d $dir || $MKDIR $dir + +AC_CONFIG_COMMANDS([default], [ +# Commands run at the end of config.status: +for i in $APR_SAVE_HEADERS; do + if cmp -s $i $i.save 2>/dev/null; then + mv $i.save $i + AC_MSG_NOTICE([$i is unchanged]) + fi + rm -f $i.save done +chmod +x apr-$APR_MAJOR_VERSION-config +],[ +dnl This section is expanded by configure UNQUOTED so variable +dnl references must be backslash-escaped as necessary. -MAKEFILE3="test/Makefile" -AC_SUBST(SUBDIRS) -AC_SUBST(MODULES) -AC_OUTPUT($MAKEFILE1 $MAKEFILE2 $MAKEFILE3 include/apr.h) +# Commands run at the beginning of config.status: +APR_SAVE_HEADERS="include/apr.h include/arch/unix/apr_private.h" +APR_MAJOR_VERSION=$APR_MAJOR_VERSION +APR_PLATFORM=$host + +for apri in \${APR_SAVE_HEADERS}; do + test -r \${apri} && mv \${apri} \${apri}.save +done +]) +AC_OUTPUT diff --git a/crypto/apr_crypto.c b/crypto/apr_crypto.c new file mode 100644 index 00000000000..3b50ca531f2 --- /dev/null +++ b/crypto/apr_crypto.c @@ -0,0 +1,602 @@ +/* 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 <ctype.h> +#include <stdio.h> + +#include "apu.h" +#include "apr_private.h" +#include "apr_pools.h" +#include "apr_dso.h" +#include "apr_strings.h" +#include "apr_hash.h" +#include "apr_thread_mutex.h" +#include "apr_lib.h" + +#if APU_HAVE_CRYPTO + +#include "apu_internal.h" +#include "apr_crypto_internal.h" +#include "apr_crypto.h" +#include "apr_version.h" + +static apr_hash_t *drivers = NULL; + +#define ERROR_SIZE 1024 + +#define CLEANUP_CAST (apr_status_t (*)(void*)) + +APR_TYPEDEF_STRUCT(apr_crypto_t, + apr_pool_t *pool; + apr_crypto_driver_t *provider; +) + +APR_TYPEDEF_STRUCT(apr_crypto_key_t, + apr_pool_t *pool; + apr_crypto_driver_t *provider; + const apr_crypto_t *f; +) + +APR_TYPEDEF_STRUCT(apr_crypto_block_t, + apr_pool_t *pool; + apr_crypto_driver_t *provider; + const apr_crypto_t *f; +) + +typedef struct apr_crypto_clear_t { + void *buffer; + apr_size_t size; +} apr_crypto_clear_t; + +#if !APR_HAVE_MODULAR_DSO +#define DRIVER_LOAD(name,driver_name,pool,params,rv,result) \ + { \ + extern const apr_crypto_driver_t driver_name; \ + apr_hash_set(drivers,name,APR_HASH_KEY_STRING,&driver_name); \ + if (driver_name.init) { \ + rv = driver_name.init(pool, params, result); \ + } \ + *driver = &driver_name; \ + } +#endif + +static apr_status_t apr_crypto_term(void *ptr) +{ + /* set drivers to NULL so init can work again */ + drivers = NULL; + + /* Everything else we need is handled by cleanups registered + * when we created mutexes and loaded DSOs + */ + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_crypto_init(apr_pool_t *pool) +{ + apr_status_t ret = APR_SUCCESS; + apr_pool_t *parent; + + if (drivers != NULL) { + return APR_SUCCESS; + } + + /* Top level pool scope, need process-scope lifetime */ + for (parent = apr_pool_parent_get(pool); + parent && parent != pool; + parent = apr_pool_parent_get(pool)) + pool = parent; +#if APR_HAVE_MODULAR_DSO + /* deprecate in 2.0 - permit implicit initialization */ + apu_dso_init(pool); +#endif + drivers = apr_hash_make(pool); + + apr_pool_cleanup_register(pool, NULL, apr_crypto_term, + apr_pool_cleanup_null); + + return ret; +} + +static apr_status_t crypto_clear(void *ptr) +{ + apr_crypto_clear_t *clear = (apr_crypto_clear_t *)ptr; + + apr_crypto_memzero(clear->buffer, clear->size); + clear->buffer = NULL; + clear->size = 0; + + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_crypto_clear(apr_pool_t *pool, + void *buffer, apr_size_t size) +{ + apr_crypto_clear_t *clear = apr_palloc(pool, sizeof(apr_crypto_clear_t)); + + clear->buffer = buffer; + clear->size = size; + + apr_pool_cleanup_register(pool, clear, crypto_clear, + apr_pool_cleanup_null); + + return APR_SUCCESS; +} + +#if defined(HAVE_WEAK_SYMBOLS) +void apr__memzero_explicit(void *buffer, apr_size_t size); + +__attribute__ ((weak)) +void apr__memzero_explicit(void *buffer, apr_size_t size) +{ + memset(buffer, 0, size); +} +#endif + +APR_DECLARE(apr_status_t) apr_crypto_memzero(void *buffer, apr_size_t size) +{ +#if defined(WIN32) + SecureZeroMemory(buffer, size); +#elif defined(HAVE_MEMSET_S) + if (size) { + return memset_s(buffer, (rsize_t)size, 0, (rsize_t)size); + } +#elif defined(HAVE_EXPLICIT_BZERO) + explicit_bzero(buffer, size); +#elif defined(HAVE_WEAK_SYMBOLS) + apr__memzero_explicit(buffer, size); +#else + apr_size_t i; + volatile unsigned char *volatile ptr = buffer; + for (i = 0; i < size; ++i) { + ptr[i] = 0; + } +#endif + return APR_SUCCESS; +} + +APR_DECLARE(int) apr_crypto_equals(const void *buf1, const void *buf2, + apr_size_t size) +{ + const unsigned char *p1 = buf1; + const unsigned char *p2 = buf2; + unsigned char diff = 0; + apr_size_t i; + + for (i = 0; i < size; ++i) { + diff |= p1[i] ^ p2[i]; + } + + return 1 & ((diff - 1) >> 8); +} + +APR_DECLARE(apr_status_t) apr_crypto_get_driver( + const apr_crypto_driver_t **driver, const char *name, + const char *params, const apu_err_t **result, apr_pool_t *pool) +{ +#if APR_HAVE_MODULAR_DSO + char modname[32]; + char symname[34]; + apr_dso_handle_t *dso; + apr_dso_handle_sym_t symbol; +#endif + apr_status_t rv; + + if (result) { + *result = NULL; /* until further notice */ + } + +#if APR_HAVE_MODULAR_DSO + rv = apu_dso_mutex_lock(); + if (rv) { + return rv; + } +#endif + *driver = apr_hash_get(drivers, name, APR_HASH_KEY_STRING); + if (*driver) { +#if APR_HAVE_MODULAR_DSO + apu_dso_mutex_unlock(); +#endif + return APR_SUCCESS; + } + +#if APR_HAVE_MODULAR_DSO + /* The driver DSO must have exactly the same lifetime as the + * drivers hash table; ignore the passed-in pool */ + pool = apr_hash_pool_get(drivers); + +#if defined(NETWARE) + apr_snprintf(modname, sizeof(modname), "crypto%s.nlm", name); +#elif defined(WIN32) || defined(__CYGWIN__) + apr_snprintf(modname, sizeof(modname), + "apr_crypto_%s-" APR_STRINGIFY(APR_MAJOR_VERSION) ".dll", name); +#else + apr_snprintf(modname, sizeof(modname), + "apr_crypto_%s-" APR_STRINGIFY(APR_MAJOR_VERSION) ".so", name); +#endif + apr_snprintf(symname, sizeof(symname), "apr_crypto_%s_driver", name); + rv = apu_dso_load(&dso, &symbol, modname, symname, pool); + if (rv == APR_SUCCESS || rv == APR_EINIT) { /* previously loaded?!? */ + apr_crypto_driver_t *d = symbol; + rv = APR_SUCCESS; + if (d->init) { + rv = d->init(pool, params, result); + } + if (APR_SUCCESS == rv) { + *driver = symbol; + name = apr_pstrdup(pool, name); + apr_hash_set(drivers, name, APR_HASH_KEY_STRING, *driver); + } + } + apu_dso_mutex_unlock(); + + if (APR_SUCCESS != rv && result && !*result) { + char *buffer = apr_pcalloc(pool, ERROR_SIZE); + apu_err_t *err = apr_pcalloc(pool, sizeof(apu_err_t)); + if (err && buffer) { + apr_dso_error(dso, buffer, ERROR_SIZE - 1); + err->msg = buffer; + err->reason = apr_pstrdup(pool, modname); + *result = err; + } + } + +#else /* not builtin and !APR_HAS_DSO => not implemented */ + rv = APR_ENOTIMPL; + + /* Load statically-linked drivers: */ +#if APU_HAVE_OPENSSL + if (name[0] == 'o' && !strcmp(name, "openssl")) { + DRIVER_LOAD("openssl", apr_crypto_openssl_driver, pool, params, rv, result); + } +#endif +#if APU_HAVE_NSS + if (name[0] == 'n' && !strcmp(name, "nss")) { + DRIVER_LOAD("nss", apr_crypto_nss_driver, pool, params, rv, result); + } +#endif +#if APU_HAVE_COMMONCRYPTO + if (name[0] == 'c' && !strcmp(name, "commoncrypto")) { + DRIVER_LOAD("commoncrypto", apr_crypto_commoncrypto_driver, pool, params, rv, result); + } +#endif +#if APU_HAVE_MSCAPI + if (name[0] == 'm' && !strcmp(name, "mscapi")) { + DRIVER_LOAD("mscapi", apr_crypto_mscapi_driver, pool, params, rv, result); + } +#endif +#if APU_HAVE_MSCNG + if (name[0] == 'm' && !strcmp(name, "mscng")) { + DRIVER_LOAD("mscng", apr_crypto_mscng_driver, pool, params, rv, result); + } +#endif + +#endif + + return rv; +} + +/** + * @brief Return the name of the driver. + * + * @param driver - The driver in use. + * @return The name of the driver. + */ +APR_DECLARE(const char *)apr_crypto_driver_name( + const apr_crypto_driver_t *driver) +{ + return driver->name; +} + +/** + * @brief Get the result of the last operation on a context. If the result + * is NULL, the operation was successful. + * @param result - the result structure + * @param f - context pointer + * @return APR_SUCCESS for success + */ +APR_DECLARE(apr_status_t) apr_crypto_error(const apu_err_t **result, + const apr_crypto_t *f) +{ + return f->provider->error(result, f); +} + +/** + * @brief Create a context for supporting encryption. Keys, certificates, + * algorithms and other parameters will be set per context. More than + * one context can be created at one time. A cleanup will be automatically + * registered with the given pool to guarantee a graceful shutdown. + * @param f - context pointer will be written here + * @param driver - driver to use + * @param params - array of key parameters + * @param pool - process pool + * @return APR_ENOENGINE when the engine specified does not exist. APR_EINITENGINE + * if the engine cannot be initialised. + * @remarks NSS: currently no params are supported. + * @remarks OpenSSL: the params can have "engine" as a key, followed by an equal + * sign and a value. + */ +APR_DECLARE(apr_status_t) apr_crypto_make(apr_crypto_t **f, + const apr_crypto_driver_t *driver, const char *params, apr_pool_t *pool) +{ + return driver->make(f, driver, params, pool); +} + +/** + * @brief Get a hash table of key types, keyed by the name of the type against + * a pointer to apr_crypto_block_key_type_t, which in turn begins with an + * integer. + * + * @param types - hashtable of key types keyed to constants. + * @param f - encryption context + * @return APR_SUCCESS for success + */ +APR_DECLARE(apr_status_t) apr_crypto_get_block_key_types(apr_hash_t **types, + const apr_crypto_t *f) +{ + return f->provider->get_block_key_types(types, f); +} + +/** + * @brief Get a hash table of key modes, keyed by the name of the mode against + * a pointer to apr_crypto_block_key_mode_t, which in turn begins with an + * integer. + * + * @param modes - hashtable of key modes keyed to constants. + * @param f - encryption context + * @return APR_SUCCESS for success + */ +APR_DECLARE(apr_status_t) apr_crypto_get_block_key_modes(apr_hash_t **modes, + const apr_crypto_t *f) +{ + return f->provider->get_block_key_modes(modes, f); +} + +/** + * @brief Create a key from the provided secret or passphrase. The key is cleaned + * up when the context is cleaned, and may be reused with multiple encryption + * or decryption operations. + * @note If *key is NULL, a apr_crypto_key_t will be created from a pool. If + * *key is not NULL, *key must point at a previously created structure. + * @param key The key returned, see note. + * @param rec The key record, from which the key will be derived. + * @param f The context to use. + * @param p The pool to use. + * @return Returns APR_ENOKEY if the pass phrase is missing or empty, or if a backend + * error occurred while generating the key. APR_ENOCIPHER if the type or mode + * is not supported by the particular backend. APR_EKEYTYPE if the key type is + * not known. APR_EPADDING if padding was requested but is not supported. + * APR_ENOTIMPL if not implemented. + */ +APR_DECLARE(apr_status_t) apr_crypto_key(apr_crypto_key_t **key, + const apr_crypto_key_rec_t *rec, const apr_crypto_t *f, apr_pool_t *p) +{ + return f->provider->key(key, rec, f, p); +} + +/** + * @brief Create a key from the given passphrase. By default, the PBKDF2 + * algorithm is used to generate the key from the passphrase. It is expected + * that the same pass phrase will generate the same key, regardless of the + * backend crypto platform used. The key is cleaned up when the context + * is cleaned, and may be reused with multiple encryption or decryption + * operations. + * @note If *key is NULL, a apr_crypto_key_t will be created from a pool. If + * *key is not NULL, *key must point at a previously created structure. + * @param key The key returned, see note. + * @param ivSize The size of the initialisation vector will be returned, based + * on whether an IV is relevant for this type of crypto. + * @param pass The passphrase to use. + * @param passLen The passphrase length in bytes + * @param salt The salt to use. + * @param saltLen The salt length in bytes + * @param type 3DES_192, AES_128, AES_192, AES_256. + * @param mode Electronic Code Book / Cipher Block Chaining. + * @param doPad Pad if necessary. + * @param iterations Number of iterations to use in algorithm + * @param f The context to use. + * @param p The pool to use. + * @return Returns APR_ENOKEY if the pass phrase is missing or empty, or if a backend + * error occurred while generating the key. APR_ENOCIPHER if the type or mode + * is not supported by the particular backend. APR_EKEYTYPE if the key type is + * not known. APR_EPADDING if padding was requested but is not supported. + * APR_ENOTIMPL if not implemented. + */ +APR_DECLARE(apr_status_t) apr_crypto_passphrase(apr_crypto_key_t **key, + apr_size_t *ivSize, const char *pass, apr_size_t passLen, + const unsigned char * salt, apr_size_t saltLen, + const apr_crypto_block_key_type_e type, + const apr_crypto_block_key_mode_e mode, const int doPad, + const int iterations, const apr_crypto_t *f, apr_pool_t *p) +{ + return f->provider->passphrase(key, ivSize, pass, passLen, salt, saltLen, + type, mode, doPad, iterations, f, p); +} + +/** + * @brief Initialise a context for encrypting arbitrary data using the given key. + * @note If *ctx is NULL, a apr_crypto_block_t will be created from a pool. If + * *ctx is not NULL, *ctx must point at a previously created structure. + * @param ctx The block context returned, see note. + * @param iv Optional initialisation vector. If the buffer pointed to is NULL, + * an IV will be created at random, in space allocated from the pool. + * If the buffer pointed to is not NULL, the IV in the buffer will be + * used. + * @param key The key structure to use. + * @param blockSize The block size of the cipher. + * @param p The pool to use. + * @return Returns APR_ENOIV if an initialisation vector is required but not specified. + * Returns APR_EINIT if the backend failed to initialise the context. Returns + * APR_ENOTIMPL if not implemented. + */ +APR_DECLARE(apr_status_t) apr_crypto_block_encrypt_init( + apr_crypto_block_t **ctx, const unsigned char **iv, + const apr_crypto_key_t *key, apr_size_t *blockSize, apr_pool_t *p) +{ + return key->provider->block_encrypt_init(ctx, iv, key, blockSize, p); +} + +/** + * @brief Encrypt data provided by in, write it to out. + * @note The number of bytes written will be written to outlen. If + * out is NULL, outlen will contain the maximum size of the + * buffer needed to hold the data, including any data + * generated by apr_crypto_block_encrypt_finish below. If *out points + * to NULL, a buffer sufficiently large will be created from + * the pool provided. If *out points to a not-NULL value, this + * value will be used as a buffer instead. + * @param out Address of a buffer to which data will be written, + * see note. + * @param outlen Length of the output will be written here. + * @param in Address of the buffer to read. + * @param inlen Length of the buffer to read. + * @param ctx The block context to use. + * @return APR_ECRYPT if an error occurred. Returns APR_ENOTIMPL if + * not implemented. + */ +APR_DECLARE(apr_status_t) apr_crypto_block_encrypt(unsigned char **out, + apr_size_t *outlen, const unsigned char *in, apr_size_t inlen, + apr_crypto_block_t *ctx) +{ + return ctx->provider->block_encrypt(out, outlen, in, inlen, ctx); +} + +/** + * @brief Encrypt final data block, write it to out. + * @note If necessary the final block will be written out after being + * padded. Typically the final block will be written to the + * same buffer used by apr_crypto_block_encrypt, offset by the + * number of bytes returned as actually written by the + * apr_crypto_block_encrypt() call. After this call, the context + * is cleaned and can be reused by apr_crypto_block_encrypt_init(). + * @param out Address of a buffer to which data will be written. This + * buffer must already exist, and is usually the same + * buffer used by apr_evp_crypt(). See note. + * @param outlen Length of the output will be written here. + * @param ctx The block context to use. + * @return APR_ECRYPT if an error occurred. + * @return APR_EPADDING if padding was enabled and the block was incorrectly + * formatted. + * @return APR_ENOTIMPL if not implemented. + */ +APR_DECLARE(apr_status_t) apr_crypto_block_encrypt_finish(unsigned char *out, + apr_size_t *outlen, apr_crypto_block_t *ctx) +{ + return ctx->provider->block_encrypt_finish(out, outlen, ctx); +} + +/** + * @brief Initialise a context for decrypting arbitrary data using the given key. + * @note If *ctx is NULL, a apr_crypto_block_t will be created from a pool. If + * *ctx is not NULL, *ctx must point at a previously created structure. + * @param ctx The block context returned, see note. + * @param blockSize The block size of the cipher. + * @param iv Optional initialisation vector. + * @param key The key structure to use. + * @param p The pool to use. + * @return Returns APR_ENOIV if an initialisation vector is required but not specified. + * Returns APR_EINIT if the backend failed to initialise the context. Returns + * APR_ENOTIMPL if not implemented. + */ +APR_DECLARE(apr_status_t) apr_crypto_block_decrypt_init( + apr_crypto_block_t **ctx, apr_size_t *blockSize, + const unsigned char *iv, const apr_crypto_key_t *key, apr_pool_t *p) +{ + return key->provider->block_decrypt_init(ctx, blockSize, iv, key, p); +} + +/** + * @brief Decrypt data provided by in, write it to out. + * @note The number of bytes written will be written to outlen. If + * out is NULL, outlen will contain the maximum size of the + * buffer needed to hold the data, including any data + * generated by apr_crypto_block_decrypt_finish below. If *out points + * to NULL, a buffer sufficiently large will be created from + * the pool provided. If *out points to a not-NULL value, this + * value will be used as a buffer instead. + * @param out Address of a buffer to which data will be written, + * see note. + * @param outlen Length of the output will be written here. + * @param in Address of the buffer to read. + * @param inlen Length of the buffer to read. + * @param ctx The block context to use. + * @return APR_ECRYPT if an error occurred. Returns APR_ENOTIMPL if + * not implemented. + */ +APR_DECLARE(apr_status_t) apr_crypto_block_decrypt(unsigned char **out, + apr_size_t *outlen, const unsigned char *in, apr_size_t inlen, + apr_crypto_block_t *ctx) +{ + return ctx->provider->block_decrypt(out, outlen, in, inlen, ctx); +} + +/** + * @brief Decrypt final data block, write it to out. + * @note If necessary the final block will be written out after being + * padded. Typically the final block will be written to the + * same buffer used by apr_crypto_block_decrypt, offset by the + * number of bytes returned as actually written by the + * apr_crypto_block_decrypt() call. After this call, the context + * is cleaned and can be reused by apr_crypto_block_decrypt_init(). + * @param out Address of a buffer to which data will be written. This + * buffer must already exist, and is usually the same + * buffer used by apr_evp_crypt(). See note. + * @param outlen Length of the output will be written here. + * @param ctx The block context to use. + * @return APR_ECRYPT if an error occurred. + * @return APR_EPADDING if padding was enabled and the block was incorrectly + * formatted. + * @return APR_ENOTIMPL if not implemented. + */ +APR_DECLARE(apr_status_t) apr_crypto_block_decrypt_finish(unsigned char *out, + apr_size_t *outlen, apr_crypto_block_t *ctx) +{ + return ctx->provider->block_decrypt_finish(out, outlen, ctx); +} + +/** + * @brief Clean encryption / decryption context. + * @note After cleanup, a context is free to be reused if necessary. + * @param ctx The block context to use. + * @return Returns APR_ENOTIMPL if not supported. + */ +APR_DECLARE(apr_status_t) apr_crypto_block_cleanup(apr_crypto_block_t *ctx) +{ + return ctx->provider->block_cleanup(ctx); +} + +/** + * @brief Clean encryption / decryption context. + * @note After cleanup, a context is free to be reused if necessary. + * @param f The context to use. + * @return Returns APR_ENOTIMPL if not supported. + */ +APR_DECLARE(apr_status_t) apr_crypto_cleanup(apr_crypto_t *f) +{ + return f->provider->cleanup(f); +} + +/** + * @brief Shutdown the crypto library. + * @note After shutdown, it is expected that the init function can be called again. + * @param driver - driver to use + * @return Returns APR_ENOTIMPL if not supported. + */ +APR_DECLARE(apr_status_t) apr_crypto_shutdown(const apr_crypto_driver_t *driver) +{ + return driver->shutdown(); +} + +#endif /* APU_HAVE_CRYPTO */ diff --git a/crypto/apr_crypto_commoncrypto.c b/crypto/apr_crypto_commoncrypto.c new file mode 100644 index 00000000000..9138933067f --- /dev/null +++ b/crypto/apr_crypto_commoncrypto.c @@ -0,0 +1,906 @@ +/* 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_lib.h" +#include "apu.h" +#include "apr_private.h" +#include "apu_errno.h" + +#include <ctype.h> +#include <assert.h> +#include <stdlib.h> + +#include "apr_strings.h" +#include "apr_time.h" +#include "apr_buckets.h" +#include "apr_random.h" + +#include "apr_crypto_internal.h" + +#if APU_HAVE_CRYPTO + +#include <CommonCrypto/CommonCrypto.h> + +#define LOG_PREFIX "apr_crypto_commoncrypto: " + +struct apr_crypto_t +{ + apr_pool_t *pool; + const apr_crypto_driver_t *provider; + apu_err_t *result; + apr_hash_t *types; + apr_hash_t *modes; + apr_random_t *rng; +}; + +struct apr_crypto_key_t +{ + apr_pool_t *pool; + const apr_crypto_driver_t *provider; + const apr_crypto_t *f; + CCAlgorithm algorithm; + CCOptions options; + unsigned char *key; + int keyLen; + int ivSize; + apr_size_t blockSize; +}; + +struct apr_crypto_block_t +{ + apr_pool_t *pool; + const apr_crypto_driver_t *provider; + const apr_crypto_t *f; + const apr_crypto_key_t *key; + CCCryptorRef ref; +}; + +static struct apr_crypto_block_key_type_t key_types[] = +{ +{ APR_KEY_3DES_192, 24, 8, 8 }, +{ APR_KEY_AES_128, 16, 16, 16 }, +{ APR_KEY_AES_192, 24, 16, 16 }, +{ APR_KEY_AES_256, 32, 16, 16 } }; + +static struct apr_crypto_block_key_mode_t key_modes[] = +{ +{ APR_MODE_ECB }, +{ APR_MODE_CBC } }; + +/** + * Fetch the most recent error from this driver. + */ +static apr_status_t crypto_error(const apu_err_t **result, + const apr_crypto_t *f) +{ + *result = f->result; + return APR_SUCCESS; +} + +/** + * Shutdown the crypto library and release resources. + */ +static apr_status_t crypto_shutdown(void) +{ + return APR_SUCCESS; +} + +static apr_status_t crypto_shutdown_helper(void *data) +{ + return crypto_shutdown(); +} + +/** + * Initialise the crypto library and perform one time initialisation. + */ +static apr_status_t crypto_init(apr_pool_t *pool, const char *params, + const apu_err_t **result) +{ + + apr_pool_cleanup_register(pool, pool, crypto_shutdown_helper, + apr_pool_cleanup_null); + + return APR_SUCCESS; +} + +/** + * @brief Clean encryption / decryption context. + * @note After cleanup, a context is free to be reused if necessary. + * @param ctx The block context to use. + * @return Returns APR_ENOTIMPL if not supported. + */ +static apr_status_t crypto_block_cleanup(apr_crypto_block_t *ctx) +{ + + if (ctx->ref) { + CCCryptorRelease(ctx->ref); + ctx->ref = NULL; + } + + return APR_SUCCESS; + +} + +static apr_status_t crypto_block_cleanup_helper(void *data) +{ + apr_crypto_block_t *block = (apr_crypto_block_t *) data; + return crypto_block_cleanup(block); +} + +/** + * @brief Clean encryption / decryption context. + * @note After cleanup, a context is free to be reused if necessary. + * @param f The context to use. + * @return Returns APR_ENOTIMPL if not supported. + */ +static apr_status_t crypto_cleanup(apr_crypto_t *f) +{ + + return APR_SUCCESS; + +} + +static apr_status_t crypto_cleanup_helper(void *data) +{ + apr_crypto_t *f = (apr_crypto_t *) data; + return crypto_cleanup(f); +} + +/** + * @brief Create a context for supporting encryption. Keys, certificates, + * algorithms and other parameters will be set per context. More than + * one context can be created at one time. A cleanup will be automatically + * registered with the given pool to guarantee a graceful shutdown. + * @param f - context pointer will be written here + * @param provider - provider to use + * @param params - array of key parameters + * @param pool - process pool + * @return APR_ENOENGINE when the engine specified does not exist. APR_EINITENGINE + * if the engine cannot be initialised. + */ +static apr_status_t crypto_make(apr_crypto_t **ff, + const apr_crypto_driver_t *provider, const char *params, + apr_pool_t *pool) +{ + apr_crypto_t *f = apr_pcalloc(pool, sizeof(apr_crypto_t)); + apr_status_t rv; + + if (!f) { + return APR_ENOMEM; + } + *ff = f; + f->pool = pool; + f->provider = provider; + + /* seed the secure random number generator */ + f->rng = apr_random_standard_new(pool); + if (!f->rng) { + return APR_ENOMEM; + } + do { + unsigned char seed[8]; + rv = apr_generate_random_bytes(seed, sizeof(seed)); + if (rv != APR_SUCCESS) { + return rv; + } + apr_random_add_entropy(f->rng, seed, sizeof(seed)); + rv = apr_random_secure_ready(f->rng); + } while (rv == APR_ENOTENOUGHENTROPY); + + f->result = apr_pcalloc(pool, sizeof(apu_err_t)); + if (!f->result) { + return APR_ENOMEM; + } + + f->types = apr_hash_make(pool); + if (!f->types) { + return APR_ENOMEM; + } + apr_hash_set(f->types, "3des192", APR_HASH_KEY_STRING, &(key_types[0])); + apr_hash_set(f->types, "aes128", APR_HASH_KEY_STRING, &(key_types[1])); + apr_hash_set(f->types, "aes192", APR_HASH_KEY_STRING, &(key_types[2])); + apr_hash_set(f->types, "aes256", APR_HASH_KEY_STRING, &(key_types[3])); + + f->modes = apr_hash_make(pool); + if (!f->modes) { + return APR_ENOMEM; + } + apr_hash_set(f->modes, "ecb", APR_HASH_KEY_STRING, &(key_modes[0])); + apr_hash_set(f->modes, "cbc", APR_HASH_KEY_STRING, &(key_modes[1])); + + apr_pool_cleanup_register(pool, f, crypto_cleanup_helper, + apr_pool_cleanup_null); + + return APR_SUCCESS; + +} + +/** + * @brief Get a hash table of key types, keyed by the name of the type against + * a pointer to apr_crypto_block_key_type_t. + * + * @param types - hashtable of key types keyed to constants. + * @param f - encryption context + * @return APR_SUCCESS for success + */ +static apr_status_t crypto_get_block_key_types(apr_hash_t **types, + const apr_crypto_t *f) +{ + *types = f->types; + return APR_SUCCESS; +} + +/** + * @brief Get a hash table of key modes, keyed by the name of the mode against + * a pointer to apr_crypto_block_key_mode_t. + * + * @param modes - hashtable of key modes keyed to constants. + * @param f - encryption context + * @return APR_SUCCESS for success + */ +static apr_status_t crypto_get_block_key_modes(apr_hash_t **modes, + const apr_crypto_t *f) +{ + *modes = f->modes; + return APR_SUCCESS; +} + +/* + * Work out which mechanism to use. + */ +static apr_status_t crypto_cipher_mechanism(apr_crypto_key_t *key, + const apr_crypto_block_key_type_e type, + const apr_crypto_block_key_mode_e mode, const int doPad, apr_pool_t *p) +{ + /* handle padding */ + key->options = doPad ? kCCOptionPKCS7Padding : 0; + + /* determine the algorithm to be used */ + switch (type) { + + case (APR_KEY_3DES_192): + + /* A 3DES key */ + if (mode == APR_MODE_CBC) { + key->algorithm = kCCAlgorithm3DES; + key->keyLen = kCCKeySize3DES; + key->ivSize = kCCBlockSize3DES; + key->blockSize = kCCBlockSize3DES; + } + else { + key->algorithm = kCCAlgorithm3DES; + key->options += kCCOptionECBMode; + key->keyLen = kCCKeySize3DES; + key->ivSize = 0; + key->blockSize = kCCBlockSize3DES; + } + break; + + case (APR_KEY_AES_128): + + if (mode == APR_MODE_CBC) { + key->algorithm = kCCAlgorithmAES128; + key->keyLen = kCCKeySizeAES128; + key->ivSize = kCCBlockSizeAES128; + key->blockSize = kCCBlockSizeAES128; + } + else { + key->algorithm = kCCAlgorithmAES128; + key->options += kCCOptionECBMode; + key->keyLen = kCCKeySizeAES128; + key->ivSize = 0; + key->blockSize = kCCBlockSizeAES128; + } + break; + + case (APR_KEY_AES_192): + + if (mode == APR_MODE_CBC) { + key->algorithm = kCCAlgorithmAES128; + key->keyLen = kCCKeySizeAES192; + key->ivSize = kCCBlockSizeAES128; + key->blockSize = kCCBlockSizeAES128; + } + else { + key->algorithm = kCCAlgorithmAES128; + key->options += kCCOptionECBMode; + key->keyLen = kCCKeySizeAES192; + key->ivSize = 0; + key->blockSize = kCCBlockSizeAES128; + } + break; + + case (APR_KEY_AES_256): + + if (mode == APR_MODE_CBC) { + key->algorithm = kCCAlgorithmAES128; + key->keyLen = kCCKeySizeAES256; + key->ivSize = kCCBlockSizeAES128; + key->blockSize = kCCBlockSizeAES128; + } + else { + key->algorithm = kCCAlgorithmAES128; + key->options += kCCOptionECBMode; + key->keyLen = kCCKeySizeAES256; + key->ivSize = 0; + key->blockSize = kCCBlockSizeAES128; + } + break; + + default: + + /* TODO: Support CAST, Blowfish */ + + /* unknown key type, give up */ + return APR_EKEYTYPE; + + } + + /* make space for the key */ + key->key = apr_palloc(p, key->keyLen); + if (!key->key) { + return APR_ENOMEM; + } + apr_crypto_clear(p, key->key, key->keyLen); + + return APR_SUCCESS; +} + +/** + * @brief Create a key from the provided secret or passphrase. The key is cleaned + * up when the context is cleaned, and may be reused with multiple encryption + * or decryption operations. + * @note If *key is NULL, a apr_crypto_key_t will be created from a pool. If + * *key is not NULL, *key must point at a previously created structure. + * @param key The key returned, see note. + * @param rec The key record, from which the key will be derived. + * @param f The context to use. + * @param p The pool to use. + * @return Returns APR_ENOKEY if the pass phrase is missing or empty, or if a backend + * error occurred while generating the key. APR_ENOCIPHER if the type or mode + * is not supported by the particular backend. APR_EKEYTYPE if the key type is + * not known. APR_EPADDING if padding was requested but is not supported. + * APR_ENOTIMPL if not implemented. + */ +static apr_status_t crypto_key(apr_crypto_key_t **k, + const apr_crypto_key_rec_t *rec, const apr_crypto_t *f, apr_pool_t *p) +{ + apr_status_t rv; + apr_crypto_key_t *key = *k; + + if (!key) { + *k = key = apr_pcalloc(p, sizeof *key); + } + if (!key) { + return APR_ENOMEM; + } + + key->f = f; + key->provider = f->provider; + + /* decide on what cipher mechanism we will be using */ + rv = crypto_cipher_mechanism(key, rec->type, rec->mode, rec->pad, p); + if (APR_SUCCESS != rv) { + return rv; + } + + switch (rec->ktype) { + + case APR_CRYPTO_KTYPE_PASSPHRASE: { + + /* generate the key */ + if ((f->result->rc = CCKeyDerivationPBKDF(kCCPBKDF2, + rec->k.passphrase.pass, rec->k.passphrase.passLen, + rec->k.passphrase.salt, rec->k.passphrase.saltLen, + kCCPRFHmacAlgSHA1, rec->k.passphrase.iterations, key->key, + key->keyLen)) == kCCParamError) { + return APR_ENOKEY; + } + + break; + } + + case APR_CRYPTO_KTYPE_SECRET: { + + /* sanity check - key correct size? */ + if (rec->k.secret.secretLen != key->keyLen) { + return APR_EKEYLENGTH; + } + + /* copy the key */ + memcpy(key->key, rec->k.secret.secret, rec->k.secret.secretLen); + + break; + } + + default: { + + return APR_ENOKEY; + + } + } + + return APR_SUCCESS; +} + +/** + * @brief Create a key from the given passphrase. By default, the PBKDF2 + * algorithm is used to generate the key from the passphrase. It is expected + * that the same pass phrase will generate the same key, regardless of the + * backend crypto platform used. The key is cleaned up when the context + * is cleaned, and may be reused with multiple encryption or decryption + * operations. + * @note If *key is NULL, a apr_crypto_key_t will be created from a pool. If + * *key is not NULL, *key must point at a previously created structure. + * @param key The key returned, see note. + * @param ivSize The size of the initialisation vector will be returned, based + * on whether an IV is relevant for this type of crypto. + * @param pass The passphrase to use. + * @param passLen The passphrase length in bytes + * @param salt The salt to use. + * @param saltLen The salt length in bytes + * @param type 3DES_192, AES_128, AES_192, AES_256. + * @param mode Electronic Code Book / Cipher Block Chaining. + * @param doPad Pad if necessary. + * @param iterations Iteration count + * @param f The context to use. + * @param p The pool to use. + * @return Returns APR_ENOKEY if the pass phrase is missing or empty, or if a backend + * error occurred while generating the key. APR_ENOCIPHER if the type or mode + * is not supported by the particular backend. APR_EKEYTYPE if the key type is + * not known. APR_EPADDING if padding was requested but is not supported. + * APR_ENOTIMPL if not implemented. + */ +static apr_status_t crypto_passphrase(apr_crypto_key_t **k, apr_size_t *ivSize, + const char *pass, apr_size_t passLen, const unsigned char * salt, + apr_size_t saltLen, const apr_crypto_block_key_type_e type, + const apr_crypto_block_key_mode_e mode, const int doPad, + const int iterations, const apr_crypto_t *f, apr_pool_t *p) +{ + apr_status_t rv; + apr_crypto_key_t *key = *k; + + if (!key) { + *k = key = apr_pcalloc(p, sizeof *key); + if (!key) { + return APR_ENOMEM; + } + } + + key->f = f; + key->provider = f->provider; + + /* decide on what cipher mechanism we will be using */ + rv = crypto_cipher_mechanism(key, type, mode, doPad, p); + if (APR_SUCCESS != rv) { + return rv; + } + + /* generate the key */ + if ((f->result->rc = CCKeyDerivationPBKDF(kCCPBKDF2, pass, passLen, salt, + saltLen, kCCPRFHmacAlgSHA1, iterations, key->key, key->keyLen)) + == kCCParamError) { + return APR_ENOKEY; + } + + if (ivSize) { + *ivSize = key->ivSize; + } + + return APR_SUCCESS; +} + +/** + * @brief Initialise a context for encrypting arbitrary data using the given key. + * @note If *ctx is NULL, a apr_crypto_block_t will be created from a pool. If + * *ctx is not NULL, *ctx must point at a previously created structure. + * @param ctx The block context returned, see note. + * @param iv Optional initialisation vector. If the buffer pointed to is NULL, + * an IV will be created at random, in space allocated from the pool. + * If the buffer pointed to is not NULL, the IV in the buffer will be + * used. + * @param key The key structure. + * @param blockSize The block size of the cipher. + * @param p The pool to use. + * @return Returns APR_ENOIV if an initialisation vector is required but not specified. + * Returns APR_EINIT if the backend failed to initialise the context. Returns + * APR_ENOTIMPL if not implemented. + */ +static apr_status_t crypto_block_encrypt_init(apr_crypto_block_t **ctx, + const unsigned char **iv, const apr_crypto_key_t *key, + apr_size_t *blockSize, apr_pool_t *p) +{ + unsigned char *usedIv; + apr_crypto_block_t *block = *ctx; + if (!block) { + *ctx = block = apr_pcalloc(p, sizeof(apr_crypto_block_t)); + } + if (!block) { + return APR_ENOMEM; + } + block->f = key->f; + block->pool = p; + block->provider = key->provider; + block->key = key; + + apr_pool_cleanup_register(p, block, crypto_block_cleanup_helper, + apr_pool_cleanup_null); + + /* generate an IV, if necessary */ + usedIv = NULL; + if (key->ivSize) { + if (iv == NULL) { + return APR_ENOIV; + } + if (*iv == NULL) { + apr_status_t status; + usedIv = apr_pcalloc(p, key->ivSize); + if (!usedIv) { + return APR_ENOMEM; + } + apr_crypto_clear(p, usedIv, key->ivSize); + status = apr_random_secure_bytes(block->f->rng, usedIv, + key->ivSize); + if (APR_SUCCESS != status) { + return status; + } + *iv = usedIv; + } + else { + usedIv = (unsigned char *) *iv; + } + } + + /* create a new context for encryption */ + switch ((block->f->result->rc = CCCryptorCreate(kCCEncrypt, key->algorithm, + key->options, key->key, key->keyLen, usedIv, &block->ref))) { + case kCCSuccess: { + break; + } + case kCCParamError: { + return APR_EINIT; + } + case kCCMemoryFailure: { + return APR_ENOMEM; + } + case kCCAlignmentError: { + return APR_EPADDING; + } + case kCCUnimplemented: { + return APR_ENOTIMPL; + } + default: { + return APR_EINIT; + } + } + + if (blockSize) { + *blockSize = key->blockSize; + } + + return APR_SUCCESS; + +} + +/** + * @brief Encrypt data provided by in, write it to out. + * @note The number of bytes written will be written to outlen. If + * out is NULL, outlen will contain the maximum size of the + * buffer needed to hold the data, including any data + * generated by apr_crypto_block_encrypt_finish below. If *out points + * to NULL, a buffer sufficiently large will be created from + * the pool provided. If *out points to a not-NULL value, this + * value will be used as a buffer instead. + * @param out Address of a buffer to which data will be written, + * see note. + * @param outlen Length of the output will be written here. + * @param in Address of the buffer to read. + * @param inlen Length of the buffer to read. + * @param ctx The block context to use. + * @return APR_ECRYPT if an error occurred. Returns APR_ENOTIMPL if + * not implemented. + */ +static apr_status_t crypto_block_encrypt(unsigned char **out, + apr_size_t *outlen, const unsigned char *in, apr_size_t inlen, + apr_crypto_block_t *ctx) +{ + apr_size_t outl = *outlen; + unsigned char *buffer; + + /* are we after the maximum size of the out buffer? */ + if (!out) { + *outlen = CCCryptorGetOutputLength(ctx->ref, inlen, 1); + return APR_SUCCESS; + } + + /* must we allocate the output buffer from a pool? */ + if (!*out) { + outl = CCCryptorGetOutputLength(ctx->ref, inlen, 1); + buffer = apr_palloc(ctx->pool, outl); + if (!buffer) { + return APR_ENOMEM; + } + apr_crypto_clear(ctx->pool, buffer, outl); + *out = buffer; + } + + switch ((ctx->f->result->rc = CCCryptorUpdate(ctx->ref, in, inlen, (*out), + outl, &outl))) { + case kCCSuccess: { + break; + } + case kCCBufferTooSmall: { + return APR_ENOSPACE; + } + default: { + return APR_ECRYPT; + } + } + *outlen = outl; + + return APR_SUCCESS; + +} + +/** + * @brief Encrypt final data block, write it to out. + * @note If necessary the final block will be written out after being + * padded. Typically the final block will be written to the + * same buffer used by apr_crypto_block_encrypt, offset by the + * number of bytes returned as actually written by the + * apr_crypto_block_encrypt() call. After this call, the context + * is cleaned and can be reused by apr_crypto_block_encrypt_init(). + * @param out Address of a buffer to which data will be written. This + * buffer must already exist, and is usually the same + * buffer used by apr_evp_crypt(). See note. + * @param outlen Length of the output will be written here. + * @param ctx The block context to use. + * @return APR_ECRYPT if an error occurred. + * @return APR_EPADDING if padding was enabled and the block was incorrectly + * formatted. + * @return APR_ENOTIMPL if not implemented. + */ +static apr_status_t crypto_block_encrypt_finish(unsigned char *out, + apr_size_t *outlen, apr_crypto_block_t *ctx) +{ + apr_size_t len = *outlen; + + ctx->f->result->rc = CCCryptorFinal(ctx->ref, out, + CCCryptorGetOutputLength(ctx->ref, 0, 1), &len); + + /* always clean up */ + crypto_block_cleanup(ctx); + + switch (ctx->f->result->rc) { + case kCCSuccess: { + break; + } + case kCCBufferTooSmall: { + return APR_ENOSPACE; + } + case kCCAlignmentError: { + return APR_EPADDING; + } + case kCCDecodeError: { + return APR_ECRYPT; + } + default: { + return APR_ECRYPT; + } + } + *outlen = len; + + return APR_SUCCESS; + +} + +/** + * @brief Initialise a context for decrypting arbitrary data using the given key. + * @note If *ctx is NULL, a apr_crypto_block_t will be created from a pool. If + * *ctx is not NULL, *ctx must point at a previously created structure. + * @param ctx The block context returned, see note. + * @param blockSize The block size of the cipher. + * @param iv Optional initialisation vector. If the buffer pointed to is NULL, + * an IV will be created at random, in space allocated from the pool. + * If the buffer is not NULL, the IV in the buffer will be used. + * @param key The key structure. + * @param p The pool to use. + * @return Returns APR_ENOIV if an initialisation vector is required but not specified. + * Returns APR_EINIT if the backend failed to initialise the context. Returns + * APR_ENOTIMPL if not implemented. + */ +static apr_status_t crypto_block_decrypt_init(apr_crypto_block_t **ctx, + apr_size_t *blockSize, const unsigned char *iv, + const apr_crypto_key_t *key, apr_pool_t *p) +{ + apr_crypto_block_t *block = *ctx; + if (!block) { + *ctx = block = apr_pcalloc(p, sizeof(apr_crypto_block_t)); + } + if (!block) { + return APR_ENOMEM; + } + block->f = key->f; + block->pool = p; + block->provider = key->provider; + + apr_pool_cleanup_register(p, block, crypto_block_cleanup_helper, + apr_pool_cleanup_null); + + /* generate an IV, if necessary */ + if (key->ivSize) { + if (iv == NULL) { + return APR_ENOIV; + } + } + + /* create a new context for decryption */ + switch ((block->f->result->rc = CCCryptorCreate(kCCDecrypt, key->algorithm, + key->options, key->key, key->keyLen, iv, &block->ref))) { + case kCCSuccess: { + break; + } + case kCCParamError: { + return APR_EINIT; + } + case kCCMemoryFailure: { + return APR_ENOMEM; + } + case kCCAlignmentError: { + return APR_EPADDING; + } + case kCCUnimplemented: { + return APR_ENOTIMPL; + } + default: { + return APR_EINIT; + } + } + + if (blockSize) { + *blockSize = key->blockSize; + } + + return APR_SUCCESS; + +} + +/** + * @brief Decrypt data provided by in, write it to out. + * @note The number of bytes written will be written to outlen. If + * out is NULL, outlen will contain the maximum size of the + * buffer needed to hold the data, including any data + * generated by apr_crypto_block_decrypt_finish below. If *out points + * to NULL, a buffer sufficiently large will be created from + * the pool provided. If *out points to a not-NULL value, this + * value will be used as a buffer instead. + * @param out Address of a buffer to which data will be written, + * see note. + * @param outlen Length of the output will be written here. + * @param in Address of the buffer to read. + * @param inlen Length of the buffer to read. + * @param ctx The block context to use. + * @return APR_ECRYPT if an error occurred. Returns APR_ENOTIMPL if + * not implemented. + */ +static apr_status_t crypto_block_decrypt(unsigned char **out, + apr_size_t *outlen, const unsigned char *in, apr_size_t inlen, + apr_crypto_block_t *ctx) +{ + apr_size_t outl = *outlen; + unsigned char *buffer; + + /* are we after the maximum size of the out buffer? */ + if (!out) { + *outlen = CCCryptorGetOutputLength(ctx->ref, inlen, 1); + return APR_SUCCESS; + } + + /* must we allocate the output buffer from a pool? */ + if (!*out) { + outl = CCCryptorGetOutputLength(ctx->ref, inlen, 1); + buffer = apr_palloc(ctx->pool, outl); + if (!buffer) { + return APR_ENOMEM; + } + apr_crypto_clear(ctx->pool, buffer, outl); + *out = buffer; + } + + switch ((ctx->f->result->rc = CCCryptorUpdate(ctx->ref, in, inlen, (*out), + outl, &outl))) { + case kCCSuccess: { + break; + } + case kCCBufferTooSmall: { + return APR_ENOSPACE; + } + default: { + return APR_ECRYPT; + } + } + *outlen = outl; + + return APR_SUCCESS; + +} + +/** + * @brief Decrypt final data block, write it to out. + * @note If necessary the final block will be written out after being + * padded. Typically the final block will be written to the + * same buffer used by apr_crypto_block_decrypt, offset by the + * number of bytes returned as actually written by the + * apr_crypto_block_decrypt() call. After this call, the context + * is cleaned and can be reused by apr_crypto_block_decrypt_init(). + * @param out Address of a buffer to which data will be written. This + * buffer must already exist, and is usually the same + * buffer used by apr_evp_crypt(). See note. + * @param outlen Length of the output will be written here. + * @param ctx The block context to use. + * @return APR_ECRYPT if an error occurred. + * @return APR_EPADDING if padding was enabled and the block was incorrectly + * formatted. + * @return APR_ENOTIMPL if not implemented. + */ +static apr_status_t crypto_block_decrypt_finish(unsigned char *out, + apr_size_t *outlen, apr_crypto_block_t *ctx) +{ + apr_size_t len = *outlen; + + ctx->f->result->rc = CCCryptorFinal(ctx->ref, out, + CCCryptorGetOutputLength(ctx->ref, 0, 1), &len); + + /* always clean up */ + crypto_block_cleanup(ctx); + + switch (ctx->f->result->rc) { + case kCCSuccess: { + break; + } + case kCCBufferTooSmall: { + return APR_ENOSPACE; + } + case kCCAlignmentError: { + return APR_EPADDING; + } + case kCCDecodeError: { + return APR_ECRYPT; + } + default: { + return APR_ECRYPT; + } + } + *outlen = len; + + return APR_SUCCESS; + +} + +/** + * OSX Common Crypto module. + */ +APR_MODULE_DECLARE_DATA const apr_crypto_driver_t apr_crypto_commoncrypto_driver = +{ + "commoncrypto", crypto_init, crypto_make, crypto_get_block_key_types, + crypto_get_block_key_modes, crypto_passphrase, + crypto_block_encrypt_init, crypto_block_encrypt, + crypto_block_encrypt_finish, crypto_block_decrypt_init, + crypto_block_decrypt, crypto_block_decrypt_finish, crypto_block_cleanup, + crypto_cleanup, crypto_shutdown, crypto_error, crypto_key +}; + +#endif diff --git a/crypto/apr_crypto_nss.c b/crypto/apr_crypto_nss.c new file mode 100644 index 00000000000..1c3bb2c6afa --- /dev/null +++ b/crypto/apr_crypto_nss.c @@ -0,0 +1,1097 @@ +/* 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_lib.h" +#include "apu.h" +#include "apr_private.h" +#include "apu_errno.h" + +#include <ctype.h> +#include <stdlib.h> + +#include "apr_strings.h" +#include "apr_time.h" +#include "apr_buckets.h" + +#include "apr_crypto_internal.h" + +#if APU_HAVE_CRYPTO + +#include <prerror.h> + +#ifdef HAVE_NSS_NSS_H +#include <nss/nss.h> +#endif +#ifdef HAVE_NSS_H +#include <nss.h> +#endif + +#ifdef HAVE_NSS_PK11PUB_H +#include <nss/pk11pub.h> +#endif +#ifdef HAVE_PK11PUB_H +#include <pk11pub.h> +#endif + +struct apr_crypto_t { + apr_pool_t *pool; + const apr_crypto_driver_t *provider; + apu_err_t *result; + apr_crypto_config_t *config; + apr_hash_t *types; + apr_hash_t *modes; +}; + +struct apr_crypto_config_t { + void *opaque; +}; + +struct apr_crypto_key_t { + apr_pool_t *pool; + const apr_crypto_driver_t *provider; + const apr_crypto_t *f; + CK_MECHANISM_TYPE cipherMech; + SECOidTag cipherOid; + PK11SymKey *symKey; + int ivSize; + int keyLength; +}; + +struct apr_crypto_block_t { + apr_pool_t *pool; + const apr_crypto_driver_t *provider; + const apr_crypto_t *f; + PK11Context *ctx; + apr_crypto_key_t *key; + SECItem *secParam; + int blockSize; +}; + +static struct apr_crypto_block_key_type_t key_types[] = +{ +{ APR_KEY_3DES_192, 24, 8, 8 }, +{ APR_KEY_AES_128, 16, 16, 16 }, +{ APR_KEY_AES_192, 24, 16, 16 }, +{ APR_KEY_AES_256, 32, 16, 16 } }; + +static struct apr_crypto_block_key_mode_t key_modes[] = +{ +{ APR_MODE_ECB }, +{ APR_MODE_CBC } }; + +/* sufficient space to wrap a key */ +#define BUFFER_SIZE 128 + +/** + * Fetch the most recent error from this driver. + */ +static apr_status_t crypto_error(const apu_err_t **result, + const apr_crypto_t *f) +{ + *result = f->result; + return APR_SUCCESS; +} + +/** + * Shutdown the crypto library and release resources. + * + * It is safe to shut down twice. + */ +static apr_status_t crypto_shutdown(void) +{ + if (NSS_IsInitialized()) { + SECStatus s = NSS_Shutdown(); + if (s != SECSuccess) { + fprintf(stderr, "NSS failed to shutdown, possible leak: %d: %s", + PR_GetError(), PR_ErrorToName(s)); + return APR_EINIT; + } + } + return APR_SUCCESS; +} + +static apr_status_t crypto_shutdown_helper(void *data) +{ + return crypto_shutdown(); +} + +/** + * Initialise the crypto library and perform one time initialisation. + */ +static apr_status_t crypto_init(apr_pool_t *pool, const char *params, + const apu_err_t **result) +{ + SECStatus s; + const char *dir = NULL; + const char *keyPrefix = NULL; + const char *certPrefix = NULL; + const char *secmod = NULL; + int noinit = 0; + PRUint32 flags = 0; + + struct { + const char *field; + const char *value; + int set; + } fields[] = { + { "dir", NULL, 0 }, + { "key3", NULL, 0 }, + { "cert7", NULL, 0 }, + { "secmod", NULL, 0 }, + { "noinit", NULL, 0 }, + { NULL, NULL, 0 } + }; + const char *ptr; + size_t klen; + char **elts = NULL; + char *elt; + int i = 0, j; + apr_status_t status; + + if (params) { + if (APR_SUCCESS != (status = apr_tokenize_to_argv(params, &elts, pool))) { + return status; + } + while ((elt = elts[i])) { + ptr = strchr(elt, '='); + if (ptr) { + for (klen = ptr - elt; klen && apr_isspace(elt[klen - 1]); --klen) + ; + ptr++; + } + else { + for (klen = strlen(elt); klen && apr_isspace(elt[klen - 1]); --klen) + ; + } + elt[klen] = 0; + + for (j = 0; fields[j].field != NULL; ++j) { + if (klen && !strcasecmp(fields[j].field, elt)) { + fields[j].set = 1; + if (ptr) { + fields[j].value = ptr; + } + break; + } + } + + i++; + } + dir = fields[0].value; + keyPrefix = fields[1].value; + certPrefix = fields[2].value; + secmod = fields[3].value; + noinit = fields[4].set; + } + + /* if we've been asked to bypass, do so here */ + if (noinit) { + return APR_SUCCESS; + } + + /* sanity check - we can only initialise NSS once */ + if (NSS_IsInitialized()) { + return APR_EREINIT; + } + + if (keyPrefix || certPrefix || secmod) { + s = NSS_Initialize(dir, certPrefix, keyPrefix, secmod, flags); + } + else if (dir) { + s = NSS_InitReadWrite(dir); + } + else { + s = NSS_NoDB_Init(NULL); + } + if (s != SECSuccess) { + if (result) { + /* Note: all memory must be owned by the caller, in case we're unloaded */ + apu_err_t *err = apr_pcalloc(pool, sizeof(apu_err_t)); + err->rc = PR_GetError(); + err->msg = apr_pstrdup(pool, PR_ErrorToName(s)); + err->reason = apr_pstrdup(pool, "Error during 'nss' initialisation"); + *result = err; + } + + return APR_ECRYPT; + } + + apr_pool_cleanup_register(pool, pool, crypto_shutdown_helper, + apr_pool_cleanup_null); + + return APR_SUCCESS; + +} + +/** + * @brief Clean encryption / decryption context. + * @note After cleanup, a context is free to be reused if necessary. + * @param f The context to use. + * @return Returns APR_ENOTIMPL if not supported. + */ +static apr_status_t crypto_block_cleanup(apr_crypto_block_t *block) +{ + + if (block->secParam) { + SECITEM_FreeItem(block->secParam, PR_TRUE); + block->secParam = NULL; + } + + if (block->ctx) { + PK11_DestroyContext(block->ctx, PR_TRUE); + block->ctx = NULL; + } + + return APR_SUCCESS; + +} + +static apr_status_t crypto_block_cleanup_helper(void *data) +{ + apr_crypto_block_t *block = (apr_crypto_block_t *) data; + return crypto_block_cleanup(block); +} + +static apr_status_t crypto_key_cleanup(void *data) +{ + apr_crypto_key_t *key = data; + if (key->symKey) { + PK11_FreeSymKey(key->symKey); + key->symKey = NULL; + } + return APR_SUCCESS; +} +/** + * @brief Clean encryption / decryption context. + * @note After cleanup, a context is free to be reused if necessary. + * @param f The context to use. + * @return Returns APR_ENOTIMPL if not supported. + */ +static apr_status_t crypto_cleanup(apr_crypto_t *f) +{ + return APR_SUCCESS; +} + +static apr_status_t crypto_cleanup_helper(void *data) +{ + apr_crypto_t *f = (apr_crypto_t *) data; + return crypto_cleanup(f); +} + +/** + * @brief Create a context for supporting encryption. Keys, certificates, + * algorithms and other parameters will be set per context. More than + * one context can be created at one time. A cleanup will be automatically + * registered with the given pool to guarantee a graceful shutdown. + * @param f - context pointer will be written here + * @param provider - provider to use + * @param params - parameter string + * @param pool - process pool + * @return APR_ENOENGINE when the engine specified does not exist. APR_EINITENGINE + * if the engine cannot be initialised. + */ +static apr_status_t crypto_make(apr_crypto_t **ff, + const apr_crypto_driver_t *provider, const char *params, + apr_pool_t *pool) +{ + apr_crypto_config_t *config = NULL; + apr_crypto_t *f; + + f = apr_pcalloc(pool, sizeof(apr_crypto_t)); + if (!f) { + return APR_ENOMEM; + } + *ff = f; + f->pool = pool; + f->provider = provider; + config = f->config = apr_pcalloc(pool, sizeof(apr_crypto_config_t)); + if (!config) { + return APR_ENOMEM; + } + f->result = apr_pcalloc(pool, sizeof(apu_err_t)); + if (!f->result) { + return APR_ENOMEM; + } + + f->types = apr_hash_make(pool); + if (!f->types) { + return APR_ENOMEM; + } + apr_hash_set(f->types, "3des192", APR_HASH_KEY_STRING, &(key_types[0])); + apr_hash_set(f->types, "aes128", APR_HASH_KEY_STRING, &(key_types[1])); + apr_hash_set(f->types, "aes192", APR_HASH_KEY_STRING, &(key_types[2])); + apr_hash_set(f->types, "aes256", APR_HASH_KEY_STRING, &(key_types[3])); + + f->modes = apr_hash_make(pool); + if (!f->modes) { + return APR_ENOMEM; + } + apr_hash_set(f->modes, "ecb", APR_HASH_KEY_STRING, &(key_modes[0])); + apr_hash_set(f->modes, "cbc", APR_HASH_KEY_STRING, &(key_modes[1])); + + apr_pool_cleanup_register(pool, f, crypto_cleanup_helper, + apr_pool_cleanup_null); + + return APR_SUCCESS; + +} + +/** + * @brief Get a hash table of key types, keyed by the name of the type against + * a pointer to apr_crypto_block_key_type_t. + * + * @param types - hashtable of key types keyed to constants. + * @param f - encryption context + * @return APR_SUCCESS for success + */ +static apr_status_t crypto_get_block_key_types(apr_hash_t **types, + const apr_crypto_t *f) +{ + *types = f->types; + return APR_SUCCESS; +} + +/** + * @brief Get a hash table of key modes, keyed by the name of the mode against + * a pointer to apr_crypto_block_key_mode_t. + * + * @param modes - hashtable of key modes keyed to constants. + * @param f - encryption context + * @return APR_SUCCESS for success + */ +static apr_status_t crypto_get_block_key_modes(apr_hash_t **modes, + const apr_crypto_t *f) +{ + *modes = f->modes; + return APR_SUCCESS; +} + +/* + * Work out which mechanism to use. + */ +static apr_status_t crypto_cipher_mechanism(apr_crypto_key_t *key, + const apr_crypto_block_key_type_e type, + const apr_crypto_block_key_mode_e mode, const int doPad) +{ + + /* decide on what cipher mechanism we will be using */ + switch (type) { + + case (APR_KEY_3DES_192): + if (APR_MODE_CBC == mode) { + key->cipherOid = SEC_OID_DES_EDE3_CBC; + } + else if (APR_MODE_ECB == mode) { + return APR_ENOCIPHER; + /* No OID for CKM_DES3_ECB; */ + } + key->keyLength = 24; + break; + case (APR_KEY_AES_128): + if (APR_MODE_CBC == mode) { + key->cipherOid = SEC_OID_AES_128_CBC; + } + else { + key->cipherOid = SEC_OID_AES_128_ECB; + } + key->keyLength = 16; + break; + case (APR_KEY_AES_192): + if (APR_MODE_CBC == mode) { + key->cipherOid = SEC_OID_AES_192_CBC; + } + else { + key->cipherOid = SEC_OID_AES_192_ECB; + } + key->keyLength = 24; + break; + case (APR_KEY_AES_256): + if (APR_MODE_CBC == mode) { + key->cipherOid = SEC_OID_AES_256_CBC; + } + else { + key->cipherOid = SEC_OID_AES_256_ECB; + } + key->keyLength = 32; + break; + default: + /* unknown key type, give up */ + return APR_EKEYTYPE; + } + + /* AES_128_CBC --> CKM_AES_CBC --> CKM_AES_CBC_PAD */ + key->cipherMech = PK11_AlgtagToMechanism(key->cipherOid); + if (key->cipherMech == CKM_INVALID_MECHANISM) { + return APR_ENOCIPHER; + } + if (doPad) { + CK_MECHANISM_TYPE paddedMech; + paddedMech = PK11_GetPadMechanism(key->cipherMech); + if (CKM_INVALID_MECHANISM == paddedMech + || key->cipherMech == paddedMech) { + return APR_EPADDING; + } + key->cipherMech = paddedMech; + } + + key->ivSize = PK11_GetIVLength(key->cipherMech); + + return APR_SUCCESS; +} + +/** + * @brief Create a key from the provided secret or passphrase. The key is cleaned + * up when the context is cleaned, and may be reused with multiple encryption + * or decryption operations. + * @note If *key is NULL, a apr_crypto_key_t will be created from a pool. If + * *key is not NULL, *key must point at a previously created structure. + * @param key The key returned, see note. + * @param rec The key record, from which the key will be derived. + * @param f The context to use. + * @param p The pool to use. + * @return Returns APR_ENOKEY if the pass phrase is missing or empty, or if a backend + * error occurred while generating the key. APR_ENOCIPHER if the type or mode + * is not supported by the particular backend. APR_EKEYTYPE if the key type is + * not known. APR_EPADDING if padding was requested but is not supported. + * APR_ENOTIMPL if not implemented. + */ +static apr_status_t crypto_key(apr_crypto_key_t **k, + const apr_crypto_key_rec_t *rec, const apr_crypto_t *f, apr_pool_t *p) +{ + apr_status_t rv = APR_SUCCESS; + PK11SlotInfo *slot, *tslot; + PK11SymKey *tkey; + SECItem secretItem; + SECItem wrappedItem; + SECItem *secParam; + PK11Context *ctx; + SECStatus s; + SECItem passItem; + SECItem saltItem; + SECAlgorithmID *algid; + void *wincx = NULL; /* what is wincx? */ + apr_crypto_key_t *key; + int blockSize; + int remainder; + + key = *k; + if (!key) { + *k = key = apr_pcalloc(p, sizeof *key); + if (!key) { + return APR_ENOMEM; + } + apr_pool_cleanup_register(p, key, crypto_key_cleanup, + apr_pool_cleanup_null); + } + + key->f = f; + key->provider = f->provider; + + /* decide on what cipher mechanism we will be using */ + rv = crypto_cipher_mechanism(key, rec->type, rec->mode, rec->pad); + if (APR_SUCCESS != rv) { + return rv; + } + + switch (rec->ktype) { + + case APR_CRYPTO_KTYPE_PASSPHRASE: { + + /* Turn the raw passphrase and salt into SECItems */ + passItem.data = (unsigned char*) rec->k.passphrase.pass; + passItem.len = rec->k.passphrase.passLen; + saltItem.data = (unsigned char*) rec->k.passphrase.salt; + saltItem.len = rec->k.passphrase.saltLen; + + /* generate the key */ + /* pbeAlg and cipherAlg are the same. */ + algid = PK11_CreatePBEV2AlgorithmID(key->cipherOid, key->cipherOid, + SEC_OID_HMAC_SHA1, key->keyLength, + rec->k.passphrase.iterations, &saltItem); + if (algid) { + slot = PK11_GetBestSlot(key->cipherMech, wincx); + if (slot) { + key->symKey = PK11_PBEKeyGen(slot, algid, &passItem, PR_FALSE, + wincx); + PK11_FreeSlot(slot); + } + SECOID_DestroyAlgorithmID(algid, PR_TRUE); + } + + break; + } + + case APR_CRYPTO_KTYPE_SECRET: { + + /* + * NSS is by default in FIPS mode, which disallows the use of unencrypted + * symmetrical keys. As per http://permalink.gmane.org/gmane.comp.mozilla.crypto/7947 + * we do the following: + * + * 1. Generate a (temporary) symmetric key in NSS. + * 2. Use that symmetric key to encrypt your symmetric key as data. + * 3. Unwrap your wrapped symmetric key, using the symmetric key + * you generated in Step 1 as the unwrapping key. + * + * http://permalink.gmane.org/gmane.comp.mozilla.crypto/7947 + */ + + /* generate the key */ + slot = PK11_GetBestSlot(key->cipherMech, NULL); + if (slot) { + unsigned char data[BUFFER_SIZE]; + + /* sanity check - key correct size? */ + if (rec->k.secret.secretLen != key->keyLength) { + PK11_FreeSlot(slot); + return APR_EKEYLENGTH; + } + + tslot = PK11_GetBestSlot(CKM_AES_ECB, NULL); + if (tslot) { + + /* generate a temporary wrapping key */ + tkey = PK11_KeyGen(tslot, CKM_AES_ECB, 0, PK11_GetBestKeyLength(tslot, CKM_AES_ECB), 0); + + /* prepare the key to wrap */ + secretItem.data = (unsigned char *) rec->k.secret.secret; + secretItem.len = rec->k.secret.secretLen; + + /* ensure our key matches the blocksize */ + secParam = PK11_GenerateNewParam(CKM_AES_ECB, tkey); + blockSize = PK11_GetBlockSize(CKM_AES_ECB, secParam); + remainder = rec->k.secret.secretLen % blockSize; + if (remainder) { + secretItem.data = + apr_pcalloc(p, rec->k.secret.secretLen + remainder); + apr_crypto_clear(p, secretItem.data, + rec->k.secret.secretLen); + memcpy(secretItem.data, rec->k.secret.secret, + rec->k.secret.secretLen); + secretItem.len += remainder; + } + + /* prepare a space for the wrapped key */ + wrappedItem.data = data; + + /* wrap the key */ + ctx = PK11_CreateContextBySymKey(CKM_AES_ECB, CKA_ENCRYPT, tkey, + secParam); + if (ctx) { + s = PK11_CipherOp(ctx, wrappedItem.data, + (int *) (&wrappedItem.len), BUFFER_SIZE, + secretItem.data, secretItem.len); + if (s == SECSuccess) { + + /* unwrap the key again */ + key->symKey = PK11_UnwrapSymKeyWithFlags(tkey, + CKM_AES_ECB, NULL, &wrappedItem, + key->cipherMech, CKA_ENCRYPT, + rec->k.secret.secretLen, 0); + + } + + PK11_DestroyContext(ctx, PR_TRUE); + } + + /* clean up */ + SECITEM_FreeItem(secParam, PR_TRUE); + PK11_FreeSymKey(tkey); + PK11_FreeSlot(tslot); + + } + + PK11_FreeSlot(slot); + } + + break; + } + + default: { + + return APR_ENOKEY; + + } + } + + /* sanity check? */ + if (!key->symKey) { + PRErrorCode perr = PORT_GetError(); + if (perr) { + f->result->rc = perr; + f->result->msg = PR_ErrorToName(perr); + rv = APR_ENOKEY; + } + } + + return rv; +} + +/** + * @brief Create a key from the given passphrase. By default, the PBKDF2 + * algorithm is used to generate the key from the passphrase. It is expected + * that the same pass phrase will generate the same key, regardless of the + * backend crypto platform used. The key is cleaned up when the context + * is cleaned, and may be reused with multiple encryption or decryption + * operations. + * @note If *key is NULL, a apr_crypto_key_t will be created from a pool. If + * *key is not NULL, *key must point at a previously created structure. + * @param key The key returned, see note. + * @param ivSize The size of the initialisation vector will be returned, based + * on whether an IV is relevant for this type of crypto. + * @param pass The passphrase to use. + * @param passLen The passphrase length in bytes + * @param salt The salt to use. + * @param saltLen The salt length in bytes + * @param type 3DES_192, AES_128, AES_192, AES_256. + * @param mode Electronic Code Book / Cipher Block Chaining. + * @param doPad Pad if necessary. + * @param iterations Iteration count + * @param f The context to use. + * @param p The pool to use. + * @return Returns APR_ENOKEY if the pass phrase is missing or empty, or if a backend + * error occurred while generating the key. APR_ENOCIPHER if the type or mode + * is not supported by the particular backend. APR_EKEYTYPE if the key type is + * not known. APR_EPADDING if padding was requested but is not supported. + * APR_ENOTIMPL if not implemented. + */ +static apr_status_t crypto_passphrase(apr_crypto_key_t **k, apr_size_t *ivSize, + const char *pass, apr_size_t passLen, const unsigned char * salt, + apr_size_t saltLen, const apr_crypto_block_key_type_e type, + const apr_crypto_block_key_mode_e mode, const int doPad, + const int iterations, const apr_crypto_t *f, apr_pool_t *p) +{ + apr_status_t rv = APR_SUCCESS; + PK11SlotInfo * slot; + SECItem passItem; + SECItem saltItem; + SECAlgorithmID *algid; + void *wincx = NULL; /* what is wincx? */ + apr_crypto_key_t *key = *k; + + if (!key) { + *k = key = apr_pcalloc(p, sizeof *key); + if (!key) { + return APR_ENOMEM; + } + apr_pool_cleanup_register(p, key, crypto_key_cleanup, + apr_pool_cleanup_null); + } + + key->f = f; + key->provider = f->provider; + + /* decide on what cipher mechanism we will be using */ + rv = crypto_cipher_mechanism(key, type, mode, doPad); + if (APR_SUCCESS != rv) { + return rv; + } + + /* Turn the raw passphrase and salt into SECItems */ + passItem.data = (unsigned char*) pass; + passItem.len = passLen; + saltItem.data = (unsigned char*) salt; + saltItem.len = saltLen; + + /* generate the key */ + /* pbeAlg and cipherAlg are the same. */ + algid = PK11_CreatePBEV2AlgorithmID(key->cipherOid, key->cipherOid, + SEC_OID_HMAC_SHA1, key->keyLength, iterations, &saltItem); + if (algid) { + slot = PK11_GetBestSlot(key->cipherMech, wincx); + if (slot) { + key->symKey = PK11_PBEKeyGen(slot, algid, &passItem, PR_FALSE, + wincx); + PK11_FreeSlot(slot); + } + SECOID_DestroyAlgorithmID(algid, PR_TRUE); + } + + /* sanity check? */ + if (!key->symKey) { + PRErrorCode perr = PORT_GetError(); + if (perr) { + f->result->rc = perr; + f->result->msg = PR_ErrorToName(perr); + rv = APR_ENOKEY; + } + } + + if (ivSize) { + *ivSize = key->ivSize; + } + + return rv; +} + +/** + * @brief Initialise a context for encrypting arbitrary data using the given key. + * @note If *ctx is NULL, a apr_crypto_block_t will be created from a pool. If + * *ctx is not NULL, *ctx must point at a previously created structure. + * @param ctx The block context returned, see note. + * @param iv Optional initialisation vector. If the buffer pointed to is NULL, + * an IV will be created at random, in space allocated from the pool. + * If the buffer pointed to is not NULL, the IV in the buffer will be + * used. + * @param key The key structure. + * @param blockSize The block size of the cipher. + * @param p The pool to use. + * @return Returns APR_ENOIV if an initialisation vector is required but not specified. + * Returns APR_EINIT if the backend failed to initialise the context. Returns + * APR_ENOTIMPL if not implemented. + */ +static apr_status_t crypto_block_encrypt_init(apr_crypto_block_t **ctx, + const unsigned char **iv, const apr_crypto_key_t *key, + apr_size_t *blockSize, apr_pool_t *p) +{ + PRErrorCode perr; + SECItem ivItem; + unsigned char * usedIv; + apr_crypto_block_t *block = *ctx; + if (!block) { + *ctx = block = apr_pcalloc(p, sizeof(apr_crypto_block_t)); + } + if (!block) { + return APR_ENOMEM; + } + block->f = key->f; + block->pool = p; + block->provider = key->provider; + + apr_pool_cleanup_register(p, block, crypto_block_cleanup_helper, + apr_pool_cleanup_null); + + if (key->ivSize) { + if (iv == NULL) { + return APR_ENOIV; + } + if (*iv == NULL) { + SECStatus s; + usedIv = apr_pcalloc(p, key->ivSize); + if (!usedIv) { + return APR_ENOMEM; + } + apr_crypto_clear(p, usedIv, key->ivSize); + s = PK11_GenerateRandom(usedIv, key->ivSize); + if (s != SECSuccess) { + return APR_ENOIV; + } + *iv = usedIv; + } + else { + usedIv = (unsigned char *) *iv; + } + ivItem.data = usedIv; + ivItem.len = key->ivSize; + block->secParam = PK11_ParamFromIV(key->cipherMech, &ivItem); + } + else { + block->secParam = PK11_GenerateNewParam(key->cipherMech, key->symKey); + } + block->blockSize = PK11_GetBlockSize(key->cipherMech, block->secParam); + block->ctx = PK11_CreateContextBySymKey(key->cipherMech, CKA_ENCRYPT, + key->symKey, block->secParam); + + /* did an error occur? */ + perr = PORT_GetError(); + if (perr || !block->ctx) { + key->f->result->rc = perr; + key->f->result->msg = PR_ErrorToName(perr); + return APR_EINIT; + } + + if (blockSize) { + *blockSize = PK11_GetBlockSize(key->cipherMech, block->secParam); + } + + return APR_SUCCESS; + +} + +/** + * @brief Encrypt data provided by in, write it to out. + * @note The number of bytes written will be written to outlen. If + * out is NULL, outlen will contain the maximum size of the + * buffer needed to hold the data, including any data + * generated by apr_crypto_block_encrypt_finish below. If *out points + * to NULL, a buffer sufficiently large will be created from + * the pool provided. If *out points to a not-NULL value, this + * value will be used as a buffer instead. + * @param out Address of a buffer to which data will be written, + * see note. + * @param outlen Length of the output will be written here. + * @param in Address of the buffer to read. + * @param inlen Length of the buffer to read. + * @param ctx The block context to use. + * @return APR_ECRYPT if an error occurred. Returns APR_ENOTIMPL if + * not implemented. + */ +static apr_status_t crypto_block_encrypt(unsigned char **out, + apr_size_t *outlen, const unsigned char *in, apr_size_t inlen, + apr_crypto_block_t *block) +{ + + unsigned char *buffer; + int outl = (int) *outlen; + SECStatus s; + if (!out) { + *outlen = inlen + block->blockSize; + return APR_SUCCESS; + } + if (!*out) { + buffer = apr_palloc(block->pool, inlen + block->blockSize); + if (!buffer) { + return APR_ENOMEM; + } + apr_crypto_clear(block->pool, buffer, inlen + block->blockSize); + *out = buffer; + } + + s = PK11_CipherOp(block->ctx, *out, &outl, inlen, (unsigned char*) in, + inlen); + if (s != SECSuccess) { + PRErrorCode perr = PORT_GetError(); + if (perr) { + block->f->result->rc = perr; + block->f->result->msg = PR_ErrorToName(perr); + } + return APR_ECRYPT; + } + *outlen = outl; + + return APR_SUCCESS; + +} + +/** + * @brief Encrypt final data block, write it to out. + * @note If necessary the final block will be written out after being + * padded. Typically the final block will be written to the + * same buffer used by apr_crypto_block_encrypt, offset by the + * number of bytes returned as actually written by the + * apr_crypto_block_encrypt() call. After this call, the context + * is cleaned and can be reused by apr_crypto_block_encrypt_init(). + * @param out Address of a buffer to which data will be written. This + * buffer must already exist, and is usually the same + * buffer used by apr_evp_crypt(). See note. + * @param outlen Length of the output will be written here. + * @param ctx The block context to use. + * @return APR_ECRYPT if an error occurred. + * @return APR_EPADDING if padding was enabled and the block was incorrectly + * formatted. + * @return APR_ENOTIMPL if not implemented. + */ +static apr_status_t crypto_block_encrypt_finish(unsigned char *out, + apr_size_t *outlen, apr_crypto_block_t *block) +{ + + apr_status_t rv = APR_SUCCESS; + unsigned int outl = *outlen; + + SECStatus s = PK11_DigestFinal(block->ctx, out, &outl, block->blockSize); + *outlen = outl; + + if (s != SECSuccess) { + PRErrorCode perr = PORT_GetError(); + if (perr) { + block->f->result->rc = perr; + block->f->result->msg = PR_ErrorToName(perr); + } + rv = APR_ECRYPT; + } + crypto_block_cleanup(block); + + return rv; + +} + +/** + * @brief Initialise a context for decrypting arbitrary data using the given key. + * @note If *ctx is NULL, a apr_crypto_block_t will be created from a pool. If + * *ctx is not NULL, *ctx must point at a previously created structure. + * @param ctx The block context returned, see note. + * @param blockSize The block size of the cipher. + * @param iv Optional initialisation vector. If the buffer pointed to is NULL, + * an IV will be created at random, in space allocated from the pool. + * If the buffer is not NULL, the IV in the buffer will be used. + * @param key The key structure. + * @param p The pool to use. + * @return Returns APR_ENOIV if an initialisation vector is required but not specified. + * Returns APR_EINIT if the backend failed to initialise the context. Returns + * APR_ENOTIMPL if not implemented. + */ +static apr_status_t crypto_block_decrypt_init(apr_crypto_block_t **ctx, + apr_size_t *blockSize, const unsigned char *iv, + const apr_crypto_key_t *key, apr_pool_t *p) +{ + PRErrorCode perr; + apr_crypto_block_t *block = *ctx; + if (!block) { + *ctx = block = apr_pcalloc(p, sizeof(apr_crypto_block_t)); + } + if (!block) { + return APR_ENOMEM; + } + block->f = key->f; + block->pool = p; + block->provider = key->provider; + + apr_pool_cleanup_register(p, block, crypto_block_cleanup_helper, + apr_pool_cleanup_null); + + if (key->ivSize) { + SECItem ivItem; + if (iv == NULL) { + return APR_ENOIV; /* Cannot initialise without an IV */ + } + ivItem.data = (unsigned char*) iv; + ivItem.len = key->ivSize; + block->secParam = PK11_ParamFromIV(key->cipherMech, &ivItem); + } + else { + block->secParam = PK11_GenerateNewParam(key->cipherMech, key->symKey); + } + block->blockSize = PK11_GetBlockSize(key->cipherMech, block->secParam); + block->ctx = PK11_CreateContextBySymKey(key->cipherMech, CKA_DECRYPT, + key->symKey, block->secParam); + + /* did an error occur? */ + perr = PORT_GetError(); + if (perr || !block->ctx) { + key->f->result->rc = perr; + key->f->result->msg = PR_ErrorToName(perr); + return APR_EINIT; + } + + if (blockSize) { + *blockSize = PK11_GetBlockSize(key->cipherMech, block->secParam); + } + + return APR_SUCCESS; + +} + +/** + * @brief Decrypt data provided by in, write it to out. + * @note The number of bytes written will be written to outlen. If + * out is NULL, outlen will contain the maximum size of the + * buffer needed to hold the data, including any data + * generated by apr_crypto_block_decrypt_finish below. If *out points + * to NULL, a buffer sufficiently large will be created from + * the pool provided. If *out points to a not-NULL value, this + * value will be used as a buffer instead. + * @param out Address of a buffer to which data will be written, + * see note. + * @param outlen Length of the output will be written here. + * @param in Address of the buffer to read. + * @param inlen Length of the buffer to read. + * @param ctx The block context to use. + * @return APR_ECRYPT if an error occurred. Returns APR_ENOTIMPL if + * not implemented. + */ +static apr_status_t crypto_block_decrypt(unsigned char **out, + apr_size_t *outlen, const unsigned char *in, apr_size_t inlen, + apr_crypto_block_t *block) +{ + + unsigned char *buffer; + int outl = (int) *outlen; + SECStatus s; + if (!out) { + *outlen = inlen + block->blockSize; + return APR_SUCCESS; + } + if (!*out) { + buffer = apr_palloc(block->pool, inlen + block->blockSize); + if (!buffer) { + return APR_ENOMEM; + } + apr_crypto_clear(block->pool, buffer, inlen + block->blockSize); + *out = buffer; + } + + s = PK11_CipherOp(block->ctx, *out, &outl, inlen, (unsigned char*) in, + inlen); + if (s != SECSuccess) { + PRErrorCode perr = PORT_GetError(); + if (perr) { + block->f->result->rc = perr; + block->f->result->msg = PR_ErrorToName(perr); + } + return APR_ECRYPT; + } + *outlen = outl; + + return APR_SUCCESS; + +} + +/** + * @brief Decrypt final data block, write it to out. + * @note If necessary the final block will be written out after being + * padded. Typically the final block will be written to the + * same buffer used by apr_crypto_block_decrypt, offset by the + * number of bytes returned as actually written by the + * apr_crypto_block_decrypt() call. After this call, the context + * is cleaned and can be reused by apr_crypto_block_decrypt_init(). + * @param out Address of a buffer to which data will be written. This + * buffer must already exist, and is usually the same + * buffer used by apr_evp_crypt(). See note. + * @param outlen Length of the output will be written here. + * @param ctx The block context to use. + * @return APR_ECRYPT if an error occurred. + * @return APR_EPADDING if padding was enabled and the block was incorrectly + * formatted. + * @return APR_ENOTIMPL if not implemented. + */ +static apr_status_t crypto_block_decrypt_finish(unsigned char *out, + apr_size_t *outlen, apr_crypto_block_t *block) +{ + + apr_status_t rv = APR_SUCCESS; + unsigned int outl = *outlen; + + SECStatus s = PK11_DigestFinal(block->ctx, out, &outl, block->blockSize); + *outlen = outl; + + if (s != SECSuccess) { + PRErrorCode perr = PORT_GetError(); + if (perr) { + block->f->result->rc = perr; + block->f->result->msg = PR_ErrorToName(perr); + } + rv = APR_ECRYPT; + } + crypto_block_cleanup(block); + + return rv; + +} + +/** + * NSS module. + */ +APR_MODULE_DECLARE_DATA const apr_crypto_driver_t apr_crypto_nss_driver = { + "nss", crypto_init, crypto_make, crypto_get_block_key_types, + crypto_get_block_key_modes, crypto_passphrase, + crypto_block_encrypt_init, crypto_block_encrypt, + crypto_block_encrypt_finish, crypto_block_decrypt_init, + crypto_block_decrypt, crypto_block_decrypt_finish, + crypto_block_cleanup, crypto_cleanup, crypto_shutdown, crypto_error, + crypto_key +}; + +#endif diff --git a/crypto/apr_crypto_nss.dsp b/crypto/apr_crypto_nss.dsp new file mode 100644 index 00000000000..663b240c47b --- /dev/null +++ b/crypto/apr_crypto_nss.dsp @@ -0,0 +1,203 @@ +# Microsoft Developer Studio Project File - Name="apr_crypto_nss" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=apr_crypto_nss - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "apr_crypto_nss.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "apr_crypto_nss.mak" CFG="apr_crypto_nss - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "apr_crypto_nss - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "apr_crypto_nss - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "apr_crypto_nss - x64 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "apr_crypto_nss - x64 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "apr_crypto_nss - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c +# ADD CPP /nologo /MD /W3 /Zi /O2 /Oy- /I "../include" /I "../../apr/include" /I "../include/private" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "APU_DSO_MODULE_BUILD" /D APU_HAVE_NSS=1 /D HAVE_NSS_H=1 /D HAVE_PK11PUB_H=1 /Fo"$(INTDIR)\" /Fd"$(INTDIR)\apr_crypto_nss_src" /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o /win32 "NUL" +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o /win32 "NUL" +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /fo"Release/apr_crypto_nss-1.res" /d DLL_NAME="apr_crypto_nss" /d "NDEBUG" /d "APU_VERSION_ONLY" /I "../include" /I "../../apr/include" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib nss3.lib nspr4.lib /nologo /base:"0x6F110000" /subsystem:windows /dll /incremental:no /debug /opt:ref +# ADD LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib nss3.lib nspr4.lib nspr4.lib /nologo /base:"0x6F110000" /subsystem:windows /dll /incremental:no /debug /out:"Release\apr_crypto_nss-1.dll" /pdb:"Release\apr_crypto_nss-1.pdb" /implib:"Release\apr_crypto_nss-1.lib" /MACHINE:X86 /opt:ref +# Begin Special Build Tool +TargetPath=Release\apr_crypto_nss-1.dll +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2 +# End Special Build Tool + +!ELSEIF "$(CFG)" == "apr_crypto_nss - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /EHsc /c +# ADD CPP /nologo /MDd /W3 /Zi /Od /I "../include" /I "../../apr/include" /I "../include/private" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "APU_DSO_MODULE_BUILD" /D APU_HAVE_NSS=1 /D HAVE_NSS_H=1 /D HAVE_PK11PUB_H=1 /D /Fo"$(INTDIR)\" /Fd"$(INTDIR)\apr_crypto_nss_src" /FD /EHsc /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o /win32 "NUL" +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o /win32 "NUL" +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /fo"Debug/apr_crypto_nss-1.res" /d DLL_NAME="apr_crypto_nss" /d "_DEBUG" /d "APU_VERSION_ONLY" /I "../include" /I "../../apr/include" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib nss3.lib nspr4.lib /nologo /base:"0x6F110000" /subsystem:windows /dll /incremental:no /debug +# ADD LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib nss3.lib nspr4.lib /nologo /base:"0x6F110000" /subsystem:windows /dll /incremental:no /debug /out:"Debug\apr_crypto_nss-1.dll" /pdb:"Debug\apr_crypto_nss-1.pdb" /implib:"Debug\apr_crypto_nss-1.lib" /MACHINE:X86 +# Begin Special Build Tool +TargetPath=Debug\apr_crypto_nss-1.dll +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2 +# End Special Build Tool + +!ELSEIF "$(CFG)" == "apr_crypto_nss - x64 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "x64\Release" +# PROP BASE Intermediate_Dir "x64\Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "x64\Release" +# PROP Intermediate_Dir "x64\Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c +# ADD CPP /nologo /MD /W3 /Zi /O2 /Oy- /I "../include" /I "../../apr/include" /I "../include/private" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "APU_DSO_MODULE_BUILD" /D APU_HAVE_NSS=1 /D HAVE_NSS_H=1 /D HAVE_PK11PUB_H=1 /D /Fo"$(INTDIR)\" /Fd"$(INTDIR)\apr_crypto_nss_src" /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o /win32 "NUL" +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o /win32 "NUL" +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /fo"x64/Release/apr_crypto_nss-1.res" /d DLL_NAME="apr_crypto_nss" /d "NDEBUG" /d "APU_VERSION_ONLY" /I "../include" /I "../../apr/include" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib nss3.lib nspr4.lib /nologo /base:"0x6F110000" /subsystem:windows /dll /incremental:no /debug /opt:ref +# ADD LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib nss3.lib nspr4.lib /nologo /base:"0x6F110000" /subsystem:windows /dll /incremental:no /debug /out:"x64\Release\apr_crypto_nss-1.dll" /pdb:"x64\Release\apr_crypto_nss-1.pdb" /implib:"x64\Release\apr_crypto_nss-1.lib" /MACHINE:X64 /opt:ref +# Begin Special Build Tool +TargetPath=x64\Release\apr_crypto_nss-1.dll +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2 +# End Special Build Tool + +!ELSEIF "$(CFG)" == "apr_crypto_nss - x64 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "x64\Debug" +# PROP BASE Intermediate_Dir "x64\Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "x64\Debug" +# PROP Intermediate_Dir "x64\Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /EHsc /c +# ADD CPP /nologo /MDd /W3 /Zi /Od /I "../include" /I "../../apr/include" /I "../include/private" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "APU_DSO_MODULE_BUILD" /D APU_HAVE_NSS=1 /D HAVE_NSS_H=1 /D HAVE_PK11PUB_H=1 /D /Fo"$(INTDIR)\" /Fd"$(INTDIR)\apr_crypto_nss_src" /FD /EHsc /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o /win32 "NUL" +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o /win32 "NUL" +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /fo"x64/Debug/apr_crypto_nss-1.res" /d DLL_NAME="apr_crypto_nss" /d "_DEBUG" /d "APU_VERSION_ONLY" /I "../include" /I "../../apr/include" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib nss3.lib nspr4.lib /nologo /base:"0x6F110000" /subsystem:windows /dll /incremental:no /debug +# ADD LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib nss3.lib nspr4.lib /nologo /base:"0x6F110000" /subsystem:windows /dll /incremental:no /debug /out:"x64\Debug\apr_crypto_nss-1.dll" /pdb:"x64\Debug\apr_crypto_nss-1.pdb" /implib:"x64\Debug\apr_crypto_nss-1.lib" /MACHINE:X64 +# Begin Special Build Tool +TargetPath=x64\Debug\apr_crypto_nss-1.dll +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2 +# End Special Build Tool + +!ENDIF + +# Begin Target + +# Name "apr_crypto_nss - Win32 Release" +# Name "apr_crypto_nss - Win32 Debug" +# Name "apr_crypto_nss - x64 Release" +# Name "apr_crypto_nss - x64 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\apr_crypto_nss.c +# End Source File +# End Group +# Begin Group "Public Header Files" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\include\apr_crypto.h +# End Source File +# End Group +# Begin Group "Internal Header Files" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\include\private\apu_config.h +# End Source File +# Begin Source File + +SOURCE=..\include\private\apu_internal.h +# End Source File +# End Group +# Begin Source File + +SOURCE=..\libaprutil.rc +# End Source File +# End Target +# End Project diff --git a/crypto/apr_crypto_openssl.c b/crypto/apr_crypto_openssl.c new file mode 100644 index 00000000000..db4d5354558 --- /dev/null +++ b/crypto/apr_crypto_openssl.c @@ -0,0 +1,952 @@ +/* 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_lib.h" +#include "apu.h" +#include "apr_private.h" +#include "apu_errno.h" + +#include <ctype.h> +#include <assert.h> +#include <stdlib.h> + +#include "apr_strings.h" +#include "apr_time.h" +#include "apr_buckets.h" + +#include "apr_crypto_internal.h" + +#if APU_HAVE_CRYPTO + +#include <openssl/evp.h> +#include <openssl/rand.h> +#include <openssl/engine.h> + +#define LOG_PREFIX "apr_crypto_openssl: " + +#ifndef APR_USE_OPENSSL_PRE_1_1_API +#if defined(LIBRESSL_VERSION_NUMBER) +/* LibreSSL declares OPENSSL_VERSION_NUMBER == 2.0 but does not include most + * changes from OpenSSL >= 1.1 (new functions, macros, deprecations, ...), so + * we have to work around this... + */ +#define APR_USE_OPENSSL_PRE_1_1_API (1) +#else +#define APR_USE_OPENSSL_PRE_1_1_API (OPENSSL_VERSION_NUMBER < 0x10100000L) +#endif +#endif + +struct apr_crypto_t { + apr_pool_t *pool; + const apr_crypto_driver_t *provider; + apu_err_t *result; + apr_crypto_config_t *config; + apr_hash_t *types; + apr_hash_t *modes; +}; + +struct apr_crypto_config_t { + ENGINE *engine; +}; + +struct apr_crypto_key_t { + apr_pool_t *pool; + const apr_crypto_driver_t *provider; + const apr_crypto_t *f; + const EVP_CIPHER * cipher; + unsigned char *key; + int keyLen; + int doPad; + int ivSize; +}; + +struct apr_crypto_block_t { + apr_pool_t *pool; + const apr_crypto_driver_t *provider; + const apr_crypto_t *f; + EVP_CIPHER_CTX *cipherCtx; + int initialised; + int ivSize; + int blockSize; + int doPad; +}; + +static struct apr_crypto_block_key_type_t key_types[] = +{ +{ APR_KEY_3DES_192, 24, 8, 8 }, +{ APR_KEY_AES_128, 16, 16, 16 }, +{ APR_KEY_AES_192, 24, 16, 16 }, +{ APR_KEY_AES_256, 32, 16, 16 } }; + +static struct apr_crypto_block_key_mode_t key_modes[] = +{ +{ APR_MODE_ECB }, +{ APR_MODE_CBC } }; + +/* sufficient space to wrap a key */ +#define BUFFER_SIZE 128 + +/** + * Fetch the most recent error from this driver. + */ +static apr_status_t crypto_error(const apu_err_t **result, + const apr_crypto_t *f) +{ + *result = f->result; + return APR_SUCCESS; +} + +/** + * Shutdown the crypto library and release resources. + */ +static apr_status_t crypto_shutdown(void) +{ +#if APR_USE_OPENSSL_PRE_1_1_API + ERR_free_strings(); + EVP_cleanup(); + ENGINE_cleanup(); +#endif + return APR_SUCCESS; +} + +static apr_status_t crypto_shutdown_helper(void *data) +{ + return crypto_shutdown(); +} + +/** + * Initialise the crypto library and perform one time initialisation. + */ +static apr_status_t crypto_init(apr_pool_t *pool, const char *params, + const apu_err_t **result) +{ +#if APR_USE_OPENSSL_PRE_1_1_API + (void)CRYPTO_malloc_init(); + ERR_load_crypto_strings(); + /* SSL_load_error_strings(); */ + OpenSSL_add_all_algorithms(); +#else + OPENSSL_malloc_init(); +#endif + ENGINE_load_builtin_engines(); + ENGINE_register_all_complete(); + + apr_pool_cleanup_register(pool, pool, crypto_shutdown_helper, + apr_pool_cleanup_null); + + return APR_SUCCESS; +} + +/** + * @brief Clean encryption / decryption context. + * @note After cleanup, a context is free to be reused if necessary. + * @param ctx The block context to use. + * @return Returns APR_ENOTIMPL if not supported. + */ +static apr_status_t crypto_block_cleanup(apr_crypto_block_t *ctx) +{ + + if (ctx->initialised) { + EVP_CIPHER_CTX_free(ctx->cipherCtx); + ctx->initialised = 0; + } + + return APR_SUCCESS; + +} + +static apr_status_t crypto_block_cleanup_helper(void *data) +{ + apr_crypto_block_t *block = (apr_crypto_block_t *) data; + return crypto_block_cleanup(block); +} + +/** + * @brief Clean encryption / decryption context. + * @note After cleanup, a context is free to be reused if necessary. + * @param f The context to use. + * @return Returns APR_ENOTIMPL if not supported. + */ +static apr_status_t crypto_cleanup(apr_crypto_t *f) +{ + + if (f->config->engine) { + ENGINE_finish(f->config->engine); + ENGINE_free(f->config->engine); + f->config->engine = NULL; + } + return APR_SUCCESS; + +} + +static apr_status_t crypto_cleanup_helper(void *data) +{ + apr_crypto_t *f = (apr_crypto_t *) data; + return crypto_cleanup(f); +} + +/** + * @brief Create a context for supporting encryption. Keys, certificates, + * algorithms and other parameters will be set per context. More than + * one context can be created at one time. A cleanup will be automatically + * registered with the given pool to guarantee a graceful shutdown. + * @param f - context pointer will be written here + * @param provider - provider to use + * @param params - array of key parameters + * @param pool - process pool + * @return APR_ENOENGINE when the engine specified does not exist. APR_EINITENGINE + * if the engine cannot be initialised. + */ +static apr_status_t crypto_make(apr_crypto_t **ff, + const apr_crypto_driver_t *provider, const char *params, + apr_pool_t *pool) +{ + apr_crypto_config_t *config = NULL; + apr_crypto_t *f = apr_pcalloc(pool, sizeof(apr_crypto_t)); + + const char *engine = NULL; + + struct { + const char *field; + const char *value; + int set; + } fields[] = { + { "engine", NULL, 0 }, + { NULL, NULL, 0 } + }; + const char *ptr; + size_t klen; + char **elts = NULL; + char *elt; + int i = 0, j; + apr_status_t status; + + if (params) { + if (APR_SUCCESS != (status = apr_tokenize_to_argv(params, &elts, pool))) { + return status; + } + while ((elt = elts[i])) { + ptr = strchr(elt, '='); + if (ptr) { + for (klen = ptr - elt; klen && apr_isspace(elt[klen - 1]); --klen) + ; + ptr++; + } + else { + for (klen = strlen(elt); klen && apr_isspace(elt[klen - 1]); --klen) + ; + } + elt[klen] = 0; + + for (j = 0; fields[j].field != NULL; ++j) { + if (!strcasecmp(fields[j].field, elt)) { + fields[j].set = 1; + if (ptr) { + fields[j].value = ptr; + } + break; + } + } + + i++; + } + engine = fields[0].value; + } + + if (!f) { + return APR_ENOMEM; + } + *ff = f; + f->pool = pool; + f->provider = provider; + config = f->config = apr_pcalloc(pool, sizeof(apr_crypto_config_t)); + if (!config) { + return APR_ENOMEM; + } + + f->result = apr_pcalloc(pool, sizeof(apu_err_t)); + if (!f->result) { + return APR_ENOMEM; + } + + f->types = apr_hash_make(pool); + if (!f->types) { + return APR_ENOMEM; + } + apr_hash_set(f->types, "3des192", APR_HASH_KEY_STRING, &(key_types[0])); + apr_hash_set(f->types, "aes128", APR_HASH_KEY_STRING, &(key_types[1])); + apr_hash_set(f->types, "aes192", APR_HASH_KEY_STRING, &(key_types[2])); + apr_hash_set(f->types, "aes256", APR_HASH_KEY_STRING, &(key_types[3])); + + f->modes = apr_hash_make(pool); + if (!f->modes) { + return APR_ENOMEM; + } + apr_hash_set(f->modes, "ecb", APR_HASH_KEY_STRING, &(key_modes[0])); + apr_hash_set(f->modes, "cbc", APR_HASH_KEY_STRING, &(key_modes[1])); + + apr_pool_cleanup_register(pool, f, crypto_cleanup_helper, + apr_pool_cleanup_null); + + if (engine) { + config->engine = ENGINE_by_id(engine); + if (!config->engine) { + return APR_ENOENGINE; + } + if (!ENGINE_init(config->engine)) { + ENGINE_free(config->engine); + config->engine = NULL; + return APR_EINITENGINE; + } + } + + return APR_SUCCESS; + +} + +/** + * @brief Get a hash table of key types, keyed by the name of the type against + * a pointer to apr_crypto_block_key_type_t. + * + * @param types - hashtable of key types keyed to constants. + * @param f - encryption context + * @return APR_SUCCESS for success + */ +static apr_status_t crypto_get_block_key_types(apr_hash_t **types, + const apr_crypto_t *f) +{ + *types = f->types; + return APR_SUCCESS; +} + +/** + * @brief Get a hash table of key modes, keyed by the name of the mode against + * a pointer to apr_crypto_block_key_mode_t. + * + * @param modes - hashtable of key modes keyed to constants. + * @param f - encryption context + * @return APR_SUCCESS for success + */ +static apr_status_t crypto_get_block_key_modes(apr_hash_t **modes, + const apr_crypto_t *f) +{ + *modes = f->modes; + return APR_SUCCESS; +} + +/* + * Work out which mechanism to use. + */ +static apr_status_t crypto_cipher_mechanism(apr_crypto_key_t *key, + const apr_crypto_block_key_type_e type, + const apr_crypto_block_key_mode_e mode, const int doPad, apr_pool_t *p) +{ + /* determine the cipher to be used */ + switch (type) { + + case (APR_KEY_3DES_192): + + /* A 3DES key */ + if (mode == APR_MODE_CBC) { + key->cipher = EVP_des_ede3_cbc(); + } + else { + key->cipher = EVP_des_ede3_ecb(); + } + break; + + case (APR_KEY_AES_128): + + if (mode == APR_MODE_CBC) { + key->cipher = EVP_aes_128_cbc(); + } + else { + key->cipher = EVP_aes_128_ecb(); + } + break; + + case (APR_KEY_AES_192): + + if (mode == APR_MODE_CBC) { + key->cipher = EVP_aes_192_cbc(); + } + else { + key->cipher = EVP_aes_192_ecb(); + } + break; + + case (APR_KEY_AES_256): + + if (mode == APR_MODE_CBC) { + key->cipher = EVP_aes_256_cbc(); + } + else { + key->cipher = EVP_aes_256_ecb(); + } + break; + + default: + + /* unknown key type, give up */ + return APR_EKEYTYPE; + + } + + /* find the length of the key we need */ + key->keyLen = EVP_CIPHER_key_length(key->cipher); + + /* make space for the key */ + key->key = apr_pcalloc(p, key->keyLen); + if (!key->key) { + return APR_ENOMEM; + } + apr_crypto_clear(p, key->key, key->keyLen); + + return APR_SUCCESS; +} + +/** + * @brief Create a key from the provided secret or passphrase. The key is cleaned + * up when the context is cleaned, and may be reused with multiple encryption + * or decryption operations. + * @note If *key is NULL, a apr_crypto_key_t will be created from a pool. If + * *key is not NULL, *key must point at a previously created structure. + * @param key The key returned, see note. + * @param rec The key record, from which the key will be derived. + * @param f The context to use. + * @param p The pool to use. + * @return Returns APR_ENOKEY if the pass phrase is missing or empty, or if a backend + * error occurred while generating the key. APR_ENOCIPHER if the type or mode + * is not supported by the particular backend. APR_EKEYTYPE if the key type is + * not known. APR_EPADDING if padding was requested but is not supported. + * APR_ENOTIMPL if not implemented. + */ +static apr_status_t crypto_key(apr_crypto_key_t **k, + const apr_crypto_key_rec_t *rec, const apr_crypto_t *f, apr_pool_t *p) +{ + apr_crypto_key_t *key = *k; + apr_status_t rv; + + if (!key) { + *k = key = apr_pcalloc(p, sizeof *key); + if (!key) { + return APR_ENOMEM; + } + } + + key->f = f; + key->provider = f->provider; + + /* decide on what cipher mechanism we will be using */ + rv = crypto_cipher_mechanism(key, rec->type, rec->mode, rec->pad, p); + if (APR_SUCCESS != rv) { + return rv; + } + + switch (rec->ktype) { + + case APR_CRYPTO_KTYPE_PASSPHRASE: { + + /* generate the key */ + if (PKCS5_PBKDF2_HMAC_SHA1(rec->k.passphrase.pass, + rec->k.passphrase.passLen, + (unsigned char *) rec->k.passphrase.salt, + rec->k.passphrase.saltLen, rec->k.passphrase.iterations, + key->keyLen, key->key) == 0) { + return APR_ENOKEY; + } + + break; + } + + case APR_CRYPTO_KTYPE_SECRET: { + + /* sanity check - key correct size? */ + if (rec->k.secret.secretLen != key->keyLen) { + return APR_EKEYLENGTH; + } + + /* copy the key */ + memcpy(key->key, rec->k.secret.secret, rec->k.secret.secretLen); + + break; + } + + default: { + + return APR_ENOKEY; + + } + } + + key->doPad = rec->pad; + + /* note: openssl incorrectly returns non zero IV size values for ECB + * algorithms, so work around this by ignoring the IV size. + */ + if (APR_MODE_ECB != rec->mode) { + key->ivSize = EVP_CIPHER_iv_length(key->cipher); + } + + return APR_SUCCESS; +} + +/** + * @brief Create a key from the given passphrase. By default, the PBKDF2 + * algorithm is used to generate the key from the passphrase. It is expected + * that the same pass phrase will generate the same key, regardless of the + * backend crypto platform used. The key is cleaned up when the context + * is cleaned, and may be reused with multiple encryption or decryption + * operations. + * @note If *key is NULL, a apr_crypto_key_t will be created from a pool. If + * *key is not NULL, *key must point at a previously created structure. + * @param key The key returned, see note. + * @param ivSize The size of the initialisation vector will be returned, based + * on whether an IV is relevant for this type of crypto. + * @param pass The passphrase to use. + * @param passLen The passphrase length in bytes + * @param salt The salt to use. + * @param saltLen The salt length in bytes + * @param type 3DES_192, AES_128, AES_192, AES_256. + * @param mode Electronic Code Book / Cipher Block Chaining. + * @param doPad Pad if necessary. + * @param iterations Iteration count + * @param f The context to use. + * @param p The pool to use. + * @return Returns APR_ENOKEY if the pass phrase is missing or empty, or if a backend + * error occurred while generating the key. APR_ENOCIPHER if the type or mode + * is not supported by the particular backend. APR_EKEYTYPE if the key type is + * not known. APR_EPADDING if padding was requested but is not supported. + * APR_ENOTIMPL if not implemented. + */ +static apr_status_t crypto_passphrase(apr_crypto_key_t **k, apr_size_t *ivSize, + const char *pass, apr_size_t passLen, const unsigned char * salt, + apr_size_t saltLen, const apr_crypto_block_key_type_e type, + const apr_crypto_block_key_mode_e mode, const int doPad, + const int iterations, const apr_crypto_t *f, apr_pool_t *p) +{ + apr_crypto_key_t *key = *k; + apr_status_t rv; + + if (!key) { + *k = key = apr_pcalloc(p, sizeof *key); + if (!key) { + return APR_ENOMEM; + } + } + + key->f = f; + key->provider = f->provider; + + /* decide on what cipher mechanism we will be using */ + rv = crypto_cipher_mechanism(key, type, mode, doPad, p); + if (APR_SUCCESS != rv) { + return rv; + } + + /* generate the key */ + if (PKCS5_PBKDF2_HMAC_SHA1(pass, passLen, (unsigned char *) salt, saltLen, + iterations, key->keyLen, key->key) == 0) { + return APR_ENOKEY; + } + + key->doPad = doPad; + + /* note: openssl incorrectly returns non zero IV size values for ECB + * algorithms, so work around this by ignoring the IV size. + */ + if (APR_MODE_ECB != mode) { + key->ivSize = EVP_CIPHER_iv_length(key->cipher); + } + if (ivSize) { + *ivSize = key->ivSize; + } + + return APR_SUCCESS; +} + +/** + * @brief Initialise a context for encrypting arbitrary data using the given key. + * @note If *ctx is NULL, a apr_crypto_block_t will be created from a pool. If + * *ctx is not NULL, *ctx must point at a previously created structure. + * @param ctx The block context returned, see note. + * @param iv Optional initialisation vector. If the buffer pointed to is NULL, + * an IV will be created at random, in space allocated from the pool. + * If the buffer pointed to is not NULL, the IV in the buffer will be + * used. + * @param key The key structure. + * @param blockSize The block size of the cipher. + * @param p The pool to use. + * @return Returns APR_ENOIV if an initialisation vector is required but not specified. + * Returns APR_EINIT if the backend failed to initialise the context. Returns + * APR_ENOTIMPL if not implemented. + */ +static apr_status_t crypto_block_encrypt_init(apr_crypto_block_t **ctx, + const unsigned char **iv, const apr_crypto_key_t *key, + apr_size_t *blockSize, apr_pool_t *p) +{ + unsigned char *usedIv; + apr_crypto_config_t *config = key->f->config; + apr_crypto_block_t *block = *ctx; + if (!block) { + *ctx = block = apr_pcalloc(p, sizeof(apr_crypto_block_t)); + } + if (!block) { + return APR_ENOMEM; + } + block->f = key->f; + block->pool = p; + block->provider = key->provider; + + apr_pool_cleanup_register(p, block, crypto_block_cleanup_helper, + apr_pool_cleanup_null); + + /* create a new context for encryption */ + if (!block->initialised) { + block->cipherCtx = EVP_CIPHER_CTX_new(); + block->initialised = 1; + } + + /* generate an IV, if necessary */ + usedIv = NULL; + if (key->ivSize) { + if (iv == NULL) { + return APR_ENOIV; + } + if (*iv == NULL) { + usedIv = apr_pcalloc(p, key->ivSize); + if (!usedIv) { + return APR_ENOMEM; + } + apr_crypto_clear(p, usedIv, key->ivSize); + if (!((RAND_status() == 1) + && (RAND_bytes(usedIv, key->ivSize) == 1))) { + return APR_ENOIV; + } + *iv = usedIv; + } + else { + usedIv = (unsigned char *) *iv; + } + } + + /* set up our encryption context */ +#if CRYPTO_OPENSSL_CONST_BUFFERS + if (!EVP_EncryptInit_ex(block->cipherCtx, key->cipher, config->engine, + key->key, usedIv)) { +#else + if (!EVP_EncryptInit_ex(block->cipherCtx, key->cipher, config->engine, (unsigned char *) key->key, (unsigned char *) usedIv)) { +#endif + return APR_EINIT; + } + + /* Clear up any read padding */ + if (!EVP_CIPHER_CTX_set_padding(block->cipherCtx, key->doPad)) { + return APR_EPADDING; + } + + if (blockSize) { + *blockSize = EVP_CIPHER_block_size(key->cipher); + } + + return APR_SUCCESS; + +} + +/** + * @brief Encrypt data provided by in, write it to out. + * @note The number of bytes written will be written to outlen. If + * out is NULL, outlen will contain the maximum size of the + * buffer needed to hold the data, including any data + * generated by apr_crypto_block_encrypt_finish below. If *out points + * to NULL, a buffer sufficiently large will be created from + * the pool provided. If *out points to a not-NULL value, this + * value will be used as a buffer instead. + * @param out Address of a buffer to which data will be written, + * see note. + * @param outlen Length of the output will be written here. + * @param in Address of the buffer to read. + * @param inlen Length of the buffer to read. + * @param ctx The block context to use. + * @return APR_ECRYPT if an error occurred. Returns APR_ENOTIMPL if + * not implemented. + */ +static apr_status_t crypto_block_encrypt(unsigned char **out, + apr_size_t *outlen, const unsigned char *in, apr_size_t inlen, + apr_crypto_block_t *ctx) +{ + int outl = *outlen; + unsigned char *buffer; + + /* are we after the maximum size of the out buffer? */ + if (!out) { + *outlen = inlen + EVP_MAX_BLOCK_LENGTH; + return APR_SUCCESS; + } + + /* must we allocate the output buffer from a pool? */ + if (!*out) { + buffer = apr_palloc(ctx->pool, inlen + EVP_MAX_BLOCK_LENGTH); + if (!buffer) { + return APR_ENOMEM; + } + apr_crypto_clear(ctx->pool, buffer, inlen + EVP_MAX_BLOCK_LENGTH); + *out = buffer; + } + +#if CRYPT_OPENSSL_CONST_BUFFERS + if (!EVP_EncryptUpdate(ctx->cipherCtx, (*out), &outl, in, inlen)) { +#else + if (!EVP_EncryptUpdate(ctx->cipherCtx, (*out), &outl, + (unsigned char *) in, inlen)) { +#endif +#if APR_USE_OPENSSL_PRE_1_1_API + EVP_CIPHER_CTX_cleanup(ctx->cipherCtx); +#else + EVP_CIPHER_CTX_reset(ctx->cipherCtx); +#endif + return APR_ECRYPT; + } + *outlen = outl; + + return APR_SUCCESS; + +} + +/** + * @brief Encrypt final data block, write it to out. + * @note If necessary the final block will be written out after being + * padded. Typically the final block will be written to the + * same buffer used by apr_crypto_block_encrypt, offset by the + * number of bytes returned as actually written by the + * apr_crypto_block_encrypt() call. After this call, the context + * is cleaned and can be reused by apr_crypto_block_encrypt_init(). + * @param out Address of a buffer to which data will be written. This + * buffer must already exist, and is usually the same + * buffer used by apr_evp_crypt(). See note. + * @param outlen Length of the output will be written here. + * @param ctx The block context to use. + * @return APR_ECRYPT if an error occurred. + * @return APR_EPADDING if padding was enabled and the block was incorrectly + * formatted. + * @return APR_ENOTIMPL if not implemented. + */ +static apr_status_t crypto_block_encrypt_finish(unsigned char *out, + apr_size_t *outlen, apr_crypto_block_t *ctx) +{ + apr_status_t rc = APR_SUCCESS; + int len = *outlen; + + if (EVP_EncryptFinal_ex(ctx->cipherCtx, out, &len) == 0) { + rc = APR_EPADDING; + } + else { + *outlen = len; + } +#if APR_USE_OPENSSL_PRE_1_1_API + EVP_CIPHER_CTX_cleanup(ctx->cipherCtx); +#else + EVP_CIPHER_CTX_reset(ctx->cipherCtx); +#endif + + return rc; + +} + +/** + * @brief Initialise a context for decrypting arbitrary data using the given key. + * @note If *ctx is NULL, a apr_crypto_block_t will be created from a pool. If + * *ctx is not NULL, *ctx must point at a previously created structure. + * @param ctx The block context returned, see note. + * @param blockSize The block size of the cipher. + * @param iv Optional initialisation vector. If the buffer pointed to is NULL, + * an IV will be created at random, in space allocated from the pool. + * If the buffer is not NULL, the IV in the buffer will be used. + * @param key The key structure. + * @param p The pool to use. + * @return Returns APR_ENOIV if an initialisation vector is required but not specified. + * Returns APR_EINIT if the backend failed to initialise the context. Returns + * APR_ENOTIMPL if not implemented. + */ +static apr_status_t crypto_block_decrypt_init(apr_crypto_block_t **ctx, + apr_size_t *blockSize, const unsigned char *iv, + const apr_crypto_key_t *key, apr_pool_t *p) +{ + apr_crypto_config_t *config = key->f->config; + apr_crypto_block_t *block = *ctx; + if (!block) { + *ctx = block = apr_pcalloc(p, sizeof(apr_crypto_block_t)); + } + if (!block) { + return APR_ENOMEM; + } + block->f = key->f; + block->pool = p; + block->provider = key->provider; + + apr_pool_cleanup_register(p, block, crypto_block_cleanup_helper, + apr_pool_cleanup_null); + + /* create a new context for encryption */ + if (!block->initialised) { + block->cipherCtx = EVP_CIPHER_CTX_new(); + block->initialised = 1; + } + + /* generate an IV, if necessary */ + if (key->ivSize) { + if (iv == NULL) { + return APR_ENOIV; + } + } + + /* set up our encryption context */ +#if CRYPTO_OPENSSL_CONST_BUFFERS + if (!EVP_DecryptInit_ex(block->cipherCtx, key->cipher, config->engine, + key->key, iv)) { +#else + if (!EVP_DecryptInit_ex(block->cipherCtx, key->cipher, config->engine, (unsigned char *) key->key, (unsigned char *) iv)) { +#endif + return APR_EINIT; + } + + /* Clear up any read padding */ + if (!EVP_CIPHER_CTX_set_padding(block->cipherCtx, key->doPad)) { + return APR_EPADDING; + } + + if (blockSize) { + *blockSize = EVP_CIPHER_block_size(key->cipher); + } + + return APR_SUCCESS; + +} + +/** + * @brief Decrypt data provided by in, write it to out. + * @note The number of bytes written will be written to outlen. If + * out is NULL, outlen will contain the maximum size of the + * buffer needed to hold the data, including any data + * generated by apr_crypto_block_decrypt_finish below. If *out points + * to NULL, a buffer sufficiently large will be created from + * the pool provided. If *out points to a not-NULL value, this + * value will be used as a buffer instead. + * @param out Address of a buffer to which data will be written, + * see note. + * @param outlen Length of the output will be written here. + * @param in Address of the buffer to read. + * @param inlen Length of the buffer to read. + * @param ctx The block context to use. + * @return APR_ECRYPT if an error occurred. Returns APR_ENOTIMPL if + * not implemented. + */ +static apr_status_t crypto_block_decrypt(unsigned char **out, + apr_size_t *outlen, const unsigned char *in, apr_size_t inlen, + apr_crypto_block_t *ctx) +{ + int outl = *outlen; + unsigned char *buffer; + + /* are we after the maximum size of the out buffer? */ + if (!out) { + *outlen = inlen + EVP_MAX_BLOCK_LENGTH; + return APR_SUCCESS; + } + + /* must we allocate the output buffer from a pool? */ + if (!(*out)) { + buffer = apr_palloc(ctx->pool, inlen + EVP_MAX_BLOCK_LENGTH); + if (!buffer) { + return APR_ENOMEM; + } + apr_crypto_clear(ctx->pool, buffer, inlen + EVP_MAX_BLOCK_LENGTH); + *out = buffer; + } + +#if CRYPT_OPENSSL_CONST_BUFFERS + if (!EVP_DecryptUpdate(ctx->cipherCtx, *out, &outl, in, inlen)) { +#else + if (!EVP_DecryptUpdate(ctx->cipherCtx, *out, &outl, (unsigned char *) in, + inlen)) { +#endif +#if APR_USE_OPENSSL_PRE_1_1_API + EVP_CIPHER_CTX_cleanup(ctx->cipherCtx); +#else + EVP_CIPHER_CTX_reset(ctx->cipherCtx); +#endif + return APR_ECRYPT; + } + *outlen = outl; + + return APR_SUCCESS; + +} + +/** + * @brief Decrypt final data block, write it to out. + * @note If necessary the final block will be written out after being + * padded. Typically the final block will be written to the + * same buffer used by apr_crypto_block_decrypt, offset by the + * number of bytes returned as actually written by the + * apr_crypto_block_decrypt() call. After this call, the context + * is cleaned and can be reused by apr_crypto_block_decrypt_init(). + * @param out Address of a buffer to which data will be written. This + * buffer must already exist, and is usually the same + * buffer used by apr_evp_crypt(). See note. + * @param outlen Length of the output will be written here. + * @param ctx The block context to use. + * @return APR_ECRYPT if an error occurred. + * @return APR_EPADDING if padding was enabled and the block was incorrectly + * formatted. + * @return APR_ENOTIMPL if not implemented. + */ +static apr_status_t crypto_block_decrypt_finish(unsigned char *out, + apr_size_t *outlen, apr_crypto_block_t *ctx) +{ + apr_status_t rc = APR_SUCCESS; + int len = *outlen; + + if (EVP_DecryptFinal_ex(ctx->cipherCtx, out, &len) == 0) { + rc = APR_EPADDING; + } + else { + *outlen = len; + } +#if APR_USE_OPENSSL_PRE_1_1_API + EVP_CIPHER_CTX_cleanup(ctx->cipherCtx); +#else + EVP_CIPHER_CTX_reset(ctx->cipherCtx); +#endif + + return rc; + +} + +/** + * OpenSSL module. + */ +APR_MODULE_DECLARE_DATA const apr_crypto_driver_t apr_crypto_openssl_driver = { + "openssl", crypto_init, crypto_make, crypto_get_block_key_types, + crypto_get_block_key_modes, crypto_passphrase, + crypto_block_encrypt_init, crypto_block_encrypt, + crypto_block_encrypt_finish, crypto_block_decrypt_init, + crypto_block_decrypt, crypto_block_decrypt_finish, + crypto_block_cleanup, crypto_cleanup, crypto_shutdown, crypto_error, + crypto_key +}; + +#endif diff --git a/crypto/apr_crypto_openssl.dsp b/crypto/apr_crypto_openssl.dsp new file mode 100644 index 00000000000..90114ce4352 --- /dev/null +++ b/crypto/apr_crypto_openssl.dsp @@ -0,0 +1,203 @@ +# Microsoft Developer Studio Project File - Name="apr_crypto_openssl" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=apr_crypto_openssl - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "apr_crypto_openssl.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "apr_crypto_openssl.mak" CFG="apr_crypto_openssl - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "apr_crypto_openssl - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "apr_crypto_openssl - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "apr_crypto_openssl - x64 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "apr_crypto_openssl - x64 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "apr_crypto_openssl - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c +# ADD CPP /nologo /MD /W3 /Zi /O2 /Oy- /I "../include" /I "../../apr/include" /I "../include/private" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "APU_DSO_MODULE_BUILD" /D APU_HAVE_OPENSSL=1 /Fo"$(INTDIR)\" /Fd"$(INTDIR)\apr_crypto_openssl_src" /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o /win32 "NUL" +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o /win32 "NUL" +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /fo"Release/apr_crypto_openssl-1.res" /d DLL_NAME="apr_crypto_openssl" /d "NDEBUG" /d "APU_VERSION_ONLY" /I "../include" /I "../../apr/include" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib libeay32.lib ssleay32.lib /nologo /base:"0x6F100000" /subsystem:windows /dll /incremental:no /debug /opt:ref +# ADD LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib libeay32.lib ssleay32.lib /nologo /base:"0x6F100000" /subsystem:windows /dll /incremental:no /debug /out:"Release\apr_crypto_openssl-1.dll" /pdb:"Release\apr_crypto_openssl-1.pdb" /implib:"Release\apr_crypto_openssl-1.lib" /MACHINE:X86 /opt:ref +# Begin Special Build Tool +TargetPath=Release\apr_crypto_openssl-1.dll +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2 +# End Special Build Tool + +!ELSEIF "$(CFG)" == "apr_crypto_openssl - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /EHsc /c +# ADD CPP /nologo /MDd /W3 /Zi /Od /I "../include" /I "../../apr/include" /I "../include/private" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "APU_DSO_MODULE_BUILD" /D APU_HAVE_OPENSSL=1 /D /Fo"$(INTDIR)\" /Fd"$(INTDIR)\apr_crypto_openssl_src" /FD /EHsc /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o /win32 "NUL" +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o /win32 "NUL" +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /fo"Debug/apr_crypto_openssl-1.res" /d DLL_NAME="apr_crypto_openssl" /d "_DEBUG" /d "APU_VERSION_ONLY" /I "../include" /I "../../apr/include" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib libeay32.lib ssleay32.lib /nologo /base:"0x6F100000" /subsystem:windows /dll /incremental:no /debug +# ADD LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib libeay32.lib ssleay32.lib /nologo /base:"0x6F100000" /subsystem:windows /dll /incremental:no /debug /out:"Debug\apr_crypto_openssl-1.dll" /pdb:"Debug\apr_crypto_openssl-1.pdb" /implib:"Debug\apr_crypto_openssl-1.lib" /MACHINE:X86 +# Begin Special Build Tool +TargetPath=Debug\apr_crypto_openssl-1.dll +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2 +# End Special Build Tool + +!ELSEIF "$(CFG)" == "apr_crypto_openssl - x64 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "x64\Release" +# PROP BASE Intermediate_Dir "x64\Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "x64\Release" +# PROP Intermediate_Dir "x64\Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c +# ADD CPP /nologo /MD /W3 /Zi /O2 /Oy- /I "../include" /I "../../apr/include" /I "../include/private" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "APU_DSO_MODULE_BUILD" /D APU_HAVE_OPENSSL=1 /D /Fo"$(INTDIR)\" /Fd"$(INTDIR)\apr_crypto_openssl_src" /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o /win32 "NUL" +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o /win32 "NUL" +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /fo"x64/Release/apr_crypto_openssl-1.res" /d DLL_NAME="apr_crypto_openssl" /d "NDEBUG" /d "APU_VERSION_ONLY" /I "../include" /I "../../apr/include" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib libeay32.lib ssleay32.lib /nologo /base:"0x6F100000" /subsystem:windows /dll /incremental:no /debug /opt:ref +# ADD LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib libeay32.lib ssleay32.lib /nologo /base:"0x6F100000" /subsystem:windows /dll /incremental:no /debug /out:"x64\Release\apr_crypto_openssl-1.dll" /pdb:"x64\Release\apr_crypto_openssl-1.pdb" /implib:"x64\Release\apr_crypto_openssl-1.lib" /MACHINE:X64 /opt:ref +# Begin Special Build Tool +TargetPath=x64\Release\apr_crypto_openssl-1.dll +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2 +# End Special Build Tool + +!ELSEIF "$(CFG)" == "apr_crypto_openssl - x64 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "x64\Debug" +# PROP BASE Intermediate_Dir "x64\Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "x64\Debug" +# PROP Intermediate_Dir "x64\Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /EHsc /c +# ADD CPP /nologo /MDd /W3 /Zi /Od /I "../include" /I "../../apr/include" /I "../include/private" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "APU_DSO_MODULE_BUILD" /D APU_HAVE_OPENSSL=1 /D /Fo"$(INTDIR)\" /Fd"$(INTDIR)\apr_crypto_openssl_src" /FD /EHsc /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o /win32 "NUL" +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o /win32 "NUL" +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /fo"x64/Debug/apr_crypto_openssl-1.res" /d DLL_NAME="apr_crypto_openssl" /d "_DEBUG" /d "APU_VERSION_ONLY" /I "../include" /I "../../apr/include" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib libeay32.lib ssleay32.lib /nologo /base:"0x6F100000" /subsystem:windows /dll /incremental:no /debug +# ADD LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib libeay32.lib ssleay32.lib /nologo /base:"0x6F100000" /subsystem:windows /dll /incremental:no /debug /out:"x64\Debug\apr_crypto_openssl-1.dll" /pdb:"x64\Debug\apr_crypto_openssl-1.pdb" /implib:"x64\Debug\apr_crypto_openssl-1.lib" /MACHINE:X64 +# Begin Special Build Tool +TargetPath=x64\Debug\apr_crypto_openssl-1.dll +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2 +# End Special Build Tool + +!ENDIF + +# Begin Target + +# Name "apr_crypto_openssl - Win32 Release" +# Name "apr_crypto_openssl - Win32 Debug" +# Name "apr_crypto_openssl - x64 Release" +# Name "apr_crypto_openssl - x64 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\apr_crypto_openssl.c +# End Source File +# End Group +# Begin Group "Public Header Files" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\include\apr_crypto.h +# End Source File +# End Group +# Begin Group "Internal Header Files" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\include\private\apu_config.h +# End Source File +# Begin Source File + +SOURCE=..\include\private\apu_internal.h +# End Source File +# End Group +# Begin Source File + +SOURCE=..\libaprutil.rc +# End Source File +# End Target +# End Project diff --git a/crypto/apr_md4.c b/crypto/apr_md4.c new file mode 100644 index 00000000000..d983cbae5c2 --- /dev/null +++ b/crypto/apr_md4.c @@ -0,0 +1,404 @@ +/* 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. + * + * This is derived from material copyright RSA Data Security, Inc. + * Their notice is reproduced below in its entirety. + * + * Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All + * rights reserved. + * + * License to copy and use this software is granted provided that it + * is identified as the "RSA Data Security, Inc. MD4 Message-Digest + * Algorithm" in all material mentioning or referencing this software + * or this function. + * + * License is also granted to make and use derivative works provided + * that such works are identified as "derived from the RSA Data + * Security, Inc. MD4 Message-Digest Algorithm" in all material + * mentioning or referencing the derived work. + * + * RSA Data Security, Inc. makes no representations concerning either + * the merchantability of this software or the suitability of this + * software for any particular purpose. It is provided "as is" + * without express or implied warranty of any kind. + * + * These notices must be retained in any copies of any part of this + * documentation and/or software. + */ + +#include "apr_strings.h" +#include "apr_md4.h" +#include "apr_lib.h" + +#if APR_HAVE_STRING_H +#include <string.h> +#endif +#if APR_HAVE_UNISTD_H +#include <unistd.h> +#endif + +/* Constants for MD4Transform routine. + */ + +#define S11 3 +#define S12 7 +#define S13 11 +#define S14 19 +#define S21 3 +#define S22 5 +#define S23 9 +#define S24 13 +#define S31 3 +#define S32 9 +#define S33 11 +#define S34 15 + +static void MD4Transform(apr_uint32_t state[4], const unsigned char block[64]); +static void Encode(unsigned char *output, const apr_uint32_t *input, + unsigned int len); +static void Decode(apr_uint32_t *output, const unsigned char *input, + unsigned int len); + +static unsigned char PADDING[64] = +{ + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +#if APR_CHARSET_EBCDIC +static apr_xlate_t *xlate_ebcdic_to_ascii; /* used in apr_md4_encode() */ +#endif + +/* F, G and I are basic MD4 functions. + */ +#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) +#define G(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) + +/* ROTATE_LEFT rotates x left n bits. + */ +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) + +/* FF, GG and HH are transformations for rounds 1, 2 and 3 */ +/* Rotation is separate from addition to prevent recomputation */ + +#define FF(a, b, c, d, x, s) { \ + (a) += F ((b), (c), (d)) + (x); \ + (a) = ROTATE_LEFT ((a), (s)); \ + } +#define GG(a, b, c, d, x, s) { \ + (a) += G ((b), (c), (d)) + (x) + (apr_uint32_t)0x5a827999; \ + (a) = ROTATE_LEFT ((a), (s)); \ + } +#define HH(a, b, c, d, x, s) { \ + (a) += H ((b), (c), (d)) + (x) + (apr_uint32_t)0x6ed9eba1; \ + (a) = ROTATE_LEFT ((a), (s)); \ + } + +/* MD4 initialization. Begins an MD4 operation, writing a new context. + */ +APR_DECLARE(apr_status_t) apr_md4_init(apr_md4_ctx_t *context) +{ + context->count[0] = context->count[1] = 0; + + /* Load magic initialization constants. */ + context->state[0] = 0x67452301; + context->state[1] = 0xefcdab89; + context->state[2] = 0x98badcfe; + context->state[3] = 0x10325476; + +#if APR_HAS_XLATE + context->xlate = NULL; +#endif + + return APR_SUCCESS; +} + +#if APR_HAS_XLATE +/* MD4 translation setup. Provides the APR translation handle + * to be used for translating the content before calculating the + * digest. + */ +APR_DECLARE(apr_status_t) apr_md4_set_xlate(apr_md4_ctx_t *context, + apr_xlate_t *xlate) +{ + apr_status_t rv; + int is_sb; + + /* TODO: remove the single-byte-only restriction from this code + */ + rv = apr_xlate_sb_get(xlate, &is_sb); + if (rv != APR_SUCCESS) { + return rv; + } + if (!is_sb) { + return APR_EINVAL; + } + context->xlate = xlate; + return APR_SUCCESS; +} +#endif /* APR_HAS_XLATE */ + +/* MD4 block update operation. Continues an MD4 message-digest + * operation, processing another message block, and updating the + * context. + */ +APR_DECLARE(apr_status_t) apr_md4_update(apr_md4_ctx_t *context, + const unsigned char *input, + apr_size_t inputLen) +{ + unsigned int i, idx, partLen; +#if APR_HAS_XLATE + apr_size_t inbytes_left, outbytes_left; +#endif + + /* Compute number of bytes mod 64 */ + idx = (unsigned int)((context->count[0] >> 3) & 0x3F); + + /* Update number of bits */ + if ((context->count[0] += ((apr_uint32_t)inputLen << 3)) + < ((apr_uint32_t)inputLen << 3)) + context->count[1]++; + context->count[1] += (apr_uint32_t)inputLen >> 29; + + partLen = 64 - idx; + + /* Transform as many times as possible. */ +#if !APR_HAS_XLATE + if (inputLen >= partLen) { + memcpy(&context->buffer[idx], input, partLen); + MD4Transform(context->state, context->buffer); + + for (i = partLen; i + 63 < inputLen; i += 64) + MD4Transform(context->state, &input[i]); + + idx = 0; + } + else + i = 0; + + /* Buffer remaining input */ + memcpy(&context->buffer[idx], &input[i], inputLen - i); +#else /*APR_HAS_XLATE*/ + if (inputLen >= partLen) { + if (context->xlate) { + inbytes_left = outbytes_left = partLen; + apr_xlate_conv_buffer(context->xlate, (const char *)input, + &inbytes_left, + (char *)&context->buffer[idx], + &outbytes_left); + } + else { + memcpy(&context->buffer[idx], input, partLen); + } + MD4Transform(context->state, context->buffer); + + for (i = partLen; i + 63 < inputLen; i += 64) { + if (context->xlate) { + unsigned char inp_tmp[64]; + inbytes_left = outbytes_left = 64; + apr_xlate_conv_buffer(context->xlate, (const char *)&input[i], + &inbytes_left, + (char *)inp_tmp, &outbytes_left); + MD4Transform(context->state, inp_tmp); + } + else { + MD4Transform(context->state, &input[i]); + } + } + + idx = 0; + } + else + i = 0; + + /* Buffer remaining input */ + if (context->xlate) { + inbytes_left = outbytes_left = inputLen - i; + apr_xlate_conv_buffer(context->xlate, (const char *)&input[i], + &inbytes_left, (char *)&context->buffer[idx], + &outbytes_left); + } + else { + memcpy(&context->buffer[idx], &input[i], inputLen - i); + } +#endif /*APR_HAS_XLATE*/ + return APR_SUCCESS; +} + +/* MD4 finalization. Ends an MD4 message-digest operation, writing the + * the message digest and zeroizing the context. + */ +APR_DECLARE(apr_status_t) apr_md4_final( + unsigned char digest[APR_MD4_DIGESTSIZE], + apr_md4_ctx_t *context) +{ + unsigned char bits[8]; + unsigned int idx, padLen; + + /* Save number of bits */ + Encode(bits, context->count, 8); + +#if APR_HAS_XLATE + /* apr_md4_update() should not translate for this final round. */ + context->xlate = NULL; +#endif /*APR_HAS_XLATE*/ + + /* Pad out to 56 mod 64. */ + idx = (unsigned int) ((context->count[0] >> 3) & 0x3f); + padLen = (idx < 56) ? (56 - idx) : (120 - idx); + apr_md4_update(context, PADDING, padLen); + + /* Append length (before padding) */ + apr_md4_update(context, bits, 8); + + /* Store state in digest */ + Encode(digest, context->state, APR_MD4_DIGESTSIZE); + + /* Zeroize sensitive information. */ + memset(context, 0, sizeof(*context)); + + return APR_SUCCESS; +} + +/* MD4 computation in one step (init, update, final) + */ +APR_DECLARE(apr_status_t) apr_md4(unsigned char digest[APR_MD4_DIGESTSIZE], + const unsigned char *input, + apr_size_t inputLen) +{ + apr_md4_ctx_t ctx; + apr_status_t rv; + + apr_md4_init(&ctx); + + if ((rv = apr_md4_update(&ctx, input, inputLen)) != APR_SUCCESS) + return rv; + + return apr_md4_final(digest, &ctx); +} + +/* MD4 basic transformation. Transforms state based on block. */ +static void MD4Transform(apr_uint32_t state[4], const unsigned char block[64]) +{ + apr_uint32_t a = state[0], b = state[1], c = state[2], d = state[3], + x[APR_MD4_DIGESTSIZE]; + + Decode(x, block, 64); + + /* Round 1 */ + FF (a, b, c, d, x[ 0], S11); /* 1 */ + FF (d, a, b, c, x[ 1], S12); /* 2 */ + FF (c, d, a, b, x[ 2], S13); /* 3 */ + FF (b, c, d, a, x[ 3], S14); /* 4 */ + FF (a, b, c, d, x[ 4], S11); /* 5 */ + FF (d, a, b, c, x[ 5], S12); /* 6 */ + FF (c, d, a, b, x[ 6], S13); /* 7 */ + FF (b, c, d, a, x[ 7], S14); /* 8 */ + FF (a, b, c, d, x[ 8], S11); /* 9 */ + FF (d, a, b, c, x[ 9], S12); /* 10 */ + FF (c, d, a, b, x[10], S13); /* 11 */ + FF (b, c, d, a, x[11], S14); /* 12 */ + FF (a, b, c, d, x[12], S11); /* 13 */ + FF (d, a, b, c, x[13], S12); /* 14 */ + FF (c, d, a, b, x[14], S13); /* 15 */ + FF (b, c, d, a, x[15], S14); /* 16 */ + + /* Round 2 */ + GG (a, b, c, d, x[ 0], S21); /* 17 */ + GG (d, a, b, c, x[ 4], S22); /* 18 */ + GG (c, d, a, b, x[ 8], S23); /* 19 */ + GG (b, c, d, a, x[12], S24); /* 20 */ + GG (a, b, c, d, x[ 1], S21); /* 21 */ + GG (d, a, b, c, x[ 5], S22); /* 22 */ + GG (c, d, a, b, x[ 9], S23); /* 23 */ + GG (b, c, d, a, x[13], S24); /* 24 */ + GG (a, b, c, d, x[ 2], S21); /* 25 */ + GG (d, a, b, c, x[ 6], S22); /* 26 */ + GG (c, d, a, b, x[10], S23); /* 27 */ + GG (b, c, d, a, x[14], S24); /* 28 */ + GG (a, b, c, d, x[ 3], S21); /* 29 */ + GG (d, a, b, c, x[ 7], S22); /* 30 */ + GG (c, d, a, b, x[11], S23); /* 31 */ + GG (b, c, d, a, x[15], S24); /* 32 */ + + /* Round 3 */ + HH (a, b, c, d, x[ 0], S31); /* 33 */ + HH (d, a, b, c, x[ 8], S32); /* 34 */ + HH (c, d, a, b, x[ 4], S33); /* 35 */ + HH (b, c, d, a, x[12], S34); /* 36 */ + HH (a, b, c, d, x[ 2], S31); /* 37 */ + HH (d, a, b, c, x[10], S32); /* 38 */ + HH (c, d, a, b, x[ 6], S33); /* 39 */ + HH (b, c, d, a, x[14], S34); /* 40 */ + HH (a, b, c, d, x[ 1], S31); /* 41 */ + HH (d, a, b, c, x[ 9], S32); /* 42 */ + HH (c, d, a, b, x[ 5], S33); /* 43 */ + HH (b, c, d, a, x[13], S34); /* 44 */ + HH (a, b, c, d, x[ 3], S31); /* 45 */ + HH (d, a, b, c, x[11], S32); /* 46 */ + HH (c, d, a, b, x[ 7], S33); /* 47 */ + HH (b, c, d, a, x[15], S34); /* 48 */ + + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + + /* Zeroize sensitive information. */ + memset(x, 0, sizeof(x)); +} + +/* Encodes input (apr_uint32_t) into output (unsigned char). Assumes len is + * a multiple of 4. + */ +static void Encode(unsigned char *output, const apr_uint32_t *input, + unsigned int len) +{ + unsigned int i, j; + apr_uint32_t k; + + for (i = 0, j = 0; j < len; i++, j += 4) { + k = input[i]; + output[j] = (unsigned char)(k & 0xff); + output[j + 1] = (unsigned char)((k >> 8) & 0xff); + output[j + 2] = (unsigned char)((k >> 16) & 0xff); + output[j + 3] = (unsigned char)((k >> 24) & 0xff); + } +} + +/* Decodes input (unsigned char) into output (apr_uint32_t). Assumes len is + * a multiple of 4. + */ +static void Decode(apr_uint32_t *output, const unsigned char *input, + unsigned int len) +{ + unsigned int i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) + output[i] = ((apr_uint32_t)input[j]) | + (((apr_uint32_t)input[j + 1]) << 8) | + (((apr_uint32_t)input[j + 2]) << 16) | + (((apr_uint32_t)input[j + 3]) << 24); +} + +#if APR_CHARSET_EBCDIC +APR_DECLARE(apr_status_t) apr_MD4InitEBCDIC(apr_xlate_t *xlate) +{ + xlate_ebcdic_to_ascii = xlate; + return APR_SUCCESS; +} +#endif diff --git a/crypto/apr_md5.c b/crypto/apr_md5.c new file mode 100644 index 00000000000..2aa0b4c4977 --- /dev/null +++ b/crypto/apr_md5.c @@ -0,0 +1,666 @@ +/* + * This is work is derived from material Copyright RSA Data Security, Inc. + * + * The RSA copyright statement and Licence for that original material is + * included below. This is followed by the Apache copyright statement and + * licence for the modifications made to that material. + */ + +/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm + */ + +/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All + rights reserved. + + License to copy and use this software is granted provided that it + is identified as the "RSA Data Security, Inc. MD5 Message-Digest + Algorithm" in all material mentioning or referencing this software + or this function. + + License is also granted to make and use derivative works provided + that such works are identified as "derived from the RSA Data + Security, Inc. MD5 Message-Digest Algorithm" in all material + mentioning or referencing the derived work. + + RSA Data Security, Inc. makes no representations concerning either + the merchantability of this software or the suitability of this + software for any particular purpose. It is provided "as is" + without express or implied warranty of any kind. + + These notices must be retained in any copies of any part of this + documentation and/or software. + */ + +/* 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 apr_md5_encode() routine uses much code obtained from the FreeBSD 3.0 + * MD5 crypt() function, which is licenced as follows: + * ---------------------------------------------------------------------------- + * "THE BEER-WARE LICENSE" (Revision 42): + * <phk@login.dknet.dk> wrote this file. As long as you retain this notice you + * can do whatever you want with this stuff. If we meet some day, and you think + * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp + * ---------------------------------------------------------------------------- + */ +#include "apr_strings.h" +#include "apr_md5.h" +#include "apr_lib.h" +#include "apr_private.h" + +#if APR_HAVE_STRING_H +#include <string.h> +#endif + +/* Constants for MD5Transform routine. + */ + +#define S11 7 +#define S12 12 +#define S13 17 +#define S14 22 +#define S21 5 +#define S22 9 +#define S23 14 +#define S24 20 +#define S31 4 +#define S32 11 +#define S33 16 +#define S34 23 +#define S41 6 +#define S42 10 +#define S43 15 +#define S44 21 + +static void MD5Transform(apr_uint32_t state[4], const unsigned char block[64]); +static void Encode(unsigned char *output, const apr_uint32_t *input, + unsigned int len); +static void Decode(apr_uint32_t *output, const unsigned char *input, + unsigned int len); + +static const unsigned char PADDING[64] = +{ + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +#if APR_CHARSET_EBCDIC +static apr_xlate_t *xlate_ebcdic_to_ascii; /* used in apr_md5_encode() */ +#endif +#define DO_XLATE 0 +#define SKIP_XLATE 1 + +/* F, G, H and I are basic MD5 functions. + */ +#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) +#define G(x, y, z) (((x) & (z)) | ((y) & (~z))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define I(x, y, z) ((y) ^ ((x) | (~z))) + +/* ROTATE_LEFT rotates x left n bits. + */ +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) + +/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. + * Rotation is separate from addition to prevent recomputation. + */ +#define FF(a, b, c, d, x, s, ac) { \ + (a) += F ((b), (c), (d)) + (x) + (apr_uint32_t)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define GG(a, b, c, d, x, s, ac) { \ + (a) += G ((b), (c), (d)) + (x) + (apr_uint32_t)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define HH(a, b, c, d, x, s, ac) { \ + (a) += H ((b), (c), (d)) + (x) + (apr_uint32_t)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define II(a, b, c, d, x, s, ac) { \ + (a) += I ((b), (c), (d)) + (x) + (apr_uint32_t)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } + +/* MD5 initialization. Begins an MD5 operation, writing a new context. + */ +APR_DECLARE(apr_status_t) apr_md5_init(apr_md5_ctx_t *context) +{ + context->count[0] = context->count[1] = 0; + + /* Load magic initialization constants. */ + context->state[0] = 0x67452301; + context->state[1] = 0xefcdab89; + context->state[2] = 0x98badcfe; + context->state[3] = 0x10325476; + context->xlate = NULL; + + return APR_SUCCESS; +} + +/* MD5 translation setup. Provides the APR translation handle + * to be used for translating the content before calculating the + * digest. + */ +APR_DECLARE(apr_status_t) apr_md5_set_xlate(apr_md5_ctx_t *context, + apr_xlate_t *xlate) +{ +#if APR_HAS_XLATE + apr_status_t rv; + int is_sb; + + /* TODO: remove the single-byte-only restriction from this code + */ + rv = apr_xlate_sb_get(xlate, &is_sb); + if (rv != APR_SUCCESS) { + return rv; + } + if (!is_sb) { + return APR_EINVAL; + } + context->xlate = xlate; + return APR_SUCCESS; +#else + return APR_ENOTIMPL; +#endif /* APR_HAS_XLATE */ +} + +/* MD5 block update operation. Continues an MD5 message-digest + * operation, processing another message block, and updating the + * context. + */ +static apr_status_t md5_update_buffer(apr_md5_ctx_t *context, + const void *vinput, + apr_size_t inputLen, + int xlate_buffer) +{ + const unsigned char *input = vinput; + unsigned int i, idx, partLen; +#if APR_HAS_XLATE + apr_size_t inbytes_left, outbytes_left; +#endif + + /* Compute number of bytes mod 64 */ + idx = (unsigned int)((context->count[0] >> 3) & 0x3F); + + /* Update number of bits */ + if ((context->count[0] += ((apr_uint32_t)inputLen << 3)) + < ((apr_uint32_t)inputLen << 3)) + context->count[1]++; + context->count[1] += (apr_uint32_t)inputLen >> 29; + + partLen = 64 - idx; + + /* Transform as many times as possible. */ +#if !APR_HAS_XLATE + if (inputLen >= partLen) { + memcpy(&context->buffer[idx], input, partLen); + MD5Transform(context->state, context->buffer); + + for (i = partLen; i + 63 < inputLen; i += 64) + MD5Transform(context->state, &input[i]); + + idx = 0; + } + else + i = 0; + + /* Buffer remaining input */ + memcpy(&context->buffer[idx], &input[i], inputLen - i); +#else /*APR_HAS_XLATE*/ + if (inputLen >= partLen) { + if (context->xlate && (xlate_buffer == DO_XLATE)) { + inbytes_left = outbytes_left = partLen; + apr_xlate_conv_buffer(context->xlate, (const char *)input, + &inbytes_left, + (char *)&context->buffer[idx], + &outbytes_left); + } + else { + memcpy(&context->buffer[idx], input, partLen); + } + MD5Transform(context->state, context->buffer); + + for (i = partLen; i + 63 < inputLen; i += 64) { + if (context->xlate && (xlate_buffer == DO_XLATE)) { + unsigned char inp_tmp[64]; + inbytes_left = outbytes_left = 64; + apr_xlate_conv_buffer(context->xlate, (const char *)&input[i], + &inbytes_left, (char *)inp_tmp, + &outbytes_left); + MD5Transform(context->state, inp_tmp); + } + else { + MD5Transform(context->state, &input[i]); + } + } + + idx = 0; + } + else + i = 0; + + /* Buffer remaining input */ + if (context->xlate && (xlate_buffer == DO_XLATE)) { + inbytes_left = outbytes_left = inputLen - i; + apr_xlate_conv_buffer(context->xlate, (const char *)&input[i], + &inbytes_left, (char *)&context->buffer[idx], + &outbytes_left); + } + else { + memcpy(&context->buffer[idx], &input[i], inputLen - i); + } +#endif /*APR_HAS_XLATE*/ + return APR_SUCCESS; +} + +/* MD5 block update operation. API with the default setting + * for EBCDIC translations + */ +APR_DECLARE(apr_status_t) apr_md5_update(apr_md5_ctx_t *context, + const void *input, + apr_size_t inputLen) +{ + return md5_update_buffer(context, input, inputLen, DO_XLATE); +} + +/* MD5 finalization. Ends an MD5 message-digest operation, writing the + * the message digest and zeroizing the context. + */ +APR_DECLARE(apr_status_t) apr_md5_final(unsigned char digest[APR_MD5_DIGESTSIZE], + apr_md5_ctx_t *context) +{ + unsigned char bits[8]; + unsigned int idx, padLen; + + /* Save number of bits */ + Encode(bits, context->count, 8); + +#if APR_HAS_XLATE + /* apr_md5_update() should not translate for this final round. */ + context->xlate = NULL; +#endif /*APR_HAS_XLATE*/ + + /* Pad out to 56 mod 64. */ + idx = (unsigned int)((context->count[0] >> 3) & 0x3f); + padLen = (idx < 56) ? (56 - idx) : (120 - idx); + apr_md5_update(context, PADDING, padLen); + + /* Append length (before padding) */ + apr_md5_update(context, bits, 8); + + /* Store state in digest */ + Encode(digest, context->state, APR_MD5_DIGESTSIZE); + + /* Zeroize sensitive information. */ + memset(context, 0, sizeof(*context)); + + return APR_SUCCESS; +} + +/* MD5 in one step (init, update, final) + */ +APR_DECLARE(apr_status_t) apr_md5(unsigned char digest[APR_MD5_DIGESTSIZE], + const void *_input, + apr_size_t inputLen) +{ + const unsigned char *input = _input; + apr_md5_ctx_t ctx; + apr_status_t rv; + + apr_md5_init(&ctx); + + if ((rv = apr_md5_update(&ctx, input, inputLen)) != APR_SUCCESS) + return rv; + + return apr_md5_final(digest, &ctx); +} + +/* MD5 basic transformation. Transforms state based on block. */ +static void MD5Transform(apr_uint32_t state[4], const unsigned char block[64]) +{ + apr_uint32_t a = state[0], b = state[1], c = state[2], d = state[3], + tmpbuf[APR_MD5_DIGESTSIZE]; + const apr_uint32_t *x; + +#if !APR_IS_BIGENDIAN + if ((apr_uintptr_t)block % sizeof(apr_uint32_t) == 0) { + x = (apr_uint32_t *)block; + } else +#endif + { + Decode(tmpbuf, block, 64); + x = tmpbuf; + } + + /* Round 1 */ + FF(a, b, c, d, x[0], S11, 0xd76aa478); /* 1 */ + FF(d, a, b, c, x[1], S12, 0xe8c7b756); /* 2 */ + FF(c, d, a, b, x[2], S13, 0x242070db); /* 3 */ + FF(b, c, d, a, x[3], S14, 0xc1bdceee); /* 4 */ + FF(a, b, c, d, x[4], S11, 0xf57c0faf); /* 5 */ + FF(d, a, b, c, x[5], S12, 0x4787c62a); /* 6 */ + FF(c, d, a, b, x[6], S13, 0xa8304613); /* 7 */ + FF(b, c, d, a, x[7], S14, 0xfd469501); /* 8 */ + FF(a, b, c, d, x[8], S11, 0x698098d8); /* 9 */ + FF(d, a, b, c, x[9], S12, 0x8b44f7af); /* 10 */ + FF(c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ + FF(b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ + FF(a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ + FF(d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ + FF(c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ + FF(b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ + + /* Round 2 */ + GG(a, b, c, d, x[1], S21, 0xf61e2562); /* 17 */ + GG(d, a, b, c, x[6], S22, 0xc040b340); /* 18 */ + GG(c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ + GG(b, c, d, a, x[0], S24, 0xe9b6c7aa); /* 20 */ + GG(a, b, c, d, x[5], S21, 0xd62f105d); /* 21 */ + GG(d, a, b, c, x[10], S22, 0x2441453); /* 22 */ + GG(c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ + GG(b, c, d, a, x[4], S24, 0xe7d3fbc8); /* 24 */ + GG(a, b, c, d, x[9], S21, 0x21e1cde6); /* 25 */ + GG(d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ + GG(c, d, a, b, x[3], S23, 0xf4d50d87); /* 27 */ + GG(b, c, d, a, x[8], S24, 0x455a14ed); /* 28 */ + GG(a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ + GG(d, a, b, c, x[2], S22, 0xfcefa3f8); /* 30 */ + GG(c, d, a, b, x[7], S23, 0x676f02d9); /* 31 */ + GG(b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ + + /* Round 3 */ + HH(a, b, c, d, x[5], S31, 0xfffa3942); /* 33 */ + HH(d, a, b, c, x[8], S32, 0x8771f681); /* 34 */ + HH(c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ + HH(b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ + HH(a, b, c, d, x[1], S31, 0xa4beea44); /* 37 */ + HH(d, a, b, c, x[4], S32, 0x4bdecfa9); /* 38 */ + HH(c, d, a, b, x[7], S33, 0xf6bb4b60); /* 39 */ + HH(b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ + HH(a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ + HH(d, a, b, c, x[0], S32, 0xeaa127fa); /* 42 */ + HH(c, d, a, b, x[3], S33, 0xd4ef3085); /* 43 */ + HH(b, c, d, a, x[6], S34, 0x4881d05); /* 44 */ + HH(a, b, c, d, x[9], S31, 0xd9d4d039); /* 45 */ + HH(d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ + HH(c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ + HH(b, c, d, a, x[2], S34, 0xc4ac5665); /* 48 */ + + /* Round 4 */ + II(a, b, c, d, x[0], S41, 0xf4292244); /* 49 */ + II(d, a, b, c, x[7], S42, 0x432aff97); /* 50 */ + II(c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ + II(b, c, d, a, x[5], S44, 0xfc93a039); /* 52 */ + II(a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ + II(d, a, b, c, x[3], S42, 0x8f0ccc92); /* 54 */ + II(c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ + II(b, c, d, a, x[1], S44, 0x85845dd1); /* 56 */ + II(a, b, c, d, x[8], S41, 0x6fa87e4f); /* 57 */ + II(d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ + II(c, d, a, b, x[6], S43, 0xa3014314); /* 59 */ + II(b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ + II(a, b, c, d, x[4], S41, 0xf7537e82); /* 61 */ + II(d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ + II(c, d, a, b, x[2], S43, 0x2ad7d2bb); /* 63 */ + II(b, c, d, a, x[9], S44, 0xeb86d391); /* 64 */ + + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + +#if !APR_IS_BIGENDIAN + if (x == tmpbuf) +#endif + { + /* Zeroize sensitive information. */ + memset(tmpbuf, 0, sizeof(tmpbuf)); + } +} + +/* Encodes input (apr_uint32_t) into output (unsigned char). Assumes len is + * a multiple of 4. + */ +static void Encode(unsigned char *output, const apr_uint32_t *input, + unsigned int len) +{ + unsigned int i, j; + apr_uint32_t k; + + for (i = 0, j = 0; j < len; i++, j += 4) { + k = input[i]; + output[j] = (unsigned char)(k & 0xff); + output[j + 1] = (unsigned char)((k >> 8) & 0xff); + output[j + 2] = (unsigned char)((k >> 16) & 0xff); + output[j + 3] = (unsigned char)((k >> 24) & 0xff); + } +} + +/* Decodes input (unsigned char) into output (apr_uint32_t). Assumes len is + * a multiple of 4. + */ +static void Decode(apr_uint32_t *output, const unsigned char *input, + unsigned int len) +{ + unsigned int i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) + output[i] = ((apr_uint32_t)input[j]) | + (((apr_uint32_t)input[j + 1]) << 8) | + (((apr_uint32_t)input[j + 2]) << 16) | + (((apr_uint32_t)input[j + 3]) << 24); +} + +#if APR_CHARSET_EBCDIC +APR_DECLARE(apr_status_t) apr_MD5InitEBCDIC(apr_xlate_t *xlate) +{ + xlate_ebcdic_to_ascii = xlate; + return APR_SUCCESS; +} +#endif + +/* + * Define the Magic String prefix that identifies a password as being + * hashed using our algorithm. + */ +static const char * const apr1_id = "$apr1$"; + +/* + * The following MD5 password encryption code was largely borrowed from + * the FreeBSD 3.0 /usr/src/lib/libcrypt/crypt.c file, which is + * licenced as stated at the top of this file. + */ + +static void to64(char *s, unsigned long v, int n) +{ + static unsigned char itoa64[] = /* 0 ... 63 => ASCII - 64 */ + "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + + while (--n >= 0) { + *s++ = itoa64[v&0x3f]; + v >>= 6; + } +} + +APR_DECLARE(apr_status_t) apr_md5_encode(const char *pw, const char *salt, + char *result, apr_size_t nbytes) +{ + /* + * Minimum size is 8 bytes for salt, plus 1 for the trailing NUL, + * plus 4 for the '$' separators, plus the password hash itself. + * Let's leave a goodly amount of leeway. + */ + + char passwd[120], *p; + const char *sp, *ep; + unsigned char final[APR_MD5_DIGESTSIZE]; + apr_ssize_t sl, pl, i; + apr_md5_ctx_t ctx, ctx1; + unsigned long l; + + /* + * Refine the salt first. It's possible we were given an already-hashed + * string as the salt argument, so extract the actual salt value from it + * if so. Otherwise just use the string up to the first '$' as the salt. + */ + sp = salt; + + /* + * If it starts with the magic string, then skip that. + */ + if (!strncmp(sp, apr1_id, strlen(apr1_id))) { + sp += strlen(apr1_id); + } + + /* + * It stops at the first '$' or 8 chars, whichever comes first + */ + for (ep = sp; (*ep != '\0') && (*ep != '$') && (ep < (sp + 8)); ep++) { + continue; + } + + /* + * Get the length of the true salt + */ + sl = ep - sp; + + /* + * 'Time to make the doughnuts..' + */ + apr_md5_init(&ctx); +#if APR_CHARSET_EBCDIC + apr_md5_set_xlate(&ctx, xlate_ebcdic_to_ascii); +#endif + + /* + * The password first, since that is what is most unknown + */ + apr_md5_update(&ctx, pw, strlen(pw)); + + /* + * Then our magic string + */ + apr_md5_update(&ctx, apr1_id, strlen(apr1_id)); + + /* + * Then the raw salt + */ + apr_md5_update(&ctx, sp, sl); + + /* + * Then just as many characters of the MD5(pw, salt, pw) + */ + apr_md5_init(&ctx1); +#if APR_CHARSET_EBCDIC + apr_md5_set_xlate(&ctx1, xlate_ebcdic_to_ascii); +#endif + apr_md5_update(&ctx1, pw, strlen(pw)); + apr_md5_update(&ctx1, sp, sl); + apr_md5_update(&ctx1, pw, strlen(pw)); + apr_md5_final(final, &ctx1); + for (pl = strlen(pw); pl > 0; pl -= APR_MD5_DIGESTSIZE) { + md5_update_buffer(&ctx, final, + (pl > APR_MD5_DIGESTSIZE) ? APR_MD5_DIGESTSIZE : pl, SKIP_XLATE); + } + + /* + * Don't leave anything around in vm they could use. + */ + memset(final, 0, sizeof(final)); + + /* + * Then something really weird... + */ + for (i = strlen(pw); i != 0; i >>= 1) { + if (i & 1) { + md5_update_buffer(&ctx, final, 1, SKIP_XLATE); + } + else { + apr_md5_update(&ctx, pw, 1); + } + } + + /* + * Now make the output string. We know our limitations, so we + * can use the string routines without bounds checking. + */ + strcpy(passwd, apr1_id); + strncat(passwd, sp, sl); + strcat(passwd, "$"); + + apr_md5_final(final, &ctx); + + /* + * And now, just to make sure things don't run too fast.. + * On a 60 Mhz Pentium this takes 34 msec, so you would + * need 30 seconds to build a 1000 entry dictionary... + */ + for (i = 0; i < 1000; i++) { + apr_md5_init(&ctx1); + /* + * apr_md5_final clears out ctx1.xlate at the end of each loop, + * so need to to set it each time through + */ +#if APR_CHARSET_EBCDIC + apr_md5_set_xlate(&ctx1, xlate_ebcdic_to_ascii); +#endif + if (i & 1) { + apr_md5_update(&ctx1, pw, strlen(pw)); + } + else { + md5_update_buffer(&ctx1, final, APR_MD5_DIGESTSIZE, SKIP_XLATE); + } + if (i % 3) { + apr_md5_update(&ctx1, sp, sl); + } + + if (i % 7) { + apr_md5_update(&ctx1, pw, strlen(pw)); + } + + if (i & 1) { + md5_update_buffer(&ctx1, final, APR_MD5_DIGESTSIZE, SKIP_XLATE); + } + else { + apr_md5_update(&ctx1, pw, strlen(pw)); + } + apr_md5_final(final,&ctx1); + } + + p = passwd + strlen(passwd); + + l = (final[ 0]<<16) | (final[ 6]<<8) | final[12]; to64(p, l, 4); p += 4; + l = (final[ 1]<<16) | (final[ 7]<<8) | final[13]; to64(p, l, 4); p += 4; + l = (final[ 2]<<16) | (final[ 8]<<8) | final[14]; to64(p, l, 4); p += 4; + l = (final[ 3]<<16) | (final[ 9]<<8) | final[15]; to64(p, l, 4); p += 4; + l = (final[ 4]<<16) | (final[10]<<8) | final[ 5]; to64(p, l, 4); p += 4; + l = final[11] ; to64(p, l, 2); p += 2; + *p = '\0'; + + /* + * Don't leave anything around in vm they could use. + */ + memset(final, 0, sizeof(final)); + + apr_cpystrn(result, passwd, nbytes - 1); + return APR_SUCCESS; +} diff --git a/crypto/apr_passwd.c b/crypto/apr_passwd.c new file mode 100644 index 00000000000..01e9860b857 --- /dev/null +++ b/crypto/apr_passwd.c @@ -0,0 +1,226 @@ +/* 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_strings.h" +#include "apr_md5.h" +#include "apr_lib.h" +#include "apr_private.h" +#include "apr_sha1.h" +#include "crypt_blowfish.h" + +#if APR_HAVE_STRING_H +#include <string.h> +#endif +#if APR_HAVE_CRYPT_H +#include <crypt.h> +#endif +#if APR_HAVE_UNISTD_H +#include <unistd.h> +#endif +#if APR_HAVE_PTHREAD_H +#include <pthread.h> +#endif +#if APR_HAVE_STDLIB_H +#include <stdlib.h> +#endif + +static const char * const apr1_id = "$apr1$"; + +#if !defined(WIN32) && !defined(BEOS) && !defined(NETWARE) +#if defined(APU_CRYPT_THREADSAFE) || !APR_HAS_THREADS || \ + defined(CRYPT_R_CRYPTD) || defined(CRYPT_R_STRUCT_CRYPT_DATA) + +#define crypt_mutex_lock() +#define crypt_mutex_unlock() + +#elif APR_HAVE_PTHREAD_H && defined(PTHREAD_MUTEX_INITIALIZER) + +static pthread_mutex_t crypt_mutex = PTHREAD_MUTEX_INITIALIZER; +static void crypt_mutex_lock(void) +{ + pthread_mutex_lock(&crypt_mutex); +} + +static void crypt_mutex_unlock(void) +{ + pthread_mutex_unlock(&crypt_mutex); +} + +#elif defined(OS2) + +static HMTX crypt_mutex = 0; +static void crypt_mutex_lock() +{ + if (crypt_mutex == 0) { + /* Prevent race condition where two threads could try to create the + * mutex concurrently + */ + DosEnterCritSec(); + + if (crypt_mutex == 0) { + DosCreateMutexSem(NULL, &crypt_mutex, 0, FALSE); + } + + DosExitCritSec(); + } + + DosRequestMutexSem(crypt_mutex, SEM_INDEFINITE_WAIT); +} + +static void crypt_mutex_unlock() +{ + DosReleaseMutexSem(crypt_mutex); +} + +#else + +#error apr_password_validate() is not threadsafe. rebuild APR without thread support. + +#endif +#endif + +#if defined(WIN32) || defined(BEOS) || defined(NETWARE) || defined(__ANDROID__) +#define CRYPT_MISSING 1 +#else +#define CRYPT_MISSING 0 +#endif + +/* + * Validate a plaintext password against a smashed one. Uses either + * crypt() (if available) or apr_md5_encode() or apr_sha1_base64(), depending + * upon the format of the smashed input password. Returns APR_SUCCESS if + * they match, or APR_EMISMATCH if they don't. If the platform doesn't + * support crypt, then the default check is against a clear text string. + */ +APR_DECLARE(apr_status_t) apr_password_validate(const char *passwd, + const char *hash) +{ + char sample[200]; +#if !CRYPT_MISSING + char *crypt_pw; +#endif + if (hash[0] == '$' + && hash[1] == '2' + && (hash[2] == 'a' || hash[2] == 'y') + && hash[3] == '$') { + if (_crypt_blowfish_rn(passwd, hash, sample, sizeof(sample)) == NULL) + return APR_FROM_OS_ERROR(errno); + } + else if (!strncmp(hash, apr1_id, strlen(apr1_id))) { + /* + * The hash was created using our custom algorithm. + */ + apr_md5_encode(passwd, hash, sample, sizeof(sample)); + } + else if (!strncmp(hash, APR_SHA1PW_ID, APR_SHA1PW_IDLEN)) { + apr_sha1_base64(passwd, (int)strlen(passwd), sample); + } + else { + /* + * It's not our algorithm, so feed it to crypt() if possible. + */ +#if CRYPT_MISSING + return (strcmp(passwd, hash) == 0) ? APR_SUCCESS : APR_EMISMATCH; +#elif defined(CRYPT_R_CRYPTD) + apr_status_t rv; + CRYPTD *buffer = malloc(sizeof(*buffer)); + + if (buffer == NULL) + return APR_ENOMEM; + crypt_pw = crypt_r(passwd, hash, buffer); + if (!crypt_pw) + rv = APR_EMISMATCH; + else + rv = (strcmp(crypt_pw, hash) == 0) ? APR_SUCCESS : APR_EMISMATCH; + free(buffer); + return rv; +#elif defined(CRYPT_R_STRUCT_CRYPT_DATA) + apr_status_t rv; + struct crypt_data *buffer = malloc(sizeof(*buffer)); + + if (buffer == NULL) + return APR_ENOMEM; + +#ifdef __GLIBC_PREREQ + /* + * For not too old glibc (>= 2.3.2), it's enough to set + * buffer.initialized = 0. For < 2.3.2 and for other platforms, + * we need to zero the whole struct. + */ +#if __GLIBC_PREREQ(2,4) +#define USE_CRYPT_DATA_INITALIZED +#endif +#endif + +#ifdef USE_CRYPT_DATA_INITALIZED + buffer->initialized = 0; +#else + memset(buffer, 0, sizeof(*buffer)); +#endif + + crypt_pw = crypt_r(passwd, hash, buffer); + if (!crypt_pw) + rv = APR_EMISMATCH; + else + rv = (strcmp(crypt_pw, hash) == 0) ? APR_SUCCESS : APR_EMISMATCH; + free(buffer); + return rv; +#else + /* Do a bit of sanity checking since we know that crypt_r() + * should always be used for threaded builds on AIX, and + * problems in configure logic can result in the wrong + * choice being made. + */ +#if defined(_AIX) && APR_HAS_THREADS +#error Configuration error! crypt_r() should have been selected! +#endif + { + apr_status_t rv; + + /* Handle thread safety issues by holding a mutex around the + * call to crypt(). + */ + crypt_mutex_lock(); + crypt_pw = crypt(passwd, hash); + if (!crypt_pw) { + rv = APR_EMISMATCH; + } + else { + rv = (strcmp(crypt_pw, hash) == 0) ? APR_SUCCESS : APR_EMISMATCH; + } + crypt_mutex_unlock(); + return rv; + } +#endif + } + return (strcmp(sample, hash) == 0) ? APR_SUCCESS : APR_EMISMATCH; +} + +static const char * const bcrypt_id = "$2y$"; +APR_DECLARE(apr_status_t) apr_bcrypt_encode(const char *pw, + unsigned int count, + const unsigned char *salt, + apr_size_t salt_len, + char *out, apr_size_t out_len) +{ + char setting[40]; + if (_crypt_gensalt_blowfish_rn(bcrypt_id, count, (const char *)salt, + salt_len, setting, sizeof(setting)) == NULL) + return APR_FROM_OS_ERROR(errno); + if (_crypt_blowfish_rn(pw, setting, out, out_len) == NULL) + return APR_FROM_OS_ERROR(errno); + return APR_SUCCESS; +} diff --git a/crypto/apr_sha1.c b/crypto/apr_sha1.c new file mode 100644 index 00000000000..4ac8b73afdb --- /dev/null +++ b/crypto/apr_sha1.c @@ -0,0 +1,368 @@ +/* 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 exported function: + * + * apr_sha1_base64(const char *clear, int len, char *out); + * + * provides a means to SHA1 crypt/encode a plaintext password in + * a way which makes password files compatible with those commonly + * used in netscape web and ldap installations. It was put together + * by Clinton Wong <clintdw@netcom.com>, who also notes that: + * + * Note: SHA1 support is useful for migration purposes, but is less + * secure than Apache's password format, since Apache's (MD5) + * password format uses a random eight character salt to generate + * one of many possible hashes for the same password. Netscape + * uses plain SHA1 without a salt, so the same password + * will always generate the same hash, making it easier + * to break since the search space is smaller. + * + * See also the documentation in support/SHA1 as to hints on how to + * migrate an existing netscape installation and other supplied utitlites. + * + * This software also makes use of the following component: + * + * NIST Secure Hash Algorithm + * heavily modified by Uwe Hollerbach uh@alumni.caltech edu + * from Peter C. Gutmann's implementation as found in + * Applied Cryptography by Bruce Schneier + * This code is hereby placed in the public domain + */ + +#include "apr_sha1.h" +#include "apr_base64.h" +#include "apr_strings.h" +#include "apr_lib.h" +#if APR_CHARSET_EBCDIC +#include "apr_xlate.h" +#endif /*APR_CHARSET_EBCDIC*/ +#include <string.h> + +/* a bit faster & bigger, if defined */ +#define UNROLL_LOOPS + +/* NIST's proposed modification to SHA, 7/11/94 */ +#define USE_MODIFIED_SHA + +/* SHA f()-functions */ +#define f1(x,y,z) ((x & y) | (~x & z)) +#define f2(x,y,z) (x ^ y ^ z) +#define f3(x,y,z) ((x & y) | (x & z) | (y & z)) +#define f4(x,y,z) (x ^ y ^ z) + +/* SHA constants */ +#define CONST1 0x5a827999L +#define CONST2 0x6ed9eba1L +#define CONST3 0x8f1bbcdcL +#define CONST4 0xca62c1d6L + +/* 32-bit rotate */ + +#define ROT32(x,n) ((x << n) | (x >> (32 - n))) + +#define FUNC(n,i) \ + temp = ROT32(A,5) + f##n(B,C,D) + E + W[i] + CONST##n; \ + E = D; D = C; C = ROT32(B,30); B = A; A = temp + +#define SHA_BLOCKSIZE 64 + +#if APR_CHARSET_EBCDIC +static apr_xlate_t *ebcdic2ascii_xlate; + +APR_DECLARE(apr_status_t) apr_SHA1InitEBCDIC(apr_xlate_t *x) +{ + apr_status_t rv; + int onoff; + + /* Only single-byte conversion is supported. + */ + rv = apr_xlate_sb_get(x, &onoff); + if (rv) { + return rv; + } + if (!onoff) { /* If conversion is not single-byte-only */ + return APR_EINVAL; + } + ebcdic2ascii_xlate = x; + return APR_SUCCESS; +} +#endif + +/* do SHA transformation */ +static void sha_transform(apr_sha1_ctx_t *sha_info) +{ + int i; + apr_uint32_t temp, A, B, C, D, E, W[80]; + + for (i = 0; i < 16; ++i) { + W[i] = sha_info->data[i]; + } + for (i = 16; i < 80; ++i) { + W[i] = W[i-3] ^ W[i-8] ^ W[i-14] ^ W[i-16]; +#ifdef USE_MODIFIED_SHA + W[i] = ROT32(W[i], 1); +#endif /* USE_MODIFIED_SHA */ + } + A = sha_info->digest[0]; + B = sha_info->digest[1]; + C = sha_info->digest[2]; + D = sha_info->digest[3]; + E = sha_info->digest[4]; +#ifdef UNROLL_LOOPS + FUNC(1, 0); FUNC(1, 1); FUNC(1, 2); FUNC(1, 3); FUNC(1, 4); + FUNC(1, 5); FUNC(1, 6); FUNC(1, 7); FUNC(1, 8); FUNC(1, 9); + FUNC(1,10); FUNC(1,11); FUNC(1,12); FUNC(1,13); FUNC(1,14); + FUNC(1,15); FUNC(1,16); FUNC(1,17); FUNC(1,18); FUNC(1,19); + + FUNC(2,20); FUNC(2,21); FUNC(2,22); FUNC(2,23); FUNC(2,24); + FUNC(2,25); FUNC(2,26); FUNC(2,27); FUNC(2,28); FUNC(2,29); + FUNC(2,30); FUNC(2,31); FUNC(2,32); FUNC(2,33); FUNC(2,34); + FUNC(2,35); FUNC(2,36); FUNC(2,37); FUNC(2,38); FUNC(2,39); + + FUNC(3,40); FUNC(3,41); FUNC(3,42); FUNC(3,43); FUNC(3,44); + FUNC(3,45); FUNC(3,46); FUNC(3,47); FUNC(3,48); FUNC(3,49); + FUNC(3,50); FUNC(3,51); FUNC(3,52); FUNC(3,53); FUNC(3,54); + FUNC(3,55); FUNC(3,56); FUNC(3,57); FUNC(3,58); FUNC(3,59); + + FUNC(4,60); FUNC(4,61); FUNC(4,62); FUNC(4,63); FUNC(4,64); + FUNC(4,65); FUNC(4,66); FUNC(4,67); FUNC(4,68); FUNC(4,69); + FUNC(4,70); FUNC(4,71); FUNC(4,72); FUNC(4,73); FUNC(4,74); + FUNC(4,75); FUNC(4,76); FUNC(4,77); FUNC(4,78); FUNC(4,79); +#else /* !UNROLL_LOOPS */ + for (i = 0; i < 20; ++i) { + FUNC(1,i); + } + for (i = 20; i < 40; ++i) { + FUNC(2,i); + } + for (i = 40; i < 60; ++i) { + FUNC(3,i); + } + for (i = 60; i < 80; ++i) { + FUNC(4,i); + } +#endif /* !UNROLL_LOOPS */ + sha_info->digest[0] += A; + sha_info->digest[1] += B; + sha_info->digest[2] += C; + sha_info->digest[3] += D; + sha_info->digest[4] += E; +} + +union endianTest { + long Long; + char Char[sizeof(long)]; +}; + +static char isLittleEndian(void) +{ + static union endianTest u; + u.Long = 1; + return (u.Char[0] == 1); +} + +/* change endianness of data */ + +/* count is the number of bytes to do an endian flip */ +static void maybe_byte_reverse(apr_uint32_t *buffer, int count) +{ + int i; + apr_byte_t ct[4], *cp; + + if (isLittleEndian()) { /* do the swap only if it is little endian */ + count /= sizeof(apr_uint32_t); + cp = (apr_byte_t *) buffer; + for (i = 0; i < count; ++i) { + ct[0] = cp[0]; + ct[1] = cp[1]; + ct[2] = cp[2]; + ct[3] = cp[3]; + cp[0] = ct[3]; + cp[1] = ct[2]; + cp[2] = ct[1]; + cp[3] = ct[0]; + cp += sizeof(apr_uint32_t); + } + } +} + +/* initialize the SHA digest */ + +APR_DECLARE(void) apr_sha1_init(apr_sha1_ctx_t *sha_info) +{ + sha_info->digest[0] = 0x67452301L; + sha_info->digest[1] = 0xefcdab89L; + sha_info->digest[2] = 0x98badcfeL; + sha_info->digest[3] = 0x10325476L; + sha_info->digest[4] = 0xc3d2e1f0L; + sha_info->count_lo = 0L; + sha_info->count_hi = 0L; + sha_info->local = 0; +} + +/* update the SHA digest */ + +APR_DECLARE(void) apr_sha1_update_binary(apr_sha1_ctx_t *sha_info, + const unsigned char *buffer, + unsigned int count) +{ + unsigned int i; + + if ((sha_info->count_lo + ((apr_uint32_t) count << 3)) < sha_info->count_lo) { + ++sha_info->count_hi; + } + sha_info->count_lo += (apr_uint32_t) count << 3; + sha_info->count_hi += (apr_uint32_t) count >> 29; + if (sha_info->local) { + i = SHA_BLOCKSIZE - sha_info->local; + if (i > count) { + i = count; + } + memcpy(((apr_byte_t *) sha_info->data) + sha_info->local, buffer, i); + count -= i; + buffer += i; + sha_info->local += i; + if (sha_info->local == SHA_BLOCKSIZE) { + maybe_byte_reverse(sha_info->data, SHA_BLOCKSIZE); + sha_transform(sha_info); + } + else { + return; + } + } + while (count >= SHA_BLOCKSIZE) { + memcpy(sha_info->data, buffer, SHA_BLOCKSIZE); + buffer += SHA_BLOCKSIZE; + count -= SHA_BLOCKSIZE; + maybe_byte_reverse(sha_info->data, SHA_BLOCKSIZE); + sha_transform(sha_info); + } + memcpy(sha_info->data, buffer, count); + sha_info->local = count; +} + +APR_DECLARE(void) apr_sha1_update(apr_sha1_ctx_t *sha_info, const char *buf, + unsigned int count) +{ +#if APR_CHARSET_EBCDIC + int i; + const apr_byte_t *buffer = (const apr_byte_t *) buf; + apr_size_t inbytes_left, outbytes_left; + + if ((sha_info->count_lo + ((apr_uint32_t) count << 3)) < sha_info->count_lo) { + ++sha_info->count_hi; + } + sha_info->count_lo += (apr_uint32_t) count << 3; + sha_info->count_hi += (apr_uint32_t) count >> 29; + /* Is there a remainder of the previous Update operation? */ + if (sha_info->local) { + i = SHA_BLOCKSIZE - sha_info->local; + if (i > count) { + i = count; + } + inbytes_left = outbytes_left = i; + apr_xlate_conv_buffer(ebcdic2ascii_xlate, buffer, &inbytes_left, + ((apr_byte_t *) sha_info->data) + sha_info->local, + &outbytes_left); + count -= i; + buffer += i; + sha_info->local += i; + if (sha_info->local == SHA_BLOCKSIZE) { + maybe_byte_reverse(sha_info->data, SHA_BLOCKSIZE); + sha_transform(sha_info); + } + else { + return; + } + } + while (count >= SHA_BLOCKSIZE) { + inbytes_left = outbytes_left = SHA_BLOCKSIZE; + apr_xlate_conv_buffer(ebcdic2ascii_xlate, buffer, &inbytes_left, + (apr_byte_t *) sha_info->data, &outbytes_left); + buffer += SHA_BLOCKSIZE; + count -= SHA_BLOCKSIZE; + maybe_byte_reverse(sha_info->data, SHA_BLOCKSIZE); + sha_transform(sha_info); + } + inbytes_left = outbytes_left = count; + apr_xlate_conv_buffer(ebcdic2ascii_xlate, buffer, &inbytes_left, + (apr_byte_t *) sha_info->data, &outbytes_left); + sha_info->local = count; +#else + apr_sha1_update_binary(sha_info, (const unsigned char *) buf, count); +#endif +} + +/* finish computing the SHA digest */ + +APR_DECLARE(void) apr_sha1_final(unsigned char digest[APR_SHA1_DIGESTSIZE], + apr_sha1_ctx_t *sha_info) +{ + int count, i, j; + apr_uint32_t lo_bit_count, hi_bit_count, k; + + lo_bit_count = sha_info->count_lo; + hi_bit_count = sha_info->count_hi; + count = (int) ((lo_bit_count >> 3) & 0x3f); + ((apr_byte_t *) sha_info->data)[count++] = 0x80; + if (count > SHA_BLOCKSIZE - 8) { + memset(((apr_byte_t *) sha_info->data) + count, 0, SHA_BLOCKSIZE - count); + maybe_byte_reverse(sha_info->data, SHA_BLOCKSIZE); + sha_transform(sha_info); + memset((apr_byte_t *) sha_info->data, 0, SHA_BLOCKSIZE - 8); + } + else { + memset(((apr_byte_t *) sha_info->data) + count, 0, + SHA_BLOCKSIZE - 8 - count); + } + maybe_byte_reverse(sha_info->data, SHA_BLOCKSIZE); + sha_info->data[14] = hi_bit_count; + sha_info->data[15] = lo_bit_count; + sha_transform(sha_info); + + for (i = 0, j = 0; j < APR_SHA1_DIGESTSIZE; i++) { + k = sha_info->digest[i]; + digest[j++] = (unsigned char) ((k >> 24) & 0xff); + digest[j++] = (unsigned char) ((k >> 16) & 0xff); + digest[j++] = (unsigned char) ((k >> 8) & 0xff); + digest[j++] = (unsigned char) (k & 0xff); + } +} + + +APR_DECLARE(void) apr_sha1_base64(const char *clear, int len, char *out) +{ + int l; + apr_sha1_ctx_t context; + apr_byte_t digest[APR_SHA1_DIGESTSIZE]; + + apr_sha1_init(&context); + apr_sha1_update(&context, clear, len); + apr_sha1_final(digest, &context); + + /* private marker. */ + apr_cpystrn(out, APR_SHA1PW_ID, APR_SHA1PW_IDLEN + 1); + + /* SHA1 hash is always 20 chars */ + l = apr_base64_encode_binary(out + APR_SHA1PW_IDLEN, digest, sizeof(digest)); + out[l + APR_SHA1PW_IDLEN] = '\0'; + + /* + * output of base64 encoded SHA1 is always 28 chars + APR_SHA1PW_IDLEN + */ +} diff --git a/crypto/apr_siphash.c b/crypto/apr_siphash.c new file mode 100644 index 00000000000..41cff70f231 --- /dev/null +++ b/crypto/apr_siphash.c @@ -0,0 +1,196 @@ +/* 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. + */ + +/* + * SipHash (C reference implementation, APR-ized), originating from: + * https://131002.net/siphash/siphash24.c. + */ + +#include "apr_siphash.h" + +#define ROTL64(x, n) (((x) << (n)) | ((x) >> (64 - (n)))) + +#define U8TO64_LE(p) \ + (((apr_uint64_t)((p)[0]) ) | \ + ((apr_uint64_t)((p)[1]) << 8) | \ + ((apr_uint64_t)((p)[2]) << 16) | \ + ((apr_uint64_t)((p)[3]) << 24) | \ + ((apr_uint64_t)((p)[4]) << 32) | \ + ((apr_uint64_t)((p)[5]) << 40) | \ + ((apr_uint64_t)((p)[6]) << 48) | \ + ((apr_uint64_t)((p)[7]) << 56)) + +#define U64TO8_LE(p, v) \ +do { \ + (p)[0] = (unsigned char)((v) ); \ + (p)[1] = (unsigned char)((v) >> 8); \ + (p)[2] = (unsigned char)((v) >> 16); \ + (p)[3] = (unsigned char)((v) >> 24); \ + (p)[4] = (unsigned char)((v) >> 32); \ + (p)[5] = (unsigned char)((v) >> 40); \ + (p)[6] = (unsigned char)((v) >> 48); \ + (p)[7] = (unsigned char)((v) >> 56); \ +} while (0) + +#define SIPROUND() \ +do { \ + v0 += v1; v1=ROTL64(v1,13); v1 ^= v0; v0=ROTL64(v0,32); \ + v2 += v3; v3=ROTL64(v3,16); v3 ^= v2; \ + v0 += v3; v3=ROTL64(v3,21); v3 ^= v0; \ + v2 += v1; v1=ROTL64(v1,17); v1 ^= v2; v2=ROTL64(v2,32); \ +} while(0) + +#define SIPHASH(r, s, n, k) \ +do { \ + const unsigned char *ptr, *end; \ + apr_uint64_t v0, v1, v2, v3, m; \ + apr_uint64_t k0, k1; \ + unsigned int rem; \ + \ + k0 = U8TO64_LE(k + 0); \ + k1 = U8TO64_LE(k + 8); \ + v3 = k1 ^ (apr_uint64_t)0x7465646279746573ULL; \ + v2 = k0 ^ (apr_uint64_t)0x6c7967656e657261ULL; \ + v1 = k1 ^ (apr_uint64_t)0x646f72616e646f6dULL; \ + v0 = k0 ^ (apr_uint64_t)0x736f6d6570736575ULL; \ + \ + rem = (unsigned int)(n & 0x7); \ + for (ptr = s, end = ptr + n - rem; ptr < end; ptr += 8) { \ + m = U8TO64_LE(ptr); \ + v3 ^= m; \ + cROUNDS \ + v0 ^= m; \ + } \ + m = (apr_uint64_t)(n & 0xff) << 56; \ + switch (rem) { \ + case 7: m |= (apr_uint64_t)ptr[6] << 48; \ + case 6: m |= (apr_uint64_t)ptr[5] << 40; \ + case 5: m |= (apr_uint64_t)ptr[4] << 32; \ + case 4: m |= (apr_uint64_t)ptr[3] << 24; \ + case 3: m |= (apr_uint64_t)ptr[2] << 16; \ + case 2: m |= (apr_uint64_t)ptr[1] << 8; \ + case 1: m |= (apr_uint64_t)ptr[0]; \ + case 0: break; \ + } \ + v3 ^= m; \ + cROUNDS \ + v0 ^= m; \ + \ + v2 ^= 0xff; \ + dROUNDS \ + \ + r = v0 ^ v1 ^ v2 ^ v3; \ +} while (0) + +APR_DECLARE(apr_uint64_t) apr_siphash(const void *src, apr_size_t len, + const unsigned char key[APR_SIPHASH_KSIZE], + unsigned int c, unsigned int d) +{ + apr_uint64_t h; + unsigned int i; + +#undef cROUNDS +#define cROUNDS \ + for (i = 0; i < c; ++i) { \ + SIPROUND(); \ + } + +#undef dROUNDS +#define dROUNDS \ + for (i = 0; i < d; ++i) { \ + SIPROUND(); \ + } + + SIPHASH(h, src, len, key); + return h; +} + +APR_DECLARE(void) apr_siphash_auth(unsigned char out[APR_SIPHASH_DSIZE], + const void *src, apr_size_t len, + const unsigned char key[APR_SIPHASH_KSIZE], + unsigned int c, unsigned int d) +{ + apr_uint64_t h; + h = apr_siphash(src, len, key, c, d); + U64TO8_LE(out, h); +} + +APR_DECLARE(apr_uint64_t) apr_siphash24(const void *src, apr_size_t len, + const unsigned char key[APR_SIPHASH_KSIZE]) +{ + apr_uint64_t h; + +#undef cROUNDS +#define cROUNDS \ + SIPROUND(); \ + SIPROUND(); + +#undef dROUNDS +#define dROUNDS \ + SIPROUND(); \ + SIPROUND(); \ + SIPROUND(); \ + SIPROUND(); + + SIPHASH(h, src, len, key); + return h; +} + +APR_DECLARE(void) apr_siphash24_auth(unsigned char out[APR_SIPHASH_DSIZE], + const void *src, apr_size_t len, + const unsigned char key[APR_SIPHASH_KSIZE]) +{ + apr_uint64_t h; + h = apr_siphash24(src, len, key); + U64TO8_LE(out, h); +} + +APR_DECLARE(apr_uint64_t) apr_siphash48(const void *src, apr_size_t len, + const unsigned char key[APR_SIPHASH_KSIZE]) +{ + apr_uint64_t h; + +#undef cROUNDS +#define cROUNDS \ + SIPROUND(); \ + SIPROUND(); \ + SIPROUND(); \ + SIPROUND(); + +#undef dROUNDS +#define dROUNDS \ + SIPROUND(); \ + SIPROUND(); \ + SIPROUND(); \ + SIPROUND(); \ + SIPROUND(); \ + SIPROUND(); \ + SIPROUND(); \ + SIPROUND(); + + SIPHASH(h, src, len, key); + return h; +} + +APR_DECLARE(void) apr_siphash48_auth(unsigned char out[APR_SIPHASH_DSIZE], + const void *src, apr_size_t len, + const unsigned char key[APR_SIPHASH_KSIZE]) +{ + apr_uint64_t h; + h = apr_siphash48(src, len, key); + U64TO8_LE(out, h); +} + diff --git a/crypto/crypt_blowfish.c b/crypto/crypt_blowfish.c new file mode 100644 index 00000000000..3d306cf8d3f --- /dev/null +++ b/crypto/crypt_blowfish.c @@ -0,0 +1,902 @@ +/* + * The crypt_blowfish homepage is: + * + * http://www.openwall.com/crypt/ + * + * This code comes from John the Ripper password cracker, with reentrant + * and crypt(3) interfaces added, but optimizations specific to password + * cracking removed. + * + * Written by Solar Designer <solar at openwall.com> in 1998-2011. + * No copyright is claimed, and the software is hereby placed in the public + * domain. In case this attempt to disclaim copyright and place the software + * in the public domain is deemed null and void, then the software is + * Copyright (c) 1998-2011 Solar Designer and it is hereby released to the + * general public under the following terms: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + * There's ABSOLUTELY NO WARRANTY, express or implied. + * + * It is my intent that you should be able to use this on your system, + * as part of a software package, or anywhere else to improve security, + * ensure compatibility, or for any other purpose. I would appreciate + * it if you give credit where it is due and keep your modifications in + * the public domain as well, but I don't require that in order to let + * you place this code and any modifications you make under a license + * of your choice. + * + * This implementation is mostly compatible with OpenBSD's bcrypt.c (prefix + * "$2a$") by Niels Provos <provos at citi.umich.edu>, and uses some of his + * ideas. The password hashing algorithm was designed by David Mazieres + * <dm at lcs.mit.edu>. For more information on the level of compatibility, + * prefer refer to the comments in BF_set_key() below and to the included + * crypt(3) man page. + * + * There's a paper on the algorithm that explains its design decisions: + * + * http://www.usenix.org/events/usenix99/provos.html + * + * Some of the tricks in BF_ROUND might be inspired by Eric Young's + * Blowfish library (I can't be sure if I would think of something if I + * hadn't seen his code). + */ + +#include <string.h> + +#include <errno.h> +#ifndef __set_errno +#define __set_errno(val) errno = (val) +#endif + +/* Just to make sure the prototypes match the actual definitions */ +#include "crypt_blowfish.h" + +#ifdef __i386__ +#define BF_ASM 0 +#define BF_SCALE 1 +#elif defined(__x86_64__) || defined(__alpha__) || defined(__hppa__) +#define BF_ASM 0 +#define BF_SCALE 1 +#else +#define BF_ASM 0 +#define BF_SCALE 0 +#endif + +typedef unsigned int BF_word; +typedef signed int BF_word_signed; + +/* Number of Blowfish rounds, this is also hardcoded into a few places */ +#define BF_N 16 + +typedef BF_word BF_key[BF_N + 2]; + +typedef struct { + BF_word S[4][0x100]; + BF_key P; +} BF_ctx; + +/* + * Magic IV for 64 Blowfish encryptions that we do at the end. + * The string is "OrpheanBeholderScryDoubt" on big-endian. + */ +static BF_word BF_magic_w[6] = { + 0x4F727068, 0x65616E42, 0x65686F6C, + 0x64657253, 0x63727944, 0x6F756274 +}; + +/* + * P-box and S-box tables initialized with digits of Pi. + */ +static BF_ctx BF_init_state = { + { + { + 0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, + 0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99, + 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16, + 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, + 0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee, + 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013, + 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, + 0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e, + 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60, + 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, + 0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce, + 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a, + 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, + 0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677, + 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193, + 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, + 0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88, + 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239, + 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, + 0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0, + 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3, + 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, + 0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88, + 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe, + 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, + 0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d, + 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b, + 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, + 0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba, + 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463, + 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, + 0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09, + 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3, + 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, + 0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279, + 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8, + 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, + 0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82, + 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db, + 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, + 0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0, + 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b, + 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, + 0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8, + 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4, + 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, + 0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7, + 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c, + 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, + 0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1, + 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299, + 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, + 0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477, + 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf, + 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, + 0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af, + 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa, + 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, + 0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41, + 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915, + 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, + 0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915, + 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664, + 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a + }, { + 0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, + 0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266, + 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, + 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, + 0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6, + 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1, + 0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, + 0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1, + 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, + 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, + 0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff, + 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd, + 0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, + 0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7, + 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41, + 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, + 0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf, + 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af, + 0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, + 0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87, + 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, + 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, + 0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16, + 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd, + 0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, + 0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509, + 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, + 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, + 0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f, + 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a, + 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, + 0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960, + 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, + 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, + 0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802, + 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84, + 0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, + 0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf, + 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, + 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, + 0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50, + 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7, + 0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, + 0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281, + 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, + 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, + 0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128, + 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73, + 0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, + 0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0, + 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, + 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, + 0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3, + 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285, + 0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, + 0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061, + 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, + 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, + 0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735, + 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc, + 0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, + 0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340, + 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, + 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7 + }, { + 0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, + 0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068, + 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af, + 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, + 0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45, + 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504, + 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, + 0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb, + 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee, + 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, + 0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42, + 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b, + 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, + 0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb, + 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527, + 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, + 0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33, + 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c, + 0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, + 0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc, + 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17, + 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, + 0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b, + 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115, + 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, + 0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728, + 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0, + 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, + 0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37, + 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d, + 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, + 0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b, + 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3, + 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, + 0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d, + 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c, + 0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, + 0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9, + 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a, + 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, + 0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d, + 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc, + 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, + 0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61, + 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2, + 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, + 0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2, + 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c, + 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, + 0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633, + 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10, + 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, + 0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52, + 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027, + 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, + 0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62, + 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634, + 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, + 0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24, + 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc, + 0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, + 0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c, + 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837, + 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0 + }, { + 0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, + 0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe, + 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b, + 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, + 0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8, + 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6, + 0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, + 0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22, + 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4, + 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, + 0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9, + 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59, + 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, + 0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51, + 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28, + 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, + 0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b, + 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28, + 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, + 0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd, + 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a, + 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, + 0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb, + 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f, + 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, + 0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32, + 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680, + 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, + 0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae, + 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb, + 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, + 0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47, + 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370, + 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, + 0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84, + 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048, + 0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, + 0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd, + 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9, + 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, + 0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38, + 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f, + 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, + 0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525, + 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1, + 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, + 0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964, + 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e, + 0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, + 0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d, + 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f, + 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, + 0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02, + 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc, + 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, + 0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a, + 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6, + 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, + 0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0, + 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060, + 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, + 0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9, + 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f, + 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6 + } + }, { + 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, + 0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89, + 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c, + 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, + 0x9216d5d9, 0x8979fb1b + } +}; + +static unsigned char BF_itoa64[64 + 1] = + "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + +static unsigned char BF_atoi64[0x60] = { + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 0, 1, + 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 64, 64, 64, 64, 64, + 64, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 64, 64, 64, 64, 64, + 64, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, + 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 64, 64, 64, 64, 64 +}; + +#define BF_safe_atoi64(dst, src) \ +{ \ + tmp = (unsigned char)(src); \ + if ((unsigned int)(tmp -= 0x20) >= 0x60) return -1; \ + tmp = BF_atoi64[tmp]; \ + if (tmp > 63) return -1; \ + (dst) = tmp; \ +} + +static int BF_decode(BF_word *dst, const char *src, int size) +{ + unsigned char *dptr = (unsigned char *)dst; + unsigned char *end = dptr + size; + const unsigned char *sptr = (const unsigned char *)src; + unsigned int tmp, c1, c2, c3, c4; + + do { + BF_safe_atoi64(c1, *sptr++); + BF_safe_atoi64(c2, *sptr++); + *dptr++ = (c1 << 2) | ((c2 & 0x30) >> 4); + if (dptr >= end) break; + + BF_safe_atoi64(c3, *sptr++); + *dptr++ = ((c2 & 0x0F) << 4) | ((c3 & 0x3C) >> 2); + if (dptr >= end) break; + + BF_safe_atoi64(c4, *sptr++); + *dptr++ = ((c3 & 0x03) << 6) | c4; + } while (dptr < end); + + return 0; +} + +static void BF_encode(char *dst, const BF_word *src, int size) +{ + const unsigned char *sptr = (const unsigned char *)src; + const unsigned char *end = sptr + size; + unsigned char *dptr = (unsigned char *)dst; + unsigned int c1, c2; + + do { + c1 = *sptr++; + *dptr++ = BF_itoa64[c1 >> 2]; + c1 = (c1 & 0x03) << 4; + if (sptr >= end) { + *dptr++ = BF_itoa64[c1]; + break; + } + + c2 = *sptr++; + c1 |= c2 >> 4; + *dptr++ = BF_itoa64[c1]; + c1 = (c2 & 0x0f) << 2; + if (sptr >= end) { + *dptr++ = BF_itoa64[c1]; + break; + } + + c2 = *sptr++; + c1 |= c2 >> 6; + *dptr++ = BF_itoa64[c1]; + *dptr++ = BF_itoa64[c2 & 0x3f]; + } while (sptr < end); +} + +static void BF_swap(BF_word *x, int count) +{ + static int endianness_check = 1; + char *is_little_endian = (char *)&endianness_check; + BF_word tmp; + + if (*is_little_endian) + do { + tmp = *x; + tmp = (tmp << 16) | (tmp >> 16); + *x++ = ((tmp & 0x00FF00FF) << 8) | ((tmp >> 8) & 0x00FF00FF); + } while (--count); +} + +#if BF_SCALE +/* Architectures which can shift addresses left by 2 bits with no extra cost */ +#define BF_ROUND(L, R, N) \ + tmp1 = L & 0xFF; \ + tmp2 = L >> 8; \ + tmp2 &= 0xFF; \ + tmp3 = L >> 16; \ + tmp3 &= 0xFF; \ + tmp4 = L >> 24; \ + tmp1 = data.ctx.S[3][tmp1]; \ + tmp2 = data.ctx.S[2][tmp2]; \ + tmp3 = data.ctx.S[1][tmp3]; \ + tmp3 += data.ctx.S[0][tmp4]; \ + tmp3 ^= tmp2; \ + R ^= data.ctx.P[N + 1]; \ + tmp3 += tmp1; \ + R ^= tmp3; +#else +/* Architectures with no complicated addressing modes supported */ +#define BF_INDEX(S, i) \ + (*((BF_word *)(((unsigned char *)S) + (i)))) +#define BF_ROUND(L, R, N) \ + tmp1 = L & 0xFF; \ + tmp1 <<= 2; \ + tmp2 = L >> 6; \ + tmp2 &= 0x3FC; \ + tmp3 = L >> 14; \ + tmp3 &= 0x3FC; \ + tmp4 = L >> 22; \ + tmp4 &= 0x3FC; \ + tmp1 = BF_INDEX(data.ctx.S[3], tmp1); \ + tmp2 = BF_INDEX(data.ctx.S[2], tmp2); \ + tmp3 = BF_INDEX(data.ctx.S[1], tmp3); \ + tmp3 += BF_INDEX(data.ctx.S[0], tmp4); \ + tmp3 ^= tmp2; \ + R ^= data.ctx.P[N + 1]; \ + tmp3 += tmp1; \ + R ^= tmp3; +#endif + +/* + * Encrypt one block, BF_N is hardcoded here. + */ +#define BF_ENCRYPT \ + L ^= data.ctx.P[0]; \ + BF_ROUND(L, R, 0); \ + BF_ROUND(R, L, 1); \ + BF_ROUND(L, R, 2); \ + BF_ROUND(R, L, 3); \ + BF_ROUND(L, R, 4); \ + BF_ROUND(R, L, 5); \ + BF_ROUND(L, R, 6); \ + BF_ROUND(R, L, 7); \ + BF_ROUND(L, R, 8); \ + BF_ROUND(R, L, 9); \ + BF_ROUND(L, R, 10); \ + BF_ROUND(R, L, 11); \ + BF_ROUND(L, R, 12); \ + BF_ROUND(R, L, 13); \ + BF_ROUND(L, R, 14); \ + BF_ROUND(R, L, 15); \ + tmp4 = R; \ + R = L; \ + L = tmp4 ^ data.ctx.P[BF_N + 1]; + +#if BF_ASM +#define BF_body() \ + _BF_body_r(&data.ctx); +#else +#define BF_body() \ + L = R = 0; \ + ptr = data.ctx.P; \ + do { \ + ptr += 2; \ + BF_ENCRYPT; \ + *(ptr - 2) = L; \ + *(ptr - 1) = R; \ + } while (ptr < &data.ctx.P[BF_N + 2]); \ +\ + ptr = data.ctx.S[0]; \ + do { \ + ptr += 2; \ + BF_ENCRYPT; \ + *(ptr - 2) = L; \ + *(ptr - 1) = R; \ + } while (ptr < &data.ctx.S[3][0xFF]); +#endif + +static void BF_set_key(const char *key, BF_key expanded, BF_key initial, + unsigned char flags) +{ + const char *ptr = key; + unsigned int bug, i, j; + BF_word safety, sign, diff, tmp[2]; + +/* + * There was a sign extension bug in older revisions of this function. While + * we would have liked to simply fix the bug and move on, we have to provide + * a backwards compatibility feature (essentially the bug) for some systems and + * a safety measure for some others. The latter is needed because for certain + * multiple inputs to the buggy algorithm there exist easily found inputs to + * the correct algorithm that produce the same hash. Thus, we optionally + * deviate from the correct algorithm just enough to avoid such collisions. + * While the bug itself affected the majority of passwords containing + * characters with the 8th bit set (although only a percentage of those in a + * collision-producing way), the anti-collision safety measure affects + * only a subset of passwords containing the '\xff' character (not even all of + * those passwords, just some of them). This character is not found in valid + * UTF-8 sequences and is rarely used in popular 8-bit character encodings. + * Thus, the safety measure is unlikely to cause much annoyance, and is a + * reasonable tradeoff to use when authenticating against existing hashes that + * are not reliably known to have been computed with the correct algorithm. + * + * We use an approach that tries to minimize side-channel leaks of password + * information - that is, we mostly use fixed-cost bitwise operations instead + * of branches or table lookups. (One conditional branch based on password + * length remains. It is not part of the bug aftermath, though, and is + * difficult and possibly unreasonable to avoid given the use of C strings by + * the caller, which results in similar timing leaks anyway.) + * + * For actual implementation, we set an array index in the variable "bug" + * (0 means no bug, 1 means sign extension bug emulation) and a flag in the + * variable "safety" (bit 16 is set when the safety measure is requested). + * Valid combinations of settings are: + * + * Prefix "$2a$": bug = 0, safety = 0x10000 + * Prefix "$2x$": bug = 1, safety = 0 + * Prefix "$2y$": bug = 0, safety = 0 + */ + bug = (unsigned int)flags & 1; + safety = ((BF_word)flags & 2) << 15; + + sign = diff = 0; + + for (i = 0; i < BF_N + 2; i++) { + tmp[0] = tmp[1] = 0; + for (j = 0; j < 4; j++) { + tmp[0] <<= 8; + tmp[0] |= (unsigned char)*ptr; /* correct */ + tmp[1] <<= 8; + tmp[1] |= (BF_word_signed)(signed char)*ptr; /* bug */ +/* + * Sign extension in the first char has no effect - nothing to overwrite yet, + * and those extra 24 bits will be fully shifted out of the 32-bit word. For + * chars 2, 3, 4 in each four-char block, we set bit 7 of "sign" if sign + * extension in tmp[1] occurs. Once this flag is set, it remains set. + */ + if (j) + sign |= tmp[1] & 0x80; + if (!*ptr) + ptr = key; + else + ptr++; + } + diff |= tmp[0] ^ tmp[1]; /* Non-zero on any differences */ + + expanded[i] = tmp[bug]; + initial[i] = BF_init_state.P[i] ^ tmp[bug]; + } + +/* + * At this point, "diff" is zero iff the correct and buggy algorithms produced + * exactly the same result. If so and if "sign" is non-zero, which indicates + * that there was a non-benign sign extension, this means that we have a + * collision between the correctly computed hash for this password and a set of + * passwords that could be supplied to the buggy algorithm. Our safety measure + * is meant to protect from such many-buggy to one-correct collisions, by + * deviating from the correct algorithm in such cases. Let's check for this. + */ + diff |= diff >> 16; /* still zero iff exact match */ + diff &= 0xffff; /* ditto */ + diff += 0xffff; /* bit 16 set iff "diff" was non-zero (on non-match) */ + sign <<= 9; /* move the non-benign sign extension flag to bit 16 */ + sign &= ~diff & safety; /* action needed? */ + +/* + * If we have determined that we need to deviate from the correct algorithm, + * flip bit 16 in initial expanded key. (The choice of 16 is arbitrary, but + * let's stick to it now. It came out of the approach we used above, and it's + * not any worse than any other choice we could make.) + * + * It is crucial that we don't do the same to the expanded key used in the main + * Eksblowfish loop. By doing it to only one of these two, we deviate from a + * state that could be directly specified by a password to the buggy algorithm + * (and to the fully correct one as well, but that's a side-effect). + */ + initial[0] ^= sign; +} + +static char *BF_crypt(const char *key, const char *setting, + char *output, int size, + BF_word min) +{ +#if BF_ASM + extern void _BF_body_r(BF_ctx *ctx); +#endif + static const unsigned char flags_by_subtype[26] = + {2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4, 0}; + struct { + BF_ctx ctx; + BF_key expanded_key; + union { + BF_word salt[4]; + BF_word output[6]; + } binary; + } data; + BF_word L, R; + BF_word tmp1, tmp2, tmp3, tmp4; + BF_word *ptr; + BF_word count; + int i; + + if (size < 7 + 22 + 31 + 1) { + __set_errno(ERANGE); + return NULL; + } + + if (setting[0] != '$' || + setting[1] != '2' || + setting[2] < 'a' || setting[2] > 'z' || + !flags_by_subtype[(unsigned int)(unsigned char)setting[2] - 'a'] || + setting[3] != '$' || + setting[4] < '0' || setting[4] > '1' || + setting[5] < '0' || setting[5] > '9' || + (setting[4] == '1' && setting[5] > '7') || + setting[6] != '$') { + __set_errno(EINVAL); + return NULL; + } + + count = (BF_word)1 << ((setting[4] - '0') * 10 + (setting[5] - '0')); + if (count < min || BF_decode(data.binary.salt, &setting[7], 16)) { + __set_errno(EINVAL); + return NULL; + } + BF_swap(data.binary.salt, 4); + + BF_set_key(key, data.expanded_key, data.ctx.P, + flags_by_subtype[(unsigned int)(unsigned char)setting[2] - 'a']); + + memcpy(data.ctx.S, BF_init_state.S, sizeof(data.ctx.S)); + + L = R = 0; + for (i = 0; i < BF_N + 2; i += 2) { + L ^= data.binary.salt[i & 2]; + R ^= data.binary.salt[(i & 2) + 1]; + BF_ENCRYPT; + data.ctx.P[i] = L; + data.ctx.P[i + 1] = R; + } + + ptr = data.ctx.S[0]; + do { + ptr += 4; + L ^= data.binary.salt[(BF_N + 2) & 3]; + R ^= data.binary.salt[(BF_N + 3) & 3]; + BF_ENCRYPT; + *(ptr - 4) = L; + *(ptr - 3) = R; + + L ^= data.binary.salt[(BF_N + 4) & 3]; + R ^= data.binary.salt[(BF_N + 5) & 3]; + BF_ENCRYPT; + *(ptr - 2) = L; + *(ptr - 1) = R; + } while (ptr < &data.ctx.S[3][0xFF]); + + do { + int done; + + for (i = 0; i < BF_N + 2; i += 2) { + data.ctx.P[i] ^= data.expanded_key[i]; + data.ctx.P[i + 1] ^= data.expanded_key[i + 1]; + } + + done = 0; + do { + BF_body(); + if (done) + break; + done = 1; + + tmp1 = data.binary.salt[0]; + tmp2 = data.binary.salt[1]; + tmp3 = data.binary.salt[2]; + tmp4 = data.binary.salt[3]; + for (i = 0; i < BF_N; i += 4) { + data.ctx.P[i] ^= tmp1; + data.ctx.P[i + 1] ^= tmp2; + data.ctx.P[i + 2] ^= tmp3; + data.ctx.P[i + 3] ^= tmp4; + } + data.ctx.P[16] ^= tmp1; + data.ctx.P[17] ^= tmp2; + } while (1); + } while (--count); + + for (i = 0; i < 6; i += 2) { + L = BF_magic_w[i]; + R = BF_magic_w[i + 1]; + + count = 64; + do { + BF_ENCRYPT; + } while (--count); + + data.binary.output[i] = L; + data.binary.output[i + 1] = R; + } + + memcpy(output, setting, 7 + 22 - 1); + output[7 + 22 - 1] = BF_itoa64[(int) + BF_atoi64[(int)setting[7 + 22 - 1] - 0x20] & 0x30]; + +/* This has to be bug-compatible with the original implementation, so + * only encode 23 of the 24 bytes. :-) */ + BF_swap(data.binary.output, 6); + BF_encode(&output[7 + 22], data.binary.output, 23); + output[7 + 22 + 31] = '\0'; + + return output; +} + +int _crypt_output_magic(const char *setting, char *output, int size) +{ + if (size < 3) + return -1; + + output[0] = '*'; + output[1] = '0'; + output[2] = '\0'; + + if (setting[0] == '*' && setting[1] == '0') + output[1] = '1'; + + return 0; +} + +/* + * Please preserve the runtime self-test. It serves two purposes at once: + * + * 1. We really can't afford the risk of producing incompatible hashes e.g. + * when there's something like gcc bug 26587 again, whereas an application or + * library integrating this code might not also integrate our external tests or + * it might not run them after every build. Even if it does, the miscompile + * might only occur on the production build, but not on a testing build (such + * as because of different optimization settings). It is painful to recover + * from incorrectly-computed hashes - merely fixing whatever broke is not + * enough. Thus, a proactive measure like this self-test is needed. + * + * 2. We don't want to leave sensitive data from our actual password hash + * computation on the stack or in registers. Previous revisions of the code + * would do explicit cleanups, but simply running the self-test after hash + * computation is more reliable. + * + * The performance cost of this quick self-test is around 0.6% at the "$2a$08" + * setting. + */ +char *_crypt_blowfish_rn(const char *key, const char *setting, + char *output, int size) +{ + const char *test_key = "8b \xd0\xc1\xd2\xcf\xcc\xd8"; + const char *test_setting = "$2a$00$abcdefghijklmnopqrstuu"; + static const char * const test_hash[2] = + {"VUrPmXD6q/nVSSp7pNDhCR9071IfIRe\0\x55", /* $2x$ */ + "i1D709vfamulimlGcq0qq3UvuUasvEa\0\x55"}; /* $2a$, $2y$ */ + char *retval; + const char *p; + int save_errno, ok; + struct { + char s[7 + 22 + 1]; + char o[7 + 22 + 31 + 1 + 1 + 1]; + } buf; + +/* Hash the supplied password */ + _crypt_output_magic(setting, output, size); + retval = BF_crypt(key, setting, output, size, 16); + save_errno = errno; + +/* + * Do a quick self-test. It is important that we make both calls to BF_crypt() + * from the same scope such that they likely use the same stack locations, + * which makes the second call overwrite the first call's sensitive data on the + * stack and makes it more likely that any alignment related issues would be + * detected by the self-test. + */ + memcpy(buf.s, test_setting, sizeof(buf.s)); + if (retval) + buf.s[2] = setting[2]; + memset(buf.o, 0x55, sizeof(buf.o)); + buf.o[sizeof(buf.o) - 1] = 0; + p = BF_crypt(test_key, buf.s, buf.o, sizeof(buf.o) - (1 + 1), 1); + + ok = (p == buf.o && + !memcmp(p, buf.s, 7 + 22) && + !memcmp(p + (7 + 22), + test_hash[(unsigned int)(unsigned char)buf.s[2] & 1], + 31 + 1 + 1 + 1)); + + { + const char *k = "\xff\xa3" "34" "\xff\xff\xff\xa3" "345"; + BF_key ae, ai, ye, yi; + BF_set_key(k, ae, ai, 2); /* $2a$ */ + BF_set_key(k, ye, yi, 4); /* $2y$ */ + ai[0] ^= 0x10000; /* undo the safety (for comparison) */ + ok = ok && ai[0] == 0xdb9c59bc && ye[17] == 0x33343500 && + !memcmp(ae, ye, sizeof(ae)) && + !memcmp(ai, yi, sizeof(ai)); + } + + __set_errno(save_errno); + if (ok) + return retval; + +/* Should not happen */ + _crypt_output_magic(setting, output, size); + __set_errno(EINVAL); /* pretend we don't support this hash type */ + return NULL; +} + +char *_crypt_gensalt_blowfish_rn(const char *prefix, unsigned long count, + const char *input, int size, char *output, int output_size) +{ + if (size < 16 || output_size < 7 + 22 + 1 || + (count && (count < 4 || count > 17)) || + prefix[0] != '$' || prefix[1] != '2' || + (prefix[2] != 'a' && prefix[2] != 'y')) { + if (output_size > 0) output[0] = '\0'; + __set_errno((output_size < 7 + 22 + 1) ? ERANGE : EINVAL); + return NULL; + } + + if (!count) count = 5; + + output[0] = '$'; + output[1] = '2'; + output[2] = prefix[2]; + output[3] = '$'; + output[4] = '0' + count / 10; + output[5] = '0' + count % 10; + output[6] = '$'; + + BF_encode(&output[7], (const BF_word *)input, 16); + output[7 + 22] = '\0'; + + return output; +} diff --git a/crypto/crypt_blowfish.h b/crypto/crypt_blowfish.h new file mode 100644 index 00000000000..2ee0d8c1d80 --- /dev/null +++ b/crypto/crypt_blowfish.h @@ -0,0 +1,27 @@ +/* + * Written by Solar Designer <solar at openwall.com> in 2000-2011. + * No copyright is claimed, and the software is hereby placed in the public + * domain. In case this attempt to disclaim copyright and place the software + * in the public domain is deemed null and void, then the software is + * Copyright (c) 2000-2011 Solar Designer and it is hereby released to the + * general public under the following terms: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + * There's ABSOLUTELY NO WARRANTY, express or implied. + * + * See crypt_blowfish.c for more information. + */ + +#ifndef _CRYPT_BLOWFISH_H +#define _CRYPT_BLOWFISH_H + +extern int _crypt_output_magic(const char *setting, char *output, int size); +extern char *_crypt_blowfish_rn(const char *key, const char *setting, + char *output, int size); +extern char *_crypt_gensalt_blowfish_rn(const char *prefix, + unsigned long count, + const char *input, int size, char *output, int output_size); + +#endif diff --git a/crypto/getuuid.c b/crypto/getuuid.c new file mode 100644 index 00000000000..94845b024c9 --- /dev/null +++ b/crypto/getuuid.c @@ -0,0 +1,208 @@ +/* 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. + */ + +/* + * This attempts to generate V1 UUIDs according to the Internet Draft + * located at http://www.webdav.org/specs/draft-leach-uuids-guids-01.txt + */ +#include "apr.h" +#include "apr_uuid.h" +#include "apr_md5.h" +#include "apr_general.h" +#include "apr_portable.h" + + +#if APR_HAVE_UNISTD_H +#include <unistd.h> /* for getpid, gethostname */ +#endif +#if APR_HAVE_STDLIB_H +#include <stdlib.h> /* for rand, srand */ +#endif + + +#if APR_HAVE_STRING_H +#include <string.h> +#endif +#if APR_HAVE_STRINGS_H +#include <strings.h> +#endif +#if APR_HAVE_NETDB_H +#include <netdb.h> +#endif +#if APR_HAVE_SYS_TIME_H +#include <sys/time.h> /* for gettimeofday */ +#endif + +#define NODE_LENGTH 6 + +static int uuid_state_seqnum; +static unsigned char uuid_state_node[NODE_LENGTH] = { 0 }; + + +static void get_random_info(unsigned char node[NODE_LENGTH]) +{ +#if APR_HAS_RANDOM + + (void) apr_generate_random_bytes(node, NODE_LENGTH); + +#else + + unsigned char seed[APR_MD5_DIGESTSIZE]; + apr_md5_ctx_t c; + + /* ### probably should revise some of this to be a bit more portable */ + + /* Leach & Salz use Linux-specific struct sysinfo; + * replace with pid/tid for portability (in the spirit of mod_unique_id) */ + struct { + /* Add thread id here, if applicable, when we get to pthread or apr */ + pid_t pid; +#ifdef NETWARE + apr_uint64_t t; +#else + struct timeval t; +#endif + char hostname[257]; + + } r; + + apr_md5_init(&c); +#ifdef NETWARE + r.pid = NXThreadGetId(); + NXGetTime(NX_SINCE_BOOT, NX_USECONDS, &(r.t)); +#else + r.pid = getpid(); + gettimeofday(&r.t, (struct timezone *)0); +#endif + gethostname(r.hostname, 256); + apr_md5_update(&c, (const unsigned char *)&r, sizeof(r)); + apr_md5_final(seed, &c); + + memcpy(node, seed, NODE_LENGTH); /* use a subset of the seed bytes */ +#endif +} + +/* This implementation generates a random node ID instead of a + system-dependent call to get IEEE node ID. This is also more secure: + we aren't passing out our MAC address. +*/ +static void get_pseudo_node_identifier(unsigned char *node) +{ + get_random_info(node); + node[0] |= 0x01; /* this designates a random multicast node ID */ +} + +static void get_system_time(apr_uint64_t *uuid_time) +{ + /* ### fix this call to be more portable? */ + *uuid_time = apr_time_now(); + + /* Offset between UUID formatted times and Unix formatted times. + UUID UTC base time is October 15, 1582. + Unix base time is January 1, 1970. */ + *uuid_time = (*uuid_time * 10) + APR_TIME_C(0x01B21DD213814000); +} + +/* true_random -- generate a crypto-quality random number. */ +static int true_random(void) +{ + apr_uint64_t time_now; + +#if APR_HAS_RANDOM + unsigned char buf[2]; + + if (apr_generate_random_bytes(buf, 2) == APR_SUCCESS) { + return (buf[0] << 8) | buf[1]; + } +#endif + + /* crap. this isn't crypto quality, but it will be Good Enough */ + + time_now = apr_time_now(); + srand((unsigned int)(((time_now >> 32) ^ time_now) & 0xffffffff)); + + return rand() & 0x0FFFF; +} + +static void init_state(void) +{ + uuid_state_seqnum = true_random(); + get_pseudo_node_identifier(uuid_state_node); +} + +static void get_current_time(apr_uint64_t *timestamp) +{ + /* ### this needs to be made thread-safe! */ + + apr_uint64_t time_now; + static apr_uint64_t time_last = 0; + static apr_uint64_t fudge = 0; + + get_system_time(&time_now); + + /* if clock reading changed since last UUID generated... */ + if (time_last != time_now) { + /* The clock reading has changed since the last UUID was generated. + Reset the fudge factor. if we are generating them too fast, then + the fudge may need to be reset to something greater than zero. */ + if (time_last + fudge > time_now) + fudge = time_last + fudge - time_now + 1; + else + fudge = 0; + time_last = time_now; + } + else { + /* We generated two really fast. Bump the fudge factor. */ + ++fudge; + } + + *timestamp = time_now + fudge; +} + +APR_DECLARE(void) apr_uuid_get(apr_uuid_t *uuid) +{ + apr_uint64_t timestamp; + unsigned char *d = uuid->data; + +#if APR_HAS_OS_UUID + if (apr_os_uuid_get(d) == APR_SUCCESS) { + return; + } +#endif /* !APR_HAS_OS_UUID */ + + if (!uuid_state_node[0]) + init_state(); + + get_current_time(×tamp); + + /* time_low, uint32 */ + d[3] = (unsigned char)timestamp; + d[2] = (unsigned char)(timestamp >> 8); + d[1] = (unsigned char)(timestamp >> 16); + d[0] = (unsigned char)(timestamp >> 24); + /* time_mid, uint16 */ + d[5] = (unsigned char)(timestamp >> 32); + d[4] = (unsigned char)(timestamp >> 40); + /* time_hi_and_version, uint16 */ + d[7] = (unsigned char)(timestamp >> 48); + d[6] = (unsigned char)(((timestamp >> 56) & 0x0F) | 0x10); + /* clock_seq_hi_and_reserved, uint8 */ + d[8] = (unsigned char)(((uuid_state_seqnum >> 8) & 0x3F) | 0x80); + /* clock_seq_low, uint8 */ + d[9] = (unsigned char)uuid_state_seqnum; + /* node, byte[6] */ + memcpy(&d[10], uuid_state_node, NODE_LENGTH); +} diff --git a/crypto/uuid.c b/crypto/uuid.c new file mode 100644 index 00000000000..9b095920943 --- /dev/null +++ b/crypto/uuid.c @@ -0,0 +1,130 @@ +/* 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 <stdio.h> /* for sprintf */ + +#include "apr.h" +#include "apr_uuid.h" +#include "apr_errno.h" +#include "apr_lib.h" + + +APR_DECLARE(void) apr_uuid_format(char *buffer, const apr_uuid_t *uuid) +{ + const unsigned char *d = uuid->data; + + sprintf(buffer, + "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", + d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7], + d[8], d[9], d[10], d[11], d[12], d[13], d[14], d[15]); +} + +/* convert a pair of hex digits to an integer value [0,255] */ +#if 'A' == 65 +static unsigned char parse_hexpair(const char *s) +{ + int result; + int temp; + + result = s[0] - '0'; + if (result > 48) + result = (result - 39) << 4; + else if (result > 16) + result = (result - 7) << 4; + else + result = result << 4; + + temp = s[1] - '0'; + if (temp > 48) + result |= temp - 39; + else if (temp > 16) + result |= temp - 7; + else + result |= temp; + + return (unsigned char)result; +} +#else +static unsigned char parse_hexpair(const char *s) +{ + int result; + + if (isdigit(*s)) { + result = (*s - '0') << 4; + } + else { + if (isupper(*s)) { + result = (*s - 'A' + 10) << 4; + } + else { + result = (*s - 'a' + 10) << 4; + } + } + + ++s; + if (isdigit(*s)) { + result |= (*s - '0'); + } + else { + if (isupper(*s)) { + result |= (*s - 'A' + 10); + } + else { + result |= (*s - 'a' + 10); + } + } + + return (unsigned char)result; +} +#endif + +APR_DECLARE(apr_status_t) apr_uuid_parse(apr_uuid_t *uuid, + const char *uuid_str) +{ + int i; + unsigned char *d = uuid->data; + + for (i = 0; i < 36; ++i) { + char c = uuid_str[i]; + if (!apr_isxdigit(c) && + !(c == '-' && (i == 8 || i == 13 || i == 18 || i == 23))) + /* ### need a better value */ + return APR_BADARG; + } + if (uuid_str[36] != '\0') { + /* ### need a better value */ + return APR_BADARG; + } + + d[0] = parse_hexpair(&uuid_str[0]); + d[1] = parse_hexpair(&uuid_str[2]); + d[2] = parse_hexpair(&uuid_str[4]); + d[3] = parse_hexpair(&uuid_str[6]); + + d[4] = parse_hexpair(&uuid_str[9]); + d[5] = parse_hexpair(&uuid_str[11]); + + d[6] = parse_hexpair(&uuid_str[14]); + d[7] = parse_hexpair(&uuid_str[16]); + + d[8] = parse_hexpair(&uuid_str[19]); + d[9] = parse_hexpair(&uuid_str[21]); + + for (i = 6; i--;) + d[10 + i] = parse_hexpair(&uuid_str[i*2+24]); + + return APR_SUCCESS; +} diff --git a/dbd/NWGNUdbdmysql b/dbd/NWGNUdbdmysql new file mode 100644 index 00000000000..bc799eb52a0 --- /dev/null +++ b/dbd/NWGNUdbdmysql @@ -0,0 +1,290 @@ +# +# Declare the sub-directories to be built here +# + +SUBDIRS = \ + $(EOLIST) + +# +# Get the 'head' of the build environment. This includes default targets and +# paths to tools +# + +ifndef EnvironmentDefined +include $(APR_WORK)/build/NWGNUhead.inc +endif + +# +# build this level's files + +# +# Make sure all needed macro's are defined +# + +# LINK_STATIC = 1 + +# for now defined here - should finally go into build/NWGNUenvironment.inc +MYSQL_INC = $(MYSQLSDK)/include +MYSQL_IMP = $(MYSQLSDK)/lib/libmysql.imp +MYSQL_LIB = $(MYSQLSDK)/lib/libmysqlclient_r.lib $(MYSQLSDK)/lib/libz.lib +MYSQL_NLM = libmysql +ifneq "$(wildcard $(MYSQL_INC)/mysql.h)" "$(MYSQL_INC)/mysql.h" +$(error MYSQLSDK does not point to a valid MySQL SDK) +endif + +# +# These directories will be at the beginning of the include list, followed by +# INCDIRS +# +XINCDIRS += \ + $(APR)/include \ + $(APR)/include/private \ + $(APR)/include/arch/netware \ + $(MYSQL_INC) \ + $(EOLIST) + +# +# These flags will come after CFLAGS +# +XCFLAGS += \ + $(EOLIST) + +# +# These defines will come after DEFINES +# +XDEFINES += \ + -DAPU_DSO_MODULE_BUILD \ + -DAPU_HAVE_MYSQL=1 \ + -DHAVE_MYSQL_H \ + $(EOLIST) + +# +# These flags will be added to the link.opt file +# +XLFLAGS += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) + +# +# These values will be appended to the correct variables based on the value of +# RELEASE +# +ifeq "$(RELEASE)" "debug" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +ifeq "$(RELEASE)" "noopt" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +ifeq "$(RELEASE)" "release" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +# +# These are used by the link target if an NLM is being generated +# This is used by the link 'name' directive to name the nlm. If left blank +# TARGET_nlm (see below) will be used. +# +NLM_NAME = dbdmysql + +# +# This is used by the link '-desc ' directive. +# If left blank, NLM_NAME will be used. +# +NLM_DESCRIPTION = Apache Portability Runtime Library $(VERSION_STR) DBD MySQL Driver Module + +# +# This is used by the '-threadname' directive. If left blank, +# NLM_NAME Thread will be used. +# +NLM_THREAD_NAME = dbdmysql + +# +# If this is specified, it will override VERSION value in +# $(APR_WORK)/build/NWGNUenvironment.inc +# +NLM_VERSION = + +# +# If this is specified, it will override the default of 64K +# +NLM_STACK_SIZE = + +# +# If this is specified it will be used by the link '-entry' directive +# +NLM_ENTRY_SYM = + +# +# If this is specified it will be used by the link '-exit' directive +# +NLM_EXIT_SYM = + +# +# If this is specified it will be used by the link '-check' directive +# +NLM_CHECK_SYM = + +# +# If these are specified it will be used by the link '-flags' directive +# +NLM_FLAGS = + +# +# If this is specified it will be linked in with the XDCData option in the def +# file instead of the default of $(NWOS)/apache.xdc. XDCData can be disabled +# by setting APACHE_UNIPROC in the environment +# +XDCDATA = + +# +# If there is an NLM target, put it here +# +TARGET_nlm = \ + $(OBJDIR)/$(NLM_NAME).nlm \ + $(EOLIST) + +# +# If there is an LIB target, put it here +# +TARGET_lib = \ + $(EOLIST) + +# +# These are the OBJ files needed to create the NLM target above. +# Paths must all use the '/' character +# +FILES_nlm_objs = \ + $(OBJDIR)/apr_dbd_mysql.o \ + $(EOLIST) + +# +# These are the LIB files needed to create the NLM target above. +# These will be added as a library command in the link.opt file. +# +FILES_nlm_libs = \ + $(PRELUDE) \ + $(EOLIST) + +ifeq ($(LINK_STATIC),1) +FILES_nlm_libs += \ + $(MYSQL_LIB) \ + $(EOLIST) +endif + +# +# These are the modules that the above NLM target depends on to load. +# These will be added as a module command in the link.opt file. +# +FILES_nlm_modules = \ + aprlib \ + libc \ + $(EOLIST) + +ifneq ($(LINK_STATIC),1) +FILES_nlm_modules += \ + $(MYSQL_NLM) \ + $(EOLIST) +endif + +# +# If the nlm has a msg file, put it's path here +# +FILE_nlm_msg = + +# +# If the nlm has a hlp file put it's path here +# +FILE_nlm_hlp = + +# +# If this is specified, it will override $(NWOS)\copyright.txt. +# +FILE_nlm_copyright = + +# +# Any additional imports go here +# +FILES_nlm_Ximports = \ + @$(APR)/aprlib.imp \ + @$(NOVI)/libc.imp \ + $(EOLIST) + +ifneq ($(LINK_STATIC),1) +FILES_nlm_Ximports += \ + @$(MYSQL_IMP) \ + $(EOLIST) +endif + +# +# Any symbols exported to here +# +FILES_nlm_exports = \ + apr_dbd_mysql_driver \ + $(EOLIST) + +# +# These are the OBJ files needed to create the LIB target above. +# Paths must all use the '/' character +# +FILES_lib_objs = \ + $(EOLIST) + +# +# implement targets and dependancies (leave this section alone) +# + +libs :: $(OBJDIR) $(TARGET_lib) + +nlms :: libs $(TARGET_nlm) + +# +# Updated this target to create necessary directories and copy files to the +# correct place. (See $(APR_WORK)/build/NWGNUhead.inc for examples) +# +install :: nlms FORCE + +# +# Any specialized rules here +# + +# +# Include the 'tail' makefile that has targets that depend on variables defined +# in this makefile +# + +include $(APRBUILD)/NWGNUtail.inc + diff --git a/dbd/NWGNUdbdpgsql b/dbd/NWGNUdbdpgsql new file mode 100644 index 00000000000..61946df51f6 --- /dev/null +++ b/dbd/NWGNUdbdpgsql @@ -0,0 +1,292 @@ +# +# Declare the sub-directories to be built here +# + +SUBDIRS = \ + $(EOLIST) + +# +# Get the 'head' of the build environment. This includes default targets and +# paths to tools +# + +ifndef EnvironmentDefined +include $(APR_WORK)/build/NWGNUhead.inc +endif + +# +# build this level's files + +# +# Make sure all needed macro's are defined +# + +# LINK_STATIC = 1 + +# for now defined here - should finally go into build/NWGNUenvironment.inc +PGSQL_INC = $(PGSQLSDK)/inc +PGSQL_IMP = $(PGSQLSDK)/imp/libpq.imp +PGSQL_LIB = $(PGSQLSDK)/lib/libpq.lib +PGSQL_NLM = libpq + +# +# These directories will be at the beginning of the include list, followed by +# INCDIRS +# +XINCDIRS += \ + $(APR)/include \ + $(APR)/include/private \ + $(APR)/include/arch/netware \ + $(PGSQL_INC) \ + $(EOLIST) + +# +# These flags will come after CFLAGS +# +XCFLAGS += \ + $(EOLIST) + +# +# These defines will come after DEFINES +# +XDEFINES += \ + -DAPU_DSO_MODULE_BUILD \ + -DAPU_HAVE_PGSQL=1 \ + -DHAVE_LIBPQ_FE_H \ + $(EOLIST) + +# +# These flags will be added to the link.opt file +# +XLFLAGS += \ + $(EOLIST) + +ifdef LINK_STATIC +XLFLAGS += \ + $(EOLIST) +else +XLFLAGS += \ + $(EOLIST) +endif + +# +# These values will be appended to the correct variables based on the value of +# RELEASE +# +ifeq "$(RELEASE)" "debug" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +ifeq "$(RELEASE)" "noopt" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +ifeq "$(RELEASE)" "release" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +# +# These are used by the link target if an NLM is being generated +# This is used by the link 'name' directive to name the nlm. If left blank +# TARGET_nlm (see below) will be used. +# +NLM_NAME = dbdpgsql + +# +# This is used by the link '-desc ' directive. +# If left blank, NLM_NAME will be used. +# +NLM_DESCRIPTION = Apache Portability Runtime Library $(VERSION_STR) DBD PostgreSQL Driver Module + +# +# This is used by the '-threadname' directive. If left blank, +# NLM_NAME Thread will be used. +# +NLM_THREAD_NAME = dbdpgsql + +# +# If this is specified, it will override VERSION value in +# $(APR_WORK)/build/NWGNUenvironment.inc +# +NLM_VERSION = + +# +# If this is specified, it will override the default of 64K +# +NLM_STACK_SIZE = + +# +# If this is specified it will be used by the link '-entry' directive +# +NLM_ENTRY_SYM = + +# +# If this is specified it will be used by the link '-exit' directive +# +NLM_EXIT_SYM = + +# +# If this is specified it will be used by the link '-check' directive +# +NLM_CHECK_SYM = + +# +# If these are specified it will be used by the link '-flags' directive +# +NLM_FLAGS = + +# +# If this is specified it will be linked in with the XDCData option in the def +# file instead of the default of $(NWOS)/apache.xdc. XDCData can be disabled +# by setting APACHE_UNIPROC in the environment +# +XDCDATA = + +# +# If there is an NLM target, put it here +# +TARGET_nlm = \ + $(OBJDIR)/$(NLM_NAME).nlm \ + $(EOLIST) + +# +# If there is an LIB target, put it here +# +TARGET_lib = \ + $(EOLIST) + +# +# These are the OBJ files needed to create the NLM target above. +# Paths must all use the '/' character +# +FILES_nlm_objs = \ + $(OBJDIR)/apr_dbd_pgsql.o \ + $(EOLIST) + +# +# These are the LIB files needed to create the NLM target above. +# These will be added as a library command in the link.opt file. +# +FILES_nlm_libs = \ + $(PRELUDE) \ + $(EOLIST) + +ifeq ($(LINK_STATIC),1) +FILES_nlm_libs += \ + $(PGSQL_LIB) \ + $(EOLIST) +endif + +# +# These are the modules that the above NLM target depends on to load. +# These will be added as a module command in the link.opt file. +# +FILES_nlm_modules = \ + aprlib \ + libc \ + $(EOLIST) + +ifneq ($(LINK_STATIC),1) +FILES_nlm_modules += \ + $(PGSQL_NLM) \ + $(EOLIST) +endif + +# +# If the nlm has a msg file, put it's path here +# +FILE_nlm_msg = + +# +# If the nlm has a hlp file put it's path here +# +FILE_nlm_hlp = + +# +# If this is specified, it will override $(NWOS)\copyright.txt. +# +FILE_nlm_copyright = + +# +# Any additional imports go here +# +FILES_nlm_Ximports = \ + @$(APR)/aprlib.imp \ + @$(NOVI)/libc.imp \ + $(EOLIST) + +ifneq ($(LINK_STATIC),1) +FILES_nlm_Ximports += \ + @$(PGSQL_IMP) \ + $(EOLIST) +endif + +# +# Any symbols exported to here +# +FILES_nlm_exports = \ + apr_dbd_pgsql_driver \ + $(EOLIST) + +# +# These are the OBJ files needed to create the LIB target above. +# Paths must all use the '/' character +# +FILES_lib_objs = \ + $(EOLIST) + +# +# implement targets and dependancies (leave this section alone) +# + +libs :: $(OBJDIR) $(TARGET_lib) + +nlms :: libs $(TARGET_nlm) + +# +# Updated this target to create necessary directories and copy files to the +# correct place. (See $(APR_WORK)/build/NWGNUhead.inc for examples) +# +install :: nlms FORCE + +# +# Any specialized rules here +# + +# +# Include the 'tail' makefile that has targets that depend on variables defined +# in this makefile +# + +include $(APRBUILD)/NWGNUtail.inc + diff --git a/dbd/NWGNUdbdsqli2 b/dbd/NWGNUdbdsqli2 new file mode 100644 index 00000000000..8887a53ffa9 --- /dev/null +++ b/dbd/NWGNUdbdsqli2 @@ -0,0 +1,291 @@ +# +# Declare the sub-directories to be built here +# + +SUBDIRS = \ + $(EOLIST) + +# +# Get the 'head' of the build environment. This includes default targets and +# paths to tools +# + +ifndef EnvironmentDefined +include $(APR_WORK)/build/NWGNUhead.inc +endif + +# +# build this level's files + +# +# Make sure all needed macro's are defined +# + +# LINK_STATIC = 1 + +# for now defined here - should finally go into build/NWGNUenvironment.inc +SQLITE2_INC = $(SQLITE2SDK)/src +SQLITE2_IMP = $(SQLITE2SDK)/lsqlite2.imp +SQLITE2_LIB = $(SQLITE2SDK)/lsqlite2.lib +SQLITE2_NLM = lsqlite2 + +# +# These directories will be at the beginning of the include list, followed by +# INCDIRS +# +XINCDIRS += \ + $(APR)/include \ + $(APR)/include/private \ + $(APR)/include/arch/netware \ + $(SQLITE2_INC) \ + $(EOLIST) + +# +# These flags will come after CFLAGS +# +XCFLAGS += \ + $(EOLIST) + +# +# These defines will come after DEFINES +# +XDEFINES += \ + -DAPU_DSO_MODULE_BUILD \ + -DAPU_HAVE_SQLITE2=1 \ + $(EOLIST) + +# +# These flags will be added to the link.opt file +# +XLFLAGS += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) + +# +# These values will be appended to the correct variables based on the value of +# RELEASE +# +ifeq "$(RELEASE)" "debug" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +ifeq "$(RELEASE)" "noopt" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +ifeq "$(RELEASE)" "release" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +# +# These are used by the link target if an NLM is being generated +# This is used by the link 'name' directive to name the nlm. If left blank +# TARGET_nlm (see below) will be used. +# +NLM_NAME = dbdsqli2 + +# +# This is used by the link '-desc ' directive. +# If left blank, NLM_NAME will be used. +# +NLM_DESCRIPTION = Apache Portability Runtime Library $(VERSION_STR) DBD SQLite2 Driver Module + +# +# This is used by the '-threadname' directive. If left blank, +# NLM_NAME Thread will be used. +# +NLM_THREAD_NAME = dbdsqli2 + +# +# If this is specified, it will override VERSION value in +# $(APR_WORK)/build/NWGNUenvironment.inc +# +NLM_VERSION = + +# +# If this is specified, it will override the default of 64K +# +NLM_STACK_SIZE = + +# +# If this is specified it will be used by the link '-entry' directive +# +NLM_ENTRY_SYM = + +# +# If this is specified it will be used by the link '-exit' directive +# +NLM_EXIT_SYM = + +# +# If this is specified it will be used by the link '-check' directive +# +NLM_CHECK_SYM = + +# +# If these are specified it will be used by the link '-flags' directive +# +NLM_FLAGS = + +# +# If this is specified it will be linked in with the XDCData option in the def +# file instead of the default of $(NWOS)/apache.xdc. XDCData can be disabled +# by setting APACHE_UNIPROC in the environment +# +XDCDATA = + +# +# If there is an NLM target, put it here +# +TARGET_nlm = \ + $(OBJDIR)/$(NLM_NAME).nlm \ + $(EOLIST) + +# +# If there is an LIB target, put it here +# +TARGET_lib = \ + $(EOLIST) + +# +# These are the OBJ files needed to create the NLM target above. +# Paths must all use the '/' character +# +FILES_nlm_objs = \ + $(OBJDIR)/apr_dbd_sqlite2.o \ + $(EOLIST) + +# +# These are the LIB files needed to create the NLM target above. +# These will be added as a library command in the link.opt file. +# +FILES_nlm_libs = \ + $(PRELUDE) \ + $(EOLIST) + +ifeq ($(LINK_STATIC),1) +FILES_nlm_libs += \ + $(SQLITE2_LIB) \ + $(EOLIST) +endif + +# +# These are the modules that the above NLM target depends on to load. +# These will be added as a module command in the link.opt file. +# +FILES_nlm_modules = \ + aprlib \ + libc \ + $(EOLIST) + +ifneq ($(LINK_STATIC),1) +FILES_nlm_modules += \ + $(SQLITE2_NLM) \ + $(EOLIST) +endif + +# +# If the nlm has a msg file, put it's path here +# +FILE_nlm_msg = + +# +# If the nlm has a hlp file put it's path here +# +FILE_nlm_hlp = + +# +# If this is specified, it will override $(NWOS)\copyright.txt. +# +FILE_nlm_copyright = + +# +# Any additional imports go here +# +FILES_nlm_Ximports = \ + @$(APR)/aprlib.imp \ + @$(NOVI)/libc.imp \ + $(EOLIST) + +FILES_nlm_imports = \ + apr_dbd_mutex_lock \ + apr_dbd_mutex_unlock \ + $(EOLIST) + +ifneq ($(LINK_STATIC),1) +FILES_nlm_Ximports += \ + @$(SQLITE2_IMP) \ + $(EOLIST) +endif + +# +# Any symbols exported to here +# +FILES_nlm_exports = \ + apr_dbd_sqlite2_driver \ + $(EOLIST) + +# +# These are the OBJ files needed to create the LIB target above. +# Paths must all use the '/' character +# +FILES_lib_objs = \ + $(EOLIST) + +# +# implement targets and dependancies (leave this section alone) +# + +libs :: $(OBJDIR) $(TARGET_lib) + +nlms :: libs $(TARGET_nlm) + +# +# Updated this target to create necessary directories and copy files to the +# correct place. (See $(APR_WORK)/build/NWGNUhead.inc for examples) +# +install :: nlms FORCE + +# +# Any specialized rules here +# + +# +# Include the 'tail' makefile that has targets that depend on variables defined +# in this makefile +# + +include $(APRBUILD)/NWGNUtail.inc + diff --git a/dbd/NWGNUdbdsqli3 b/dbd/NWGNUdbdsqli3 new file mode 100644 index 00000000000..cf495d21cfc --- /dev/null +++ b/dbd/NWGNUdbdsqli3 @@ -0,0 +1,291 @@ +# +# Declare the sub-directories to be built here +# + +SUBDIRS = \ + $(EOLIST) + +# +# Get the 'head' of the build environment. This includes default targets and +# paths to tools +# + +ifndef EnvironmentDefined +include $(APR_WORK)/build/NWGNUhead.inc +endif + +# +# build this level's files + +# +# Make sure all needed macro's are defined +# + +# LINK_STATIC = 1 + +# for now defined here - should finally go into build/NWGNUenvironment.inc +SQLITE3_INC = $(SQLITE3SDK)/src +SQLITE3_IMP = $(SQLITE3SDK)/lsqlite3.imp +SQLITE3_LIB = $(SQLITE3SDK)/lsqlite3.lib +SQLITE3_NLM = lsqlite3 + +# +# These directories will be at the beginning of the include list, followed by +# INCDIRS +# +XINCDIRS += \ + $(APR)/include \ + $(APR)/include/private \ + $(APR)/include/arch/netware \ + $(SQLITE3_INC) \ + $(EOLIST) + +# +# These flags will come after CFLAGS +# +XCFLAGS += \ + $(EOLIST) + +# +# These defines will come after DEFINES +# +XDEFINES += \ + -DAPU_DSO_MODULE_BUILD \ + -DAPU_HAVE_SQLITE3=1 \ + $(EOLIST) + +# +# These flags will be added to the link.opt file +# +XLFLAGS += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) + +# +# These values will be appended to the correct variables based on the value of +# RELEASE +# +ifeq "$(RELEASE)" "debug" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +ifeq "$(RELEASE)" "noopt" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +ifeq "$(RELEASE)" "release" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +# +# These are used by the link target if an NLM is being generated +# This is used by the link 'name' directive to name the nlm. If left blank +# TARGET_nlm (see below) will be used. +# +NLM_NAME = dbdsqli3 + +# +# This is used by the link '-desc ' directive. +# If left blank, NLM_NAME will be used. +# +NLM_DESCRIPTION = Apache Portability Runtime Library $(VERSION_STR) DBD SQLite3 Driver Module + +# +# This is used by the '-threadname' directive. If left blank, +# NLM_NAME Thread will be used. +# +NLM_THREAD_NAME = dbdsqli3 + +# +# If this is specified, it will override VERSION value in +# $(APR_WORK)/build/NWGNUenvironment.inc +# +NLM_VERSION = + +# +# If this is specified, it will override the default of 64K +# +NLM_STACK_SIZE = + +# +# If this is specified it will be used by the link '-entry' directive +# +NLM_ENTRY_SYM = + +# +# If this is specified it will be used by the link '-exit' directive +# +NLM_EXIT_SYM = + +# +# If this is specified it will be used by the link '-check' directive +# +NLM_CHECK_SYM = + +# +# If these are specified it will be used by the link '-flags' directive +# +NLM_FLAGS = + +# +# If this is specified it will be linked in with the XDCData option in the def +# file instead of the default of $(NWOS)/apache.xdc. XDCData can be disabled +# by setting APACHE_UNIPROC in the environment +# +XDCDATA = + +# +# If there is an NLM target, put it here +# +TARGET_nlm = \ + $(OBJDIR)/$(NLM_NAME).nlm \ + $(EOLIST) + +# +# If there is an LIB target, put it here +# +TARGET_lib = \ + $(EOLIST) + +# +# These are the OBJ files needed to create the NLM target above. +# Paths must all use the '/' character +# +FILES_nlm_objs = \ + $(OBJDIR)/apr_dbd_sqlite3.o \ + $(EOLIST) + +# +# These are the LIB files needed to create the NLM target above. +# These will be added as a library command in the link.opt file. +# +FILES_nlm_libs = \ + $(PRELUDE) \ + $(EOLIST) + +ifeq ($(LINK_STATIC),1) +FILES_nlm_libs += \ + $(SQLITE3_LIB) \ + $(EOLIST) +endif + +# +# These are the modules that the above NLM target depends on to load. +# These will be added as a module command in the link.opt file. +# +FILES_nlm_modules = \ + aprlib \ + libc \ + $(EOLIST) + +ifneq ($(LINK_STATIC),1) +FILES_nlm_modules += \ + $(SQLITE3_NLM) \ + $(EOLIST) +endif + +# +# If the nlm has a msg file, put it's path here +# +FILE_nlm_msg = + +# +# If the nlm has a hlp file put it's path here +# +FILE_nlm_hlp = + +# +# If this is specified, it will override $(NWOS)\copyright.txt. +# +FILE_nlm_copyright = + +# +# Any additional imports go here +# +FILES_nlm_Ximports = \ + @$(APR)/aprlib.imp \ + @$(NOVI)/libc.imp \ + $(EOLIST) + +FILES_nlm_imports = \ + apr_dbd_mutex_lock \ + apr_dbd_mutex_unlock \ + $(EOLIST) + +ifneq ($(LINK_STATIC),1) +FILES_nlm_Ximports += \ + @$(SQLITE3_IMP) \ + $(EOLIST) +endif + +# +# Any symbols exported to here +# +FILES_nlm_exports = \ + apr_dbd_sqlite3_driver \ + $(EOLIST) + +# +# These are the OBJ files needed to create the LIB target above. +# Paths must all use the '/' character +# +FILES_lib_objs = \ + $(EOLIST) + +# +# implement targets and dependancies (leave this section alone) +# + +libs :: $(OBJDIR) $(TARGET_lib) + +nlms :: libs $(TARGET_nlm) + +# +# Updated this target to create necessary directories and copy files to the +# correct place. (See $(APR_WORK)/build/NWGNUhead.inc for examples) +# +install :: nlms FORCE + +# +# Any specialized rules here +# + +# +# Include the 'tail' makefile that has targets that depend on variables defined +# in this makefile +# + +include $(APRBUILD)/NWGNUtail.inc + diff --git a/dbd/NWGNUmakefile b/dbd/NWGNUmakefile new file mode 100644 index 00000000000..90f8aae20d8 --- /dev/null +++ b/dbd/NWGNUmakefile @@ -0,0 +1,257 @@ +# +# Declare the sub-directories to be built here +# + +SUBDIRS = \ + $(EOLIST) + +# +# Get the 'head' of the build environment. This includes default targets and +# paths to tools +# + +include $(APR_WORK)/build/NWGNUhead.inc + +# +# build this level's files + +# +# Make sure all needed macro's are defined +# + +# +# These directories will be at the beginning of the include list, followed by +# INCDIRS +# +XINCDIRS += \ + $(EOLIST) + +# +# These flags will come after CFLAGS +# +XCFLAGS += \ + $(EOLIST) + +# +# These defines will come after DEFINES +# +XDEFINES += \ + $(EOLIST) + +# +# These flags will be added to the link.opt file +# +XLFLAGS += \ + $(EOLIST) + +# +# These values will be appended to the correct variables based on the value of +# RELEASE +# +ifeq "$(RELEASE)" "debug" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +ifeq "$(RELEASE)" "noopt" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +ifeq "$(RELEASE)" "release" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +# +# These are used by the link target if an NLM is being generated +# This is used by the link 'name' directive to name the nlm. If left blank +# TARGET_nlm (see below) will be used. +# +NLM_NAME = + +# +# This is used by the link '-desc ' directive. +# If left blank, NLM_NAME will be used. +# +NLM_DESCRIPTION = + +# +# This is used by the '-threadname' directive. If left blank, +# NLM_NAME Thread will be used. +# +NLM_THREAD_NAME = + +# +# If this is specified, it will override VERSION value in +# $(APR_WORK)/build/NWGNUenvironment.inc +# +NLM_VERSION = + +# +# If this is specified, it will override the default of 64K +# +NLM_STACK_SIZE = + + +# +# If this is specified it will be used by the link '-entry' directive +# +NLM_ENTRY_SYM = + +# +# If this is specified it will be used by the link '-exit' directive +# +NLM_EXIT_SYM = + +# +# If this is specified it will be used by the link '-check' directive +# +NLM_CHECK_SYM = + +# +# If these are specified it will be used by the link '-flags' directive +# +NLM_FLAGS = + +# +# If this is specified it will be linked in with the XDCData option in the def +# file instead of the default of $(NWOS)/apache.xdc. XDCData can be disabled +# by setting APACHE_UNIPROC in the environment +# +XDCDATA = + +# +# If there is an NLM target, put it here +# +TARGET_nlm = \ + $(EOLIST) + +ifeq "$(APU_HAVE_MYSQL)" "1" +TARGET_nlm += $(OBJDIR)/dbdmysql.nlm $(OBJDIR)/dbdmysql.nlm $(EOLIST) +endif +ifeq "$(APU_HAVE_PGSQL)" "1" +TARGET_nlm += $(OBJDIR)/dbdpgsql.nlm $(OBJDIR)/dbdpgsql.nlm $(EOLIST) +endif +ifeq "$(APU_HAVE_SQLITE2)" "1" +TARGET_nlm += $(OBJDIR)/dbdsqli2.nlm $(OBJDIR)/dbdsqli2.nlm $(EOLIST) +endif +ifeq "$(APU_HAVE_SQLITE3)" "1" +TARGET_nlm += $(OBJDIR)/dbdsqli3.nlm $(OBJDIR)/dbdsqli3.nlm $(EOLIST) +endif + +# +# If there is an LIB target, put it here +# +TARGET_lib = \ + $(EOLIST) + +# +# These are the OBJ files needed to create the NLM target above. +# Paths must all use the '/' character +# +FILES_nlm_objs = \ + $(EOLIST) + +# +# These are the LIB files needed to create the NLM target above. +# These will be added as a library command in the link.opt file. +# +FILES_nlm_libs = \ + $(EOLIST) + +# +# These are the modules that the above NLM target depends on to load. +# These will be added as a module command in the link.opt file. +# +FILES_nlm_modules = \ + $(EOLIST) + +# +# If the nlm has a msg file, put it's path here +# +FILE_nlm_msg = + +# +# If the nlm has a hlp file put it's path here +# +FILE_nlm_hlp = + +# +# If this is specified, it will override $(NWOS)\copyright.txt. +# +FILE_nlm_copyright = + +# +# Any additional imports go here +# +FILES_nlm_Ximports = \ + $(EOLIST) + +# +# Any symbols exported to here +# +FILES_nlm_exports = \ + $(EOLIST) + +# +# These are the OBJ files needed to create the LIB target above. +# Paths must all use the '/' character +# +FILES_lib_objs = \ + $(EOLIST) + +# +# implement targets and dependancies (leave this section alone) +# + +libs :: $(OBJDIR) $(TARGET_lib) + +nlms :: libs $(TARGET_nlm) + +# +# Updated this target to create necessary directories and copy files to the +# correct place. (See $(APR_WORK)/build/NWGNUhead.inc for examples) +# +install :: nlms $(INSTDIRS) FORCE + $(call COPY,$(OBJDIR)/*.nlm,$(INSTALLBASE)/) + +# +# Any specialized rules here +# + +# +# Include the 'tail' makefile that has targets that depend on variables defined +# in this makefile +# + +include $(APRBUILD)/NWGNUtail.inc + + diff --git a/dbd/apr_dbd.c b/dbd/apr_dbd.c new file mode 100644 index 00000000000..be7b61be8ce --- /dev/null +++ b/dbd/apr_dbd.c @@ -0,0 +1,572 @@ +/* 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 <ctype.h> +#include <stdio.h> + +#include "apu.h" +#include "apr_private.h" +#include "apr_pools.h" +#include "apr_dso.h" +#include "apr_strings.h" +#include "apr_hash.h" +#include "apr_thread_mutex.h" +#include "apr_lib.h" +#include "apr_atomic.h" +#include "apr_version.h" + +#include "apu_internal.h" +#include "apr_dbd_internal.h" +#include "apr_dbd.h" + +static apr_hash_t *drivers = NULL; +static apr_uint32_t initialised = 0, in_init = 1; + +#define CLEANUP_CAST (apr_status_t (*)(void*)) + +#if APR_HAS_THREADS +/* deprecated, but required for existing providers. Existing and new + * providers should be refactored to use a provider-specific mutex so + * that different providers do not block one another. + * In APR 1.3 this is no longer used for dso module loading, and + * apu_dso_mutex_[un]lock is used instead. + * In APR 2.0 this should become entirely local to libaprutil-2.so and + * no longer be exported. + */ +static apr_thread_mutex_t* mutex = NULL; +APR_DECLARE(apr_status_t) apr_dbd_mutex_lock() +{ + return apr_thread_mutex_lock(mutex); +} +APR_DECLARE(apr_status_t) apr_dbd_mutex_unlock() +{ + return apr_thread_mutex_unlock(mutex); +} +#else +APR_DECLARE(apr_status_t) apr_dbd_mutex_lock() { + return APR_SUCCESS; +} +APR_DECLARE(apr_status_t) apr_dbd_mutex_unlock() { + return APR_SUCCESS; +} +#endif + +#if !APR_HAVE_MODULAR_DSO +#define DRIVER_LOAD(name,driver,pool) \ + { \ + extern const apr_dbd_driver_t driver; \ + apr_hash_set(drivers,name,APR_HASH_KEY_STRING,&driver); \ + if (driver.init) { \ + driver.init(pool); \ + } \ + } +#endif + +static apr_status_t apr_dbd_term(void *ptr) +{ + /* set drivers to NULL so init can work again */ + drivers = NULL; + + /* Everything else we need is handled by cleanups registered + * when we created mutexes and loaded DSOs + */ + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_dbd_init(apr_pool_t *pool) +{ + apr_status_t ret = APR_SUCCESS; + apr_pool_t *parent; + + if (apr_atomic_inc32(&initialised)) { + apr_atomic_set32(&initialised, 1); /* prevent wrap-around */ + + while (apr_atomic_read32(&in_init)) /* wait until we get fully inited */ + ; + + return APR_SUCCESS; + } + + /* Top level pool scope, need process-scope lifetime */ + for (parent = apr_pool_parent_get(pool); + parent && parent != pool; + parent = apr_pool_parent_get(pool)) + pool = parent; +#if APR_HAVE_MODULAR_DSO + /* deprecate in 2.0 - permit implicit initialization */ + apu_dso_init(pool); +#endif + + drivers = apr_hash_make(pool); + +#if APR_HAS_THREADS + ret = apr_thread_mutex_create(&mutex, APR_THREAD_MUTEX_DEFAULT, pool); + /* This already registers a pool cleanup */ +#endif + +#if !APR_HAVE_MODULAR_DSO + + /* Load statically-linked drivers: */ +#if APU_HAVE_MYSQL + DRIVER_LOAD("mysql", apr_dbd_mysql_driver, pool); +#endif +#if APU_HAVE_PGSQL + DRIVER_LOAD("pgsql", apr_dbd_pgsql_driver, pool); +#endif +#if APU_HAVE_SQLITE3 + DRIVER_LOAD("sqlite3", apr_dbd_sqlite3_driver, pool); +#endif +#if APU_HAVE_SQLITE2 + DRIVER_LOAD("sqlite2", apr_dbd_sqlite2_driver, pool); +#endif +#if APU_HAVE_ORACLE + DRIVER_LOAD("oracle", apr_dbd_oracle_driver, pool); +#endif +#if APU_HAVE_ODBC + DRIVER_LOAD("odbc", apr_dbd_odbc_driver, pool); +#endif +#if APU_HAVE_SOME_OTHER_BACKEND + DRIVER_LOAD("firebird", apr_dbd_other_driver, pool); +#endif +#endif /* APR_HAVE_MODULAR_DSO */ + + apr_pool_cleanup_register(pool, NULL, apr_dbd_term, + apr_pool_cleanup_null); + + apr_atomic_dec32(&in_init); + + return ret; +} + +APR_DECLARE(apr_status_t) apr_dbd_get_driver(apr_pool_t *pool, const char *name, + const apr_dbd_driver_t **driver) +{ +#if APR_HAVE_MODULAR_DSO + char modname[32]; + char symname[34]; + apr_dso_handle_sym_t symbol; +#endif + apr_status_t rv; + +#if APR_HAVE_MODULAR_DSO + rv = apu_dso_mutex_lock(); + if (rv) { + return rv; + } +#endif + *driver = apr_hash_get(drivers, name, APR_HASH_KEY_STRING); + if (*driver) { +#if APR_HAVE_MODULAR_DSO + apu_dso_mutex_unlock(); +#endif + return APR_SUCCESS; + } + +#if APR_HAVE_MODULAR_DSO + /* The driver DSO must have exactly the same lifetime as the + * drivers hash table; ignore the passed-in pool */ + pool = apr_hash_pool_get(drivers); + +#if defined(NETWARE) + apr_snprintf(modname, sizeof(modname), "dbd%s.nlm", name); +#elif defined(WIN32) || defined(__CYGWIN__) + apr_snprintf(modname, sizeof(modname), + "apr_dbd_%s-" APR_STRINGIFY(APR_MAJOR_VERSION) ".dll", name); +#else + apr_snprintf(modname, sizeof(modname), + "apr_dbd_%s-" APR_STRINGIFY(APR_MAJOR_VERSION) ".so", name); +#endif + apr_snprintf(symname, sizeof(symname), "apr_dbd_%s_driver", name); + rv = apu_dso_load(NULL, &symbol, modname, symname, pool); + if (rv == APR_SUCCESS || rv == APR_EINIT) { /* previously loaded?!? */ + *driver = symbol; + name = apr_pstrdup(pool, name); + apr_hash_set(drivers, name, APR_HASH_KEY_STRING, *driver); + rv = APR_SUCCESS; + if ((*driver)->init) { + (*driver)->init(pool); + } + } + apu_dso_mutex_unlock(); + +#else /* not builtin and !APR_HAVE_MODULAR_DSO => not implemented */ + rv = APR_ENOTIMPL; +#endif + + return rv; +} + +APR_DECLARE(apr_status_t) apr_dbd_open_ex(const apr_dbd_driver_t *driver, + apr_pool_t *pool, const char *params, + apr_dbd_t **handle, + const char **error) +{ + apr_status_t rv; + *handle = (driver->open)(pool, params, error); + if (*handle == NULL) { + return APR_EGENERAL; + } + rv = apr_dbd_check_conn(driver, pool, *handle); + if ((rv != APR_SUCCESS) && (rv != APR_ENOTIMPL)) { + /* XXX: rv is APR error code, but apr_dbd_error() takes int! */ + if (error) { + *error = apr_dbd_error(driver, *handle, rv); + } + apr_dbd_close(driver, *handle); + return APR_EGENERAL; + } + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_dbd_open(const apr_dbd_driver_t *driver, + apr_pool_t *pool, const char *params, + apr_dbd_t **handle) +{ + return apr_dbd_open_ex(driver,pool,params,handle,NULL); +} + +APR_DECLARE(int) apr_dbd_transaction_start(const apr_dbd_driver_t *driver, + apr_pool_t *pool, apr_dbd_t *handle, + apr_dbd_transaction_t **trans) +{ + int ret = driver->start_transaction(pool, handle, trans); + if (*trans) { + apr_pool_cleanup_register(pool, *trans, + CLEANUP_CAST driver->end_transaction, + apr_pool_cleanup_null); + } + return ret; +} + +APR_DECLARE(int) apr_dbd_transaction_end(const apr_dbd_driver_t *driver, + apr_pool_t *pool, + apr_dbd_transaction_t *trans) +{ + apr_pool_cleanup_kill(pool, trans, CLEANUP_CAST driver->end_transaction); + return driver->end_transaction(trans); +} + +APR_DECLARE(int) apr_dbd_transaction_mode_get(const apr_dbd_driver_t *driver, + apr_dbd_transaction_t *trans) +{ + return driver->transaction_mode_get(trans); +} + +APR_DECLARE(int) apr_dbd_transaction_mode_set(const apr_dbd_driver_t *driver, + apr_dbd_transaction_t *trans, + int mode) +{ + return driver->transaction_mode_set(trans, mode); +} + +APR_DECLARE(apr_status_t) apr_dbd_close(const apr_dbd_driver_t *driver, + apr_dbd_t *handle) +{ + return driver->close(handle); +} + +APR_DECLARE(const char*) apr_dbd_name(const apr_dbd_driver_t *driver) +{ + return driver->name; +} + +APR_DECLARE(void*) apr_dbd_native_handle(const apr_dbd_driver_t *driver, + apr_dbd_t *handle) +{ + return driver->native_handle(handle); +} + +APR_DECLARE(int) apr_dbd_check_conn(const apr_dbd_driver_t *driver, + apr_pool_t *pool, + apr_dbd_t *handle) +{ + return driver->check_conn(pool, handle); +} + +APR_DECLARE(int) apr_dbd_set_dbname(const apr_dbd_driver_t *driver, + apr_pool_t *pool, + apr_dbd_t *handle, const char *name) +{ + return driver->set_dbname(pool,handle,name); +} + +APR_DECLARE(int) apr_dbd_query(const apr_dbd_driver_t *driver, + apr_dbd_t *handle, + int *nrows, const char *statement) +{ + return driver->query(handle,nrows,statement); +} + +APR_DECLARE(int) apr_dbd_select(const apr_dbd_driver_t *driver, + apr_pool_t *pool, + apr_dbd_t *handle, apr_dbd_results_t **res, + const char *statement, int random) +{ + return driver->select(pool,handle,res,statement,random); +} + +APR_DECLARE(int) apr_dbd_num_cols(const apr_dbd_driver_t *driver, + apr_dbd_results_t *res) +{ + return driver->num_cols(res); +} + +APR_DECLARE(int) apr_dbd_num_tuples(const apr_dbd_driver_t *driver, + apr_dbd_results_t *res) +{ + return driver->num_tuples(res); +} + +APR_DECLARE(int) apr_dbd_get_row(const apr_dbd_driver_t *driver, + apr_pool_t *pool, + apr_dbd_results_t *res, apr_dbd_row_t **row, + int rownum) +{ + return driver->get_row(pool,res,row,rownum); +} + +APR_DECLARE(const char*) apr_dbd_get_entry(const apr_dbd_driver_t *driver, + apr_dbd_row_t *row, int col) +{ + return driver->get_entry(row,col); +} + +APR_DECLARE(const char*) apr_dbd_get_name(const apr_dbd_driver_t *driver, + apr_dbd_results_t *res, int col) +{ + return driver->get_name(res,col); +} + +APR_DECLARE(const char*) apr_dbd_error(const apr_dbd_driver_t *driver, + apr_dbd_t *handle, int errnum) +{ + return driver->error(handle,errnum); +} + +APR_DECLARE(const char*) apr_dbd_escape(const apr_dbd_driver_t *driver, + apr_pool_t *pool, const char *string, + apr_dbd_t *handle) +{ + return driver->escape(pool,string,handle); +} + +APR_DECLARE(int) apr_dbd_prepare(const apr_dbd_driver_t *driver, + apr_pool_t *pool, + apr_dbd_t *handle, const char *query, + const char *label, + apr_dbd_prepared_t **statement) +{ + size_t qlen; + int i, nargs = 0, nvals = 0; + char *p, *pq; + const char *q; + apr_dbd_type_e *t; + + if (!driver->pformat) { + return APR_ENOTIMPL; + } + + /* find the number of parameters in the query */ + for (q = query; *q; q++) { + if (q[0] == '%') { + if (apr_isalpha(q[1])) { + nargs++; + } else if (q[1] == '%') { + q++; + } + } + } + nvals = nargs; + + qlen = strlen(query) + + nargs * (strlen(driver->pformat) + sizeof(nargs) * 3 + 2) + 1; + pq = apr_palloc(pool, qlen); + t = apr_pcalloc(pool, sizeof(*t) * nargs); + + for (p = pq, q = query, i = 0; *q; q++) { + if (q[0] == '%') { + if (apr_isalpha(q[1])) { + switch (q[1]) { + case 'd': t[i] = APR_DBD_TYPE_INT; break; + case 'u': t[i] = APR_DBD_TYPE_UINT; break; + case 'f': t[i] = APR_DBD_TYPE_FLOAT; break; + case 'h': + switch (q[2]) { + case 'h': + switch (q[3]){ + case 'd': t[i] = APR_DBD_TYPE_TINY; q += 2; break; + case 'u': t[i] = APR_DBD_TYPE_UTINY; q += 2; break; + } + break; + case 'd': t[i] = APR_DBD_TYPE_SHORT; q++; break; + case 'u': t[i] = APR_DBD_TYPE_USHORT; q++; break; + } + break; + case 'l': + switch (q[2]) { + case 'l': + switch (q[3]){ + case 'd': t[i] = APR_DBD_TYPE_LONGLONG; q += 2; break; + case 'u': t[i] = APR_DBD_TYPE_ULONGLONG; q += 2; break; + } + break; + case 'd': t[i] = APR_DBD_TYPE_LONG; q++; break; + case 'u': t[i] = APR_DBD_TYPE_ULONG; q++; break; + case 'f': t[i] = APR_DBD_TYPE_DOUBLE; q++; break; + } + break; + case 'p': + if (q[2] == 'D') { + switch (q[3]) { + case 't': t[i] = APR_DBD_TYPE_TEXT; q += 2; break; + case 'i': t[i] = APR_DBD_TYPE_TIME; q += 2; break; + case 'd': t[i] = APR_DBD_TYPE_DATE; q += 2; break; + case 'a': t[i] = APR_DBD_TYPE_DATETIME; q += 2; break; + case 's': t[i] = APR_DBD_TYPE_TIMESTAMP; q += 2; break; + case 'z': t[i] = APR_DBD_TYPE_ZTIMESTAMP; q += 2; break; + case 'b': t[i] = APR_DBD_TYPE_BLOB; q += 2; break; + case 'c': t[i] = APR_DBD_TYPE_CLOB; q += 2; break; + case 'n': t[i] = APR_DBD_TYPE_NULL; q += 2; break; + } + } + break; + } + q++; + + switch (t[i]) { + case APR_DBD_TYPE_NONE: /* by default, we expect strings */ + t[i] = APR_DBD_TYPE_STRING; + break; + case APR_DBD_TYPE_BLOB: + case APR_DBD_TYPE_CLOB: /* three (3) more values passed in */ + nvals += 3; + break; + default: + break; + } + + /* insert database specific parameter reference */ + p += apr_snprintf(p, qlen - (p - pq), driver->pformat, ++i); + } else if (q[1] == '%') { /* reduce %% to % */ + *p++ = *q++; + } else { + *p++ = *q; + } + } else { + *p++ = *q; + } + } + *p = '\0'; + + return driver->prepare(pool,handle,pq,label,nargs,nvals,t,statement); +} + +APR_DECLARE(int) apr_dbd_pquery(const apr_dbd_driver_t *driver, + apr_pool_t *pool, + apr_dbd_t *handle, int *nrows, + apr_dbd_prepared_t *statement, + int nargs, const char **args) +{ + return driver->pquery(pool,handle,nrows,statement,args); +} + +APR_DECLARE(int) apr_dbd_pselect(const apr_dbd_driver_t *driver, + apr_pool_t *pool, + apr_dbd_t *handle, apr_dbd_results_t **res, + apr_dbd_prepared_t *statement, int random, + int nargs, const char **args) +{ + return driver->pselect(pool,handle,res,statement,random,args); +} + +APR_DECLARE_NONSTD(int) apr_dbd_pvquery(const apr_dbd_driver_t *driver, + apr_pool_t *pool, + apr_dbd_t *handle, int *nrows, + apr_dbd_prepared_t *statement, ...) +{ + int ret; + va_list args; + va_start(args, statement); + ret = driver->pvquery(pool,handle,nrows,statement,args); + va_end(args); + return ret; +} + +APR_DECLARE_NONSTD(int) apr_dbd_pvselect(const apr_dbd_driver_t *driver, + apr_pool_t *pool, apr_dbd_t *handle, + apr_dbd_results_t **res, + apr_dbd_prepared_t *statement, + int random, ...) +{ + int ret; + va_list args; + va_start(args, random); + ret = driver->pvselect(pool,handle,res,statement,random,args); + va_end(args); + return ret; +} + +APR_DECLARE(int) apr_dbd_pbquery(const apr_dbd_driver_t *driver, + apr_pool_t *pool, + apr_dbd_t *handle, int *nrows, + apr_dbd_prepared_t *statement, + const void **args) +{ + return driver->pbquery(pool,handle,nrows,statement,args); +} + +APR_DECLARE(int) apr_dbd_pbselect(const apr_dbd_driver_t *driver, + apr_pool_t *pool, + apr_dbd_t *handle, apr_dbd_results_t **res, + apr_dbd_prepared_t *statement, int random, + const void **args) +{ + return driver->pbselect(pool,handle,res,statement,random,args); +} + +APR_DECLARE_NONSTD(int) apr_dbd_pvbquery(const apr_dbd_driver_t *driver, + apr_pool_t *pool, + apr_dbd_t *handle, int *nrows, + apr_dbd_prepared_t *statement, ...) +{ + int ret; + va_list args; + va_start(args, statement); + ret = driver->pvbquery(pool,handle,nrows,statement,args); + va_end(args); + return ret; +} + +APR_DECLARE_NONSTD(int) apr_dbd_pvbselect(const apr_dbd_driver_t *driver, + apr_pool_t *pool, apr_dbd_t *handle, + apr_dbd_results_t **res, + apr_dbd_prepared_t *statement, + int random, ...) +{ + int ret; + va_list args; + va_start(args, random); + ret = driver->pvbselect(pool,handle,res,statement,random,args); + va_end(args); + return ret; +} + +APR_DECLARE(apr_status_t) apr_dbd_datum_get(const apr_dbd_driver_t *driver, + apr_dbd_row_t *row, int col, + apr_dbd_type_e type, void *data) +{ + return driver->datum_get(row,col,type,data); +} diff --git a/dbd/apr_dbd_mysql.c b/dbd/apr_dbd_mysql.c new file mode 100644 index 00000000000..9d715855b21 --- /dev/null +++ b/dbd/apr_dbd_mysql.c @@ -0,0 +1,1335 @@ +/* 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 "apu.h" + +#if APU_HAVE_MYSQL + +#include "apr_private.h" + +#include <ctype.h> +#include <stdlib.h> + +#if defined(HAVE_MYSQL_MYSQL_H) +#if defined(HAVE_MYSQL_MY_GLOBAL_H) +#include <mysql/my_global.h> +#if defined(HAVE_MYSQL_MY_SYS_H) +#include <mysql/my_sys.h> +#endif +#endif +#include <mysql/mysql.h> +#include <mysql/errmsg.h> +#else /* !defined(HAVE_MYSQL_MYSQL_H) */ +#if defined(HAVE_MY_GLOBAL_H) +#include <my_global.h> +#if defined(HAVE_MY_SYS_H) +#include <my_sys.h> +#endif +#endif +#include <mysql.h> +#include <errmsg.h> +#endif + +#include "apr_strings.h" +#include "apr_lib.h" +#include "apr_buckets.h" + +#include "apr_dbd_internal.h" + +/* default maximum field size 1 MB */ +#define FIELDSIZE 1048575 + +struct apr_dbd_prepared_t { + MYSQL_STMT* stmt; + int nargs; + int nvals; + apr_dbd_type_e *types; +}; + +struct apr_dbd_transaction_t { + int mode; + int errnum; + apr_dbd_t *handle; +}; + +struct apr_dbd_t { + MYSQL* conn ; + apr_dbd_transaction_t* trans ; + unsigned long fldsz; +}; + +struct apr_dbd_results_t { + int random; + MYSQL_RES *res; + MYSQL_STMT *statement; + MYSQL_BIND *bind; + apr_pool_t *pool; +}; +struct apr_dbd_row_t { + MYSQL_ROW row; + apr_dbd_results_t *res; + unsigned long *len; +}; + +/* MySQL specific bucket for BLOB types */ +typedef struct apr_bucket_lob apr_bucket_lob; +/** + * A bucket referring to a MySQL BLOB + */ +struct apr_bucket_lob { + /** Number of buckets using this memory */ + apr_bucket_refcount refcount; + /** The row this bucket refers to */ + const apr_dbd_row_t *row; + /** The column this bucket refers to */ + int col; + /** The pool into which any needed structures should + * be created while reading from this bucket */ + apr_pool_t *readpool; +}; + +static void lob_bucket_destroy(void *data); +static apr_status_t lob_bucket_read(apr_bucket *e, const char **str, + apr_size_t *len, apr_read_type_e block); +static apr_bucket *apr_bucket_lob_make(apr_bucket *b, + const apr_dbd_row_t *row, int col, + apr_off_t offset, apr_size_t len, + apr_pool_t *p); +static apr_bucket *apr_bucket_lob_create(const apr_dbd_row_t *row, int col, + apr_off_t offset, + apr_size_t len, apr_pool_t *p, + apr_bucket_alloc_t *list); +static int dbd_mysql_num_cols(apr_dbd_results_t *res); + +static const apr_bucket_type_t apr_bucket_type_lob = { + "LOB", 5, APR_BUCKET_DATA, + lob_bucket_destroy, + lob_bucket_read, + apr_bucket_setaside_notimpl, + apr_bucket_shared_split, + apr_bucket_shared_copy +}; + +static void lob_bucket_destroy(void *data) +{ + apr_bucket_lob *f = data; + + if (apr_bucket_shared_destroy(f)) { + /* no need to destroy database objects here; it will get + * done automatically when the pool gets cleaned up */ + apr_bucket_free(f); + } +} + +static apr_status_t lob_bucket_read(apr_bucket *e, const char **str, + apr_size_t *len, apr_read_type_e block) +{ + apr_bucket_lob *a = e->data; + const apr_dbd_row_t *row = a->row; + apr_dbd_results_t *res = row->res; + int col = a->col; + apr_bucket *b = NULL; + int rv; + apr_size_t blength = e->length; /* bytes remaining in file past offset */ + apr_off_t boffset = e->start; + MYSQL_BIND *bind = &res->bind[col]; + + *str = NULL; /* in case we die prematurely */ + + /* fetch from offset if not at the beginning */ + if (boffset > 0) { + rv = mysql_stmt_fetch_column(res->statement, bind, col, + (unsigned long) boffset); + if (rv != 0) { + return APR_EGENERAL; + } + } + blength -= blength > bind->buffer_length ? bind->buffer_length : blength; + *len = e->length - blength; + *str = bind->buffer; + + /* allocate new buffer, since we used this one for the bucket */ + bind->buffer = apr_palloc(res->pool, bind->buffer_length); + + /* + * Change the current bucket to refer to what we read, + * even if we read nothing because we hit EOF. + */ + apr_bucket_pool_make(e, *str, *len, res->pool); + + /* If we have more to read from the field, then create another bucket */ + if (blength > 0) { + /* for efficiency, we can just build a new apr_bucket struct + * to wrap around the existing LOB bucket */ + b = apr_bucket_alloc(sizeof(*b), e->list); + b->start = boffset + *len; + b->length = blength; + b->data = a; + b->type = &apr_bucket_type_lob; + b->free = apr_bucket_free; + b->list = e->list; + APR_BUCKET_INSERT_AFTER(e, b); + } + else { + lob_bucket_destroy(a); + } + + return APR_SUCCESS; +} + +static apr_bucket *apr_bucket_lob_make(apr_bucket *b, + const apr_dbd_row_t *row, int col, + apr_off_t offset, apr_size_t len, + apr_pool_t *p) +{ + apr_bucket_lob *f; + + f = apr_bucket_alloc(sizeof(*f), b->list); + f->row = row; + f->col = col; + f->readpool = p; + + b = apr_bucket_shared_make(b, f, offset, len); + b->type = &apr_bucket_type_lob; + + return b; +} + +static apr_bucket *apr_bucket_lob_create(const apr_dbd_row_t *row, int col, + apr_off_t offset, + apr_size_t len, apr_pool_t *p, + apr_bucket_alloc_t *list) +{ + apr_bucket *b = apr_bucket_alloc(sizeof(*b), list); + + APR_BUCKET_INIT(b); + b->free = apr_bucket_free; + b->list = list; + return apr_bucket_lob_make(b, row, col, offset, len, p); +} + +static apr_status_t free_result(void *data) +{ + mysql_free_result(data); + return APR_SUCCESS; +} + +static int dbd_mysql_select(apr_pool_t *pool, apr_dbd_t *sql, + apr_dbd_results_t **results, + const char *query, int seek) +{ + int sz; + int ret; + if (sql->trans && sql->trans->errnum) { + return sql->trans->errnum; + } + ret = mysql_query(sql->conn, query); + if (!ret) { + if (sz = mysql_field_count(sql->conn), sz > 0) { + if (!*results) { + *results = apr_palloc(pool, sizeof(apr_dbd_results_t)); + } + (*results)->random = seek; + (*results)->statement = NULL; + (*results)->pool = pool; + if (seek) { + (*results)->res = mysql_store_result(sql->conn); + } + else { + (*results)->res = mysql_use_result(sql->conn); + } + apr_pool_cleanup_register(pool, (*results)->res, + free_result,apr_pool_cleanup_null); + } + } else { + ret = mysql_errno(sql->conn); + } + + if (TXN_NOTICE_ERRORS(sql->trans)) { + sql->trans->errnum = ret; + } + return ret; +} + +static const char *dbd_mysql_get_name(const apr_dbd_results_t *res, int n) +{ + if ((n < 0) || (n >= (int) mysql_num_fields(res->res))) { + return NULL; + } + + return mysql_fetch_fields(res->res)[n].name; +} + +static int dbd_mysql_get_row(apr_pool_t *pool, apr_dbd_results_t *res, + apr_dbd_row_t **row, int rownum) +{ + MYSQL_ROW r = NULL; + int ret = 0; + + if (res->statement) { + if (res->random) { + if (rownum > 0) { + mysql_stmt_data_seek(res->statement, (my_ulonglong) --rownum); + } + else { + return -1; /* invalid row */ + } + } + ret = mysql_stmt_fetch(res->statement); + switch (ret) { + case 1: + ret = mysql_stmt_errno(res->statement); + break; + case MYSQL_NO_DATA: + ret = -1; + break; + default: + ret = 0; /* bad luck - get_entry will deal with this */ + break; + } + } + else { + if (res->random) { + if (rownum > 0) { + mysql_data_seek(res->res, (my_ulonglong) --rownum); + } + else { + return -1; /* invalid row */ + } + } + r = mysql_fetch_row(res->res); + if (r == NULL) { + ret = -1; + } + } + if (ret == 0) { + if (!*row) { + *row = apr_palloc(pool, sizeof(apr_dbd_row_t)); + } + (*row)->row = r; + (*row)->res = res; + (*row)->len = mysql_fetch_lengths(res->res); + } + else { + apr_pool_cleanup_run(res->pool, res->res, free_result); + } + return ret; +} +#if 0 +/* An improved API that was proposed but not followed up */ +static int dbd_mysql_get_entry(const apr_dbd_row_t *row, int n, + apr_dbd_datum_t *val) +{ + MYSQL_BIND *bind; + if (dbd_mysql_num_cols(row->res) <= n) { + return NULL; + } + if (row->res->statement) { + bind = &row->res->bind[n]; + if (mysql_stmt_fetch_column(row->res->statement, bind, n, 0) != 0) { + val->type = APR_DBD_VALUE_NULL; + return -1; + } + if (*bind->is_null) { + val->type = APR_DBD_VALUE_NULL; + return -1; + } + else { + val->type = APR_DBD_VALUE_STRING; + val->value.stringval = bind->buffer; + } + } + else { + val->type = APR_DBD_VALUE_STRING; + val->value.stringval = row->row[n]; + } + return 0; +} +#else + +static const char *dbd_mysql_get_entry(const apr_dbd_row_t *row, int n) +{ + MYSQL_BIND *bind; + const char *result = NULL; + if (dbd_mysql_num_cols(row->res) <= n) { + return NULL; + } + if (row->res->statement) { + bind = &row->res->bind[n]; + if (mysql_stmt_fetch_column(row->res->statement, bind, n, 0) != 0) { + return NULL; + } + if (*bind->is_null) { + return NULL; + } + else { + result = bind->buffer; + } + } + else { + result = row->row[n]; + } + if (result != NULL) { + /* need to copy this - PR 46421 + * Don't know why, when it apparently came from an array + * in the first place. + */ + result = apr_pstrdup(row->res->pool, result); + } + return result; +} +#endif + +static apr_status_t dbd_mysql_datum_get(const apr_dbd_row_t *row, int n, + apr_dbd_type_e type, void *data) +{ + if (row->res->statement) { + MYSQL_BIND *bind = &row->res->bind[n]; + unsigned long len = *bind->length; + + if (mysql_stmt_fetch_column(row->res->statement, bind, n, 0) != 0) { + return APR_EGENERAL; + } + + if (*bind->is_null) { + return APR_ENOENT; + } + + switch (type) { + case APR_DBD_TYPE_TINY: + *(char*)data = atoi(bind->buffer); + break; + case APR_DBD_TYPE_UTINY: + *(unsigned char*)data = atoi(bind->buffer); + break; + case APR_DBD_TYPE_SHORT: + *(short*)data = atoi(bind->buffer); + break; + case APR_DBD_TYPE_USHORT: + *(unsigned short*)data = atoi(bind->buffer); + break; + case APR_DBD_TYPE_INT: + *(int*)data = atoi(bind->buffer); + break; + case APR_DBD_TYPE_UINT: + *(unsigned int*)data = atoi(bind->buffer); + break; + case APR_DBD_TYPE_LONG: + *(long*)data = atol(bind->buffer); + break; + case APR_DBD_TYPE_ULONG: + *(unsigned long*)data = atol(bind->buffer); + break; + case APR_DBD_TYPE_LONGLONG: + *(apr_int64_t*)data = apr_atoi64(bind->buffer); + break; + case APR_DBD_TYPE_ULONGLONG: + *(apr_uint64_t*)data = apr_atoi64(bind->buffer); + break; + case APR_DBD_TYPE_FLOAT: + *(float*)data = (float) atof(bind->buffer); + break; + case APR_DBD_TYPE_DOUBLE: + *(double*)data = atof(bind->buffer); + break; + case APR_DBD_TYPE_STRING: + case APR_DBD_TYPE_TEXT: + case APR_DBD_TYPE_TIME: + case APR_DBD_TYPE_DATE: + case APR_DBD_TYPE_DATETIME: + case APR_DBD_TYPE_TIMESTAMP: + case APR_DBD_TYPE_ZTIMESTAMP: + *((char*)bind->buffer+bind->buffer_length-1) = '\0'; + *(char**)data = bind->buffer; + break; + case APR_DBD_TYPE_BLOB: + case APR_DBD_TYPE_CLOB: + { + apr_bucket *e; + apr_bucket_brigade *b = (apr_bucket_brigade*)data; + + e = apr_bucket_lob_create(row, n, 0, len, + row->res->pool, b->bucket_alloc); + APR_BRIGADE_INSERT_TAIL(b, e); + } + break; + case APR_DBD_TYPE_NULL: + *(void**)data = NULL; + break; + default: + return APR_EGENERAL; + } + } + else { + if (row->row[n] == NULL) { + return APR_ENOENT; + } + + switch (type) { + case APR_DBD_TYPE_TINY: + *(char*)data = atoi(row->row[n]); + break; + case APR_DBD_TYPE_UTINY: + *(unsigned char*)data = atoi(row->row[n]); + break; + case APR_DBD_TYPE_SHORT: + *(short*)data = atoi(row->row[n]); + break; + case APR_DBD_TYPE_USHORT: + *(unsigned short*)data = atoi(row->row[n]); + break; + case APR_DBD_TYPE_INT: + *(int*)data = atoi(row->row[n]); + break; + case APR_DBD_TYPE_UINT: + *(unsigned int*)data = atoi(row->row[n]); + break; + case APR_DBD_TYPE_LONG: + *(long*)data = atol(row->row[n]); + break; + case APR_DBD_TYPE_ULONG: + *(unsigned long*)data = atol(row->row[n]); + break; + case APR_DBD_TYPE_LONGLONG: + *(apr_int64_t*)data = apr_atoi64(row->row[n]); + break; + case APR_DBD_TYPE_ULONGLONG: + *(apr_uint64_t*)data = apr_atoi64(row->row[n]); + break; + case APR_DBD_TYPE_FLOAT: + *(float*)data = (float) atof(row->row[n]); + break; + case APR_DBD_TYPE_DOUBLE: + *(double*)data = atof(row->row[n]); + break; + case APR_DBD_TYPE_STRING: + case APR_DBD_TYPE_TEXT: + case APR_DBD_TYPE_TIME: + case APR_DBD_TYPE_DATE: + case APR_DBD_TYPE_DATETIME: + case APR_DBD_TYPE_TIMESTAMP: + case APR_DBD_TYPE_ZTIMESTAMP: + *(char**)data = row->row[n]; + break; + case APR_DBD_TYPE_BLOB: + case APR_DBD_TYPE_CLOB: + { + apr_bucket *e; + apr_bucket_brigade *b = (apr_bucket_brigade*)data; + + e = apr_bucket_pool_create(row->row[n], row->len[n], + row->res->pool, b->bucket_alloc); + APR_BRIGADE_INSERT_TAIL(b, e); + } + break; + case APR_DBD_TYPE_NULL: + *(void**)data = NULL; + break; + default: + return APR_EGENERAL; + } + } + return 0; +} + +static const char *dbd_mysql_error(apr_dbd_t *sql, int n) +{ + return mysql_error(sql->conn); +} + +static int dbd_mysql_query(apr_dbd_t *sql, int *nrows, const char *query) +{ + int ret; + if (sql->trans && sql->trans->errnum) { + return sql->trans->errnum; + } + ret = mysql_query(sql->conn, query); + if (ret != 0) { + ret = mysql_errno(sql->conn); + } + *nrows = (int) mysql_affected_rows(sql->conn); + if (TXN_NOTICE_ERRORS(sql->trans)) { + sql->trans->errnum = ret; + } + return ret; +} + +static const char *dbd_mysql_escape(apr_pool_t *pool, const char *arg, + apr_dbd_t *sql) +{ + unsigned long len = strlen(arg); + char *ret = apr_palloc(pool, 2*len + 1); + mysql_real_escape_string(sql->conn, ret, arg, len); + return ret; +} + +static apr_status_t stmt_close(void *data) +{ + mysql_stmt_close(data); + return APR_SUCCESS; +} + +static int dbd_mysql_prepare(apr_pool_t *pool, apr_dbd_t *sql, + const char *query, const char *label, + int nargs, int nvals, apr_dbd_type_e *types, + apr_dbd_prepared_t **statement) +{ + /* Translate from apr_dbd to native query format */ + int ret; + + if (!*statement) { + *statement = apr_palloc(pool, sizeof(apr_dbd_prepared_t)); + } + (*statement)->stmt = mysql_stmt_init(sql->conn); + + if ((*statement)->stmt) { + apr_pool_cleanup_register(pool, (*statement)->stmt, + stmt_close, apr_pool_cleanup_null); + ret = mysql_stmt_prepare((*statement)->stmt, query, strlen(query)); + + if (ret != 0) { + ret = mysql_stmt_errno((*statement)->stmt); + } + + (*statement)->nargs = nargs; + (*statement)->nvals = nvals; + (*statement)->types = types; + + return ret; + } + + return CR_OUT_OF_MEMORY; +} + +static void dbd_mysql_bind(apr_dbd_prepared_t *statement, + const char **values, MYSQL_BIND *bind) +{ + int i, j; + + for (i = 0, j = 0; i < statement->nargs; i++, j++) { + bind[i].length = &bind[i].buffer_length; + bind[i].is_unsigned = 0; + bind[i].is_null = NULL; + + if (values[j] == NULL) { + bind[i].buffer_type = MYSQL_TYPE_NULL; + } + else { + switch (statement->types[i]) { + case APR_DBD_TYPE_BLOB: + case APR_DBD_TYPE_CLOB: + bind[i].buffer_type = MYSQL_TYPE_LONG_BLOB; + bind[i].buffer = (void*)values[j]; + bind[i].buffer_length = atol(values[++j]); + + /* skip table and column */ + j += 2; + break; + default: + bind[i].buffer_type = MYSQL_TYPE_VAR_STRING; + bind[i].buffer = (void*)values[j]; + bind[i].buffer_length = strlen(values[j]); + break; + } + } + } + + return; +} + +static int dbd_mysql_pquery_internal(apr_pool_t *pool, apr_dbd_t *sql, + int *nrows, apr_dbd_prepared_t *statement, + MYSQL_BIND *bind) +{ + int ret; + + ret = mysql_stmt_bind_param(statement->stmt, bind); + if (ret != 0) { + *nrows = 0; + ret = mysql_stmt_errno(statement->stmt); + } + else { + ret = mysql_stmt_execute(statement->stmt); + if (ret != 0) { + ret = mysql_stmt_errno(statement->stmt); + } + *nrows = (int) mysql_stmt_affected_rows(statement->stmt); + } + + return ret; +} + +static int dbd_mysql_pquery(apr_pool_t *pool, apr_dbd_t *sql, + int *nrows, apr_dbd_prepared_t *statement, + const char **values) +{ + MYSQL_BIND *bind; + int ret; + + if (sql->trans && sql->trans->errnum) { + return sql->trans->errnum; + } + + bind = apr_palloc(pool, statement->nargs * sizeof(MYSQL_BIND)); + + dbd_mysql_bind(statement, values, bind); + + ret = dbd_mysql_pquery_internal(pool, sql, nrows, statement, bind); + + if (TXN_NOTICE_ERRORS(sql->trans)) { + sql->trans->errnum = ret; + } + return ret; +} + +static int dbd_mysql_pvquery(apr_pool_t *pool, apr_dbd_t *sql, int *nrows, + apr_dbd_prepared_t *statement, va_list args) +{ + const char **values; + int i; + + if (sql->trans && sql->trans->errnum) { + return sql->trans->errnum; + } + + values = apr_palloc(pool, sizeof(*values) * statement->nvals); + + for (i = 0; i < statement->nvals; i++) { + values[i] = va_arg(args, const char*); + } + + return dbd_mysql_pquery(pool, sql, nrows, statement, values); +} + +static int dbd_mysql_pselect_internal(apr_pool_t *pool, apr_dbd_t *sql, + apr_dbd_results_t **res, + apr_dbd_prepared_t *statement, + int random, MYSQL_BIND *bind) +{ + int nfields, i; + my_bool *is_nullr; +#if MYSQL_VERSION_ID >= 50000 + my_bool *error; +#endif + int ret; + unsigned long *length, maxlen; + + ret = mysql_stmt_bind_param(statement->stmt, bind); + if (ret == 0) { + ret = mysql_stmt_execute(statement->stmt); + if (!ret) { + if (!*res) { + *res = apr_pcalloc(pool, sizeof(apr_dbd_results_t)); + } + (*res)->random = random; + (*res)->statement = statement->stmt; + (*res)->res = mysql_stmt_result_metadata(statement->stmt); + (*res)->pool = pool; + apr_pool_cleanup_register(pool, (*res)->res, + free_result, apr_pool_cleanup_null); + nfields = mysql_num_fields((*res)->res); + if (!(*res)->bind) { + (*res)->bind = apr_palloc(pool, nfields*sizeof(MYSQL_BIND)); + length = apr_pcalloc(pool, nfields*sizeof(unsigned long)); +#if MYSQL_VERSION_ID >= 50000 + error = apr_palloc(pool, nfields*sizeof(my_bool)); +#endif + is_nullr = apr_pcalloc(pool, nfields*sizeof(my_bool)); + for ( i = 0; i < nfields; ++i ) { + maxlen = ((*res)->res->fields[i].length < sql->fldsz ? + (*res)->res->fields[i].length : sql->fldsz) + 1; + if ((*res)->res->fields[i].type == MYSQL_TYPE_BLOB) { + (*res)->bind[i].buffer_type = MYSQL_TYPE_LONG_BLOB; + } + else { + (*res)->bind[i].buffer_type = MYSQL_TYPE_VAR_STRING; + } + (*res)->bind[i].buffer_length = maxlen; + (*res)->bind[i].length = &length[i]; + (*res)->bind[i].buffer = apr_palloc(pool, maxlen); + (*res)->bind[i].is_null = is_nullr+i; +#if MYSQL_VERSION_ID >= 50000 + (*res)->bind[i].error = error+i; +#endif + } + } + ret = mysql_stmt_bind_result(statement->stmt, (*res)->bind); + if (!ret) { + ret = mysql_stmt_store_result(statement->stmt); + } + } + } + if (ret != 0) { + ret = mysql_stmt_errno(statement->stmt); + } + + return ret; +} + +static int dbd_mysql_pselect(apr_pool_t *pool, apr_dbd_t *sql, + apr_dbd_results_t **res, + apr_dbd_prepared_t *statement, int random, + const char **args) +{ + int ret; + MYSQL_BIND *bind; + + if (sql->trans && sql->trans->errnum) { + return sql->trans->errnum; + } + + bind = apr_palloc(pool, statement->nargs * sizeof(MYSQL_BIND)); + + dbd_mysql_bind(statement, args, bind); + + ret = dbd_mysql_pselect_internal(pool, sql, res, statement, random, bind); + + if (TXN_NOTICE_ERRORS(sql->trans)) { + sql->trans->errnum = ret; + } + return ret; +} + +static int dbd_mysql_pvselect(apr_pool_t *pool, apr_dbd_t *sql, + apr_dbd_results_t **res, + apr_dbd_prepared_t *statement, int random, + va_list args) +{ + const char **values; + int i; + + if (sql->trans && sql->trans->errnum) { + return sql->trans->errnum; + } + + values = apr_palloc(pool, sizeof(*values) * statement->nvals); + + for (i = 0; i < statement->nvals; i++) { + values[i] = va_arg(args, const char*); + } + + return dbd_mysql_pselect(pool, sql, res, statement, random, values); +} + +static void dbd_mysql_bbind(apr_pool_t *pool, apr_dbd_prepared_t *statement, + const void **values, MYSQL_BIND *bind) +{ + void *arg; + int i, j; + apr_dbd_type_e type; + + for (i = 0, j = 0; i < statement->nargs; i++, j++) { + arg = (void *)values[j]; + + bind[i].length = &bind[i].buffer_length; + bind[i].is_null = NULL; + + type = (arg == NULL ? APR_DBD_TYPE_NULL : statement->types[i]); + switch (type) { + case APR_DBD_TYPE_TINY: + bind[i].buffer = arg; + bind[i].buffer_type = MYSQL_TYPE_TINY; + bind[i].is_unsigned = 0; + break; + case APR_DBD_TYPE_UTINY: + bind[i].buffer = arg; + bind[i].buffer_type = MYSQL_TYPE_TINY; + bind[i].is_unsigned = 1; + break; + case APR_DBD_TYPE_SHORT: + bind[i].buffer = arg; + bind[i].buffer_type = MYSQL_TYPE_SHORT; + bind[i].is_unsigned = 0; + break; + case APR_DBD_TYPE_USHORT: + bind[i].buffer = arg; + bind[i].buffer_type = MYSQL_TYPE_SHORT; + bind[i].is_unsigned = 1; + break; + case APR_DBD_TYPE_INT: + bind[i].buffer = arg; + bind[i].buffer_type = MYSQL_TYPE_LONG; + bind[i].is_unsigned = 0; + break; + case APR_DBD_TYPE_UINT: + bind[i].buffer = arg; + bind[i].buffer_type = MYSQL_TYPE_LONG; + bind[i].is_unsigned = 1; + break; + case APR_DBD_TYPE_LONG: + if (sizeof(int) == sizeof(long)) { + bind[i].buffer = arg; + } + else { + bind[i].buffer = apr_palloc(pool, sizeof(int)); + *(int*)bind[i].buffer = *(long*)arg; + } + bind[i].buffer_type = MYSQL_TYPE_LONG; + bind[i].is_unsigned = 0; + break; + case APR_DBD_TYPE_ULONG: + if (sizeof(unsigned int) == sizeof(unsigned long)) { + bind[i].buffer = arg; + } + else { + bind[i].buffer = apr_palloc(pool, sizeof(unsigned int)); + *(unsigned int*)bind[i].buffer = *(unsigned long*)arg; + } + bind[i].buffer_type = MYSQL_TYPE_LONG; + bind[i].is_unsigned = 1; + break; + case APR_DBD_TYPE_LONGLONG: + if (sizeof(my_ulonglong) == sizeof(apr_int64_t)) { + bind[i].buffer = arg; + bind[i].buffer_type = MYSQL_TYPE_LONGLONG; + } + else { /* have to downsize, long long is not portable */ + bind[i].buffer = apr_palloc(pool, sizeof(long)); + *(long*)bind[i].buffer = (long) *(apr_int64_t*)arg; + bind[i].buffer_type = MYSQL_TYPE_LONG; + } + bind[i].is_unsigned = 0; + break; + case APR_DBD_TYPE_ULONGLONG: + if (sizeof(my_ulonglong) == sizeof(apr_uint64_t)) { + bind[i].buffer = arg; + bind[i].buffer_type = MYSQL_TYPE_LONGLONG; + } + else { /* have to downsize, long long is not portable */ + bind[i].buffer = apr_palloc(pool, sizeof(long)); + *(unsigned long*)bind[i].buffer = + (unsigned long) *(apr_uint64_t*)arg; + bind[i].buffer_type = MYSQL_TYPE_LONG; + } + bind[i].is_unsigned = 1; + break; + case APR_DBD_TYPE_FLOAT: + bind[i].buffer = arg; + bind[i].buffer_type = MYSQL_TYPE_FLOAT; + bind[i].is_unsigned = 0; + break; + case APR_DBD_TYPE_DOUBLE: + bind[i].buffer = arg; + bind[i].buffer_type = MYSQL_TYPE_DOUBLE; + bind[i].is_unsigned = 0; + break; + case APR_DBD_TYPE_STRING: + case APR_DBD_TYPE_TEXT: + case APR_DBD_TYPE_TIME: + case APR_DBD_TYPE_DATE: + case APR_DBD_TYPE_DATETIME: + case APR_DBD_TYPE_TIMESTAMP: + case APR_DBD_TYPE_ZTIMESTAMP: + bind[i].buffer = arg; + bind[i].buffer_type = MYSQL_TYPE_VAR_STRING; + bind[i].is_unsigned = 0; + bind[i].buffer_length = strlen((const char *)arg); + break; + case APR_DBD_TYPE_BLOB: + case APR_DBD_TYPE_CLOB: + bind[i].buffer = (void *)arg; + bind[i].buffer_type = MYSQL_TYPE_LONG_BLOB; + bind[i].is_unsigned = 0; + bind[i].buffer_length = *(apr_size_t*)values[++j]; + + /* skip table and column */ + j += 2; + break; + case APR_DBD_TYPE_NULL: + default: + bind[i].buffer_type = MYSQL_TYPE_NULL; + break; + } + } + + return; +} + +static int dbd_mysql_pbquery(apr_pool_t *pool, apr_dbd_t *sql, + int *nrows, apr_dbd_prepared_t *statement, + const void **values) +{ + MYSQL_BIND *bind; + int ret; + + if (sql->trans && sql->trans->errnum) { + return sql->trans->errnum; + } + + bind = apr_palloc(pool, statement->nargs * sizeof(MYSQL_BIND)); + + dbd_mysql_bbind(pool, statement, values, bind); + + ret = dbd_mysql_pquery_internal(pool, sql, nrows, statement, bind); + + if (TXN_NOTICE_ERRORS(sql->trans)) { + sql->trans->errnum = ret; + } + return ret; +} + +static int dbd_mysql_pvbquery(apr_pool_t *pool, apr_dbd_t *sql, int *nrows, + apr_dbd_prepared_t *statement, va_list args) +{ + const void **values; + int i; + + if (sql->trans && sql->trans->errnum) { + return sql->trans->errnum; + } + + values = apr_palloc(pool, sizeof(*values) * statement->nvals); + + for (i = 0; i < statement->nvals; i++) { + values[i] = va_arg(args, const void*); + } + + return dbd_mysql_pbquery(pool, sql, nrows, statement, values); +} + +static int dbd_mysql_pbselect(apr_pool_t *pool, apr_dbd_t *sql, + apr_dbd_results_t **res, + apr_dbd_prepared_t *statement, int random, + const void **args) +{ + int ret; + MYSQL_BIND *bind; + + if (sql->trans && sql->trans->errnum) { + return sql->trans->errnum; + } + + bind = apr_palloc(pool, statement->nargs * sizeof(MYSQL_BIND)); + + dbd_mysql_bbind(pool, statement, args, bind); + + ret = dbd_mysql_pselect_internal(pool, sql, res, statement, random, bind); + + if (TXN_NOTICE_ERRORS(sql->trans)) { + sql->trans->errnum = ret; + } + return ret; +} + +static int dbd_mysql_pvbselect(apr_pool_t *pool, apr_dbd_t *sql, + apr_dbd_results_t **res, + apr_dbd_prepared_t *statement, int random, + va_list args) +{ + const void **values; + int i; + + if (sql->trans && sql->trans->errnum) { + return sql->trans->errnum; + } + + values = apr_palloc(pool, sizeof(*values) * statement->nvals); + + for (i = 0; i < statement->nvals; i++) { + values[i] = va_arg(args, const void*); + } + + return dbd_mysql_pbselect(pool, sql, res, statement, random, values); +} + +static int dbd_mysql_end_transaction(apr_dbd_transaction_t *trans) +{ + int ret = -1; + if (trans) { + /* rollback on error or explicit rollback request */ + if (trans->errnum || TXN_DO_ROLLBACK(trans)) { + trans->errnum = 0; + ret = mysql_rollback(trans->handle->conn); + } + else { + ret = mysql_commit(trans->handle->conn); + } + ret |= mysql_autocommit(trans->handle->conn, 1); + trans->handle->trans = NULL; + } + return ret; +} +/* Whether or not transactions work depends on whether the + * underlying DB supports them within MySQL. Unfortunately + * it fails silently with the default InnoDB. + */ + +static int dbd_mysql_transaction(apr_pool_t *pool, apr_dbd_t *handle, + apr_dbd_transaction_t **trans) +{ + /* Don't try recursive transactions here */ + if (handle->trans) { + dbd_mysql_end_transaction(handle->trans) ; + } + if (!*trans) { + *trans = apr_pcalloc(pool, sizeof(apr_dbd_transaction_t)); + } + (*trans)->errnum = mysql_autocommit(handle->conn, 0); + (*trans)->handle = handle; + handle->trans = *trans; + return (*trans)->errnum; +} + +static int dbd_mysql_transaction_mode_get(apr_dbd_transaction_t *trans) +{ + if (!trans) + return APR_DBD_TRANSACTION_COMMIT; + + return trans->mode; +} + +static int dbd_mysql_transaction_mode_set(apr_dbd_transaction_t *trans, + int mode) +{ + if (!trans) + return APR_DBD_TRANSACTION_COMMIT; + + return trans->mode = (mode & TXN_MODE_BITS); +} + +static apr_dbd_t *dbd_mysql_open(apr_pool_t *pool, const char *params, + const char **error) +{ + static const char *const delims = " \r\n\t;|,"; + const char *ptr; + int i; + const char *key; + size_t klen; + const char *value; + size_t vlen; +#if MYSQL_VERSION_ID >= 50013 + my_bool do_reconnect = 1; +#endif + MYSQL *real_conn; + unsigned long flags = 0; + + struct { + const char *field; + const char *value; + } fields[] = { + {"host", NULL}, + {"user", NULL}, + {"pass", NULL}, + {"dbname", NULL}, + {"port", NULL}, + {"sock", NULL}, + {"flags", NULL}, + {"fldsz", NULL}, + {"group", NULL}, +#if MYSQL_VERSION_ID >= 50013 + {"reconnect", NULL}, + {"connecttimeout", NULL}, + {"readtimeout", NULL}, + {"writetimeout", NULL}, +#endif + {NULL, NULL} + }; + unsigned int port = 0; +#if MYSQL_VERSION_ID >= 50013 + unsigned int timeout = 0; +#endif + apr_dbd_t *sql = apr_pcalloc(pool, sizeof(apr_dbd_t)); + sql->fldsz = FIELDSIZE; + sql->conn = mysql_init(sql->conn); + if ( sql->conn == NULL ) { + return NULL; + } + for (ptr = strchr(params, '='); ptr; ptr = strchr(ptr, '=')) { + /* don't dereference memory that may not belong to us */ + if (ptr == params) { + ++ptr; + continue; + } + for (key = ptr-1; apr_isspace(*key); --key); + klen = 0; + while (apr_isalpha(*key)) { + /* don't parse backwards off the start of the string */ + if (key == params) { + --key; + ++klen; + break; + } + --key; + ++klen; + } + ++key; + for (value = ptr+1; apr_isspace(*value); ++value); + vlen = strcspn(value, delims); + for (i = 0; fields[i].field != NULL; i++) { + if (!strncasecmp(fields[i].field, key, klen)) { + fields[i].value = apr_pstrndup(pool, value, vlen); + break; + } + } + ptr = value+vlen; + } + if (fields[4].value != NULL) { + port = atoi(fields[4].value); + } + if (fields[6].value != NULL && + !strcmp(fields[6].value, "CLIENT_FOUND_ROWS")) { + flags |= CLIENT_FOUND_ROWS; /* only option we know */ + } + if (fields[7].value != NULL) { + sql->fldsz = atol(fields[7].value); + } + if (fields[8].value != NULL) { + mysql_options(sql->conn, MYSQL_READ_DEFAULT_GROUP, fields[8].value); + } +#if MYSQL_VERSION_ID >= 50013 + if (fields[9].value != NULL) { + do_reconnect = atoi(fields[9].value) ? 1 : 0; + } + if (fields[10].value != NULL) { + timeout = atoi(fields[10].value); + mysql_options(sql->conn, MYSQL_OPT_CONNECT_TIMEOUT, + (const void *)&timeout); + } + if (fields[11].value != NULL) { + timeout = atoi(fields[11].value); + mysql_options(sql->conn, MYSQL_OPT_READ_TIMEOUT, + (const void *)&timeout); + } + if (fields[12].value != NULL) { + timeout = atoi(fields[12].value); + mysql_options(sql->conn, MYSQL_OPT_WRITE_TIMEOUT, + (const void *)&timeout); + } +#endif + +#if MYSQL_VERSION_ID >= 50013 + /* the MySQL manual says this should be BEFORE mysql_real_connect */ + mysql_options(sql->conn, MYSQL_OPT_RECONNECT, &do_reconnect); +#endif + + real_conn = mysql_real_connect(sql->conn, fields[0].value, + fields[1].value, fields[2].value, + fields[3].value, port, + fields[5].value, flags); + + if(real_conn == NULL) { + if (error) { + *error = apr_pstrdup(pool, mysql_error(sql->conn)); + } + mysql_close(sql->conn); + return NULL; + } + +#if MYSQL_VERSION_ID >= 50013 + /* Some say this should be AFTER mysql_real_connect */ + mysql_options(sql->conn, MYSQL_OPT_RECONNECT, &do_reconnect); +#endif + + return sql; +} + +static apr_status_t dbd_mysql_close(apr_dbd_t *handle) +{ + mysql_close(handle->conn); + return APR_SUCCESS; +} + +static apr_status_t dbd_mysql_check_conn(apr_pool_t *pool, + apr_dbd_t *handle) +{ + return mysql_ping(handle->conn) ? APR_EGENERAL : APR_SUCCESS; +} + +static int dbd_mysql_select_db(apr_pool_t *pool, apr_dbd_t* handle, + const char* name) +{ + return mysql_select_db(handle->conn, name); +} + +static void *dbd_mysql_native(apr_dbd_t *handle) +{ + return handle->conn; +} + +static int dbd_mysql_num_cols(apr_dbd_results_t *res) +{ + if (res->statement) { + return mysql_stmt_field_count(res->statement); + } + else { + return mysql_num_fields(res->res); + } +} + +static int dbd_mysql_num_tuples(apr_dbd_results_t *res) +{ + if (res->random) { + if (res->statement) { + return (int) mysql_stmt_num_rows(res->statement); + } + else { + return (int) mysql_num_rows(res->res); + } + } + else { + return -1; + } +} + +static apr_status_t thread_end(void *data) +{ + mysql_thread_end(); + return APR_SUCCESS; +} + +static void dbd_mysql_init(apr_pool_t *pool) +{ + my_init(); + mysql_thread_init(); + + /* FIXME: this is a guess; find out what it really does */ + apr_pool_cleanup_register(pool, NULL, thread_end, apr_pool_cleanup_null); +} +APR_MODULE_DECLARE_DATA const apr_dbd_driver_t apr_dbd_mysql_driver = { + "mysql", + dbd_mysql_init, + dbd_mysql_native, + dbd_mysql_open, + dbd_mysql_check_conn, + dbd_mysql_close, + dbd_mysql_select_db, + dbd_mysql_transaction, + dbd_mysql_end_transaction, + dbd_mysql_query, + dbd_mysql_select, + dbd_mysql_num_cols, + dbd_mysql_num_tuples, + dbd_mysql_get_row, + dbd_mysql_get_entry, + dbd_mysql_error, + dbd_mysql_escape, + dbd_mysql_prepare, + dbd_mysql_pvquery, + dbd_mysql_pvselect, + dbd_mysql_pquery, + dbd_mysql_pselect, + dbd_mysql_get_name, + dbd_mysql_transaction_mode_get, + dbd_mysql_transaction_mode_set, + "?", + dbd_mysql_pvbquery, + dbd_mysql_pvbselect, + dbd_mysql_pbquery, + dbd_mysql_pbselect, + dbd_mysql_datum_get +}; + +#endif diff --git a/dbd/apr_dbd_mysql.dsp b/dbd/apr_dbd_mysql.dsp new file mode 100644 index 00000000000..dbaff5d3e33 --- /dev/null +++ b/dbd/apr_dbd_mysql.dsp @@ -0,0 +1,207 @@ +# Microsoft Developer Studio Project File - Name="apr_dbd_mysql" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=apr_dbd_mysql - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "apr_dbd_mysql.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "apr_dbd_mysql.mak" CFG="apr_dbd_mysql - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "apr_dbd_mysql - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "apr_dbd_mysql - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "apr_dbd_mysql - x64 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "apr_dbd_mysql - x64 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "apr_dbd_mysql - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c +# ADD CPP /nologo /MD /W3 /Zi /O2 /Oy- /I "../include" /I "../include/arch/win32" /I "../include/private" /I "../../mysql/include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "APU_DSO_MODULE_BUILD" /D APU_HAVE_MYSQL=1 /D "HAVE_MYSQL_H" /Fo"$(INTDIR)\" /Fd"$(INTDIR)\apr_dbd_mysql_src" /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o /win32 "NUL" +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o /win32 "NUL" +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /fo"Release/apr_dbd_mysql-1.res" /d DLL_NAME="apr_dbd_mysql" /d "NDEBUG" /d "APU_VERSION_ONLY" /I "../include" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib libmysql.lib /nologo /base:"0x6EF50000" /subsystem:windows /dll /incremental:no /debug /opt:ref +# ADD LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib libmysql.lib /nologo /base:"0x6EF50000" /subsystem:windows /dll /incremental:no /debug /libpath:"..\..\mysql\lib" /out:"Release\apr_dbd_mysql-1.dll" /pdb:"Release\apr_dbd_mysql-1.pdb" /implib:"Release\apr_dbd_mysql-1.lib" /MACHINE:X86 /opt:ref +# Begin Special Build Tool +TargetPath=Release\apr_dbd_mysql-1.dll +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2 +# End Special Build Tool + +!ELSEIF "$(CFG)" == "apr_dbd_mysql - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /EHsc /c +# ADD CPP /nologo /MDd /W3 /Zi /Od /I "../include" /I "../include/arch/win32" /I "../include/private" /I "../../mysql/include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "APU_DSO_MODULE_BUILD" /D APU_HAVE_MYSQL=1 /D "HAVE_MYSQL_H" /Fo"$(INTDIR)\" /Fd"$(INTDIR)\apr_dbd_mysql_src" /FD /EHsc /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o /win32 "NUL" +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o /win32 "NUL" +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /fo"Debug/apr_dbd_mysql-1.res" /d DLL_NAME="apr_dbd_mysql" /d "_DEBUG" /d "APU_VERSION_ONLY" /I "../include" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib libmysqld.lib /nologo /base:"0x6EF50000" /subsystem:windows /dll /incremental:no /debug +# ADD LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib libmysqld.lib /nologo /base:"0x6EF50000" /subsystem:windows /dll /incremental:no /debug /libpath:"..\..\mysql\lib" /out:"Debug\apr_dbd_mysql-1.dll" /pdb:"Debug\apr_dbd_mysql-1.pdb" /implib:"Debug\apr_dbd_mysql-1.lib" /MACHINE:X86 +# Begin Special Build Tool +TargetPath=Debug\apr_dbd_mysql-1.dll +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2 +# End Special Build Tool + +!ELSEIF "$(CFG)" == "apr_dbd_mysql - x64 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "x64\Release" +# PROP BASE Intermediate_Dir "x64\Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "x64\Release" +# PROP Intermediate_Dir "x64\Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c +# ADD CPP /nologo /MD /W3 /Zi /O2 /Oy- /I "../include" /I "../include/arch/win32" /I "../include/private" /I "../../mysql/include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "APU_DSO_MODULE_BUILD" /D APU_HAVE_MYSQL=1 /D "HAVE_MYSQL_H" /Fo"$(INTDIR)\" /Fd"$(INTDIR)\apr_dbd_mysql_src" /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o /win32 "NUL" +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o /win32 "NUL" +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /fo"x64/Release/apr_dbd_mysql-1.res" /d DLL_NAME="apr_dbd_mysql" /d "NDEBUG" /d "APU_VERSION_ONLY" /I "../include" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib libmysql.lib /nologo /base:"0x6EF50000" /subsystem:windows /dll /incremental:no /debug /opt:ref +# ADD LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib libmysql.lib /nologo /base:"0x6EF50000" /subsystem:windows /dll /incremental:no /debug /libpath:"..\..\mysql\lib" /out:"x64\Release\apr_dbd_mysql-1.dll" /pdb:"x64\Release\apr_dbd_mysql-1.pdb" /implib:"x64\Release\apr_dbd_mysql-1.lib" /MACHINE:X64 /opt:ref +# Begin Special Build Tool +TargetPath=x64\Release\apr_dbd_mysql-1.dll +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2 +# End Special Build Tool + +!ELSEIF "$(CFG)" == "apr_dbd_mysql - x64 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "x64\Debug" +# PROP BASE Intermediate_Dir "x64\Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "x64\Debug" +# PROP Intermediate_Dir "x64\Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /EHsc /c +# ADD CPP /nologo /MDd /W3 /Zi /Od /I "../include" /I "../include/arch/win32" /I "../include/private" /I "../../mysql/include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "APU_DSO_MODULE_BUILD" /D APU_HAVE_MYSQL=1 /D "HAVE_MYSQL_H" /Fo"$(INTDIR)\" /Fd"$(INTDIR)\apr_dbd_mysql_src" /FD /EHsc /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o /win32 "NUL" +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o /win32 "NUL" +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /fo"x64/Debug/apr_dbd_mysql-1.res" /d DLL_NAME="apr_dbd_mysql" /d "_DEBUG" /d "APU_VERSION_ONLY" /I "../include" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib libmysqld.lib /nologo /base:"0x6EF50000" /subsystem:windows /dll /incremental:no /debug +# ADD LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib libmysqld.lib /nologo /base:"0x6EF50000" /subsystem:windows /dll /incremental:no /debug /libpath:"..\..\mysql\lib" /out:"x64\Debug\apr_dbd_mysql-1.dll" /pdb:"x64\Debug\apr_dbd_mysql-1.pdb" /implib:"x64\Debug\apr_dbd_mysql-1.lib" /MACHINE:X64 +# Begin Special Build Tool +TargetPath=x64\Debug\apr_dbd_mysql-1.dll +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2 +# End Special Build Tool + +!ENDIF + +# Begin Target + +# Name "apr_dbd_mysql - Win32 Release" +# Name "apr_dbd_mysql - Win32 Debug" +# Name "apr_dbd_mysql - x64 Release" +# Name "apr_dbd_mysql - x64 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\apr_dbd_mysql.c +# End Source File +# End Group +# Begin Group "Public Header Files" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\include\apr_dbd.h +# End Source File +# End Group +# Begin Group "Internal Header Files" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\include\private\apu_config.h +# End Source File +# Begin Source File + +SOURCE=..\include\private\apu_dbd_internal.h +# End Source File +# Begin Source File + +SOURCE=..\include\private\apu_internal.h +# End Source File +# End Group +# Begin Source File + +SOURCE=..\libapr.rc +# End Source File +# End Target +# End Project diff --git a/dbd/apr_dbd_odbc.c b/dbd/apr_dbd_odbc.c new file mode 100644 index 00000000000..65306792026 --- /dev/null +++ b/dbd/apr_dbd_odbc.c @@ -0,0 +1,1734 @@ +/* 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 "apu.h" +#include "apr_private.h" +#if APU_HAVE_ODBC + +#include "apr.h" +#include "apr_strings.h" +#include "apr_buckets.h" +#include "apr_env.h" +#include "apr_file_io.h" +#include "apr_file_info.h" +#include "apr_dbd_internal.h" +#include "apr_thread_proc.h" +#include "apr_version.h" + +#include <stdlib.h> + +/* If library is ODBC-V2, use macros for limited ODBC-V2 support + * No random access in V2. + */ +#ifdef ODBCV2 +#define ODBCVER 0x0200 +#include "apr_dbd_odbc_v2.h" +#endif + +/* standard ODBC include files */ +#ifdef HAVE_SQL_H +#include <sql.h> +#include <sqlext.h> +#elif defined(HAVE_ODBC_SQL_H) +#include <odbc/sql.h> +#include <odbc/sqlext.h> +#endif + +/* Driver name is "odbc" and the entry point is 'apr_dbd_odbc_driver' + * unless ODBC_DRIVER_NAME is defined and it is linked with another db library which + * is ODBC source-compatible. e.g. DB2, Informix, TimesTen, mysql. + */ +#ifndef ODBC_DRIVER_NAME +#define ODBC_DRIVER_NAME odbc +#endif +#define STRINGIFY(x) #x +#define NAMIFY2(n) apr_dbd_##n##_driver +#define NAMIFY1(n) NAMIFY2(n) +#define ODBC_DRIVER_STRING STRINGIFY(ODBC_DRIVER_NAME) +#define ODBC_DRIVER_ENTRY NAMIFY1(ODBC_DRIVER_NAME) + +/* Required APR version for this driver */ +#define DRIVER_APR_VERSION_MAJOR APR_MAJOR_VERSION +#define DRIVER_APR_VERSION_MINOR APR_MINOR_VERSION + +static SQLHANDLE henv = NULL; /* ODBC ENV handle is process-wide */ + +/* Use a CHECK_ERROR macro so we can grab the source line numbers + * for error reports + */ +static void check_error(apr_dbd_t *a, const char *step, SQLRETURN rc, + SQLSMALLINT type, SQLHANDLE h, int line); +#define CHECK_ERROR(a,s,r,t,h) check_error(a,s,r,t,h, __LINE__) + +#define SOURCE_FILE __FILE__ /* source file for error messages */ +#define MAX_ERROR_STRING 1024 /* max length of message in dbc */ +#define MAX_COLUMN_NAME 256 /* longest column name recognized */ +#define DEFAULT_BUFFER_SIZE 1024 /* value for defaultBufferSize */ + +#define MAX_PARAMS 20 +#define DEFAULTSEPS " \t\r\n,=" +#define CSINGLEQUOTE '\'' +#define SSINGLEQUOTE "\'" + +#define TEXTMODE 1 /* used for text (APR 1.2) mode params */ +#define BINARYMODE 0 /* used for binary (APR 1.3+) mode params */ + +/* Identify datatypes which are LOBs + * - DB2 DRDA driver uses undefined types -98 and -99 for CLOB & BLOB + */ +#define IS_LOB(t) (t == SQL_LONGVARCHAR \ + || t == SQL_LONGVARBINARY || t == SQL_VARBINARY \ + || t == -98 || t == -99) + +/* These types are CLOBs + * - DB2 DRDA driver uses undefined type -98 for CLOB + */ +#define IS_CLOB(t) \ + (t == SQL_LONGVARCHAR || t == -98) + +/* Convert a SQL result to an APR result */ +#define APR_FROM_SQL_RESULT(rc) \ + (SQL_SUCCEEDED(rc) ? APR_SUCCESS : APR_EGENERAL) + +/* DBD opaque structures */ +struct apr_dbd_t +{ + SQLHANDLE dbc; /* SQL connection handle - NULL after close */ + apr_pool_t *pool; /* connection lifetime pool */ + char *dbname; /* ODBC datasource */ + int lasterrorcode; + int lineNumber; + char lastError[MAX_ERROR_STRING]; + int defaultBufferSize; /* used for CLOBs in text mode, + * and when fld size is indeterminate */ + apr_intptr_t transaction_mode; + apr_intptr_t dboptions; /* driver options re SQLGetData */ + apr_intptr_t default_transaction_mode; + int can_commit; /* controls end_trans behavior */ +}; + +struct apr_dbd_results_t +{ + SQLHANDLE stmt; /* parent sql statement handle */ + SQLHANDLE dbc; /* parent sql connection handle */ + apr_pool_t *pool; /* pool from query or select */ + apr_dbd_t *apr_dbd; /* parent DBD connection handle */ + int random; /* random access requested */ + int ncols; /* number of columns */ + int isclosed; /* cursor has been closed */ + char **colnames; /* array of column names (NULL until used) */ + SQLPOINTER *colptrs; /* pointers to column data */ + SQLINTEGER *colsizes; /* sizes for columns (enough for txt or bin) */ + SQLINTEGER *coltextsizes; /* max-sizes if converted to text */ + SQLSMALLINT *coltypes; /* array of SQL data types for columns */ + SQLLEN *colinds; /* array of SQL data indicator/strlens */ + int *colstate; /* array of column states + * - avail, bound, present, unavail + */ + int *all_data_fetched; /* flags data as all fetched, for LOBs */ + void *data; /* buffer for all data for one row */ +}; + +enum /* results column states */ +{ + COL_AVAIL, /* data may be retrieved with SQLGetData */ + COL_PRESENT, /* data has been retrieved with SQLGetData */ + COL_BOUND, /* column is bound to colptr */ + COL_RETRIEVED, /* all data from column has been returned */ + COL_UNAVAIL /* column is unavailable because ODBC driver + * requires that columns be retrieved + * in ascending order and a higher col + * was accessed + */ +}; + +struct apr_dbd_row_t { + SQLHANDLE stmt; /* parent ODBC statement handle */ + SQLHANDLE dbc; /* parent ODBC connection handle */ + apr_pool_t *pool; /* pool from get_row */ + apr_dbd_results_t *res; +}; + +struct apr_dbd_transaction_t { + SQLHANDLE dbc; /* parent ODBC connection handle */ + apr_dbd_t *apr_dbd; /* parent DBD connection handle */ +}; + +struct apr_dbd_prepared_t { + SQLHANDLE stmt; /* ODBC statement handle */ + SQLHANDLE dbc; /* parent ODBC connection handle */ + apr_dbd_t *apr_dbd; + int nargs; + int nvals; + int *types; /* array of DBD data types */ +}; + +static void odbc_lob_bucket_destroy(void *data); +static apr_status_t odbc_lob_bucket_setaside(apr_bucket *e, apr_pool_t *pool); +static apr_status_t odbc_lob_bucket_read(apr_bucket *e, const char **str, + apr_size_t *len, apr_read_type_e block); + +/* the ODBC LOB bucket type */ +static const apr_bucket_type_t odbc_bucket_type = { + "ODBC_LOB", 5, APR_BUCKET_DATA, + odbc_lob_bucket_destroy, + odbc_lob_bucket_read, + odbc_lob_bucket_setaside, + apr_bucket_shared_split, + apr_bucket_shared_copy +}; + +/* ODBC LOB bucket data */ +typedef struct { + /** Ref count for shared bucket */ + apr_bucket_refcount refcount; + const apr_dbd_row_t *row; + int col; + SQLSMALLINT type; +} odbc_bucket; + +/* SQL datatype mappings to DBD datatypes + * These tables must correspond *exactly* to the apr_dbd_type_e enum + * in apr_dbd.h + */ + +/* ODBC "C" types to DBD datatypes */ +static SQLSMALLINT const sqlCtype[] = { + SQL_C_DEFAULT, /* APR_DBD_TYPE_NONE */ + SQL_C_STINYINT, /* APR_DBD_TYPE_TINY, \%hhd */ + SQL_C_UTINYINT, /* APR_DBD_TYPE_UTINY, \%hhu */ + SQL_C_SSHORT, /* APR_DBD_TYPE_SHORT, \%hd */ + SQL_C_USHORT, /* APR_DBD_TYPE_USHORT, \%hu */ + SQL_C_SLONG, /* APR_DBD_TYPE_INT, \%d */ + SQL_C_ULONG, /* APR_DBD_TYPE_UINT, \%u */ + SQL_C_SLONG, /* APR_DBD_TYPE_LONG, \%ld */ + SQL_C_ULONG, /* APR_DBD_TYPE_ULONG, \%lu */ + SQL_C_SBIGINT, /* APR_DBD_TYPE_LONGLONG, \%lld */ + SQL_C_UBIGINT, /* APR_DBD_TYPE_ULONGLONG, \%llu */ + SQL_C_FLOAT, /* APR_DBD_TYPE_FLOAT, \%f */ + SQL_C_DOUBLE, /* APR_DBD_TYPE_DOUBLE, \%lf */ + SQL_C_CHAR, /* APR_DBD_TYPE_STRING, \%s */ + SQL_C_CHAR, /* APR_DBD_TYPE_TEXT, \%pDt */ + SQL_C_CHAR, /*SQL_C_TYPE_TIME, APR_DBD_TYPE_TIME, \%pDi */ + SQL_C_CHAR, /*SQL_C_TYPE_DATE, APR_DBD_TYPE_DATE, \%pDd */ + SQL_C_CHAR, /*SQL_C_TYPE_TIMESTAMP, APR_DBD_TYPE_DATETIME, \%pDa */ + SQL_C_CHAR, /*SQL_C_TYPE_TIMESTAMP, APR_DBD_TYPE_TIMESTAMP, \%pDs */ + SQL_C_CHAR, /*SQL_C_TYPE_TIMESTAMP, APR_DBD_TYPE_ZTIMESTAMP, \%pDz */ + SQL_LONGVARBINARY, /* APR_DBD_TYPE_BLOB, \%pDb */ + SQL_LONGVARCHAR, /* APR_DBD_TYPE_CLOB, \%pDc */ + SQL_TYPE_NULL /* APR_DBD_TYPE_NULL \%pDn */ +}; +#define NUM_APR_DBD_TYPES (sizeof(sqlCtype) / sizeof(sqlCtype[0])) + +/* ODBC Base types to DBD datatypes */ +static SQLSMALLINT const sqlBaseType[] = { + SQL_C_DEFAULT, /* APR_DBD_TYPE_NONE */ + SQL_TINYINT, /* APR_DBD_TYPE_TINY, \%hhd */ + SQL_TINYINT, /* APR_DBD_TYPE_UTINY, \%hhu */ + SQL_SMALLINT, /* APR_DBD_TYPE_SHORT, \%hd */ + SQL_SMALLINT, /* APR_DBD_TYPE_USHORT, \%hu */ + SQL_INTEGER, /* APR_DBD_TYPE_INT, \%d */ + SQL_INTEGER, /* APR_DBD_TYPE_UINT, \%u */ + SQL_INTEGER, /* APR_DBD_TYPE_LONG, \%ld */ + SQL_INTEGER, /* APR_DBD_TYPE_ULONG, \%lu */ + SQL_BIGINT, /* APR_DBD_TYPE_LONGLONG, \%lld */ + SQL_BIGINT, /* APR_DBD_TYPE_ULONGLONG, \%llu */ + SQL_FLOAT, /* APR_DBD_TYPE_FLOAT, \%f */ + SQL_DOUBLE, /* APR_DBD_TYPE_DOUBLE, \%lf */ + SQL_CHAR, /* APR_DBD_TYPE_STRING, \%s */ + SQL_CHAR, /* APR_DBD_TYPE_TEXT, \%pDt */ + SQL_CHAR, /*SQL_TIME, APR_DBD_TYPE_TIME, \%pDi */ + SQL_CHAR, /*SQL_DATE, APR_DBD_TYPE_DATE, \%pDd */ + SQL_CHAR, /*SQL_TIMESTAMP, APR_DBD_TYPE_DATETIME, \%pDa */ + SQL_CHAR, /*SQL_TIMESTAMP, APR_DBD_TYPE_TIMESTAMP, \%pDs */ + SQL_CHAR, /*SQL_TIMESTAMP, APR_DBD_TYPE_ZTIMESTAMP, \%pDz */ + SQL_LONGVARBINARY, /* APR_DBD_TYPE_BLOB, \%pDb */ + SQL_LONGVARCHAR, /* APR_DBD_TYPE_CLOB, \%pDc */ + SQL_TYPE_NULL /* APR_DBD_TYPE_NULL \%pDn */ +}; + +/* result sizes for DBD datatypes (-1 for null-terminated) */ +static int const sqlSizes[] = { + 0, + sizeof(char), /**< \%hhd out: char* */ + sizeof(unsigned char), /**< \%hhu out: unsigned char* */ + sizeof(short), /**< \%hd out: short* */ + sizeof(unsigned short), /**< \%hu out: unsigned short* */ + sizeof(int), /**< \%d out: int* */ + sizeof(unsigned int), /**< \%u out: unsigned int* */ + sizeof(long), /**< \%ld out: long* */ + sizeof(unsigned long), /**< \%lu out: unsigned long* */ + sizeof(apr_int64_t), /**< \%lld out: apr_int64_t* */ + sizeof(apr_uint64_t), /**< \%llu out: apr_uint64_t* */ + sizeof(float), /**< \%f out: float* */ + sizeof(double), /**< \%lf out: double* */ + -1, /**< \%s out: char** */ + -1, /**< \%pDt out: char** */ + -1, /**< \%pDi out: char** */ + -1, /**< \%pDd out: char** */ + -1, /**< \%pDa out: char** */ + -1, /**< \%pDs out: char** */ + -1, /**< \%pDz out: char** */ + sizeof(apr_bucket_brigade), /**< \%pDb out: apr_bucket_brigade* */ + sizeof(apr_bucket_brigade), /**< \%pDc out: apr_bucket_brigade* */ + 0 /**< \%pDn : in: void*, out: void** */ +}; + +/* + * local functions + */ + +/* close any open results for the connection */ +static apr_status_t odbc_close_results(void *d) +{ + apr_dbd_results_t *dbr = (apr_dbd_results_t *)d; + SQLRETURN rc = SQL_SUCCESS; + + if (dbr && dbr->apr_dbd && dbr->apr_dbd->dbc) { + if (!dbr->isclosed) + rc = SQLCloseCursor(dbr->stmt); + dbr->isclosed = 1; + } + return APR_FROM_SQL_RESULT(rc); +} + +/* close the ODBC statement handle from a prepare */ +static apr_status_t odbc_close_pstmt(void *s) +{ + SQLRETURN rc = APR_SUCCESS; + apr_dbd_prepared_t *statement = s; + + /* stmt is closed if connection has already been closed */ + if (statement) { + SQLHANDLE hstmt = statement->stmt; + + if (hstmt && statement->apr_dbd && statement->apr_dbd->dbc) { + rc = SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + } + statement->stmt = NULL; + } + return APR_FROM_SQL_RESULT(rc); +} + +/* close: close/release a connection obtained from open() */ +static apr_status_t odbc_close(apr_dbd_t *handle) +{ + SQLRETURN rc = SQL_SUCCESS; + + if (handle->dbc) { + rc = SQLDisconnect(handle->dbc); + CHECK_ERROR(handle, "SQLDisconnect", rc, SQL_HANDLE_DBC, handle->dbc); + rc = SQLFreeHandle(SQL_HANDLE_DBC, handle->dbc); + CHECK_ERROR(handle, "SQLFreeHandle (DBC)", rc, SQL_HANDLE_ENV, henv); + handle->dbc = NULL; + } + return APR_FROM_SQL_RESULT(rc); +} + +/* odbc_close re-defined for passing to pool cleanup */ +static apr_status_t odbc_close_cleanup(void *handle) +{ + return odbc_close((apr_dbd_t *)handle); +} + +/* close the ODBC environment handle at process termination */ +static apr_status_t odbc_close_env(SQLHANDLE henv) +{ + SQLRETURN rc; + + rc = SQLFreeHandle(SQL_HANDLE_ENV, henv); + henv = NULL; + return APR_FROM_SQL_RESULT(rc); +} + +/* setup the arrays in results for all the returned columns */ +static SQLRETURN odbc_set_result_column(int icol, apr_dbd_results_t *res, + SQLHANDLE stmt) +{ + SQLRETURN rc; + apr_intptr_t maxsize, textsize, realsize, type, isunsigned = 1; + + /* discover the sql type */ + rc = SQLColAttribute(stmt, icol + 1, SQL_DESC_UNSIGNED, NULL, 0, NULL, + (SQLPOINTER)&isunsigned); + isunsigned = (isunsigned == SQL_TRUE); + + rc = SQLColAttribute(stmt, icol + 1, SQL_DESC_TYPE, NULL, 0, NULL, + (SQLPOINTER)&type); + if (!SQL_SUCCEEDED(rc) || type == SQL_UNKNOWN_TYPE) { + /* MANY ODBC v2 datasources only supply CONCISE_TYPE */ + rc = SQLColAttribute(stmt, icol + 1, SQL_DESC_CONCISE_TYPE, NULL, + 0, NULL, (SQLPOINTER)&type); + } + + if (!SQL_SUCCEEDED(rc)) { + /* if still unknown make it CHAR */ + type = SQL_C_CHAR; + } + + switch (type) { + case SQL_INTEGER: + case SQL_SMALLINT: + case SQL_TINYINT: + case SQL_BIGINT: + /* fix these numeric binary types up as signed/unsigned for C types */ + type += (isunsigned) ? SQL_UNSIGNED_OFFSET : SQL_SIGNED_OFFSET; + break; + /* LOB types are not changed to C types */ + case SQL_LONGVARCHAR: + type = SQL_LONGVARCHAR; + break; + case SQL_LONGVARBINARY: + type = SQL_LONGVARBINARY; + break; + case SQL_FLOAT : + type = SQL_C_FLOAT; + break; + case SQL_DOUBLE : + type = SQL_C_DOUBLE; + break; + + /* DBD wants times as strings */ + case SQL_TIMESTAMP: + case SQL_DATE: + case SQL_TIME: + default: + type = SQL_C_CHAR; + } + + res->coltypes[icol] = (SQLSMALLINT)type; + + /* size if retrieved as text */ + rc = SQLColAttribute(stmt, icol + 1, SQL_DESC_DISPLAY_SIZE, NULL, 0, + NULL, (SQLPOINTER)&textsize); + if (!SQL_SUCCEEDED(rc) || textsize < 0) { + textsize = res->apr_dbd->defaultBufferSize; + } + /* for null-term, which sometimes isn't included */ + textsize++; + + /* real size */ + rc = SQLColAttribute(stmt, icol + 1, SQL_DESC_OCTET_LENGTH, NULL, 0, + NULL, (SQLPOINTER)&realsize); + if (!SQL_SUCCEEDED(rc)) { + realsize = textsize; + } + + maxsize = (textsize > realsize) ? textsize : realsize; + if (IS_LOB(type) || maxsize <= 0) { + /* LOB types are never bound and have a NULL colptr for binary. + * Ingore their real (1-2gb) length & use a default - the larger + * of defaultBufferSize or APR_BUCKET_BUFF_SIZE. + * If not a LOB, but simply unknown length - always use defaultBufferSize. + */ + maxsize = res->apr_dbd->defaultBufferSize; + if (IS_LOB(type) && maxsize < APR_BUCKET_BUFF_SIZE) { + maxsize = APR_BUCKET_BUFF_SIZE; + } + + res->colptrs[icol] = NULL; + res->colstate[icol] = COL_AVAIL; + res->colsizes[icol] = (SQLINTEGER)maxsize; + rc = SQL_SUCCESS; + } + else { + res->colptrs[icol] = apr_pcalloc(res->pool, maxsize); + res->colsizes[icol] = (SQLINTEGER)maxsize; + if (res->apr_dbd->dboptions & SQL_GD_BOUND) { + /* we are allowed to call SQLGetData if we need to */ + rc = SQLBindCol(stmt, icol + 1, res->coltypes[icol], + res->colptrs[icol], maxsize, + &(res->colinds[icol])); + CHECK_ERROR(res->apr_dbd, "SQLBindCol", rc, SQL_HANDLE_STMT, + stmt); + res->colstate[icol] = SQL_SUCCEEDED(rc) ? COL_BOUND : COL_AVAIL; + } + else { + /* this driver won't allow us to call SQLGetData on bound + * columns - so don't bind any + */ + res->colstate[icol] = COL_AVAIL; + rc = SQL_SUCCESS; + } + } + return rc; +} + +/* create and populate an apr_dbd_results_t for a select */ +static SQLRETURN odbc_create_results(apr_dbd_t *handle, SQLHANDLE hstmt, + apr_pool_t *pool, const int random, + apr_dbd_results_t **res) +{ + SQLRETURN rc; + SQLSMALLINT ncols; + + *res = apr_pcalloc(pool, sizeof(apr_dbd_results_t)); + (*res)->stmt = hstmt; + (*res)->dbc = handle->dbc; + (*res)->pool = pool; + (*res)->random = random; + (*res)->apr_dbd = handle; + rc = SQLNumResultCols(hstmt, &ncols); + CHECK_ERROR(handle, "SQLNumResultCols", rc, SQL_HANDLE_STMT, hstmt); + (*res)->ncols = ncols; + + if (SQL_SUCCEEDED(rc)) { + int i; + + (*res)->colnames = apr_pcalloc(pool, ncols * sizeof(char *)); + (*res)->colptrs = apr_pcalloc(pool, ncols * sizeof(void *)); + (*res)->colsizes = apr_pcalloc(pool, ncols * sizeof(SQLINTEGER)); + (*res)->coltypes = apr_pcalloc(pool, ncols * sizeof(SQLSMALLINT)); + (*res)->colinds = apr_pcalloc(pool, ncols * sizeof(SQLLEN)); + (*res)->colstate = apr_pcalloc(pool, ncols * sizeof(int)); + (*res)->ncols = ncols; + + for (i = 0; i < ncols; i++) { + odbc_set_result_column(i, (*res), hstmt); + } + } + return rc; +} + + +/* bind a parameter - input params only, does not support output parameters */ +static SQLRETURN odbc_bind_param(apr_pool_t *pool, + apr_dbd_prepared_t *statement, const int narg, + const SQLSMALLINT type, int *argp, + const void **args, const int textmode) +{ + SQLRETURN rc; + SQLSMALLINT baseType, cType; + void *ptr; + SQLULEN len; + SQLLEN *indicator; + static SQLLEN nullValue = SQL_NULL_DATA; + static SQLSMALLINT inOut = SQL_PARAM_INPUT; /* only input params */ + + /* bind a NULL data value */ + if (args[*argp] == NULL || type == APR_DBD_TYPE_NULL) { + baseType = SQL_CHAR; + cType = SQL_C_CHAR; + ptr = &nullValue; + len = sizeof(SQLINTEGER); + indicator = &nullValue; + (*argp)++; + } + /* bind a non-NULL data value */ + else { + if (type < 0 || type >= NUM_APR_DBD_TYPES) { + return APR_EGENERAL; + } + + baseType = sqlBaseType[type]; + cType = sqlCtype[type]; + indicator = NULL; + /* LOBs */ + if (IS_LOB(cType)) { + ptr = (void *)args[*argp]; + len = (SQLULEN) * (apr_size_t *)args[*argp + 1]; + cType = (IS_CLOB(cType)) ? SQL_C_CHAR : SQL_C_DEFAULT; + (*argp) += 4; /* LOBs consume 4 args (last two are unused) */ + } + /* non-LOBs */ + else { + switch (baseType) { + case SQL_CHAR: + case SQL_DATE: + case SQL_TIME: + case SQL_TIMESTAMP: + ptr = (void *)args[*argp]; + len = (SQLULEN)strlen(ptr); + break; + case SQL_TINYINT: + ptr = apr_palloc(pool, sizeof(unsigned char)); + len = sizeof(unsigned char); + *(unsigned char *)ptr = + (textmode ? + atoi(args[*argp]) : *(unsigned char *)args[*argp]); + break; + case SQL_SMALLINT: + ptr = apr_palloc(pool, sizeof(short)); + len = sizeof(short); + *(short *)ptr = + (textmode ? atoi(args[*argp]) : *(short *)args[*argp]); + break; + case SQL_INTEGER: + ptr = apr_palloc(pool, sizeof(int)); + len = sizeof(int); + *(long *)ptr = + (textmode ? atol(args[*argp]) : *(long *)args[*argp]); + break; + case SQL_FLOAT: + ptr = apr_palloc(pool, sizeof(float)); + len = sizeof(float); + *(float *)ptr = + (textmode ? + (float)atof(args[*argp]) : *(float *)args[*argp]); + break; + case SQL_DOUBLE: + ptr = apr_palloc(pool, sizeof(double)); + len = sizeof(double); + *(double *)ptr = + (textmode ? atof(args[*argp]) : *(double *) + args[*argp]); + break; + case SQL_BIGINT: + ptr = apr_palloc(pool, sizeof(apr_int64_t)); + len = sizeof(apr_int64_t); + *(apr_int64_t *)ptr = + (textmode ? + apr_atoi64(args[*argp]) : *(apr_int64_t *)args[*argp]); + break; + default: + return APR_EGENERAL; + } + (*argp)++; /* non LOBs consume one argument */ + } + } + rc = SQLBindParameter(statement->stmt, narg, inOut, cType, + baseType, len, 0, ptr, len, indicator); + CHECK_ERROR(statement->apr_dbd, "SQLBindParameter", rc, SQL_HANDLE_STMT, + statement->stmt); + return rc; +} + +/* LOB / Bucket Brigade functions */ + +/* bucket type specific destroy */ +static void odbc_lob_bucket_destroy(void *data) +{ + odbc_bucket *bd = data; + + if (apr_bucket_shared_destroy(bd)) + apr_bucket_free(bd); +} + +/* set aside a bucket if possible */ +static apr_status_t odbc_lob_bucket_setaside(apr_bucket *e, apr_pool_t *pool) +{ + odbc_bucket *bd = (odbc_bucket *)e->data; + + /* Unlikely - but if the row pool is ancestor of this pool then it is OK */ + if (apr_pool_is_ancestor(bd->row->pool, pool)) + return APR_SUCCESS; + + return apr_bucket_setaside_notimpl(e, pool); +} + +/* split a bucket into a heap bucket followed by a LOB bkt w/remaining data */ +static apr_status_t odbc_lob_bucket_read(apr_bucket *e, const char **str, + apr_size_t *len, apr_read_type_e block) +{ + SQLRETURN rc; + SQLLEN len_indicator; + SQLSMALLINT type; + odbc_bucket *bd = (odbc_bucket *)e->data; + apr_bucket *nxt; + void *buf; + int bufsize = bd->row->res->apr_dbd->defaultBufferSize; + int eos; + + /* C type is CHAR for CLOBs, DEFAULT for BLOBs */ + type = bd->row->res->coltypes[bd->col]; + type = (type == SQL_LONGVARCHAR) ? SQL_C_CHAR : SQL_C_DEFAULT; + + /* LOB buffers are always at least APR_BUCKET_BUFF_SIZE, + * but they may be much bigger per the BUFSIZE parameter. + */ + if (bufsize < APR_BUCKET_BUFF_SIZE) + bufsize = APR_BUCKET_BUFF_SIZE; + + buf = apr_bucket_alloc(bufsize, e->list); + *str = NULL; + *len = 0; + + rc = SQLGetData(bd->row->res->stmt, bd->col + 1, + type, buf, bufsize, + &len_indicator); + + CHECK_ERROR(bd->row->res->apr_dbd, "SQLGetData", rc, + SQL_HANDLE_STMT, bd->row->res->stmt); + + if (rc == SQL_NO_DATA || len_indicator == SQL_NULL_DATA || len_indicator < 0) + len_indicator = 0; + + if (SQL_SUCCEEDED(rc) || rc == SQL_NO_DATA) { + + if (rc == SQL_SUCCESS_WITH_INFO + && (len_indicator == SQL_NO_TOTAL || len_indicator >= bufsize)) { + /* not the last read = a full buffer. CLOBs have a null terminator */ + *len = bufsize - (IS_CLOB(bd->type) ? 1 : 0 ); + + eos = 0; + } + else { + /* the last read - len_indicator is supposed to be the length, + * but some driver get this wrong and return the total length. + * We try to handle both interpretations. + */ + *len = (len_indicator > bufsize + && len_indicator >= (SQLLEN)e->start) + ? (len_indicator - (SQLLEN)e->start) : len_indicator; + + eos = 1; + } + + if (!eos) { + /* Create a new LOB bucket to append and append it */ + nxt = apr_bucket_alloc(sizeof(apr_bucket *), e->list); + APR_BUCKET_INIT(nxt); + nxt->length = -1; + nxt->data = e->data; + nxt->type = &odbc_bucket_type; + nxt->free = apr_bucket_free; + nxt->list = e->list; + nxt->start = e->start + *len; + APR_BUCKET_INSERT_AFTER(e, nxt); + } + else { + odbc_lob_bucket_destroy(e->data); + } + /* make current bucket into a heap bucket */ + apr_bucket_heap_make(e, buf, *len, apr_bucket_free); + *str = buf; + + /* No data is success in this context */ + rc = SQL_SUCCESS; + } + return APR_FROM_SQL_RESULT(rc); +} + +/* Create a bucket brigade on the row pool for a LOB column */ +static apr_status_t odbc_create_bucket(const apr_dbd_row_t *row, const int col, + SQLSMALLINT type, apr_bucket_brigade *bb) +{ + apr_bucket_alloc_t *list = bb->bucket_alloc; + apr_bucket *b = apr_bucket_alloc(sizeof(*b), list); + odbc_bucket *bd = apr_bucket_alloc(sizeof(odbc_bucket), list); + apr_bucket *eos = apr_bucket_eos_create(list); + + bd->row = row; + bd->col = col; + bd->type = type; + + APR_BUCKET_INIT(b); + b->type = &odbc_bucket_type; + b->free = apr_bucket_free; + b->list = list; + /* LOB lengths are unknown in ODBC */ + b = apr_bucket_shared_make(b, bd, 0, -1); + + APR_BRIGADE_INSERT_TAIL(bb, b); + APR_BRIGADE_INSERT_TAIL(bb, eos); + + return APR_SUCCESS; +} + +/* returns a data pointer for a column, returns NULL for NULL value, + * return -1 if data not available + */ +static void *odbc_get(const apr_dbd_row_t *row, const int col, + const SQLSMALLINT sqltype) +{ + SQLRETURN rc; + SQLLEN indicator; + int state = row->res->colstate[col]; + apr_intptr_t options = row->res->apr_dbd->dboptions; + + switch (state) { + case (COL_UNAVAIL): + return (void *)-1; + case (COL_RETRIEVED): + return NULL; + + case (COL_BOUND): + case (COL_PRESENT): + if (sqltype == row->res->coltypes[col]) { + /* same type and we already have the data */ + row->res->colstate[col] = COL_RETRIEVED; + return (row->res->colinds[col] == SQL_NULL_DATA) ? + NULL : row->res->colptrs[col]; + } + } + + /* we need to get the data now */ + if (!(options & SQL_GD_ANY_ORDER)) { + /* this ODBC driver requires columns to be retrieved in order, + * so we attempt to get every prior un-gotten non-LOB column + */ + int i; + for (i = 0; i < col; i++) { + if (row->res->colstate[i] == COL_AVAIL) { + if (IS_LOB(row->res->coltypes[i])) + row->res->colstate[i] = COL_UNAVAIL; + else { + odbc_get(row, i, row->res->coltypes[i]); + row->res->colstate[i] = COL_PRESENT; + } + } + } + } + + if ((state == COL_BOUND && !(options & SQL_GD_BOUND))) + /* this driver won't let us re-get bound columns */ + return (void *)-1; + + /* a LOB might not have a buffer allocated yet - so create one */ + if (!row->res->colptrs[col]) + row->res->colptrs[col] = apr_pcalloc(row->pool, row->res->colsizes[col]); + + rc = SQLGetData(row->res->stmt, col + 1, sqltype, row->res->colptrs[col], + row->res->colsizes[col], &indicator); + CHECK_ERROR(row->res->apr_dbd, "SQLGetData", rc, SQL_HANDLE_STMT, + row->res->stmt); + if (indicator == SQL_NULL_DATA || rc == SQL_NO_DATA) + return NULL; + + if (SQL_SUCCEEDED(rc)) { + /* whatever it was originally, it is now this sqltype */ + row->res->coltypes[col] = sqltype; + /* this allows getting CLOBs in text mode by calling get_entry + * until it returns NULL + */ + row->res->colstate[col] = + (rc == SQL_SUCCESS_WITH_INFO) ? COL_AVAIL : COL_RETRIEVED; + return row->res->colptrs[col]; + } + else + return (void *)-1; +} + +/* Parse the parameter string for open */ +static apr_status_t odbc_parse_params(apr_pool_t *pool, const char *params, + int *connect, SQLCHAR **datasource, + SQLCHAR **user, SQLCHAR **password, + int *defaultBufferSize, int *nattrs, + int **attrs, apr_intptr_t **attrvals) +{ + char *seps, *last, *next, *name[MAX_PARAMS], *val[MAX_PARAMS]; + int nparams = 0, i, j; + + *attrs = apr_pcalloc(pool, MAX_PARAMS * sizeof(char *)); + *attrvals = apr_pcalloc(pool, MAX_PARAMS * sizeof(apr_intptr_t)); + *nattrs = 0; + seps = DEFAULTSEPS; + name[nparams] = apr_strtok(apr_pstrdup(pool, params), seps, &last); + + /* no params is OK here - let connect return a more useful error msg */ + if (!name[nparams]) + return SQL_SUCCESS; + + do { + if (last[strspn(last, seps)] == CSINGLEQUOTE) { + last += strspn(last, seps); + seps=SSINGLEQUOTE; + } + val[nparams] = apr_strtok(NULL, seps, &last); + seps = DEFAULTSEPS; + + ++nparams; + next = apr_strtok(NULL, seps, &last); + if (!next) { + break; + } + if (nparams >= MAX_PARAMS) { + /* too many parameters, no place to store */ + return APR_EGENERAL; + } + name[nparams] = next; + } while (1); + + for (j = i = 0; i < nparams; i++) { + if (!apr_strnatcasecmp(name[i], "CONNECT")) { + *datasource = (SQLCHAR *)apr_pstrdup(pool, val[i]); + *connect = 1; + } + else if (!apr_strnatcasecmp(name[i], "DATASOURCE")) { + *datasource = (SQLCHAR *)apr_pstrdup(pool, val[i]); + *connect = 0; + } + else if (!apr_strnatcasecmp(name[i], "USER")) { + *user = (SQLCHAR *)apr_pstrdup(pool, val[i]); + } + else if (!apr_strnatcasecmp(name[i], "PASSWORD")) { + *password = (SQLCHAR *)apr_pstrdup(pool, val[i]); + } + else if (!apr_strnatcasecmp(name[i], "BUFSIZE")) { + *defaultBufferSize = atoi(val[i]); + } + else if (!apr_strnatcasecmp(name[i], "ACCESS")) { + if (!apr_strnatcasecmp(val[i], "READ_ONLY")) + (*attrvals)[j] = SQL_MODE_READ_ONLY; + else if (!apr_strnatcasecmp(val[i], "READ_WRITE")) + (*attrvals)[j] = SQL_MODE_READ_WRITE; + else + return SQL_ERROR; + (*attrs)[j++] = SQL_ATTR_ACCESS_MODE; + } + else if (!apr_strnatcasecmp(name[i], "CTIMEOUT")) { + (*attrvals)[j] = atoi(val[i]); + (*attrs)[j++] = SQL_ATTR_LOGIN_TIMEOUT; + } + else if (!apr_strnatcasecmp(name[i], "STIMEOUT")) { + (*attrvals)[j] = atoi(val[i]); + (*attrs)[j++] = SQL_ATTR_CONNECTION_TIMEOUT; + } + else if (!apr_strnatcasecmp(name[i], "TXMODE")) { + if (!apr_strnatcasecmp(val[i], "READ_UNCOMMITTED")) + (*attrvals)[j] = SQL_TXN_READ_UNCOMMITTED; + else if (!apr_strnatcasecmp(val[i], "READ_COMMITTED")) + (*attrvals)[j] = SQL_TXN_READ_COMMITTED; + else if (!apr_strnatcasecmp(val[i], "REPEATABLE_READ")) + (*attrvals)[j] = SQL_TXN_REPEATABLE_READ; + else if (!apr_strnatcasecmp(val[i], "SERIALIZABLE")) + (*attrvals)[j] = SQL_TXN_SERIALIZABLE; + else if (!apr_strnatcasecmp(val[i], "DEFAULT")) + continue; + else + return SQL_ERROR; + (*attrs)[j++] = SQL_ATTR_TXN_ISOLATION; + } + else + return SQL_ERROR; + } + *nattrs = j; + return (*datasource && *defaultBufferSize) ? APR_SUCCESS : SQL_ERROR; +} + +/* common handling after ODBC calls - save error info (code and text) in dbc */ +static void check_error(apr_dbd_t *dbc, const char *step, SQLRETURN rc, + SQLSMALLINT type, SQLHANDLE h, int line) +{ + SQLCHAR buffer[512]; + SQLCHAR sqlstate[128]; + SQLINTEGER native; + SQLSMALLINT reslength; + char *res, *p, *end, *logval = NULL; + int i; + + /* set info about last error in dbc - fast return for SQL_SUCCESS */ + if (rc == SQL_SUCCESS) { + char successMsg[] = "[dbd_odbc] SQL_SUCCESS "; + apr_size_t successMsgLen = sizeof successMsg - 1; + + dbc->lasterrorcode = SQL_SUCCESS; + apr_cpystrn(dbc->lastError, successMsg, sizeof dbc->lastError); + apr_cpystrn(dbc->lastError + successMsgLen, step, + sizeof dbc->lastError - successMsgLen); + return; + } + switch (rc) { + case SQL_INVALID_HANDLE: + res = "SQL_INVALID_HANDLE"; + break; + case SQL_ERROR: + res = "SQL_ERROR"; + break; + case SQL_SUCCESS_WITH_INFO: + res = "SQL_SUCCESS_WITH_INFO"; + break; + case SQL_STILL_EXECUTING: + res = "SQL_STILL_EXECUTING"; + break; + case SQL_NEED_DATA: + res = "SQL_NEED_DATA"; + break; + case SQL_NO_DATA: + res = "SQL_NO_DATA"; + break; + default: + res = "unrecognized SQL return code"; + } + /* these two returns are expected during normal execution */ + if (rc != SQL_SUCCESS_WITH_INFO && rc != SQL_NO_DATA + && dbc->can_commit != APR_DBD_TRANSACTION_IGNORE_ERRORS) { + dbc->can_commit = APR_DBD_TRANSACTION_ROLLBACK; + } + p = dbc->lastError; + end = p + sizeof(dbc->lastError); + dbc->lasterrorcode = rc; + p += sprintf(p, "[dbd_odbc] %.64s returned %.30s (%d) at %.24s:%d ", + step, res, rc, SOURCE_FILE, line - 1); + for (i = 1, rc = 0; rc == 0; i++) { + rc = SQLGetDiagRec(type, h, i, sqlstate, &native, buffer, + sizeof(buffer), &reslength); + if (SQL_SUCCEEDED(rc) && (p < (end - 280))) + p += sprintf(p, "%.256s %.20s ", buffer, sqlstate); + } + apr_env_get(&logval, "apr_dbd_odbc_log", dbc->pool); + /* if env var was set or call was init/open (no dbname) - log to stderr */ + if (logval || !dbc->dbname ) { + char timestamp[APR_CTIME_LEN]; + + apr_file_t *se; + apr_ctime(timestamp, apr_time_now()); + apr_file_open_stderr(&se, dbc->pool); + apr_file_printf(se, "[%s] %s\n", timestamp, dbc->lastError); + } +} + +static APR_INLINE int odbc_check_rollback(apr_dbd_t *handle) +{ + if (handle->can_commit == APR_DBD_TRANSACTION_ROLLBACK) { + handle->lasterrorcode = SQL_ERROR; + apr_cpystrn(handle->lastError, "[dbd_odbc] Rollback pending ", + sizeof handle->lastError); + return 1; + } + return 0; +} + +/* + * public functions per DBD driver API + */ + +/** init: allow driver to perform once-only initialisation. **/ +static void odbc_init(apr_pool_t *pool) +{ + SQLRETURN rc; + char *step; + apr_version_t aprver; + + apr_version(&aprver); + if (aprver.major != DRIVER_APR_VERSION_MAJOR + || aprver.minor != DRIVER_APR_VERSION_MINOR) { + apr_file_t *se; + + apr_file_open_stderr(&se, pool); + apr_file_printf(se, "Incorrect " ODBC_DRIVER_STRING " dbd driver version\n" + "Attempt to load APR version %d.%d driver with APR version %d.%d\n", + DRIVER_APR_VERSION_MAJOR, DRIVER_APR_VERSION_MINOR, + aprver.major, aprver.minor); + abort(); + } + + if (henv) + return; + + step = "SQLAllocHandle (SQL_HANDLE_ENV)"; + rc = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv); + apr_pool_cleanup_register(pool, henv, odbc_close_env, apr_pool_cleanup_null); + if (SQL_SUCCEEDED(rc)) { + step = "SQLSetEnvAttr"; + rc = SQLSetEnvAttr(henv,SQL_ATTR_ODBC_VERSION, + (SQLPOINTER)SQL_OV_ODBC3, 0); + } + else { + apr_dbd_t tmp_dbc; + SQLHANDLE err_h = henv; + + tmp_dbc.pool = pool; + tmp_dbc.dbname = NULL; + CHECK_ERROR(&tmp_dbc, step, rc, SQL_HANDLE_ENV, err_h); + } +} + +/** native_handle: return the native database handle of the underlying db **/ +static void *odbc_native_handle(apr_dbd_t *handle) +{ + return handle->dbc; +} + +/** open: obtain a database connection from the server rec. **/ + +/* It would be more efficient to allocate a single statement handle + * here - but SQL_ATTR_CURSOR_SCROLLABLE must be set before + * SQLPrepare, and we don't know whether random-access is + * specified until SQLExecute so we cannot. + */ + +static apr_dbd_t *odbc_open(apr_pool_t *pool, const char *params, const char **error) +{ + SQLRETURN rc; + SQLHANDLE hdbc = NULL; + apr_dbd_t *handle; + char *err_step; + int err_htype, i; + int defaultBufferSize = DEFAULT_BUFFER_SIZE; + SQLHANDLE err_h = NULL; + SQLCHAR *datasource = (SQLCHAR *)"", *user = (SQLCHAR *)"", + *password = (SQLCHAR *)""; + int nattrs = 0, *attrs = NULL, connect = 0; + apr_intptr_t *attrvals = NULL; + + err_step = "SQLAllocHandle (SQL_HANDLE_DBC)"; + err_htype = SQL_HANDLE_ENV; + err_h = henv; + rc = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc); + if (SQL_SUCCEEDED(rc)) { + err_step = "Invalid DBD Parameters - open"; + err_htype = SQL_HANDLE_DBC; + err_h = hdbc; + rc = odbc_parse_params(pool, params, &connect, &datasource, &user, + &password, &defaultBufferSize, &nattrs, &attrs, + &attrvals); + } + if (SQL_SUCCEEDED(rc)) { + for (i = 0; i < nattrs && SQL_SUCCEEDED(rc); i++) { + err_step = "SQLSetConnectAttr (from DBD Parameters)"; + err_htype = SQL_HANDLE_DBC; + err_h = hdbc; + rc = SQLSetConnectAttr(hdbc, attrs[i], (SQLPOINTER)attrvals[i], 0); + } + } + if (SQL_SUCCEEDED(rc)) { + if (connect) { + SQLCHAR out[1024]; + SQLSMALLINT outlen; + + err_step = "SQLDriverConnect"; + err_htype = SQL_HANDLE_DBC; + err_h = hdbc; + rc = SQLDriverConnect(hdbc, NULL, datasource, + (SQLSMALLINT)strlen((char *)datasource), + out, sizeof(out), &outlen, SQL_DRIVER_NOPROMPT); + } + else { + err_step = "SQLConnect"; + err_htype = SQL_HANDLE_DBC; + err_h = hdbc; + rc = SQLConnect(hdbc, datasource, + (SQLSMALLINT)strlen((char *)datasource), + user, (SQLSMALLINT)strlen((char *)user), + password, (SQLSMALLINT)strlen((char *)password)); + } + } + if (SQL_SUCCEEDED(rc)) { + handle = apr_pcalloc(pool, sizeof(apr_dbd_t)); + handle->dbname = apr_pstrdup(pool, (char *)datasource); + handle->dbc = hdbc; + handle->pool = pool; + handle->defaultBufferSize = defaultBufferSize; + CHECK_ERROR(handle, "SQLConnect", rc, SQL_HANDLE_DBC, handle->dbc); + handle->default_transaction_mode = 0; + handle->can_commit = APR_DBD_TRANSACTION_IGNORE_ERRORS; + SQLGetInfo(hdbc, SQL_DEFAULT_TXN_ISOLATION, + &(handle->default_transaction_mode), sizeof(apr_intptr_t), NULL); + handle->transaction_mode = handle->default_transaction_mode; + SQLGetInfo(hdbc, SQL_GETDATA_EXTENSIONS ,&(handle->dboptions), + sizeof(apr_intptr_t), NULL); + apr_pool_cleanup_register(pool, handle, odbc_close_cleanup, apr_pool_cleanup_null); + return handle; + } + else { + apr_dbd_t tmp_dbc; + + tmp_dbc.pool = pool; + tmp_dbc.dbname = NULL; + CHECK_ERROR(&tmp_dbc, err_step, rc, err_htype, err_h); + if (error) + *error = apr_pstrdup(pool, tmp_dbc.lastError); + if (hdbc) + SQLFreeHandle(SQL_HANDLE_DBC, hdbc); + return NULL; + } +} + +/** check_conn: check status of a database connection **/ +static apr_status_t odbc_check_conn(apr_pool_t *pool, apr_dbd_t *handle) +{ + SQLUINTEGER isDead; + SQLRETURN rc; + + rc = SQLGetConnectAttr(handle->dbc, SQL_ATTR_CONNECTION_DEAD, &isDead, + sizeof(SQLUINTEGER), NULL); + CHECK_ERROR(handle, "SQLGetConnectAttr (SQL_ATTR_CONNECTION_DEAD)", rc, + SQL_HANDLE_DBC, handle->dbc); + /* if driver cannot check connection, say so */ + if (rc != SQL_SUCCESS) + return APR_ENOTIMPL; + + return (isDead == SQL_CD_FALSE) ? APR_SUCCESS : APR_EGENERAL; +} + +/** set_dbname: select database name. May be a no-op if not supported. **/ +static int odbc_set_dbname(apr_pool_t*pool, apr_dbd_t *handle, + const char *name) +{ + if (apr_strnatcmp(name, handle->dbname)) { + return APR_EGENERAL; /* It's illegal to change dbname in ODBC */ + } + CHECK_ERROR(handle, "set_dbname (no-op)", SQL_SUCCESS, SQL_HANDLE_DBC, + handle->dbc); + return APR_SUCCESS; /* OK if it's the same name */ +} + +/** transaction: start a transaction. May be a no-op. **/ +static int odbc_start_transaction(apr_pool_t *pool, apr_dbd_t *handle, + apr_dbd_transaction_t **trans) +{ + SQLRETURN rc = SQL_SUCCESS; + + if (handle->transaction_mode) { + rc = SQLSetConnectAttr(handle->dbc, SQL_ATTR_TXN_ISOLATION, + (SQLPOINTER)handle->transaction_mode, 0); + CHECK_ERROR(handle, "SQLSetConnectAttr (SQL_ATTR_TXN_ISOLATION)", rc, + SQL_HANDLE_DBC, handle->dbc); + } + if (SQL_SUCCEEDED(rc)) { + /* turn off autocommit for transactions */ + rc = SQLSetConnectAttr(handle->dbc, SQL_ATTR_AUTOCOMMIT, + SQL_AUTOCOMMIT_OFF, 0); + CHECK_ERROR(handle, "SQLSetConnectAttr (SQL_ATTR_AUTOCOMMIT)", rc, + SQL_HANDLE_DBC, handle->dbc); + } + if (SQL_SUCCEEDED(rc)) { + *trans = apr_palloc(pool, sizeof(apr_dbd_transaction_t)); + (*trans)->dbc = handle->dbc; + (*trans)->apr_dbd = handle; + } + handle->can_commit = APR_DBD_TRANSACTION_COMMIT; + return APR_FROM_SQL_RESULT(rc); +} + +/** end_transaction: end a transaction **/ +static int odbc_end_transaction(apr_dbd_transaction_t *trans) +{ + SQLRETURN rc; + int action = (trans->apr_dbd->can_commit != APR_DBD_TRANSACTION_ROLLBACK) + ? SQL_COMMIT : SQL_ROLLBACK; + + rc = SQLEndTran(SQL_HANDLE_DBC, trans->dbc, action); + CHECK_ERROR(trans->apr_dbd, "SQLEndTran", rc, SQL_HANDLE_DBC, trans->dbc); + if (SQL_SUCCEEDED(rc)) { + rc = SQLSetConnectAttr(trans->dbc, SQL_ATTR_AUTOCOMMIT, + (SQLPOINTER)SQL_AUTOCOMMIT_ON, 0); + CHECK_ERROR(trans->apr_dbd, "SQLSetConnectAttr (SQL_ATTR_AUTOCOMMIT)", + rc, SQL_HANDLE_DBC, trans->dbc); + } + trans->apr_dbd->can_commit = APR_DBD_TRANSACTION_IGNORE_ERRORS; + return APR_FROM_SQL_RESULT(rc); +} + +/** query: execute an SQL statement which doesn't return a result set **/ +static int odbc_query(apr_dbd_t *handle, int *nrows, const char *statement) +{ + SQLRETURN rc; + SQLHANDLE hstmt = NULL; + size_t len = strlen(statement); + + if (odbc_check_rollback(handle)) + return APR_EGENERAL; + + rc = SQLAllocHandle(SQL_HANDLE_STMT, handle->dbc, &hstmt); + CHECK_ERROR(handle, "SQLAllocHandle (STMT)", rc, SQL_HANDLE_DBC, + handle->dbc); + if (!SQL_SUCCEEDED(rc)) + return APR_FROM_SQL_RESULT(rc); + + rc = SQLExecDirect(hstmt, (SQLCHAR *)statement, (SQLINTEGER)len); + CHECK_ERROR(handle, "SQLExecDirect", rc, SQL_HANDLE_STMT, hstmt); + + if (SQL_SUCCEEDED(rc)) { + SQLLEN rowcount; + + rc = SQLRowCount(hstmt, &rowcount); + *nrows = (int)rowcount; + CHECK_ERROR(handle, "SQLRowCount", rc, SQL_HANDLE_STMT, hstmt); + } + + SQLFreeHandle(SQL_HANDLE_STMT, hstmt); + return APR_FROM_SQL_RESULT(rc); +} + +/** select: execute an SQL statement which returns a result set **/ +static int odbc_select(apr_pool_t *pool, apr_dbd_t *handle, + apr_dbd_results_t **res, const char *statement, + int random) +{ + SQLRETURN rc; + SQLHANDLE hstmt; + apr_dbd_prepared_t *stmt; + size_t len = strlen(statement); + + if (odbc_check_rollback(handle)) + return APR_EGENERAL; + + rc = SQLAllocHandle(SQL_HANDLE_STMT, handle->dbc, &hstmt); + CHECK_ERROR(handle, "SQLAllocHandle (STMT)", rc, SQL_HANDLE_DBC, + handle->dbc); + if (!SQL_SUCCEEDED(rc)) + return APR_FROM_SQL_RESULT(rc); + /* Prepare an apr_dbd_prepared_t for pool cleanup, even though this + * is not a prepared statement. We want the same cleanup mechanism. + */ + stmt = apr_pcalloc(pool, sizeof(apr_dbd_prepared_t)); + stmt->apr_dbd = handle; + stmt->dbc = handle->dbc; + stmt->stmt = hstmt; + apr_pool_cleanup_register(pool, stmt, odbc_close_pstmt, apr_pool_cleanup_null); + if (random) { + rc = SQLSetStmtAttr(hstmt, SQL_ATTR_CURSOR_SCROLLABLE, + (SQLPOINTER)SQL_SCROLLABLE, 0); + CHECK_ERROR(handle, "SQLSetStmtAttr (SQL_ATTR_CURSOR_SCROLLABLE)", rc, + SQL_HANDLE_STMT, hstmt); + } + if (SQL_SUCCEEDED(rc)) { + rc = SQLExecDirect(hstmt, (SQLCHAR *)statement, (SQLINTEGER)len); + CHECK_ERROR(handle, "SQLExecDirect", rc, SQL_HANDLE_STMT, hstmt); + } + if (SQL_SUCCEEDED(rc)) { + rc = odbc_create_results(handle, hstmt, pool, random, res); + apr_pool_cleanup_register(pool, *res, + odbc_close_results, apr_pool_cleanup_null); + } + return APR_FROM_SQL_RESULT(rc); +} + +/** num_cols: get the number of columns in a results set **/ +static int odbc_num_cols(apr_dbd_results_t *res) +{ + return res->ncols; +} + +/** num_tuples: get the number of rows in a results set **/ +static int odbc_num_tuples(apr_dbd_results_t *res) +{ + SQLRETURN rc; + SQLLEN nrows; + + rc = SQLRowCount(res->stmt, &nrows); + CHECK_ERROR(res->apr_dbd, "SQLRowCount", rc, SQL_HANDLE_STMT, res->stmt); + return SQL_SUCCEEDED(rc) ? (int)nrows : -1; +} + +/** get_row: get a row from a result set **/ +static int odbc_get_row(apr_pool_t *pool, apr_dbd_results_t *res, + apr_dbd_row_t **row, int rownum) +{ + SQLRETURN rc; + char *fetchtype; + int c; + + *row = apr_pcalloc(pool, sizeof(apr_dbd_row_t)); + (*row)->stmt = res->stmt; + (*row)->dbc = res->dbc; + (*row)->res = res; + (*row)->pool = res->pool; + + /* mark all the columns as needing SQLGetData unless they are bound */ + for (c = 0; c < res->ncols; c++) { + if (res->colstate[c] != COL_BOUND) { + res->colstate[c] = COL_AVAIL; + } + /* some drivers do not null-term zero-len CHAR data */ + if (res->colptrs[c]) + *(char *)res->colptrs[c] = 0; + } + if (res->random && (rownum > 0)) { + fetchtype = "SQLFetchScroll"; + rc = SQLFetchScroll(res->stmt, SQL_FETCH_ABSOLUTE, rownum); + } + else { + fetchtype = "SQLFetch"; + rc = SQLFetch(res->stmt); + } + CHECK_ERROR(res->apr_dbd, fetchtype, rc, SQL_HANDLE_STMT, res->stmt); + (*row)->stmt = res->stmt; + if (!SQL_SUCCEEDED(rc) && !res->random) { + /* early close on any error (usually SQL_NO_DATA) if fetching + * sequentially to release resources ASAP + */ + odbc_close_results(res); + return -1; + } + return SQL_SUCCEEDED(rc) ? 0 : -1; +} + +/** datum_get: get a binary entry from a row **/ +static apr_status_t odbc_datum_get(const apr_dbd_row_t *row, int col, + apr_dbd_type_e dbdtype, void *data) +{ + SQLSMALLINT sqltype; + void *p; + int len; + + if (col >= row->res->ncols) + return APR_EGENERAL; + + if (dbdtype < 0 || dbdtype >= NUM_APR_DBD_TYPES) { + data = NULL; /* invalid type */ + return APR_EGENERAL; + } + + len = sqlSizes[dbdtype]; + sqltype = sqlCtype[dbdtype]; + + /* must not memcpy a brigade, sentinals are relative to orig loc */ + if (IS_LOB(sqltype)) + return odbc_create_bucket(row, col, sqltype, data); + + p = odbc_get(row, col, sqltype); + if (p == (void *)-1) + return APR_EGENERAL; + + if (p == NULL) + return APR_ENOENT; /* SQL NULL value */ + + if (len < 0) + *(char**)data = (char *)p; + else + memcpy(data, p, len); + + return APR_SUCCESS; + +} + +/** get_entry: get an entry from a row (string data) **/ +static const char *odbc_get_entry(const apr_dbd_row_t *row, int col) +{ + void *p; + + if (col >= row->res->ncols) + return NULL; + + p = odbc_get(row, col, SQL_C_CHAR); + + /* NULL or invalid (-1) */ + if (p == NULL || p == (void *)-1) + return p; + else + return apr_pstrdup(row->pool, p); +} + +/** error: get current error message (if any) **/ +static const char *odbc_error(apr_dbd_t *handle, int errnum) +{ + return (handle) ? handle->lastError : "[dbd_odbc]No error message available"; +} + +/** escape: escape a string so it is safe for use in query/select **/ +static const char *odbc_escape(apr_pool_t *pool, const char *s, + apr_dbd_t *handle) +{ + char *newstr, *src, *dst, *sq; + int qcount; + + /* return the original if there are no single-quotes */ + if (!(sq = strchr(s, '\''))) + return (char *)s; + /* count the single-quotes and allocate a new buffer */ + for (qcount = 1; (sq = strchr(sq + 1, '\'')); ) + qcount++; + newstr = apr_palloc(pool, strlen(s) + qcount + 1); + + /* move chars, doubling all single-quotes */ + src = (char *)s; + for (dst = newstr; *src; src++) { + if ((*dst++ = *src) == '\'') + *dst++ = '\''; + } + *dst = 0; + return newstr; +} + +/** prepare: prepare a statement **/ +static int odbc_prepare(apr_pool_t *pool, apr_dbd_t *handle, + const char *query, const char *label, int nargs, + int nvals, apr_dbd_type_e *types, + apr_dbd_prepared_t **statement) +{ + SQLRETURN rc; + size_t len = strlen(query); + + if (odbc_check_rollback(handle)) + return APR_EGENERAL; + + *statement = apr_pcalloc(pool, sizeof(apr_dbd_prepared_t)); + (*statement)->dbc = handle->dbc; + (*statement)->apr_dbd = handle; + (*statement)->nargs = nargs; + (*statement)->nvals = nvals; + (*statement)->types = + apr_pmemdup(pool, types, nargs * sizeof(apr_dbd_type_e)); + rc = SQLAllocHandle(SQL_HANDLE_STMT, handle->dbc, &((*statement)->stmt)); + apr_pool_cleanup_register(pool, *statement, + odbc_close_pstmt, apr_pool_cleanup_null); + CHECK_ERROR(handle, "SQLAllocHandle (STMT)", rc, + SQL_HANDLE_DBC, handle->dbc); + rc = SQLPrepare((*statement)->stmt, (SQLCHAR *)query, (SQLINTEGER)len); + CHECK_ERROR(handle, "SQLPrepare", rc, SQL_HANDLE_STMT, + (*statement)->stmt); + return APR_FROM_SQL_RESULT(rc); +} + +/** pquery: query using a prepared statement + args **/ +static int odbc_pquery(apr_pool_t *pool, apr_dbd_t *handle, int *nrows, + apr_dbd_prepared_t *statement, const char **args) +{ + SQLRETURN rc = SQL_SUCCESS; + int i, argp; + + if (odbc_check_rollback(handle)) + return APR_EGENERAL; + + for (i = argp = 0; i < statement->nargs && SQL_SUCCEEDED(rc); i++) { + rc = odbc_bind_param(pool, statement, i + 1, statement->types[i], + &argp, (const void **)args, TEXTMODE); + } + if (SQL_SUCCEEDED(rc)) { + rc = SQLExecute(statement->stmt); + CHECK_ERROR(handle, "SQLExecute", rc, SQL_HANDLE_STMT, + statement->stmt); + } + if (SQL_SUCCEEDED(rc)) { + SQLLEN rowcount; + + rc = SQLRowCount(statement->stmt, &rowcount); + *nrows = (int)rowcount; + CHECK_ERROR(handle, "SQLRowCount", rc, SQL_HANDLE_STMT, + statement->stmt); + } + return APR_FROM_SQL_RESULT(rc); +} + +/** pvquery: query using a prepared statement + args **/ +static int odbc_pvquery(apr_pool_t *pool, apr_dbd_t *handle, int *nrows, + apr_dbd_prepared_t *statement, va_list args) +{ + const char **values; + int i; + + values = apr_palloc(pool, sizeof(*values) * statement->nvals); + for (i = 0; i < statement->nvals; i++) + values[i] = va_arg(args, const char *); + return odbc_pquery(pool, handle, nrows, statement, values); +} + +/** pselect: select using a prepared statement + args **/ +static int odbc_pselect(apr_pool_t *pool, apr_dbd_t *handle, + apr_dbd_results_t **res, apr_dbd_prepared_t *statement, + int random, const char **args) +{ + SQLRETURN rc = SQL_SUCCESS; + int i, argp; + + if (odbc_check_rollback(handle)) + return APR_EGENERAL; + + if (random) { + rc = SQLSetStmtAttr(statement->stmt, SQL_ATTR_CURSOR_SCROLLABLE, + (SQLPOINTER)SQL_SCROLLABLE, 0); + CHECK_ERROR(handle, "SQLSetStmtAttr (SQL_ATTR_CURSOR_SCROLLABLE)", + rc, SQL_HANDLE_STMT, statement->stmt); + } + if (SQL_SUCCEEDED(rc)) { + for (i = argp = 0; i < statement->nargs && SQL_SUCCEEDED(rc); i++) { + rc = odbc_bind_param(pool, statement, i + 1, statement->types[i], + &argp, (const void **)args, TEXTMODE); + } + } + if (SQL_SUCCEEDED(rc)) { + rc = SQLExecute(statement->stmt); + CHECK_ERROR(handle, "SQLExecute", rc, SQL_HANDLE_STMT, + statement->stmt); + } + if (SQL_SUCCEEDED(rc)) { + rc = odbc_create_results(handle, statement->stmt, pool, random, res); + apr_pool_cleanup_register(pool, *res, + odbc_close_results, apr_pool_cleanup_null); + } + return APR_FROM_SQL_RESULT(rc); +} + +/** pvselect: select using a prepared statement + args **/ +static int odbc_pvselect(apr_pool_t *pool, apr_dbd_t *handle, + apr_dbd_results_t **res, + apr_dbd_prepared_t *statement, int random, + va_list args) +{ + const char **values; + int i; + + values = apr_palloc(pool, sizeof(*values) * statement->nvals); + for (i = 0; i < statement->nvals; i++) + values[i] = va_arg(args, const char *); + return odbc_pselect(pool, handle, res, statement, random, values); +} + +/** get_name: get a column title from a result set **/ +static const char *odbc_get_name(const apr_dbd_results_t *res, int col) +{ + SQLRETURN rc; + char buffer[MAX_COLUMN_NAME]; + SQLSMALLINT colnamelength, coltype, coldecimal, colnullable; + SQLULEN colsize; + + if (col >= res->ncols) + return NULL; /* bogus column number */ + if (res->colnames[col] != NULL) + return res->colnames[col]; /* we already retrieved it */ + rc = SQLDescribeCol(res->stmt, col + 1, + (SQLCHAR *)buffer, sizeof(buffer), &colnamelength, + &coltype, &colsize, &coldecimal, &colnullable); + CHECK_ERROR(res->apr_dbd, "SQLDescribeCol", rc, + SQL_HANDLE_STMT, res->stmt); + res->colnames[col] = apr_pstrdup(res->pool, buffer); + return res->colnames[col]; +} + +/** transaction_mode_get: get the mode of transaction **/ +static int odbc_transaction_mode_get(apr_dbd_transaction_t *trans) +{ + return (int)trans->apr_dbd->can_commit; +} + +/** transaction_mode_set: set the mode of transaction **/ +static int odbc_transaction_mode_set(apr_dbd_transaction_t *trans, int mode) +{ + int legal = ( APR_DBD_TRANSACTION_IGNORE_ERRORS + | APR_DBD_TRANSACTION_COMMIT + | APR_DBD_TRANSACTION_ROLLBACK); + + if ((mode & legal) != mode) + return APR_EGENERAL; + + trans->apr_dbd->can_commit = mode; + return APR_SUCCESS; +} + +/** pbquery: query using a prepared statement + binary args **/ +static int odbc_pbquery(apr_pool_t *pool, apr_dbd_t *handle, int *nrows, + apr_dbd_prepared_t *statement, const void **args) +{ + SQLRETURN rc = SQL_SUCCESS; + int i, argp; + + if (odbc_check_rollback(handle)) + return APR_EGENERAL; + + for (i = argp = 0; i < statement->nargs && SQL_SUCCEEDED(rc); i++) + rc = odbc_bind_param(pool, statement, i + 1, statement->types[i], + &argp, args, BINARYMODE); + + if (SQL_SUCCEEDED(rc)) { + rc = SQLExecute(statement->stmt); + CHECK_ERROR(handle, "SQLExecute", rc, SQL_HANDLE_STMT, + statement->stmt); + } + if (SQL_SUCCEEDED(rc)) { + SQLLEN rowcount; + + rc = SQLRowCount(statement->stmt, &rowcount); + *nrows = (int)rowcount; + CHECK_ERROR(handle, "SQLRowCount", rc, SQL_HANDLE_STMT, + statement->stmt); + } + return APR_FROM_SQL_RESULT(rc); +} + +/** pbselect: select using a prepared statement + binary args **/ +static int odbc_pbselect(apr_pool_t *pool, apr_dbd_t *handle, + apr_dbd_results_t **res, + apr_dbd_prepared_t *statement, + int random, const void **args) +{ + SQLRETURN rc = SQL_SUCCESS; + int i, argp; + + if (odbc_check_rollback(handle)) + return APR_EGENERAL; + + if (random) { + rc = SQLSetStmtAttr(statement->stmt, SQL_ATTR_CURSOR_SCROLLABLE, + (SQLPOINTER)SQL_SCROLLABLE, 0); + CHECK_ERROR(handle, "SQLSetStmtAttr (SQL_ATTR_CURSOR_SCROLLABLE)", + rc, SQL_HANDLE_STMT, statement->stmt); + } + if (SQL_SUCCEEDED(rc)) { + for (i = argp = 0; i < statement->nargs && SQL_SUCCEEDED(rc); i++) { + rc = odbc_bind_param(pool, statement, i + 1, statement->types[i], + &argp, args, BINARYMODE); + } + } + if (SQL_SUCCEEDED(rc)) { + rc = SQLExecute(statement->stmt); + CHECK_ERROR(handle, "SQLExecute", rc, SQL_HANDLE_STMT, + statement->stmt); + } + if (SQL_SUCCEEDED(rc)) { + rc = odbc_create_results(handle, statement->stmt, pool, random, res); + apr_pool_cleanup_register(pool, *res, + odbc_close_results, apr_pool_cleanup_null); + } + + return APR_FROM_SQL_RESULT(rc); +} + +/** pvbquery: query using a prepared statement + binary args **/ +static int odbc_pvbquery(apr_pool_t *pool, apr_dbd_t *handle, int *nrows, + apr_dbd_prepared_t *statement, va_list args) +{ + const char **values; + int i; + + values = apr_palloc(pool, sizeof(*values) * statement->nvals); + for (i = 0; i < statement->nvals; i++) + values[i] = va_arg(args, const char *); + return odbc_pbquery(pool, handle, nrows, statement, (const void **)values); +} + +/** pvbselect: select using a prepared statement + binary args **/ +static int odbc_pvbselect(apr_pool_t *pool, apr_dbd_t *handle, + apr_dbd_results_t **res, + apr_dbd_prepared_t *statement, + int random, va_list args) +{ + const char **values; + int i; + + values = apr_palloc(pool, sizeof(*values) * statement->nvals); + for (i = 0; i < statement->nvals; i++) + values[i] = va_arg(args, const char *); + return odbc_pbselect(pool, handle, res, statement, random, (const void **)values); +} + +APR_MODULE_DECLARE_DATA const apr_dbd_driver_t ODBC_DRIVER_ENTRY = { + ODBC_DRIVER_STRING, + odbc_init, + odbc_native_handle, + odbc_open, + odbc_check_conn, + odbc_close, + odbc_set_dbname, + odbc_start_transaction, + odbc_end_transaction, + odbc_query, + odbc_select, + odbc_num_cols, + odbc_num_tuples, + odbc_get_row, + odbc_get_entry, + odbc_error, + odbc_escape, + odbc_prepare, + odbc_pvquery, + odbc_pvselect, + odbc_pquery, + odbc_pselect, + odbc_get_name, + odbc_transaction_mode_get, + odbc_transaction_mode_set, + "?", + odbc_pvbquery, + odbc_pvbselect, + odbc_pbquery, + odbc_pbselect, + odbc_datum_get +}; + +#endif diff --git a/dbd/apr_dbd_odbc.dsp b/dbd/apr_dbd_odbc.dsp new file mode 100644 index 00000000000..3ea69f1a304 --- /dev/null +++ b/dbd/apr_dbd_odbc.dsp @@ -0,0 +1,191 @@ +# Microsoft Developer Studio Project File - Name="apr_dbd_odbc" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=apr_dbd_odbc - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "apr_dbd_odbc.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "apr_dbd_odbc.mak" CFG="apr_dbd_odbc - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "apr_dbd_odbc - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "apr_dbd_odbc - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "apr_dbd_odbc - x64 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "apr_dbd_odbc - x64 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "apr_dbd_odbc - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c +# ADD CPP /nologo /MD /W3 /Zi /O2 /Oy- /I "../include" /I "../include/arch/win32" /I "../include/private" /D "NDEBUG" /D "HAVE_SQL_H" /D "WIN32" /D "_WINDOWS" /D "APU_DSO_MODULE_BUILD" /D APU_HAVE_ODBC=1 /Fo"$(INTDIR)\" /Fd"$(INTDIR)\apr_dbd_odbc_src" /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o /win32 "NUL" +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o /win32 "NUL" +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /fo"Release/apr_dbd_odbc-1.res" /d DLL_NAME="apr_dbd_odbc" /d "NDEBUG" /d "APU_VERSION_ONLY" /I "../include" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib odbc32.lib odbccp32.lib /nologo /base:"0x6EF00000" /subsystem:windows /dll /incremental:no /debug +# ADD LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib odbc32.lib odbccp32.lib /nologo /base:"0x6EF00000" /subsystem:windows /dll /incremental:no /debug /out:"Release\apr_dbd_odbc-1.dll" /implib:"Release\apr_dbd_odbc-1.lib" /MACHINE:X86 /opt:ref +# Begin Special Build Tool +TargetPath=Release\apr_dbd_odbc-1.dll +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2 +# End Special Build Tool + +!ELSEIF "$(CFG)" == "apr_dbd_odbc - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /EHsc /c +# ADD CPP /nologo /MDd /W3 /Zi /Od /I "../include" /I "../include/arch/win32" /I "../include/private" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "APU_DSO_MODULE_BUILD" /D APU_HAVE_ODBC=1 /D "HAVE_SQL_H" /Fo"$(INTDIR)\" /Fd"$(INTDIR)\apr_dbd_odbc_src" /FD /EHsc /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o /win32 "NUL" +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o /win32 "NUL" +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /fo"Debug/apr_dbd_odbc-1.res" /d DLL_NAME="apr_dbd_odbc" /d "_DEBUG" /d "APU_VERSION_ONLY" /I "../include" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib odbc32.lib odbccp32.lib /nologo /base:"0x6EF00000" /subsystem:windows /dll /incremental:no /debug +# ADD LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib odbc32.lib odbccp32.lib /nologo /base:"0x6EF00000" /subsystem:windows /dll /incremental:no /debug /out:"Debug\apr_dbd_odbc-1.dll" /implib:"Debug\apr_dbd_odbc-1.lib" /MACHINE:X86 +# Begin Special Build Tool +TargetPath=Debug\apr_dbd_odbc-1.dll +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2 +# End Special Build Tool + +!ELSEIF "$(CFG)" == "apr_dbd_odbc - x64 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "x64\Release" +# PROP BASE Intermediate_Dir "x64\Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "x64\Release" +# PROP Intermediate_Dir "x64\Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c +# ADD CPP /nologo /MD /W3 /Zi /O2 /Oy- /I "../include" /I "../include/arch/win32" /I "../include/private" /D "NDEBUG" /D "HAVE_SQL_H" /D "WIN32" /D "_WINDOWS" /D "APU_DSO_MODULE_BUILD" /D APU_HAVE_ODBC=1 /Fo"$(INTDIR)\" /Fd"$(INTDIR)\apr_dbd_odbc_src" /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o /win32 "NUL" +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o /win32 "NUL" +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /fo"x64\Release/apr_dbd_odbc-1.res" /d DLL_NAME="apr_dbd_odbc" /d "NDEBUG" /d "APU_VERSION_ONLY" /I "../include" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib odbc32.lib odbccp32.lib /nologo /base:"0x6EF00000" /subsystem:windows /dll /incremental:no /debug +# ADD LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib odbc32.lib odbccp32.lib /nologo /base:"0x6EF00000" /subsystem:windows /dll /incremental:no /debug /out:"x64\Release\apr_dbd_odbc-1.dll" /implib:"x64\Release\apr_dbd_odbc-1.lib" /MACHINE:X64 /opt:ref +# Begin Special Build Tool +TargetPath=x64\Release\apr_dbd_odbc-1.dll +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2 +# End Special Build Tool + +!ELSEIF "$(CFG)" == "apr_dbd_odbc - x64 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "x64\Debug" +# PROP BASE Intermediate_Dir "x64\Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "x64\Debug" +# PROP Intermediate_Dir "x64\Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /EHsc /c +# ADD CPP /nologo /MDd /W3 /Zi /Od /I "../include" /I "../include/arch/win32" /I "../include/private" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "APU_DSO_MODULE_BUILD" /D APU_HAVE_ODBC=1 /D "HAVE_SQL_H" /Fo"$(INTDIR)\" /Fd"$(INTDIR)\apr_dbd_odbc_src" /FD /EHsc /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o /win32 "NUL" +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o /win32 "NUL" +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /fo"x64/debug/apr_dbd_odbc-1.res" /d DLL_NAME="apr_dbd_odbc" /d "_DEBUG" /d "APU_VERSION_ONLY" /I "../include" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib odbc32.lib odbccp32.lib /nologo /base:"0x6EF00000" /subsystem:windows /dll /incremental:no /debug +# ADD LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib odbc32.lib odbccp32.lib /nologo /base:"0x6EF00000" /subsystem:windows /dll /incremental:no /debug /out:"x64\Debug\apr_dbd_odbc-1.dll" /implib:"x64\Debug\apr_dbd_odbc-1.lib" /MACHINE:X64 +# Begin Special Build Tool +TargetPath=x64\Debug\apr_dbd_odbc-1.dll +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2 +# End Special Build Tool + +!ENDIF + +# Begin Target + +# Name "apr_dbd_odbc - Win32 Release" +# Name "apr_dbd_odbc - Win32 Debug" +# Name "apr_dbd_odbc - x64 Release" +# Name "apr_dbd_odbc - x64 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\apr_dbd_odbc.c +# End Source File +# End Group +# Begin Group "Public Header Files" + +# PROP Default_Filter ".h" +# Begin Source File + +SOURCE=..\include\apr_dbd.h +# End Source File +# End Group +# Begin Group "Internal Header Files" + +# PROP Default_Filter ".h" +# End Group +# End Target +# End Project diff --git a/dbd/apr_dbd_oracle.c b/dbd/apr_dbd_oracle.c new file mode 100644 index 00000000000..a851e1f925c --- /dev/null +++ b/dbd/apr_dbd_oracle.c @@ -0,0 +1,2221 @@ +/* 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. + */ + +/* Developed initially by Nick Kew and Chris Darroch. + * Contributed to the APR project by kind permission of + * Pearson Education Core Technology Group (CTG), + * formerly Central Media Group (CMG). + */ + +/* apr_dbd_oracle - a painful attempt + * + * Based first on the documentation at + * http://download-west.oracle.com/docs/cd/B10501_01/appdev.920/a96584/toc.htm + * + * Those docs have a lot of internal inconsistencies, contradictions, etc + * So I've snarfed the demo programs (from Oracle 8, not included in + * the current downloadable oracle), and used code from them. + * + * Why do cdemo81.c and cdemo82.c do the same thing in very different ways? + * e.g. cdemo82 releases all its handle on shutdown; cdemo81 doesn't + * + * All the ORA* functions return a "sword". Some of them are documented; + * others aren't. So I've adopted a policy of using switch statements + * everywhere, even when we're not doing anything with the return values. + * + * This makes no attempt at performance tuning, such as setting + * prefetch cache size. We need some actual performance data + * to make that meaningful. Input from someone with experience + * as a sysop using oracle would be a good start. + */ + +/* shut compiler up */ +#ifdef DEBUG +#define int_errorcode int errorcode +#else +#define int_errorcode +#endif + +#include "apu.h" +#include "apr_private.h" + +#if APU_HAVE_ORACLE + +#include <ctype.h> +#include <stdlib.h> +#include <stdio.h> + +#include <oci.h> + +#include "apr_strings.h" +#include "apr_lib.h" +#include "apr_time.h" +#include "apr_hash.h" +#include "apr_buckets.h" + +#define TRANS_TIMEOUT 30 +#define MAX_ARG_LEN 256 /* in line with other apr_dbd drivers. We alloc this + * lots of times, so a large value gets hungry. + * Should really make it configurable + */ +#define DEFAULT_LONG_SIZE 4096 +#define DBD_ORACLE_MAX_COLUMNS 256 +#define NUMERIC_FIELD_SIZE 32 + +#define CHECK_CONN_QUERY "SELECT 1 FROM dual" + +#define ERR_BUF_SIZE 200 + +#ifdef DEBUG +#include <stdio.h> +#endif + +#include "apr_dbd_internal.h" + +/* declarations */ +static const char *dbd_oracle_error(apr_dbd_t *sql, int n); +static int dbd_oracle_prepare(apr_pool_t *pool, apr_dbd_t *sql, + const char *query, const char *label, + int nargs, int nvals, apr_dbd_type_e *types, + apr_dbd_prepared_t **statement); +static int outputParams(apr_dbd_t*, apr_dbd_prepared_t*); +static int dbd_oracle_pselect(apr_pool_t *pool, apr_dbd_t *sql, + apr_dbd_results_t **results, + apr_dbd_prepared_t *statement, + int seek, const char **values); +static int dbd_oracle_pquery(apr_pool_t *pool, apr_dbd_t *sql, + int *nrows, apr_dbd_prepared_t *statement, + const char **values); +static int dbd_oracle_start_transaction(apr_pool_t *pool, apr_dbd_t *sql, + apr_dbd_transaction_t **trans); +static int dbd_oracle_end_transaction(apr_dbd_transaction_t *trans); + +struct apr_dbd_transaction_t { + int mode; + enum { TRANS_NONE, TRANS_ERROR, TRANS_1, TRANS_2 } status; + apr_dbd_t *handle; + OCITrans *trans; + OCISnapshot *snapshot1; + OCISnapshot *snapshot2; +}; + +struct apr_dbd_results_t { + apr_pool_t *pool; + apr_dbd_t* handle; + unsigned int rownum; + int seek; + int nrows; + apr_dbd_prepared_t *statement; +}; + +struct apr_dbd_t { + sword status; + OCIError *err; + OCIServer *svr; + OCISvcCtx *svc; + OCISession *auth; + apr_dbd_transaction_t* trans; + apr_pool_t *pool; + char buf[ERR_BUF_SIZE]; /* for error messages */ + apr_size_t long_size; + apr_dbd_prepared_t *check_conn_stmt; +}; + +struct apr_dbd_row_t { + int n; + apr_dbd_results_t *res; + apr_pool_t *pool; +}; + +typedef struct { + apr_dbd_type_e type; + sb2 ind; + sb4 len; + OCIBind *bind; + union { + void *raw; + char *sval; + int ival; + unsigned int uval; + double fval; + OCILobLocator *lobval; + } value; +} bind_arg; + +typedef struct { + int type; + sb2 ind; + ub2 len; /* length of actual output */ + OCIDefine *defn; + apr_size_t sz; /* length of buf for output */ + union { + void *raw; + char *sval; + OCILobLocator *lobval; + } buf; + const char *name; +} define_arg; + +struct apr_dbd_prepared_t { + OCIStmt *stmt; + int nargs; + int nvals; + bind_arg *args; + int nout; + define_arg *out; + apr_dbd_t *handle; + apr_pool_t *pool; + ub2 type; +}; + +/* AFAICT from the docs, the OCIEnv thingey can be used async + * across threads, so lets have a global one. + * + * We'll need shorter-lived envs to deal with requests and connections + * + * Hmmm, that doesn't work: we don't have a usermem framework. + * OK, forget about using APR pools here, until we figure out + * the right way to do it (if such a thing exists). + */ +static OCIEnv *dbd_oracle_env = NULL; + +/* Oracle specific bucket for BLOB/CLOB types */ +typedef struct apr_bucket_lob apr_bucket_lob; +/** + * A bucket referring to a Oracle BLOB/CLOB + */ +struct apr_bucket_lob { + /** Number of buckets using this memory */ + apr_bucket_refcount refcount; + /** The row this bucket refers to */ + const apr_dbd_row_t *row; + /** The column this bucket refers to */ + int col; + /** The pool into which any needed structures should + * be created while reading from this bucket */ + apr_pool_t *readpool; +}; + +static void lob_bucket_destroy(void *data); +static apr_status_t lob_bucket_read(apr_bucket *e, const char **str, + apr_size_t *len, apr_read_type_e block); +static apr_bucket *apr_bucket_lob_make(apr_bucket *b, + const apr_dbd_row_t *row, int col, + apr_off_t offset, apr_size_t len, + apr_pool_t *p); +static apr_bucket *apr_bucket_lob_create(const apr_dbd_row_t *row, int col, + apr_off_t offset, + apr_size_t len, apr_pool_t *p, + apr_bucket_alloc_t *list); + +static const apr_bucket_type_t apr_bucket_type_lob = { + "LOB", 5, APR_BUCKET_DATA, + lob_bucket_destroy, + lob_bucket_read, + apr_bucket_setaside_notimpl, + apr_bucket_shared_split, + apr_bucket_shared_copy +}; + +static void lob_bucket_destroy(void *data) +{ + apr_bucket_lob *f = data; + + if (apr_bucket_shared_destroy(f)) { + /* no need to destroy database objects here; it will get + * done automatically when the pool gets cleaned up */ + apr_bucket_free(f); + } +} + +static apr_status_t lob_bucket_read(apr_bucket *e, const char **str, + apr_size_t *len, apr_read_type_e block) +{ + apr_bucket_lob *a = e->data; + const apr_dbd_row_t *row = a->row; + apr_dbd_results_t *res = row->res; + int col = a->col; + apr_bucket *b = NULL; + apr_size_t blength = e->length; /* bytes remaining in file past offset */ + apr_off_t boffset = e->start; + define_arg *val = &res->statement->out[col]; + apr_dbd_t *sql = res->handle; +/* Only with 10g, unfortunately + oraub8 length = APR_BUCKET_BUFF_SIZE; +*/ + ub4 length = APR_BUCKET_BUFF_SIZE; + char *buf = NULL; + + *str = NULL; /* in case we die prematurely */ + + /* fetch from offset if not at the beginning */ + buf = apr_palloc(row->pool, APR_BUCKET_BUFF_SIZE); + sql->status = OCILobRead(sql->svc, sql->err, val->buf.lobval, + &length, 1 + (size_t)boffset, + (dvoid*) buf, APR_BUCKET_BUFF_SIZE, + NULL, NULL, 0, SQLCS_IMPLICIT); +/* Only with 10g, unfortunately + sql->status = OCILobRead2(sql->svc, sql->err, val->buf.lobval, + &length, NULL, 1 + boffset, + (dvoid*) buf, APR_BUCKET_BUFF_SIZE, + OCI_ONE_PIECE, NULL, NULL, 0, SQLCS_IMPLICIT); +*/ + if (sql->status != OCI_SUCCESS) { + return APR_EGENERAL; + } + blength -= length; + *len = length; + *str = buf; + + /* + * Change the current bucket to refer to what we read, + * even if we read nothing because we hit EOF. + */ + apr_bucket_pool_make(e, *str, *len, res->pool); + + /* If we have more to read from the field, then create another bucket */ + if (blength > 0) { + /* for efficiency, we can just build a new apr_bucket struct + * to wrap around the existing LOB bucket */ + b = apr_bucket_alloc(sizeof(*b), e->list); + b->start = boffset + *len; + b->length = blength; + b->data = a; + b->type = &apr_bucket_type_lob; + b->free = apr_bucket_free; + b->list = e->list; + APR_BUCKET_INSERT_AFTER(e, b); + } + else { + lob_bucket_destroy(a); + } + + return APR_SUCCESS; +} + +static apr_bucket *apr_bucket_lob_make(apr_bucket *b, + const apr_dbd_row_t *row, int col, + apr_off_t offset, apr_size_t len, + apr_pool_t *p) +{ + apr_bucket_lob *f; + + f = apr_bucket_alloc(sizeof(*f), b->list); + f->row = row; + f->col = col; + f->readpool = p; + + b = apr_bucket_shared_make(b, f, offset, len); + b->type = &apr_bucket_type_lob; + + return b; +} + +static apr_bucket *apr_bucket_lob_create(const apr_dbd_row_t *row, int col, + apr_off_t offset, + apr_size_t len, apr_pool_t *p, + apr_bucket_alloc_t *list) +{ + apr_bucket *b = apr_bucket_alloc(sizeof(*b), list); + + APR_BUCKET_INIT(b); + b->free = apr_bucket_free; + b->list = list; + return apr_bucket_lob_make(b, row, col, offset, len, p); +} + +static apr_status_t dbd_free_lobdesc(void *lob) +{ + switch (OCIDescriptorFree(lob, OCI_DTYPE_LOB)) { + case OCI_SUCCESS: + return APR_SUCCESS; + default: + return APR_EGENERAL; + } +} + +static apr_status_t dbd_free_snapshot(void *snap) +{ + switch (OCIDescriptorFree(snap, OCI_DTYPE_SNAP)) { + case OCI_SUCCESS: + return APR_SUCCESS; + default: + return APR_EGENERAL; + } +} + +static void dbd_oracle_init(apr_pool_t *pool) +{ + if (dbd_oracle_env == NULL) { + /* Sadly, OCI_SHARED seems to be impossible to use, due to + * various Oracle bugs. See, for example, Oracle MetaLink bug 2972890 + * and PHP bug http://bugs.php.net/bug.php?id=23733 + */ +#ifdef OCI_NEW_LENGTH_SEMANTICS + OCIEnvCreate(&dbd_oracle_env, OCI_THREADED|OCI_NEW_LENGTH_SEMANTICS, + NULL, NULL, NULL, NULL, 0, NULL); +#else + OCIEnvCreate(&dbd_oracle_env, OCI_THREADED, + NULL, NULL, NULL, NULL, 0, NULL); +#endif + } +} + +static apr_dbd_t *dbd_oracle_open(apr_pool_t *pool, const char *params, + const char **error) +{ + apr_dbd_t *ret = apr_pcalloc(pool, sizeof(apr_dbd_t)); + int errorcode; + + char *BLANK = ""; + struct { + const char *field; + char *value; + } fields[] = { + {"user", BLANK}, + {"pass", BLANK}, + {"dbname", BLANK}, + {"server", BLANK}, + {NULL, NULL} + }; + int i; + const char *ptr; + const char *key; + size_t klen; + const char *value; + size_t vlen; + static const char *const delims = " \r\n\t;|,"; + + ret->pool = pool; + ret->long_size = DEFAULT_LONG_SIZE; + + /* snitch parsing from the MySQL driver */ + for (ptr = strchr(params, '='); ptr; ptr = strchr(ptr, '=')) { + /* don't dereference memory that may not belong to us */ + if (ptr == params) { + ++ptr; + continue; + } + for (key = ptr-1; apr_isspace(*key); --key); + klen = 0; + while (apr_isalpha(*key)) { + if (key == params) { + /* Don't parse off the front of the params */ + --key; + ++klen; + break; + } + --key; + ++klen; + } + ++key; + for (value = ptr+1; apr_isspace(*value); ++value); + vlen = strcspn(value, delims); + for (i=0; fields[i].field != NULL; ++i) { + if (!strncasecmp(fields[i].field, key, klen)) { + fields[i].value = apr_pstrndup(pool, value, vlen); + break; + } + } + ptr = value+vlen; + } + + ret->status = OCIHandleAlloc(dbd_oracle_env, (dvoid**)&ret->err, + OCI_HTYPE_ERROR, 0, NULL); + switch (ret->status) { + default: +#ifdef DEBUG + printf("ret->status is %d\n", ret->status); + break; +#else + return NULL; +#endif + case OCI_SUCCESS: + break; + } + + ret->status = OCIHandleAlloc(dbd_oracle_env, (dvoid**)&ret->svr, + OCI_HTYPE_SERVER, 0, NULL); + switch (ret->status) { + default: +#ifdef DEBUG + OCIErrorGet(ret->err, 1, NULL, &errorcode, ret->buf, + sizeof(ret->buf), OCI_HTYPE_ERROR); + printf("OPEN ERROR %d (alloc svr): %s\n", ret->status, ret->buf); + break; +#else + if (error) { + *error = apr_pcalloc(pool, ERR_BUF_SIZE); + OCIErrorGet(ret->err, 1, NULL, &errorcode, (unsigned char*)(*error), + ERR_BUF_SIZE, OCI_HTYPE_ERROR); + } + return NULL; +#endif + case OCI_SUCCESS: + break; + } + + ret->status = OCIHandleAlloc(dbd_oracle_env, (dvoid**)&ret->svc, + OCI_HTYPE_SVCCTX, 0, NULL); + switch (ret->status) { + default: +#ifdef DEBUG + OCIErrorGet(ret->err, 1, NULL, &errorcode, ret->buf, + sizeof(ret->buf), OCI_HTYPE_ERROR); + printf("OPEN ERROR %d (alloc svc): %s\n", ret->status, ret->buf); + break; +#else + if (error) { + *error = apr_pcalloc(pool, ERR_BUF_SIZE); + OCIErrorGet(ret->err, 1, NULL, &errorcode, (unsigned char*)(*error), + ERR_BUF_SIZE, OCI_HTYPE_ERROR); + } + return NULL; +#endif + case OCI_SUCCESS: + break; + } + +/* All the examples use the #else */ +#if CAN_DO_LOGIN + ret->status = OCILogon(dbd_oracle_env, ret->err, &ret->svc, fields[0].value, + strlen(fields[0].value), fields[1].value, + strlen(fields[1].value), fields[2].value, + strlen(fields[2].value)); + switch (ret->status) { + default: +#ifdef DEBUG + OCIErrorGet(ret->err, 1, NULL, &errorcode, ret->buf, + sizeof(ret->buf), OCI_HTYPE_ERROR); + printf("OPEN ERROR: %s\n", ret->buf); + break; +#else + if (error) { + *error = apr_pcalloc(pool, ERR_BUF_SIZE); + OCIErrorGet(ret->err, 1, NULL, &errorcode, (unsigned char*)(*error), + ERR_BUF_SIZE, OCI_HTYPE_ERROR); + } + return NULL; +#endif + case OCI_SUCCESS: + break; + } +#else + ret->status = OCIServerAttach(ret->svr, ret->err, (text*) fields[3].value, + strlen(fields[3].value), OCI_DEFAULT); + switch (ret->status) { + default: +#ifdef DEBUG + OCIErrorGet(ret->err, 1, NULL, &errorcode, ret->buf, + sizeof(ret->buf), OCI_HTYPE_ERROR); + printf("OPEN ERROR %d (server attach): %s\n", ret->status, ret->buf); + break; +#else + if (error) { + *error = apr_pcalloc(pool, ERR_BUF_SIZE); + OCIErrorGet(ret->err, 1, NULL, &errorcode, (unsigned char*)(*error), + ERR_BUF_SIZE, OCI_HTYPE_ERROR); + } + return NULL; +#endif + case OCI_SUCCESS: + break; + } + ret->status = OCIAttrSet(ret->svc, OCI_HTYPE_SVCCTX, ret->svr, 0, + OCI_ATTR_SERVER, ret->err); + switch (ret->status) { + default: +#ifdef DEBUG + OCIErrorGet(ret->err, 1, NULL, &errorcode, ret->buf, + sizeof(ret->buf), OCI_HTYPE_ERROR); + printf("OPEN ERROR %d (attr set): %s\n", ret->status, ret->buf); + break; +#else + if (error) { + *error = apr_pcalloc(pool, ERR_BUF_SIZE); + OCIErrorGet(ret->err, 1, NULL, &errorcode, (unsigned char*)(*error), + ERR_BUF_SIZE, OCI_HTYPE_ERROR); + } + return NULL; +#endif + case OCI_SUCCESS: + break; + } + ret->status = OCIHandleAlloc(dbd_oracle_env, (dvoid**)&ret->auth, + OCI_HTYPE_SESSION, 0, NULL); + switch (ret->status) { + default: +#ifdef DEBUG + OCIErrorGet(ret->err, 1, NULL, &errorcode, ret->buf, + sizeof(ret->buf), OCI_HTYPE_ERROR); + printf("OPEN ERROR %d (alloc auth): %s\n", ret->status, ret->buf); + break; +#else + if (error) { + *error = apr_pcalloc(pool, ERR_BUF_SIZE); + OCIErrorGet(ret->err, 1, NULL, &errorcode, (unsigned char*)(*error), + ERR_BUF_SIZE, OCI_HTYPE_ERROR); + } + return NULL; +#endif + case OCI_SUCCESS: + break; + } + ret->status = OCIAttrSet(ret->auth, OCI_HTYPE_SESSION, fields[0].value, + strlen(fields[0].value), OCI_ATTR_USERNAME, ret->err); + switch (ret->status) { + default: +#ifdef DEBUG + OCIErrorGet(ret->err, 1, NULL, &errorcode, ret->buf, + sizeof(ret->buf), OCI_HTYPE_ERROR); + printf("OPEN ERROR %d (attr username): %s\n", ret->status, ret->buf); + break; +#else + if (error) { + *error = apr_pcalloc(pool, ERR_BUF_SIZE); + OCIErrorGet(ret->err, 1, NULL, &errorcode, (unsigned char*)(*error), + ERR_BUF_SIZE, OCI_HTYPE_ERROR); + } + return NULL; +#endif + case OCI_SUCCESS: + break; + } + ret->status = OCIAttrSet(ret->auth, OCI_HTYPE_SESSION, fields[1].value, + strlen(fields[1].value), OCI_ATTR_PASSWORD, ret->err); + switch (ret->status) { + default: +#ifdef DEBUG + OCIErrorGet(ret->err, 1, NULL, &errorcode, ret->buf, + sizeof(ret->buf), OCI_HTYPE_ERROR); + printf("OPEN ERROR %d (attr password): %s\n", ret->status, ret->buf); + break; +#else + if (error) { + *error = apr_pcalloc(pool, ERR_BUF_SIZE); + OCIErrorGet(ret->err, 1, NULL, &errorcode, (unsigned char*)(*error), + ERR_BUF_SIZE, OCI_HTYPE_ERROR); + } + return NULL; +#endif + case OCI_SUCCESS: + break; + } + ret->status = OCISessionBegin(ret->svc, ret->err, ret->auth, + OCI_CRED_RDBMS, OCI_DEFAULT); + switch (ret->status) { + default: +#ifdef DEBUG + OCIErrorGet(ret->err, 1, NULL, &errorcode, ret->buf, + sizeof(ret->buf), OCI_HTYPE_ERROR); + printf("OPEN ERROR %d (session begin): %s\n", ret->status, ret->buf); + break; +#else + if (error) { + *error = apr_pcalloc(pool, ERR_BUF_SIZE); + OCIErrorGet(ret->err, 1, NULL, &errorcode, (unsigned char*)(*error), + ERR_BUF_SIZE, OCI_HTYPE_ERROR); + } + return NULL; +#endif + case OCI_SUCCESS: + break; + } + ret->status = OCIAttrSet(ret->svc, OCI_HTYPE_SVCCTX, ret->auth, 0, + OCI_ATTR_SESSION, ret->err); + switch (ret->status) { + default: +#ifdef DEBUG + OCIErrorGet(ret->err, 1, NULL, &errorcode, ret->buf, + sizeof(ret->buf), OCI_HTYPE_ERROR); + printf("OPEN ERROR %d (attr session): %s\n", ret->status, ret->buf); +#else + if (error) { + *error = apr_pcalloc(pool, ERR_BUF_SIZE); + OCIErrorGet(ret->err, 1, NULL, &errorcode, (unsigned char*)(*error), + ERR_BUF_SIZE, OCI_HTYPE_ERROR); + } + return NULL; +#endif + break; + case OCI_SUCCESS: + break; + } +#endif + + if(dbd_oracle_prepare(pool, ret, CHECK_CONN_QUERY, NULL, 0, 0, NULL, + &ret->check_conn_stmt) != 0) { + return NULL; + } + + return ret; +} + +#ifdef EXPORT_NATIVE_FUNCS +static apr_size_t dbd_oracle_long_size_set(apr_dbd_t *sql, + apr_size_t long_size) +{ + apr_size_t old_size = sql->long_size; + sql->long_size = long_size; + return old_size; +} +#endif + +static const char *dbd_oracle_get_name(const apr_dbd_results_t *res, int n) +{ + define_arg *val = &res->statement->out[n]; + + if ((n < 0) || (n >= res->statement->nout)) { + return NULL; + } + return val->name; +} + +static int dbd_oracle_get_row(apr_pool_t *pool, apr_dbd_results_t *res, + apr_dbd_row_t **rowp, int rownum) +{ + apr_dbd_row_t *row = *rowp; + apr_dbd_t *sql = res->handle; + int_errorcode; + + if (row == NULL) { + row = apr_palloc(pool, sizeof(apr_dbd_row_t)); + *rowp = row; + row->res = res; + /* Oracle starts counting at 1 according to the docs */ + row->n = res->seek ? rownum : 1; + row->pool = pool; + } + else { + if (res->seek) { + row->n = rownum; + } + else { + ++row->n; + } + } + + if (res->seek) { + sql->status = OCIStmtFetch2(res->statement->stmt, res->handle->err, 1, + OCI_FETCH_ABSOLUTE, row->n, OCI_DEFAULT); + } + else { + sql->status = OCIStmtFetch2(res->statement->stmt, res->handle->err, 1, + OCI_FETCH_NEXT, 0, OCI_DEFAULT); + } + switch (sql->status) { + case OCI_SUCCESS: + (*rowp)->res = res; + return 0; + case OCI_NO_DATA: + return -1; + case OCI_ERROR: +#ifdef DEBUG + OCIErrorGet(sql->err, 1, NULL, &errorcode, + sql->buf, sizeof(sql->buf), OCI_HTYPE_ERROR); + printf("Execute error %d: %s\n", sql->status, sql->buf); +#endif + /* fallthrough */ + default: + return 1; + } + return 0; +} + +static const char *dbd_oracle_error(apr_dbd_t *sql, int n) +{ + /* This is ugly. Needs us to pass in a buffer of unknown size. + * Either we put it on the handle, or we have to keep allocing/copying + */ + sb4 errorcode; + + switch (sql->status) { + case OCI_SUCCESS: + return "OCI_SUCCESS"; + case OCI_SUCCESS_WITH_INFO: + return "OCI_SUCCESS_WITH_INFO"; + case OCI_NEED_DATA: + return "OCI_NEED_DATA"; + case OCI_NO_DATA: + return "OCI_NO_DATA"; + case OCI_INVALID_HANDLE: + return "OCI_INVALID_HANDLE"; + case OCI_STILL_EXECUTING: + return "OCI_STILL_EXECUTING"; + case OCI_CONTINUE: + return "OCI_CONTINUE"; + } + + switch (OCIErrorGet(sql->err, 1, NULL, &errorcode, + (text*) sql->buf, sizeof(sql->buf), OCI_HTYPE_ERROR)) { + case OCI_SUCCESS: + return sql->buf; + default: + return "internal error: OCIErrorGet failed"; + } +} + +static apr_status_t freeStatement(void *statement) +{ + int rv = APR_SUCCESS; + OCIStmt *stmt = ((apr_dbd_prepared_t*)statement)->stmt; + +#ifdef PREPARE2 + OCIError *err; + + if (OCIHandleAlloc(dbd_oracle_env, (dvoid**)&err, OCI_HTYPE_ERROR, + 0, NULL) != OCI_SUCCESS) { + return APR_EGENERAL; + } + if (OCIStmtRelease(stmt, err, NULL, 0, OCI_DEFAULT) != OCI_SUCCESS) { + rv = APR_EGENERAL; + } + if (OCIHandleFree(err, OCI_HTYPE_ERROR) != OCI_SUCCESS) { + rv = APR_EGENERAL; + } +#else + if (OCIHandleFree(stmt, OCI_HTYPE_STMT) != OCI_SUCCESS) { + rv = APR_EGENERAL; + } +#endif + + return rv; +} + +static int dbd_oracle_select(apr_pool_t *pool, apr_dbd_t *sql, + apr_dbd_results_t **results, + const char *query, int seek) +{ + int ret = 0; + apr_dbd_prepared_t *statement = NULL; + + ret = dbd_oracle_prepare(pool, sql, query, NULL, 0, 0, NULL, &statement); + if (ret != 0) { + return ret; + } + + ret = dbd_oracle_pselect(pool, sql, results, statement, seek, NULL); + if (ret != 0) { + return ret; + } + + return ret; +} + +static int dbd_oracle_query(apr_dbd_t *sql, int *nrows, const char *query) +{ + int ret = 0; + apr_pool_t *pool; + apr_dbd_prepared_t *statement = NULL; + + if (sql->trans && sql->trans->status == TRANS_ERROR) { + return 1; + } + + /* make our own pool so that APR allocations don't linger and so that + * both Stmt and LOB handles are cleaned up (LOB handles may be + * allocated when preparing APR_DBD_TYPE_CLOB/BLOBs) + */ + apr_pool_create(&pool, sql->pool); + + ret = dbd_oracle_prepare(pool, sql, query, NULL, 0, 0, NULL, &statement); + if (ret == 0) { + ret = dbd_oracle_pquery(pool, sql, nrows, statement, NULL); + if (ret == 0) { + sql->status = OCIAttrGet(statement->stmt, OCI_HTYPE_STMT, + nrows, 0, OCI_ATTR_ROW_COUNT, + sql->err); + } + } + + apr_pool_destroy(pool); + + return ret; +} + +static const char *dbd_oracle_escape(apr_pool_t *pool, const char *arg, + apr_dbd_t *sql) +{ + return arg; /* OCI has no concept of string escape */ +} + +static int dbd_oracle_prepare(apr_pool_t *pool, apr_dbd_t *sql, + const char *query, const char *label, + int nargs, int nvals, apr_dbd_type_e *types, + apr_dbd_prepared_t **statement) +{ + int ret = 0; + int i; + apr_dbd_prepared_t *stmt ; + + if (*statement == NULL) { + *statement = apr_pcalloc(pool, sizeof(apr_dbd_prepared_t)); + } + stmt = *statement; + stmt->handle = sql; + stmt->pool = pool; + stmt->nargs = nargs; + stmt->nvals = nvals; + + /* populate our own args, if any */ + if (nargs > 0) { + stmt->args = apr_pcalloc(pool, nargs*sizeof(bind_arg)); + for (i = 0; i < nargs; i++) { + stmt->args[i].type = types[i]; + } + } + + sql->status = OCIHandleAlloc(dbd_oracle_env, (dvoid**) &stmt->stmt, + OCI_HTYPE_STMT, 0, NULL); + if (sql->status != OCI_SUCCESS) { + return 1; + } + + sql->status = OCIStmtPrepare(stmt->stmt, sql->err, (text*) query, + strlen(query), OCI_NTV_SYNTAX, OCI_DEFAULT); + if (sql->status != OCI_SUCCESS) { + OCIHandleFree(stmt->stmt, OCI_HTYPE_STMT); + return 1; + } + + apr_pool_cleanup_register(pool, stmt, freeStatement, + apr_pool_cleanup_null); + + /* Perl gets statement type here */ + sql->status = OCIAttrGet(stmt->stmt, OCI_HTYPE_STMT, &stmt->type, 0, + OCI_ATTR_STMT_TYPE, sql->err); + if (sql->status != OCI_SUCCESS) { + return 1; + } + +/* Perl sets PREFETCH_MEMORY here, but the docs say there's a working default */ +#if 0 + sql->status = OCIAttrSet(stmt->stmt, OCI_HTYPE_STMT, &prefetch_size, + sizeof(prefetch_size), OCI_ATTR_PREFETCH_MEMORY, + sql->err); + if (sql->status != OCI_SUCCESS) { + return 1; + } +#endif + + if (stmt->type == OCI_STMT_SELECT) { + ret = outputParams(sql, stmt); + } + return ret; +} + +static void dbd_oracle_bind(apr_dbd_prepared_t *statement, const char **values) +{ + OCIStmt *stmt = statement->stmt; + apr_dbd_t *sql = statement->handle; + int i, j; + sb2 null_ind = -1; + + for (i = 0, j = 0; i < statement->nargs; i++, j++) { + if (values[j] == NULL) { + sql->status = OCIBindByPos(stmt, &statement->args[i].bind, + sql->err, i + 1, + NULL, 0, SQLT_STR, + &null_ind, NULL, + (ub2) 0, (ub4) 0, + (ub4 *) 0, OCI_DEFAULT); + } + else { + switch (statement->args[i].type) { + case APR_DBD_TYPE_BLOB: + { + char *data = (char *)values[j]; + int size = atoi((char*)values[++j]); + + /* skip table and column for now */ + j += 2; + + sql->status = OCIBindByPos(stmt, &statement->args[i].bind, + sql->err, i + 1, + data, size, SQLT_LBI, + &statement->args[i].ind, + NULL, + (ub2) 0, (ub4) 0, + (ub4 *) 0, OCI_DEFAULT); + } + break; + case APR_DBD_TYPE_CLOB: + { + char *data = (char *)values[j]; + int size = atoi((char*)values[++j]); + + /* skip table and column for now */ + j += 2; + + sql->status = OCIBindByPos(stmt, &statement->args[i].bind, + sql->err, i + 1, + data, size, SQLT_LNG, + &statement->args[i].ind, + NULL, + (ub2) 0, (ub4) 0, + (ub4 *) 0, OCI_DEFAULT); + } + break; + default: + sql->status = OCIBindByPos(stmt, &statement->args[i].bind, + sql->err, i + 1, + (dvoid*) values[j], + strlen(values[j]) + 1, + SQLT_STR, + &statement->args[i].ind, + NULL, + (ub2) 0, (ub4) 0, + (ub4 *) 0, OCI_DEFAULT); + break; + } + } + + if (sql->status != OCI_SUCCESS) { + return; + } + } + + return; +} + +static int outputParams(apr_dbd_t *sql, apr_dbd_prepared_t *stmt) +{ + OCIParam *parms; + int i; + ub2 paramtype[DBD_ORACLE_MAX_COLUMNS]; + ub2 paramsize[DBD_ORACLE_MAX_COLUMNS]; + char *paramname[DBD_ORACLE_MAX_COLUMNS]; + ub4 paramnamelen[DBD_ORACLE_MAX_COLUMNS]; + int_errorcode; + + /* Perl uses 0 where we used 1 */ + sql->status = OCIStmtExecute(sql->svc, stmt->stmt, sql->err, 0, 0, + NULL, NULL, OCI_DESCRIBE_ONLY); + switch (sql->status) { + case OCI_SUCCESS: + case OCI_SUCCESS_WITH_INFO: + break; + case OCI_ERROR: +#ifdef DEBUG + OCIErrorGet(sql->err, 1, NULL, &errorcode, + sql->buf, sizeof(sql->buf), OCI_HTYPE_ERROR); + printf("Describing prepared statement: %s\n", sql->buf); +#endif + default: + return 1; + } + while (sql->status == OCI_SUCCESS) { + sql->status = OCIParamGet(stmt->stmt, OCI_HTYPE_STMT, + sql->err, (dvoid**)&parms, stmt->nout+1); + switch (sql->status) { + case OCI_SUCCESS: + sql->status = OCIAttrGet(parms, OCI_DTYPE_PARAM, + ¶mtype[stmt->nout], + 0, OCI_ATTR_DATA_TYPE, sql->err); + sql->status = OCIAttrGet(parms, OCI_DTYPE_PARAM, + ¶msize[stmt->nout], + 0, OCI_ATTR_DATA_SIZE, sql->err); + sql->status = OCIAttrGet(parms, OCI_DTYPE_PARAM, + ¶mname[stmt->nout], + ¶mnamelen[stmt->nout], + OCI_ATTR_NAME, sql->err); + ++stmt->nout; + } + } + switch (sql->status) { + case OCI_SUCCESS: + break; + case OCI_ERROR: + break; /* this is what we expect at end-of-loop */ + default: + return 1; + } + + /* OK, the above works. We have the params; now OCIDefine them */ + stmt->out = apr_palloc(stmt->pool, stmt->nout*sizeof(define_arg)); + for (i=0; i<stmt->nout; ++i) { + stmt->out[i].type = paramtype[i]; + stmt->out[i].len = stmt->out[i].sz = paramsize[i]; + stmt->out[i].name = apr_pstrmemdup(stmt->pool, + paramname[i], paramnamelen[i]); + switch (stmt->out[i].type) { + default: + switch (stmt->out[i].type) { + case SQLT_NUM: /* 2: numeric, Perl worst case=130+38+3 */ + stmt->out[i].sz = 171; + break; + case SQLT_CHR: /* 1: char */ + case SQLT_AFC: /* 96: ANSI fixed char */ + stmt->out[i].sz *= 4; /* ugh, wasteful UCS-4 handling */ + break; + case SQLT_DAT: /* 12: date, depends on NLS date format */ + stmt->out[i].sz = 75; + break; + case SQLT_BIN: /* 23: raw binary, perhaps UTF-16? */ + stmt->out[i].sz *= 2; + break; + case SQLT_RID: /* 11: rowid */ + case SQLT_RDD: /* 104: rowid descriptor */ + stmt->out[i].sz = 20; + break; + case SQLT_TIMESTAMP: /* 187: timestamp */ + case SQLT_TIMESTAMP_TZ: /* 188: timestamp with time zone */ + case SQLT_INTERVAL_YM: /* 189: interval year-to-month */ + case SQLT_INTERVAL_DS: /* 190: interval day-to-second */ + case SQLT_TIMESTAMP_LTZ: /* 232: timestamp with local time zone */ + stmt->out[i].sz = 75; + break; + default: +#ifdef DEBUG + printf("Unsupported data type: %d\n", stmt->out[i].type); +#endif + break; + } + ++stmt->out[i].sz; + stmt->out[i].buf.raw = apr_palloc(stmt->pool, stmt->out[i].sz); + sql->status = OCIDefineByPos(stmt->stmt, &stmt->out[i].defn, + sql->err, i+1, + stmt->out[i].buf.sval, + stmt->out[i].sz, SQLT_STR, + &stmt->out[i].ind, &stmt->out[i].len, + 0, OCI_DEFAULT); + break; + case SQLT_LNG: /* 8: long */ + stmt->out[i].sz = sql->long_size * 4 + 4; /* ugh, UCS-4 handling */ + stmt->out[i].buf.raw = apr_palloc(stmt->pool, stmt->out[i].sz); + sql->status = OCIDefineByPos(stmt->stmt, &stmt->out[i].defn, + sql->err, i+1, + stmt->out[i].buf.raw, + stmt->out[i].sz, SQLT_LVC, + &stmt->out[i].ind, NULL, + 0, OCI_DEFAULT); + break; + case SQLT_LBI: /* 24: long binary, perhaps UTF-16? */ + stmt->out[i].sz = sql->long_size * 2 + 4; /* room for int prefix */ + stmt->out[i].buf.raw = apr_palloc(stmt->pool, stmt->out[i].sz); + sql->status = OCIDefineByPos(stmt->stmt, &stmt->out[i].defn, + sql->err, i+1, + stmt->out[i].buf.raw, + stmt->out[i].sz, SQLT_LVB, + &stmt->out[i].ind, NULL, + 0, OCI_DEFAULT); + break; + case SQLT_BLOB: /* 113 */ + case SQLT_CLOB: /* 112 */ +/*http://download-west.oracle.com/docs/cd/B10501_01/appdev.920/a96584/oci05bnd.htm#434937*/ + sql->status = OCIDescriptorAlloc(dbd_oracle_env, + (dvoid**)&stmt->out[i].buf.lobval, + OCI_DTYPE_LOB, 0, NULL); + apr_pool_cleanup_register(stmt->pool, stmt->out[i].buf.lobval, + dbd_free_lobdesc, + apr_pool_cleanup_null); + sql->status = OCIDefineByPos(stmt->stmt, &stmt->out[i].defn, + sql->err, i+1, + (dvoid*) &stmt->out[i].buf.lobval, + -1, stmt->out[i].type, + &stmt->out[i].ind, &stmt->out[i].len, + 0, OCI_DEFAULT); + break; + } + switch (sql->status) { + case OCI_SUCCESS: + break; + default: + return 1; + } + } + return 0; +} + +static int dbd_oracle_pquery(apr_pool_t *pool, apr_dbd_t *sql, + int *nrows, apr_dbd_prepared_t *statement, + const char **values) +{ + OCISnapshot *oldsnapshot = NULL; + OCISnapshot *newsnapshot = NULL; + apr_dbd_transaction_t* trans = sql->trans; + int exec_mode; + int_errorcode; + + if (trans) { + switch (trans->status) { + case TRANS_ERROR: + return -1; + case TRANS_NONE: + trans = NULL; + break; + case TRANS_1: + oldsnapshot = trans->snapshot1; + newsnapshot = trans->snapshot2; + trans->status = TRANS_2; + break; + case TRANS_2: + oldsnapshot = trans->snapshot2; + newsnapshot = trans->snapshot1; + trans->status = TRANS_1; + break; + } + exec_mode = OCI_DEFAULT; + } + else { + exec_mode = OCI_COMMIT_ON_SUCCESS; + } + + dbd_oracle_bind(statement, values); + + sql->status = OCIStmtExecute(sql->svc, statement->stmt, sql->err, 1, 0, + oldsnapshot, newsnapshot, exec_mode); + switch (sql->status) { + case OCI_SUCCESS: + break; + case OCI_ERROR: +#ifdef DEBUG + OCIErrorGet(sql->err, 1, NULL, &errorcode, + sql->buf, sizeof(sql->buf), OCI_HTYPE_ERROR); + printf("Execute error %d: %s\n", sql->status, sql->buf); +#endif + /* fallthrough */ + default: + if (TXN_NOTICE_ERRORS(trans)) { + trans->status = TRANS_ERROR; + } + return 1; + } + + sql->status = OCIAttrGet(statement->stmt, OCI_HTYPE_STMT, nrows, 0, + OCI_ATTR_ROW_COUNT, sql->err); + return 0; +} + +static int dbd_oracle_pvquery(apr_pool_t *pool, apr_dbd_t *sql, + int *nrows, apr_dbd_prepared_t *statement, + va_list args) +{ + const char **values; + int i; + + if (sql->trans && sql->trans->status == TRANS_ERROR) { + return -1; + } + + values = apr_palloc(pool, sizeof(*values) * statement->nvals); + + for (i = 0; i < statement->nvals; i++) { + values[i] = va_arg(args, const char*); + } + + return dbd_oracle_pquery(pool, sql, nrows, statement, values); +} + +static int dbd_oracle_pselect(apr_pool_t *pool, apr_dbd_t *sql, + apr_dbd_results_t **results, + apr_dbd_prepared_t *statement, + int seek, const char **values) +{ + int exec_mode = seek ? OCI_STMT_SCROLLABLE_READONLY : OCI_DEFAULT; + OCISnapshot *oldsnapshot = NULL; + OCISnapshot *newsnapshot = NULL; + apr_dbd_transaction_t* trans = sql->trans; + int_errorcode; + + if (trans) { + switch (trans->status) { + case TRANS_ERROR: + return 1; + case TRANS_NONE: + trans = NULL; + break; + case TRANS_1: + oldsnapshot = trans->snapshot1; + newsnapshot = trans->snapshot2; + trans->status = TRANS_2; + break; + case TRANS_2: + oldsnapshot = trans->snapshot2; + newsnapshot = trans->snapshot1; + trans->status = TRANS_1; + break; + } + } + + dbd_oracle_bind(statement, values); + + sql->status = OCIStmtExecute(sql->svc, statement->stmt, sql->err, 0, 0, + oldsnapshot, newsnapshot, exec_mode); + switch (sql->status) { + case OCI_SUCCESS: + break; + case OCI_ERROR: +#ifdef DEBUG + OCIErrorGet(sql->err, 1, NULL, &errorcode, + sql->buf, sizeof(sql->buf), OCI_HTYPE_ERROR); + printf("Executing prepared statement: %s\n", sql->buf); +#endif + /* fallthrough */ + default: + if (TXN_NOTICE_ERRORS(trans)) { + trans->status = TRANS_ERROR; + } + return 1; + } + + if (!*results) { + *results = apr_palloc(pool, sizeof(apr_dbd_results_t)); + } + (*results)->handle = sql; + (*results)->statement = statement; + (*results)->seek = seek; + (*results)->rownum = seek ? 0 : -1; + (*results)->pool = pool; + + return 0; +} + +static int dbd_oracle_pvselect(apr_pool_t *pool, apr_dbd_t *sql, + apr_dbd_results_t **results, + apr_dbd_prepared_t *statement, + int seek, va_list args) +{ + const char **values; + int i; + + if (sql->trans && sql->trans->status == TRANS_ERROR) { + return -1; + } + + values = apr_palloc(pool, sizeof(*values) * statement->nvals); + + for (i = 0; i < statement->nvals; i++) { + values[i] = va_arg(args, const char*); + } + + return dbd_oracle_pselect(pool, sql, results, statement, seek, values); +} + +static void dbd_oracle_bbind(apr_dbd_prepared_t * statement, + const void **values) +{ + OCIStmt *stmt = statement->stmt; + apr_dbd_t *sql = statement->handle; + int i, j; + sb2 null_ind = -1; + apr_dbd_type_e type; + + for (i = 0, j = 0; i < statement->nargs; i++, j++) { + type = (values[j] == NULL ? APR_DBD_TYPE_NULL + : statement->args[i].type); + + switch (type) { + case APR_DBD_TYPE_TINY: + statement->args[i].value.ival = *(char*)values[j]; + sql->status = OCIBindByPos(stmt, &statement->args[i].bind, + sql->err, i + 1, + &statement->args[i].value.ival, + sizeof(statement->args[i].value.ival), + SQLT_INT, + &statement->args[i].ind, NULL, + (ub2) 0, (ub4) 0, + (ub4 *) 0, OCI_DEFAULT); + break; + case APR_DBD_TYPE_UTINY: + statement->args[i].value.uval = *(unsigned char*)values[j]; + sql->status = OCIBindByPos(stmt, &statement->args[i].bind, + sql->err, i + 1, + &statement->args[i].value.uval, + sizeof(statement->args[i].value.uval), + SQLT_UIN, + &statement->args[i].ind, NULL, + (ub2) 0, (ub4) 0, + (ub4 *) 0, OCI_DEFAULT); + break; + case APR_DBD_TYPE_SHORT: + statement->args[i].value.ival = *(short*)values[j]; + sql->status = OCIBindByPos(stmt, &statement->args[i].bind, + sql->err, i + 1, + &statement->args[i].value.ival, + sizeof(statement->args[i].value.ival), + SQLT_INT, + &statement->args[i].ind, NULL, + (ub2) 0, (ub4) 0, + (ub4 *) 0, OCI_DEFAULT); + break; + case APR_DBD_TYPE_USHORT: + statement->args[i].value.uval = *(unsigned short*)values[j]; + sql->status = OCIBindByPos(stmt, &statement->args[i].bind, + sql->err, i + 1, + &statement->args[i].value.uval, + sizeof(statement->args[i].value.uval), + SQLT_UIN, + &statement->args[i].ind, NULL, + (ub2) 0, (ub4) 0, + (ub4 *) 0, OCI_DEFAULT); + break; + case APR_DBD_TYPE_INT: + statement->args[i].value.ival = *(int*)values[j]; + sql->status = OCIBindByPos(stmt, &statement->args[i].bind, + sql->err, i + 1, + &statement->args[i].value.ival, + sizeof(statement->args[i].value.ival), + SQLT_INT, + &statement->args[i].ind, NULL, + (ub2) 0, (ub4) 0, + (ub4 *) 0, OCI_DEFAULT); + break; + case APR_DBD_TYPE_UINT: + statement->args[i].value.uval = *(unsigned int*)values[j]; + sql->status = OCIBindByPos(stmt, &statement->args[i].bind, + sql->err, i + 1, + &statement->args[i].value.uval, + sizeof(statement->args[i].value.uval), + SQLT_UIN, + &statement->args[i].ind, NULL, + (ub2) 0, (ub4) 0, + (ub4 *) 0, OCI_DEFAULT); + break; + case APR_DBD_TYPE_LONG: + statement->args[i].value.sval = + apr_psprintf(statement->pool, "%ld", *(long*)values[j]); + sql->status = OCIBindByPos(stmt, &statement->args[i].bind, + sql->err, i + 1, + statement->args[i].value.sval, + strlen(statement->args[i].value.sval)+1, + SQLT_STR, + &statement->args[i].ind, NULL, + (ub2) 0, (ub4) 0, + (ub4 *) 0, OCI_DEFAULT); + break; + case APR_DBD_TYPE_ULONG: + statement->args[i].value.sval = + apr_psprintf(statement->pool, "%lu", + *(unsigned long*)values[j]); + sql->status = OCIBindByPos(stmt, &statement->args[i].bind, + sql->err, i + 1, + statement->args[i].value.sval, + strlen(statement->args[i].value.sval)+1, + SQLT_STR, + &statement->args[i].ind, NULL, + (ub2) 0, (ub4) 0, + (ub4 *) 0, OCI_DEFAULT); + break; + case APR_DBD_TYPE_LONGLONG: + statement->args[i].value.sval = + apr_psprintf(statement->pool, "%" APR_INT64_T_FMT, + *(apr_int64_t*)values[j]); + sql->status = OCIBindByPos(stmt, &statement->args[i].bind, + sql->err, i + 1, + statement->args[i].value.sval, + strlen(statement->args[i].value.sval)+1, + SQLT_STR, + &statement->args[i].ind, NULL, + (ub2) 0, (ub4) 0, + (ub4 *) 0, OCI_DEFAULT); + break; + case APR_DBD_TYPE_ULONGLONG: + statement->args[i].value.sval = + apr_psprintf(statement->pool, "%" APR_UINT64_T_FMT, + *(apr_uint64_t*)values[j]); + sql->status = OCIBindByPos(stmt, &statement->args[i].bind, + sql->err, i + 1, + statement->args[i].value.sval, + strlen(statement->args[i].value.sval)+1, + SQLT_UIN, + &statement->args[i].ind, NULL, + (ub2) 0, (ub4) 0, + (ub4 *) 0, OCI_DEFAULT); + break; + case APR_DBD_TYPE_FLOAT: + statement->args[i].value.fval = *(float*)values[j]; + sql->status = OCIBindByPos(stmt, &statement->args[i].bind, + sql->err, i + 1, + &statement->args[i].value.fval, + sizeof(statement->args[i].value.fval), + SQLT_FLT, + &statement->args[i].ind, NULL, + (ub2) 0, (ub4) 0, + (ub4 *) 0, OCI_DEFAULT); + break; + case APR_DBD_TYPE_DOUBLE: + statement->args[i].value.fval = *(double*)values[j]; + sql->status = OCIBindByPos(stmt, &statement->args[i].bind, + sql->err, i + 1, + &statement->args[i].value.fval, + sizeof(statement->args[i].value.fval), + SQLT_FLT, + &statement->args[i].ind, NULL, + (ub2) 0, (ub4) 0, + (ub4 *) 0, OCI_DEFAULT); + break; + case APR_DBD_TYPE_STRING: + case APR_DBD_TYPE_TEXT: + case APR_DBD_TYPE_TIME: + case APR_DBD_TYPE_DATE: + case APR_DBD_TYPE_DATETIME: + case APR_DBD_TYPE_TIMESTAMP: + case APR_DBD_TYPE_ZTIMESTAMP: + sql->status = OCIBindByPos(stmt, &statement->args[i].bind, + sql->err, i + 1, + (dvoid*) values[j], + strlen(values[j]) + 1, + SQLT_STR, + &statement->args[i].ind, NULL, + (ub2) 0, (ub4) 0, + (ub4 *) 0, OCI_DEFAULT); + break; + case APR_DBD_TYPE_BLOB: + { + char *data = (char *)values[j]; + apr_size_t size = *(apr_size_t*)values[++j]; + + /* skip table and column for now */ + j += 2; + + sql->status = OCIBindByPos(stmt, &statement->args[i].bind, + sql->err, i + 1, + data, size, SQLT_LBI, + &statement->args[i].ind, + NULL, + (ub2) 0, (ub4) 0, + (ub4 *) 0, OCI_DEFAULT); + } + break; + case APR_DBD_TYPE_CLOB: + { + char *data = (char *)values[j]; + apr_size_t size = *(apr_size_t*)values[++j]; + + /* skip table and column for now */ + j += 2; + + sql->status = OCIBindByPos(stmt, &statement->args[i].bind, + sql->err, i + 1, + data, size, SQLT_LNG, + &statement->args[i].ind, + NULL, + (ub2) 0, (ub4) 0, + (ub4 *) 0, OCI_DEFAULT); + } + break; + case APR_DBD_TYPE_NULL: + default: + sql->status = OCIBindByPos(stmt, &statement->args[i].bind, + sql->err, i + 1, + NULL, 0, SQLT_STR, + &null_ind, NULL, + (ub2) 0, (ub4) 0, + (ub4 *) 0, OCI_DEFAULT); + break; + } + + if (sql->status != OCI_SUCCESS) { + return; + } + } + + return; +} + +static int dbd_oracle_pbquery(apr_pool_t * pool, apr_dbd_t * sql, + int *nrows, apr_dbd_prepared_t * statement, + const void **values) +{ + OCISnapshot *oldsnapshot = NULL; + OCISnapshot *newsnapshot = NULL; + apr_dbd_transaction_t* trans = sql->trans; + int exec_mode; + int_errorcode; + + if (trans) { + switch (trans->status) { + case TRANS_ERROR: + return -1; + case TRANS_NONE: + trans = NULL; + break; + case TRANS_1: + oldsnapshot = trans->snapshot1; + newsnapshot = trans->snapshot2; + trans->status = TRANS_2; + break; + case TRANS_2: + oldsnapshot = trans->snapshot2; + newsnapshot = trans->snapshot1; + trans->status = TRANS_1; + break; + } + exec_mode = OCI_DEFAULT; + } + else { + exec_mode = OCI_COMMIT_ON_SUCCESS; + } + + dbd_oracle_bbind(statement, values); + + sql->status = OCIStmtExecute(sql->svc, statement->stmt, sql->err, 1, 0, + oldsnapshot, newsnapshot, exec_mode); + switch (sql->status) { + case OCI_SUCCESS: + break; + case OCI_ERROR: +#ifdef DEBUG + OCIErrorGet(sql->err, 1, NULL, &errorcode, + sql->buf, sizeof(sql->buf), OCI_HTYPE_ERROR); + printf("Execute error %d: %s\n", sql->status, sql->buf); +#endif + /* fallthrough */ + default: + if (TXN_NOTICE_ERRORS(trans)) { + trans->status = TRANS_ERROR; + } + return 1; + } + + sql->status = OCIAttrGet(statement->stmt, OCI_HTYPE_STMT, nrows, 0, + OCI_ATTR_ROW_COUNT, sql->err); + return 0; +} + +static int dbd_oracle_pvbquery(apr_pool_t * pool, apr_dbd_t * sql, + int *nrows, apr_dbd_prepared_t * statement, + va_list args) +{ + const void **values; + int i; + + if (sql->trans && sql->trans->status == TRANS_ERROR) { + return -1; + } + + values = apr_palloc(pool, sizeof(*values) * statement->nvals); + + for (i = 0; i < statement->nvals; i++) { + values[i] = va_arg(args, const void*); + } + + return dbd_oracle_pbquery(pool, sql, nrows, statement, values); +} + +static int dbd_oracle_pbselect(apr_pool_t * pool, apr_dbd_t * sql, + apr_dbd_results_t ** results, + apr_dbd_prepared_t * statement, + int seek, const void **values) +{ + int exec_mode = seek ? OCI_STMT_SCROLLABLE_READONLY : OCI_DEFAULT; + OCISnapshot *oldsnapshot = NULL; + OCISnapshot *newsnapshot = NULL; + apr_dbd_transaction_t* trans = sql->trans; + int_errorcode; + + if (trans) { + switch (trans->status) { + case TRANS_ERROR: + return 1; + case TRANS_NONE: + trans = NULL; + break; + case TRANS_1: + oldsnapshot = trans->snapshot1; + newsnapshot = trans->snapshot2; + trans->status = TRANS_2; + break; + case TRANS_2: + oldsnapshot = trans->snapshot2; + newsnapshot = trans->snapshot1; + trans->status = TRANS_1; + break; + } + } + + dbd_oracle_bbind(statement, values); + + sql->status = OCIStmtExecute(sql->svc, statement->stmt, sql->err, 0, 0, + oldsnapshot, newsnapshot, exec_mode); + switch (sql->status) { + case OCI_SUCCESS: + break; + case OCI_ERROR: +#ifdef DEBUG + OCIErrorGet(sql->err, 1, NULL, &errorcode, + sql->buf, sizeof(sql->buf), OCI_HTYPE_ERROR); + printf("Executing prepared statement: %s\n", sql->buf); +#endif + /* fallthrough */ + default: + if (TXN_NOTICE_ERRORS(trans)) { + trans->status = TRANS_ERROR; + } + return 1; + } + + if (!*results) { + *results = apr_palloc(pool, sizeof(apr_dbd_results_t)); + } + (*results)->handle = sql; + (*results)->statement = statement; + (*results)->seek = seek; + (*results)->rownum = seek ? 0 : -1; + (*results)->pool = pool; + + return 0; +} + +static int dbd_oracle_pvbselect(apr_pool_t * pool, apr_dbd_t * sql, + apr_dbd_results_t ** results, + apr_dbd_prepared_t * statement, int seek, + va_list args) +{ + const void **values; + int i; + + if (sql->trans && sql->trans->status == TRANS_ERROR) { + return -1; + } + + values = apr_palloc(pool, sizeof(*values) * statement->nvals); + + for (i = 0; i < statement->nvals; i++) { + values[i] = va_arg(args, const void*); + } + + return dbd_oracle_pbselect(pool, sql, results, statement, seek, values); +} + +static int dbd_oracle_start_transaction(apr_pool_t *pool, apr_dbd_t *sql, + apr_dbd_transaction_t **trans) +{ + int ret = 0; + int_errorcode; + if (*trans) { + dbd_oracle_end_transaction(*trans); + } + else { + *trans = apr_pcalloc(pool, sizeof(apr_dbd_transaction_t)); + OCIHandleAlloc(dbd_oracle_env, (dvoid**)&(*trans)->trans, + OCI_HTYPE_TRANS, 0, 0); + OCIAttrSet(sql->svc, OCI_HTYPE_SVCCTX, (*trans)->trans, 0, + OCI_ATTR_TRANS, sql->err); + } + + + sql->status = OCITransStart(sql->svc, sql->err, TRANS_TIMEOUT, + OCI_TRANS_NEW); + switch (sql->status) { + case OCI_ERROR: +#ifdef DEBUG + OCIErrorGet(sql->err, 1, NULL, &errorcode, sql->buf, + sizeof(sql->buf), OCI_HTYPE_ERROR); + printf("Transaction: %s\n", sql->buf); +#endif + ret = 1; + break; + case OCI_SUCCESS: + (*trans)->handle = sql; + (*trans)->status = TRANS_1; + sql->trans = *trans; + switch (OCIDescriptorAlloc(dbd_oracle_env, + (dvoid**)&(*trans)->snapshot1, + OCI_DTYPE_SNAP, 0, NULL)) { + case OCI_SUCCESS: + apr_pool_cleanup_register(pool, (*trans)->snapshot1, + dbd_free_snapshot, apr_pool_cleanup_null); + break; + case OCI_INVALID_HANDLE: + ret = 1; + break; + } + switch (OCIDescriptorAlloc(dbd_oracle_env, + (dvoid**)&(*trans)->snapshot2, + OCI_DTYPE_SNAP, 0, NULL)) { + case OCI_SUCCESS: + apr_pool_cleanup_register(pool, (*trans)->snapshot2, + dbd_free_snapshot, apr_pool_cleanup_null); + break; + case OCI_INVALID_HANDLE: + ret = 1; + break; + } + break; + default: + ret = 1; + break; + } + return ret; +} + +static int dbd_oracle_end_transaction(apr_dbd_transaction_t *trans) +{ + int ret = 1; /* no transaction is an error cond */ + sword status; + if (trans) { + apr_dbd_t *handle = trans->handle; + switch (trans->status) { + case TRANS_NONE: /* No trans is an error here */ + status = OCI_ERROR; + break; + case TRANS_ERROR: + status = OCITransRollback(handle->svc, handle->err, OCI_DEFAULT); + break; + default: + /* rollback on explicit rollback request */ + if (TXN_DO_ROLLBACK(trans)) { + status = OCITransRollback(handle->svc, handle->err, OCI_DEFAULT); + } else { + status = OCITransCommit(handle->svc, handle->err, OCI_DEFAULT); + } + break; + } + + handle->trans = NULL; + + switch (status) { + case OCI_SUCCESS: + ret = 0; + break; + default: + ret = 3; + break; + } + } + return ret; +} + +static int dbd_oracle_transaction_mode_get(apr_dbd_transaction_t *trans) +{ + if (!trans) + return APR_DBD_TRANSACTION_COMMIT; + + return trans->mode; +} + +static int dbd_oracle_transaction_mode_set(apr_dbd_transaction_t *trans, + int mode) +{ + if (!trans) + return APR_DBD_TRANSACTION_COMMIT; + + return trans->mode = (mode & TXN_MODE_BITS); +} + +/* This doesn't work for BLOB because of NULLs, but it can fake it + * if the BLOB is really a string + */ +static const char *dbd_oracle_get_entry(const apr_dbd_row_t *row, int n) +{ + ub4 len = 0; + ub1 csform = 0; + ub2 csid = 0; + apr_size_t buflen = 0; + char *buf = NULL; + define_arg *val = &row->res->statement->out[n]; + apr_dbd_t *sql = row->res->handle; + int_errorcode; + + if ((n < 0) || (n >= row->res->statement->nout) || (val->ind == -1)) { + return NULL; + } + + switch (val->type) { + case SQLT_BLOB: + case SQLT_CLOB: + sql->status = OCILobGetLength(sql->svc, sql->err, val->buf.lobval, + &len); + switch (sql->status) { + case OCI_SUCCESS: + case OCI_SUCCESS_WITH_INFO: + if (len == 0) { + buf = ""; + } + break; + case OCI_ERROR: +#ifdef DEBUG + OCIErrorGet(sql->err, 1, NULL, &errorcode, + sql->buf, sizeof(sql->buf), OCI_HTYPE_ERROR); + printf("Finding LOB length: %s\n", sql->buf); + break; +#endif + default: + break; + } + + if (len == 0) { + break; + } + + if (val->type == APR_DBD_TYPE_CLOB) { +#if 1 + /* Is this necessary, or can it be defaulted? */ + sql->status = OCILobCharSetForm(dbd_oracle_env, sql->err, + val->buf.lobval, &csform); + if (sql->status == OCI_SUCCESS) { + sql->status = OCILobCharSetId(dbd_oracle_env, sql->err, + val->buf.lobval, &csid); + } + switch (sql->status) { + case OCI_SUCCESS: + case OCI_SUCCESS_WITH_INFO: + buflen = (len+1) * 4; /* ugh, wasteful UCS-4 handling */ + /* zeroise all - where the string ends depends on charset */ + buf = apr_pcalloc(row->pool, buflen); + break; +#ifdef DEBUG + case OCI_ERROR: + OCIErrorGet(sql->err, 1, NULL, &errorcode, + sql->buf, sizeof(sql->buf), OCI_HTYPE_ERROR); + printf("Reading LOB character set: %s\n", sql->buf); + break; /*** XXX?? ***/ +#endif + default: + break; /*** XXX?? ***/ + } +#else /* ignore charset */ + buflen = (len+1) * 4; /* ugh, wasteful UCS-4 handling */ + /* zeroise all - where the string ends depends on charset */ + buf = apr_pcalloc(row->pool, buflen); +#endif + } else { + /* BUG: this'll only work if the BLOB looks like a string */ + buflen = len; + buf = apr_palloc(row->pool, buflen+1); + buf[buflen] = 0; + } + + if (!buf) { + break; + } + + sql->status = OCILobRead(sql->svc, sql->err, val->buf.lobval, + &len, 1, (dvoid*) buf, buflen, + NULL, NULL, csid, csform); + switch (sql->status) { + case OCI_SUCCESS: + case OCI_SUCCESS_WITH_INFO: + break; +#ifdef DEBUG + case OCI_ERROR: + OCIErrorGet(sql->err, 1, NULL, &errorcode, + sql->buf, sizeof(sql->buf), OCI_HTYPE_ERROR); + printf("Reading LOB: %s\n", sql->buf); + buf = NULL; /*** XXX?? ***/ + break; +#endif + default: + buf = NULL; /*** XXX?? ***/ + break; + } + + break; + case SQLT_LNG: + case SQLT_LBI: + /* raw is struct { ub4 len; char *buf; } */ + len = *(ub4*) val->buf.raw; + buf = apr_pstrndup(row->pool, val->buf.sval + sizeof(ub4), len); + break; + default: + buf = apr_pstrndup(row->pool, val->buf.sval, val->len); + break; + } + return (const char*) buf; +} + +/* XXX Should this use Oracle proper API instead of calling get_entry()? */ +static apr_status_t dbd_oracle_datum_get(const apr_dbd_row_t *row, int n, + apr_dbd_type_e type, void *data) +{ + define_arg *val = &row->res->statement->out[n]; + const char *entry; + + if ((n < 0) || (n >= row->res->statement->nout)) { + return APR_EGENERAL; + } + + if(val->ind == -1) { + return APR_ENOENT; + } + + switch (type) { + case APR_DBD_TYPE_TINY: + entry = dbd_oracle_get_entry(row, n); + if (entry == NULL) { + return APR_ENOENT; + } + *(char*)data = atoi(entry); + break; + case APR_DBD_TYPE_UTINY: + entry = dbd_oracle_get_entry(row, n); + if (entry == NULL) { + return APR_ENOENT; + } + *(unsigned char*)data = atoi(entry); + break; + case APR_DBD_TYPE_SHORT: + entry = dbd_oracle_get_entry(row, n); + if (entry == NULL) { + return APR_ENOENT; + } + *(short*)data = atoi(entry); + break; + case APR_DBD_TYPE_USHORT: + entry = dbd_oracle_get_entry(row, n); + if (entry == NULL) { + return APR_ENOENT; + } + *(unsigned short*)data = atoi(entry); + break; + case APR_DBD_TYPE_INT: + entry = dbd_oracle_get_entry(row, n); + if (entry == NULL) { + return APR_ENOENT; + } + *(int*)data = atoi(entry); + break; + case APR_DBD_TYPE_UINT: + entry = dbd_oracle_get_entry(row, n); + if (entry == NULL) { + return APR_ENOENT; + } + *(unsigned int*)data = atoi(entry); + break; + case APR_DBD_TYPE_LONG: + entry = dbd_oracle_get_entry(row, n); + if (entry == NULL) { + return APR_ENOENT; + } + *(long*)data = atol(entry); + break; + case APR_DBD_TYPE_ULONG: + entry = dbd_oracle_get_entry(row, n); + if (entry == NULL) { + return APR_ENOENT; + } + *(unsigned long*)data = atol(entry); + break; + case APR_DBD_TYPE_LONGLONG: + entry = dbd_oracle_get_entry(row, n); + if (entry == NULL) { + return APR_ENOENT; + } + *(apr_int64_t*)data = apr_atoi64(entry); + break; + case APR_DBD_TYPE_ULONGLONG: + entry = dbd_oracle_get_entry(row, n); + if (entry == NULL) { + return APR_ENOENT; + } + *(apr_uint64_t*)data = apr_atoi64(entry); + break; + case APR_DBD_TYPE_FLOAT: + entry = dbd_oracle_get_entry(row, n); + if (entry == NULL) { + return APR_ENOENT; + } + *(float*)data = (float)atof(entry); + break; + case APR_DBD_TYPE_DOUBLE: + entry = dbd_oracle_get_entry(row, n); + if (entry == NULL) { + return APR_ENOENT; + } + *(double*)data = atof(entry); + break; + case APR_DBD_TYPE_STRING: + case APR_DBD_TYPE_TEXT: + case APR_DBD_TYPE_TIME: + case APR_DBD_TYPE_DATE: + case APR_DBD_TYPE_DATETIME: + case APR_DBD_TYPE_TIMESTAMP: + case APR_DBD_TYPE_ZTIMESTAMP: + entry = dbd_oracle_get_entry(row, n); + if (entry == NULL) { + return APR_ENOENT; + } + *(char**)data = (char*)entry; + break; + case APR_DBD_TYPE_BLOB: + case APR_DBD_TYPE_CLOB: + { + apr_bucket *e; + apr_bucket_brigade *b = (apr_bucket_brigade*)data; + apr_dbd_t *sql = row->res->handle; + ub4 len = 0; + + switch (val->type) { + case SQLT_BLOB: + case SQLT_CLOB: + sql->status = OCILobGetLength(sql->svc, sql->err, + val->buf.lobval, &len); + switch(sql->status) { + case OCI_SUCCESS: + case OCI_SUCCESS_WITH_INFO: + if (len == 0) { + e = apr_bucket_eos_create(b->bucket_alloc); + } + else { + e = apr_bucket_lob_create(row, n, 0, len, + row->pool, b->bucket_alloc); + } + break; + default: + return APR_ENOENT; + } + break; + default: + entry = dbd_oracle_get_entry(row, n); + if (entry == NULL) { + return APR_ENOENT; + } + e = apr_bucket_pool_create(entry, strlen(entry), + row->pool, b->bucket_alloc); + break; + } + APR_BRIGADE_INSERT_TAIL(b, e); + } + break; + case APR_DBD_TYPE_NULL: + *(void**)data = NULL; + break; + default: + return APR_EGENERAL; + } + + return APR_SUCCESS; +} + +static apr_status_t dbd_oracle_close(apr_dbd_t *handle) +{ + /* FIXME: none of the oracle docs/examples say anything about + * closing/releasing handles. Which seems unlikely ... + */ + + /* OK, let's grab from cdemo again. + * cdemo81 does nothing; cdemo82 does OCIHandleFree on the handles + */ + switch (OCISessionEnd(handle->svc, handle->err, handle->auth, + (ub4)OCI_DEFAULT)) { + default: + break; + } + switch (OCIServerDetach(handle->svr, handle->err, (ub4) OCI_DEFAULT )) { + default: + break; + } + /* does OCISessionEnd imply this? */ + switch (OCIHandleFree((dvoid *) handle->auth, (ub4) OCI_HTYPE_SESSION)) { + default: + break; + } + switch (OCIHandleFree((dvoid *) handle->svr, (ub4) OCI_HTYPE_SERVER)) { + default: + break; + } + switch (OCIHandleFree((dvoid *) handle->svc, (ub4) OCI_HTYPE_SVCCTX)) { + default: + break; + } + switch (OCIHandleFree((dvoid *) handle->err, (ub4) OCI_HTYPE_ERROR)) { + default: + break; + } + return APR_SUCCESS; +} + +static apr_status_t dbd_oracle_check_conn(apr_pool_t *pool, apr_dbd_t *sql) +{ + apr_dbd_results_t *res = NULL; + apr_dbd_row_t *row = NULL; + + if(dbd_oracle_pselect(pool, sql, &res, sql->check_conn_stmt, + 0, NULL) != 0) { + return APR_EGENERAL; + } + + if(dbd_oracle_get_row(pool, res, &row, -1) != 0) { + return APR_EGENERAL; + } + + if(dbd_oracle_get_row(pool, res, &row, -1) != -1) { + return APR_EGENERAL; + } + + return APR_SUCCESS; +} + +static int dbd_oracle_select_db(apr_pool_t *pool, apr_dbd_t *handle, + const char *name) +{ + /* FIXME: need to find this in the docs */ + return APR_ENOTIMPL; +} + +static void *dbd_oracle_native(apr_dbd_t *handle) +{ + /* FIXME: can we do anything better? Oracle doesn't seem to have + * a concept of a handle in the sense we use it. + */ + return dbd_oracle_env; +} + +static int dbd_oracle_num_cols(apr_dbd_results_t* res) +{ + return res->statement->nout; +} + +static int dbd_oracle_num_tuples(apr_dbd_results_t* res) +{ + if (!res->seek) { + return -1; + } + if (res->nrows >= 0) { + return res->nrows; + } + res->handle->status = OCIAttrGet(res->statement->stmt, OCI_HTYPE_STMT, + &res->nrows, 0, OCI_ATTR_ROW_COUNT, + res->handle->err); + return res->nrows; +} + +APR_MODULE_DECLARE_DATA const apr_dbd_driver_t apr_dbd_oracle_driver = { + "oracle", + dbd_oracle_init, + dbd_oracle_native, + dbd_oracle_open, + dbd_oracle_check_conn, + dbd_oracle_close, + dbd_oracle_select_db, + dbd_oracle_start_transaction, + dbd_oracle_end_transaction, + dbd_oracle_query, + dbd_oracle_select, + dbd_oracle_num_cols, + dbd_oracle_num_tuples, + dbd_oracle_get_row, + dbd_oracle_get_entry, + dbd_oracle_error, + dbd_oracle_escape, + dbd_oracle_prepare, + dbd_oracle_pvquery, + dbd_oracle_pvselect, + dbd_oracle_pquery, + dbd_oracle_pselect, + dbd_oracle_get_name, + dbd_oracle_transaction_mode_get, + dbd_oracle_transaction_mode_set, + ":apr%d", + dbd_oracle_pvbquery, + dbd_oracle_pvbselect, + dbd_oracle_pbquery, + dbd_oracle_pbselect, + dbd_oracle_datum_get +}; +#endif diff --git a/dbd/apr_dbd_oracle.dsp b/dbd/apr_dbd_oracle.dsp new file mode 100644 index 00000000000..91134138807 --- /dev/null +++ b/dbd/apr_dbd_oracle.dsp @@ -0,0 +1,207 @@ +# Microsoft Developer Studio Project File - Name="apr_dbd_oracle" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=apr_dbd_oracle - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "apr_dbd_oracle.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "apr_dbd_oracle.mak" CFG="apr_dbd_oracle - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "apr_dbd_oracle - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "apr_dbd_oracle - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "apr_dbd_oracle - x64 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "apr_dbd_oracle - x64 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "apr_dbd_oracle - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c +# ADD CPP /nologo /MD /W3 /Zi /O2 /Oy- /I "../include" /I "../include/arch/win32" /I "../include/private" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "APU_DSO_MODULE_BUILD" /D APU_HAVE_ORACLE=1 /Fo"$(INTDIR)\" /Fd"$(INTDIR)\apr_dbd_oracle_src" /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o /win32 "NUL" +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o /win32 "NUL" +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /fo"Release/apr_dbd_oracle-1.res" /d DLL_NAME="apr_dbd_oracle" /d "NDEBUG" /d "APU_VERSION_ONLY" /I "../include" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib oci.lib /nologo /base:"0x6EF40000" /subsystem:windows /dll /incremental:no /debug /opt:ref +# ADD LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib oci.lib /nologo /base:"0x6EF40000" /subsystem:windows /dll /incremental:no /debug /out:"Release\apr_dbd_oracle-1.dll" /pdb:"Release\apr_dbd_oracle-1.pdb" /implib:"Release\apr_dbd_oracle-1.lib" /MACHINE:X86 /opt:ref +# Begin Special Build Tool +TargetPath=Release\apr_dbd_oracle-1.dll +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2 +# End Special Build Tool + +!ELSEIF "$(CFG)" == "apr_dbd_oracle - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /EHsc /c +# ADD CPP /nologo /MDd /W3 /Zi /Od /I "../include" /I "../include/arch/win32" /I "../include/private" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "APU_DSO_MODULE_BUILD" /D APU_HAVE_ORACLE=1 /Fo"$(INTDIR)\" /Fd"$(INTDIR)\apr_dbd_oracle_src" /FD /EHsc /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o /win32 "NUL" +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o /win32 "NUL" +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /fo"Debug/apr_dbd_oracle-1.res" /d DLL_NAME="apr_dbd_oracle" /d "_DEBUG" /d "APU_VERSION_ONLY" /I "../include" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib oci.lib /nologo /base:"0x6EF40000" /subsystem:windows /dll /incremental:no /debug +# ADD LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib oci.lib /nologo /base:"0x6EF40000" /subsystem:windows /dll /incremental:no /debug /out:"Debug\apr_dbd_oracle-1.dll" /pdb:"Debug\apr_dbd_oracle-1.pdb" /implib:"Debug\apr_dbd_oracle-1.lib" /MACHINE:X86 +# Begin Special Build Tool +TargetPath=Debug\apr_dbd_oracle-1.dll +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2 +# End Special Build Tool + +!ELSEIF "$(CFG)" == "apr_dbd_oracle - x64 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "x64\Release" +# PROP BASE Intermediate_Dir "x64\Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "x64\Release" +# PROP Intermediate_Dir "x64\Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c +# ADD CPP /nologo /MD /W3 /Zi /O2 /Oy- /I "../include" /I "../include/arch/win32" /I "../include/private" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "APU_DSO_MODULE_BUILD" /D APU_HAVE_ORACLE=1 /Fo"$(INTDIR)\" /Fd"$(INTDIR)\apr_dbd_oracle_src" /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o /win32 "NUL" +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o /win32 "NUL" +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /fo"x64/Release/apr_dbd_oracle-1.res" /d DLL_NAME="apr_dbd_oracle" /d "NDEBUG" /d "APU_VERSION_ONLY" /I "../include" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib oci.lib /nologo /base:"0x6EF40000" /subsystem:windows /dll /incremental:no /debug /opt:ref +# ADD LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib oci.lib /nologo /base:"0x6EF40000" /subsystem:windows /dll /incremental:no /debug /out:"x64\Release\apr_dbd_oracle-1.dll" /pdb:"x64\Release\apr_dbd_oracle-1.pdb" /implib:"x64\Release\apr_dbd_oracle-1.lib" /MACHINE:X64 /opt:ref +# Begin Special Build Tool +TargetPath=x64\Release\apr_dbd_oracle-1.dll +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2 +# End Special Build Tool + +!ELSEIF "$(CFG)" == "apr_dbd_oracle - x64 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "x64\Debug" +# PROP BASE Intermediate_Dir "x64\Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "x64\Debug" +# PROP Intermediate_Dir "x64\Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /EHsc /c +# ADD CPP /nologo /MDd /W3 /Zi /Od /I "../include" /I "../include/arch/win32" /I "../include/private" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "APU_DSO_MODULE_BUILD" /D APU_HAVE_ORACLE=1 /Fo"$(INTDIR)\" /Fd"$(INTDIR)\apr_dbd_oracle_src" /FD /EHsc /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o /win32 "NUL" +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o /win32 "NUL" +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /fo"x64/Debug/apr_dbd_oracle-1.res" /d DLL_NAME="apr_dbd_oracle" /d "_DEBUG" /d "APU_VERSION_ONLY" /I "../include" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib oci.lib /nologo /base:"0x6EF40000" /subsystem:windows /dll /incremental:no /debug +# ADD LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib oci.lib /nologo /base:"0x6EF40000" /subsystem:windows /dll /incremental:no /debug /out:"x64\Debug\apr_dbd_oracle-1.dll" /pdb:"x64\Debug\apr_dbd_oracle-1.pdb" /implib:"x64\Debug\apr_dbd_oracle-1.lib" /MACHINE:X64 +# Begin Special Build Tool +TargetPath=x64\Debug\apr_dbd_oracle-1.dll +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2 +# End Special Build Tool + +!ENDIF + +# Begin Target + +# Name "apr_dbd_oracle - Win32 Release" +# Name "apr_dbd_oracle - Win32 Debug" +# Name "apr_dbd_oracle - x64 Release" +# Name "apr_dbd_oracle - x64 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\apr_dbd_oracle.c +# End Source File +# End Group +# Begin Group "Public Header Files" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\include\apr_dbd.h +# End Source File +# End Group +# Begin Group "Internal Header Files" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\include\private\apu_config.h +# End Source File +# Begin Source File + +SOURCE=..\include\private\apu_dbd_internal.h +# End Source File +# Begin Source File + +SOURCE=..\include\private\apu_internal.h +# End Source File +# End Group +# Begin Source File + +SOURCE=..\libapr.rc +# End Source File +# End Target +# End Project diff --git a/dbd/apr_dbd_pgsql.c b/dbd/apr_dbd_pgsql.c new file mode 100644 index 00000000000..af09e0a478f --- /dev/null +++ b/dbd/apr_dbd_pgsql.c @@ -0,0 +1,1314 @@ +/* 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 "apu.h" +#include "apr_private.h" + +#if APU_HAVE_PGSQL + +#include <ctype.h> +#include <stdlib.h> + +#ifdef HAVE_LIBPQ_FE_H +#include <libpq-fe.h> +#elif defined(HAVE_POSTGRESQL_LIBPQ_FE_H) +#include <postgresql/libpq-fe.h> +#endif + +#include "apr_strings.h" +#include "apr_time.h" +#include "apr_buckets.h" + +#include "apr_dbd_internal.h" + +struct apr_dbd_transaction_t { + int mode; + int errnum; + apr_dbd_t *handle; +}; + +struct apr_dbd_t { + PGconn *conn; + apr_dbd_transaction_t *trans; +}; + +struct apr_dbd_results_t { + int random; + PGconn *handle; + PGresult *res; + size_t ntuples; + size_t sz; + size_t index; + apr_pool_t *pool; +}; + +struct apr_dbd_row_t { + int n; + apr_dbd_results_t *res; +}; + +struct apr_dbd_prepared_t { + const char *name; + int prepared; + int nargs; + int nvals; + apr_dbd_type_e *types; +}; + +#define dbd_pgsql_is_success(x) (((x) == PGRES_EMPTY_QUERY) \ + || ((x) == PGRES_COMMAND_OK) \ + || ((x) == PGRES_TUPLES_OK)) + +static apr_status_t clear_result(void *data) +{ + PQclear(data); + return APR_SUCCESS; +} + +static int dbd_pgsql_select(apr_pool_t *pool, apr_dbd_t *sql, + apr_dbd_results_t **results, + const char *query, int seek) +{ + PGresult *res; + int ret; + if ( sql->trans && sql->trans->errnum ) { + return sql->trans->errnum; + } + if (seek) { /* synchronous query */ + if (TXN_IGNORE_ERRORS(sql->trans)) { + PGresult *res = PQexec(sql->conn, "SAVEPOINT APR_DBD_TXN_SP"); + if (res) { + int ret = PQresultStatus(res); + PQclear(res); + if (!dbd_pgsql_is_success(ret)) { + sql->trans->errnum = ret; + return PGRES_FATAL_ERROR; + } + } else { + return sql->trans->errnum = PGRES_FATAL_ERROR; + } + } + res = PQexec(sql->conn, query); + if (res) { + ret = PQresultStatus(res); + if (dbd_pgsql_is_success(ret)) { + ret = 0; + } else { + PQclear(res); + } + } else { + ret = PGRES_FATAL_ERROR; + } + if (ret != 0) { + if (TXN_IGNORE_ERRORS(sql->trans)) { + PGresult *res = PQexec(sql->conn, + "ROLLBACK TO SAVEPOINT APR_DBD_TXN_SP"); + if (res) { + int ret = PQresultStatus(res); + PQclear(res); + if (!dbd_pgsql_is_success(ret)) { + sql->trans->errnum = ret; + return PGRES_FATAL_ERROR; + } + } else { + return sql->trans->errnum = PGRES_FATAL_ERROR; + } + } else if (TXN_NOTICE_ERRORS(sql->trans)){ + sql->trans->errnum = ret; + } + return ret; + } else { + if (TXN_IGNORE_ERRORS(sql->trans)) { + PGresult *res = PQexec(sql->conn, + "RELEASE SAVEPOINT APR_DBD_TXN_SP"); + if (res) { + int ret = PQresultStatus(res); + PQclear(res); + if (!dbd_pgsql_is_success(ret)) { + sql->trans->errnum = ret; + return PGRES_FATAL_ERROR; + } + } else { + return sql->trans->errnum = PGRES_FATAL_ERROR; + } + } + } + if (!*results) { + *results = apr_pcalloc(pool, sizeof(apr_dbd_results_t)); + } + (*results)->res = res; + (*results)->ntuples = PQntuples(res); + (*results)->sz = PQnfields(res); + (*results)->random = seek; + (*results)->pool = pool; + apr_pool_cleanup_register(pool, res, clear_result, + apr_pool_cleanup_null); + } + else { + if (TXN_IGNORE_ERRORS(sql->trans)) { + PGresult *res = PQexec(sql->conn, "SAVEPOINT APR_DBD_TXN_SP"); + if (res) { + int ret = PQresultStatus(res); + PQclear(res); + if (!dbd_pgsql_is_success(ret)) { + sql->trans->errnum = ret; + return PGRES_FATAL_ERROR; + } + } else { + return sql->trans->errnum = PGRES_FATAL_ERROR; + } + } + if (PQsendQuery(sql->conn, query) == 0) { + if (TXN_IGNORE_ERRORS(sql->trans)) { + PGresult *res = PQexec(sql->conn, + "ROLLBACK TO SAVEPOINT APR_DBD_TXN_SP"); + if (res) { + int ret = PQresultStatus(res); + PQclear(res); + if (!dbd_pgsql_is_success(ret)) { + sql->trans->errnum = ret; + return PGRES_FATAL_ERROR; + } + } else { + return sql->trans->errnum = PGRES_FATAL_ERROR; + } + } else if (TXN_NOTICE_ERRORS(sql->trans)){ + sql->trans->errnum = 1; + } + return 1; + } else { + if (TXN_IGNORE_ERRORS(sql->trans)) { + PGresult *res = PQexec(sql->conn, + "RELEASE SAVEPOINT APR_DBD_TXN_SP"); + if (res) { + int ret = PQresultStatus(res); + PQclear(res); + if (!dbd_pgsql_is_success(ret)) { + sql->trans->errnum = ret; + return PGRES_FATAL_ERROR; + } + } else { + return sql->trans->errnum = PGRES_FATAL_ERROR; + } + } + } + if (*results == NULL) { + *results = apr_pcalloc(pool, sizeof(apr_dbd_results_t)); + } + (*results)->random = seek; + (*results)->handle = sql->conn; + (*results)->pool = pool; + } + return 0; +} + +static const char *dbd_pgsql_get_name(const apr_dbd_results_t *res, int n) +{ + if (res->res) { + if ((n>=0) && (PQnfields(res->res) > n)) { + return PQfname(res->res,n); + } + } + return NULL; +} + +static int dbd_pgsql_get_row(apr_pool_t *pool, apr_dbd_results_t *res, + apr_dbd_row_t **rowp, int rownum) +{ + apr_dbd_row_t *row = *rowp; + int sequential = ((rownum >= 0) && res->random) ? 0 : 1; + + if (row == NULL) { + row = apr_palloc(pool, sizeof(apr_dbd_row_t)); + *rowp = row; + row->res = res; + if ( sequential ) { + row->n = 0; + } + else { + if (rownum > 0) { + row->n = --rownum; + } + else { + return -1; /* invalid row */ + } + } + } + else { + if ( sequential ) { + ++row->n; + } + else { + if (rownum > 0) { + row->n = --rownum; + } + else { + return -1; /* invalid row */ + } + } + } + + if (res->random) { + if ((row->n >= 0) && (size_t)row->n >= res->ntuples) { + *rowp = NULL; + apr_pool_cleanup_run(res->pool, res->res, clear_result); + res->res = NULL; + return -1; + } + } + else { + if ((row->n >= 0) && (size_t)row->n >= res->ntuples) { + /* no data; we have to fetch some */ + row->n -= res->ntuples; + if (res->res != NULL) { + PQclear(res->res); + } + res->res = PQgetResult(res->handle); + if (res->res) { + res->ntuples = PQntuples(res->res); + while (res->ntuples == 0) { + /* if we got an empty result, clear it, wait a mo, try + * again */ + PQclear(res->res); + apr_sleep(100000); /* 0.1 secs */ + res->res = PQgetResult(res->handle); + if (res->res) { + res->ntuples = PQntuples(res->res); + } + else { + return -1; + } + } + if (res->sz == 0) { + res->sz = PQnfields(res->res); + } + } + else { + return -1; + } + } + } + return 0; +} + +static const char *dbd_pgsql_get_entry(const apr_dbd_row_t *row, int n) +{ + return PQgetvalue(row->res->res, row->n, n); +} + +static apr_status_t dbd_pgsql_datum_get(const apr_dbd_row_t *row, int n, + apr_dbd_type_e type, void *data) +{ + if (PQgetisnull(row->res->res, row->n, n)) { + return APR_ENOENT; + } + + switch (type) { + case APR_DBD_TYPE_TINY: + *(char*)data = atoi(PQgetvalue(row->res->res, row->n, n)); + break; + case APR_DBD_TYPE_UTINY: + *(unsigned char*)data = atoi(PQgetvalue(row->res->res, row->n, n)); + break; + case APR_DBD_TYPE_SHORT: + *(short*)data = atoi(PQgetvalue(row->res->res, row->n, n)); + break; + case APR_DBD_TYPE_USHORT: + *(unsigned short*)data = atoi(PQgetvalue(row->res->res, row->n, n)); + break; + case APR_DBD_TYPE_INT: + *(int*)data = atoi(PQgetvalue(row->res->res, row->n, n)); + break; + case APR_DBD_TYPE_UINT: + *(unsigned int*)data = atoi(PQgetvalue(row->res->res, row->n, n)); + break; + case APR_DBD_TYPE_LONG: + *(long*)data = atol(PQgetvalue(row->res->res, row->n, n)); + break; + case APR_DBD_TYPE_ULONG: + *(unsigned long*)data = atol(PQgetvalue(row->res->res, row->n, n)); + break; + case APR_DBD_TYPE_LONGLONG: + *(apr_int64_t*)data = apr_atoi64(PQgetvalue(row->res->res, row->n, n)); + break; + case APR_DBD_TYPE_ULONGLONG: + *(apr_uint64_t*)data = apr_atoi64(PQgetvalue(row->res->res, row->n, n)); + break; + case APR_DBD_TYPE_FLOAT: + *(float*)data = (float)atof(PQgetvalue(row->res->res, row->n, n)); + break; + case APR_DBD_TYPE_DOUBLE: + *(double*)data = atof(PQgetvalue(row->res->res, row->n, n)); + break; + case APR_DBD_TYPE_STRING: + case APR_DBD_TYPE_TEXT: + case APR_DBD_TYPE_TIME: + case APR_DBD_TYPE_DATE: + case APR_DBD_TYPE_DATETIME: + case APR_DBD_TYPE_TIMESTAMP: + case APR_DBD_TYPE_ZTIMESTAMP: + *(char**)data = PQgetvalue(row->res->res, row->n, n); + break; + case APR_DBD_TYPE_BLOB: + case APR_DBD_TYPE_CLOB: + { + apr_bucket *e; + apr_bucket_brigade *b = (apr_bucket_brigade*)data; + + e = apr_bucket_pool_create(PQgetvalue(row->res->res, row->n, n), + PQgetlength(row->res->res, row->n, n), + row->res->pool, b->bucket_alloc); + APR_BRIGADE_INSERT_TAIL(b, e); + } + break; + case APR_DBD_TYPE_NULL: + *(void**)data = NULL; + break; + default: + return APR_EGENERAL; + } + + return APR_SUCCESS; +} + +static const char *dbd_pgsql_error(apr_dbd_t *sql, int n) +{ + return PQerrorMessage(sql->conn); +} + +static int dbd_pgsql_query(apr_dbd_t *sql, int *nrows, const char *query) +{ + PGresult *res; + int ret; + if (sql->trans && sql->trans->errnum) { + return sql->trans->errnum; + } + + if (TXN_IGNORE_ERRORS(sql->trans)) { + PGresult *res = PQexec(sql->conn, "SAVEPOINT APR_DBD_TXN_SP"); + if (res) { + int ret = PQresultStatus(res); + PQclear(res); + if (!dbd_pgsql_is_success(ret)) { + sql->trans->errnum = ret; + return PGRES_FATAL_ERROR; + } + } else { + return sql->trans->errnum = PGRES_FATAL_ERROR; + } + } + + res = PQexec(sql->conn, query); + if (res) { + ret = PQresultStatus(res); + if (dbd_pgsql_is_success(ret)) { + /* ugh, making 0 return-success doesn't fit */ + ret = 0; + } + *nrows = atoi(PQcmdTuples(res)); + PQclear(res); + } + else { + ret = PGRES_FATAL_ERROR; + } + + if (ret != 0){ + if (TXN_IGNORE_ERRORS(sql->trans)) { + PGresult *res = PQexec(sql->conn, + "ROLLBACK TO SAVEPOINT APR_DBD_TXN_SP"); + if (res) { + int ret = PQresultStatus(res); + PQclear(res); + if (!dbd_pgsql_is_success(ret)) { + sql->trans->errnum = ret; + return PGRES_FATAL_ERROR; + } + } else { + sql->trans->errnum = ret; + return PGRES_FATAL_ERROR; + } + } else if (TXN_NOTICE_ERRORS(sql->trans)){ + sql->trans->errnum = ret; + } + } else { + if (TXN_IGNORE_ERRORS(sql->trans)) { + PGresult *res = PQexec(sql->conn, + "RELEASE SAVEPOINT APR_DBD_TXN_SP"); + if (res) { + int ret = PQresultStatus(res); + PQclear(res); + if (!dbd_pgsql_is_success(ret)) { + sql->trans->errnum = ret; + return PGRES_FATAL_ERROR; + } + } else { + sql->trans->errnum = ret; + return PGRES_FATAL_ERROR; + } + } + } + + return ret; +} + +static const char *dbd_pgsql_escape(apr_pool_t *pool, const char *arg, + apr_dbd_t *sql) +{ + size_t len = strlen(arg); + char *ret = apr_palloc(pool, 2*len + 2); + PQescapeStringConn(sql->conn, ret, arg, len, NULL); + return ret; +} + +static int dbd_pgsql_prepare(apr_pool_t *pool, apr_dbd_t *sql, + const char *query, const char *label, + int nargs, int nvals, apr_dbd_type_e *types, + apr_dbd_prepared_t **statement) +{ + char *sqlcmd; + char *sqlptr; + size_t length, qlen; + int i = 0; + const char **args; + size_t alen; + int ret; + PGresult *res; + + if (!*statement) { + *statement = apr_palloc(pool, sizeof(apr_dbd_prepared_t)); + } + (*statement)->nargs = nargs; + (*statement)->nvals = nvals; + (*statement)->types = types; + + args = apr_palloc(pool, nargs * sizeof(*args)); + + qlen = strlen(query); + length = qlen + 1; + + for (i = 0; i < nargs; i++) { + switch (types[i]) { + case APR_DBD_TYPE_TINY: + case APR_DBD_TYPE_UTINY: + case APR_DBD_TYPE_SHORT: + case APR_DBD_TYPE_USHORT: + args[i] = "smallint"; + break; + case APR_DBD_TYPE_INT: + case APR_DBD_TYPE_UINT: + args[i] = "integer"; + break; + case APR_DBD_TYPE_LONG: + case APR_DBD_TYPE_ULONG: + case APR_DBD_TYPE_LONGLONG: + case APR_DBD_TYPE_ULONGLONG: + args[i] = "bigint"; + break; + case APR_DBD_TYPE_FLOAT: + args[i] = "real"; + break; + case APR_DBD_TYPE_DOUBLE: + args[i] = "double precision"; + break; + case APR_DBD_TYPE_TEXT: + args[i] = "text"; + break; + case APR_DBD_TYPE_TIME: + args[i] = "time"; + break; + case APR_DBD_TYPE_DATE: + args[i] = "date"; + break; + case APR_DBD_TYPE_DATETIME: + case APR_DBD_TYPE_TIMESTAMP: + args[i] = "timestamp"; + break; + case APR_DBD_TYPE_ZTIMESTAMP: + args[i] = "timestamp with time zone"; + break; + case APR_DBD_TYPE_BLOB: + case APR_DBD_TYPE_CLOB: + args[i] = "bytea"; + break; + case APR_DBD_TYPE_NULL: + args[i] = "varchar"; /* XXX Eh? */ + break; + default: + args[i] = "varchar"; + break; + } + length += 1 + strlen(args[i]); + } + + if (!label) { + /* don't really prepare; use in execParams instead */ + (*statement)->prepared = 0; + (*statement)->name = apr_pstrdup(pool, query); + return 0; + } + (*statement)->name = apr_pstrdup(pool, label); + + /* length of SQL query that prepares this statement */ + length = 8 + strlen(label) + 2 + 4 + length + 1; + sqlcmd = apr_palloc(pool, length); + sqlptr = sqlcmd; + memcpy(sqlptr, "PREPARE ", 8); + sqlptr += 8; + length = strlen(label); + memcpy(sqlptr, label, length); + sqlptr += length; + if (nargs > 0) { + memcpy(sqlptr, " (",2); + sqlptr += 2; + for (i=0; i < nargs; ++i) { + alen = strlen(args[i]); + memcpy(sqlptr, args[i], alen); + sqlptr += alen; + *sqlptr++ = ','; + } + sqlptr[-1] = ')'; + } + memcpy(sqlptr, " AS ", 4); + sqlptr += 4; + memcpy(sqlptr, query, qlen); + sqlptr += qlen; + *sqlptr = 0; + + res = PQexec(sql->conn, sqlcmd); + if ( res ) { + ret = PQresultStatus(res); + if (dbd_pgsql_is_success(ret)) { + ret = 0; + } + /* Hmmm, do we do this here or register it on the pool? */ + PQclear(res); + } + else { + ret = PGRES_FATAL_ERROR; + } + (*statement)->prepared = 1; + + return ret; +} + +static int dbd_pgsql_pquery_internal(apr_pool_t *pool, apr_dbd_t *sql, + int *nrows, apr_dbd_prepared_t *statement, + const char **values, + const int *len, const int *fmt) +{ + int ret; + PGresult *res; + + if (TXN_IGNORE_ERRORS(sql->trans)) { + PGresult *res = PQexec(sql->conn, "SAVEPOINT APR_DBD_TXN_SP"); + if (res) { + int ret = PQresultStatus(res); + PQclear(res); + if (!dbd_pgsql_is_success(ret)) { + sql->trans->errnum = ret; + return PGRES_FATAL_ERROR; + } + } else { + return sql->trans->errnum = PGRES_FATAL_ERROR; + } + } + + if (statement->prepared) { + res = PQexecPrepared(sql->conn, statement->name, statement->nargs, + values, len, fmt, 0); + } + else { + res = PQexecParams(sql->conn, statement->name, statement->nargs, 0, + values, len, fmt, 0); + } + if (res) { + ret = PQresultStatus(res); + if (dbd_pgsql_is_success(ret)) { + ret = 0; + } + *nrows = atoi(PQcmdTuples(res)); + PQclear(res); + } + else { + ret = PGRES_FATAL_ERROR; + } + + if (ret != 0){ + if (TXN_IGNORE_ERRORS(sql->trans)) { + PGresult *res = PQexec(sql->conn, + "ROLLBACK TO SAVEPOINT APR_DBD_TXN_SP"); + if (res) { + int ret = PQresultStatus(res); + PQclear(res); + if (!dbd_pgsql_is_success(ret)) { + sql->trans->errnum = ret; + return PGRES_FATAL_ERROR; + } + } else { + sql->trans->errnum = ret; + return PGRES_FATAL_ERROR; + } + } else if (TXN_NOTICE_ERRORS(sql->trans)){ + sql->trans->errnum = ret; + } + } else { + if (TXN_IGNORE_ERRORS(sql->trans)) { + PGresult *res = PQexec(sql->conn, + "RELEASE SAVEPOINT APR_DBD_TXN_SP"); + if (res) { + int ret = PQresultStatus(res); + PQclear(res); + if (!dbd_pgsql_is_success(ret)) { + sql->trans->errnum = ret; + return PGRES_FATAL_ERROR; + } + } else { + sql->trans->errnum = ret; + return PGRES_FATAL_ERROR; + } + } + } + + return ret; +} + +static void dbd_pgsql_bind(apr_dbd_prepared_t *statement, + const char **values, + const char **val, int *len, int *fmt) +{ + int i, j; + + for (i = 0, j = 0; i < statement->nargs; i++, j++) { + if (values[j] == NULL) { + val[i] = NULL; + } + else { + switch (statement->types[i]) { + case APR_DBD_TYPE_BLOB: + case APR_DBD_TYPE_CLOB: + val[i] = (char *)values[j]; + len[i] = atoi(values[++j]); + fmt[i] = 1; + + /* skip table and column */ + j += 2; + break; + default: + val[i] = values[j]; + break; + } + } + } + + return; +} + +static int dbd_pgsql_pquery(apr_pool_t *pool, apr_dbd_t *sql, + int *nrows, apr_dbd_prepared_t *statement, + const char **values) +{ + int *len, *fmt; + const char **val; + + if (sql->trans && sql->trans->errnum) { + return sql->trans->errnum; + } + + val = apr_palloc(pool, sizeof(*val) * statement->nargs); + len = apr_pcalloc(pool, sizeof(*len) * statement->nargs); + fmt = apr_pcalloc(pool, sizeof(*fmt) * statement->nargs); + + dbd_pgsql_bind(statement, values, val, len, fmt); + + return dbd_pgsql_pquery_internal(pool, sql, nrows, statement, + val, len, fmt); +} + +static int dbd_pgsql_pvquery(apr_pool_t *pool, apr_dbd_t *sql, + int *nrows, apr_dbd_prepared_t *statement, + va_list args) +{ + const char **values; + int i; + + if (sql->trans && sql->trans->errnum) { + return sql->trans->errnum; + } + + values = apr_palloc(pool, sizeof(*values) * statement->nvals); + + for (i = 0; i < statement->nvals; i++) { + values[i] = va_arg(args, const char*); + } + + return dbd_pgsql_pquery(pool, sql, nrows, statement, values); +} + +static int dbd_pgsql_pselect_internal(apr_pool_t *pool, apr_dbd_t *sql, + apr_dbd_results_t **results, + apr_dbd_prepared_t *statement, + int seek, const char **values, + const int *len, const int *fmt) +{ + PGresult *res; + int rv; + int ret = 0; + + if (seek) { /* synchronous query */ + if (TXN_IGNORE_ERRORS(sql->trans)) { + PGresult *res = PQexec(sql->conn, "SAVEPOINT APR_DBD_TXN_SP"); + if (res) { + int ret = PQresultStatus(res); + PQclear(res); + if (!dbd_pgsql_is_success(ret)) { + sql->trans->errnum = ret; + return PGRES_FATAL_ERROR; + } + } else { + sql->trans->errnum = ret; + return PGRES_FATAL_ERROR; + } + } + if (statement->prepared) { + res = PQexecPrepared(sql->conn, statement->name, statement->nargs, + values, len, fmt, 0); + } + else { + res = PQexecParams(sql->conn, statement->name, statement->nargs, 0, + values, len, fmt, 0); + } + if (res) { + ret = PQresultStatus(res); + if (dbd_pgsql_is_success(ret)) { + ret = 0; + } + else { + PQclear(res); + } + } + else { + ret = PGRES_FATAL_ERROR; + } + if (ret != 0) { + if (TXN_IGNORE_ERRORS(sql->trans)) { + PGresult *res = PQexec(sql->conn, + "ROLLBACK TO SAVEPOINT APR_DBD_TXN_SP"); + if (res) { + int ret = PQresultStatus(res); + PQclear(res); + if (!dbd_pgsql_is_success(ret)) { + sql->trans->errnum = ret; + return PGRES_FATAL_ERROR; + } + } else { + sql->trans->errnum = ret; + return PGRES_FATAL_ERROR; + } + } else if (TXN_NOTICE_ERRORS(sql->trans)){ + sql->trans->errnum = ret; + } + return ret; + } else { + if (TXN_IGNORE_ERRORS(sql->trans)) { + PGresult *res = PQexec(sql->conn, + "RELEASE SAVEPOINT APR_DBD_TXN_SP"); + if (res) { + int ret = PQresultStatus(res); + PQclear(res); + if (!dbd_pgsql_is_success(ret)) { + sql->trans->errnum = ret; + return PGRES_FATAL_ERROR; + } + } else { + sql->trans->errnum = ret; + return PGRES_FATAL_ERROR; + } + } + } + if (!*results) { + *results = apr_pcalloc(pool, sizeof(apr_dbd_results_t)); + } + (*results)->res = res; + (*results)->ntuples = PQntuples(res); + (*results)->sz = PQnfields(res); + (*results)->random = seek; + (*results)->pool = pool; + apr_pool_cleanup_register(pool, res, clear_result, + apr_pool_cleanup_null); + } + else { + if (TXN_IGNORE_ERRORS(sql->trans)) { + PGresult *res = PQexec(sql->conn, "SAVEPOINT APR_DBD_TXN_SP"); + if (res) { + int ret = PQresultStatus(res); + PQclear(res); + if (!dbd_pgsql_is_success(ret)) { + sql->trans->errnum = ret; + return PGRES_FATAL_ERROR; + } + } else { + sql->trans->errnum = ret; + return PGRES_FATAL_ERROR; + } + } + if (statement->prepared) { + rv = PQsendQueryPrepared(sql->conn, statement->name, + statement->nargs, values, len, fmt, 0); + } + else { + rv = PQsendQueryParams(sql->conn, statement->name, + statement->nargs, 0, values, len, fmt, 0); + } + if (rv == 0) { + if (TXN_IGNORE_ERRORS(sql->trans)) { + PGresult *res = PQexec(sql->conn, + "ROLLBACK TO SAVEPOINT APR_DBD_TXN_SP"); + if (res) { + int ret = PQresultStatus(res); + PQclear(res); + if (!dbd_pgsql_is_success(ret)) { + sql->trans->errnum = ret; + return PGRES_FATAL_ERROR; + } + } else { + sql->trans->errnum = ret; + return PGRES_FATAL_ERROR; + } + } else if (TXN_NOTICE_ERRORS(sql->trans)){ + sql->trans->errnum = 1; + } + return 1; + } else { + if (TXN_IGNORE_ERRORS(sql->trans)) { + PGresult *res = PQexec(sql->conn, + "RELEASE SAVEPOINT APR_DBD_TXN_SP"); + if (res) { + int ret = PQresultStatus(res); + PQclear(res); + if (!dbd_pgsql_is_success(ret)) { + sql->trans->errnum = ret; + return PGRES_FATAL_ERROR; + } + } else { + sql->trans->errnum = ret; + return PGRES_FATAL_ERROR; + } + } + } + if (!*results) { + *results = apr_pcalloc(pool, sizeof(apr_dbd_results_t)); + } + (*results)->random = seek; + (*results)->handle = sql->conn; + (*results)->pool = pool; + } + + return ret; +} + +static int dbd_pgsql_pselect(apr_pool_t *pool, apr_dbd_t *sql, + apr_dbd_results_t **results, + apr_dbd_prepared_t *statement, + int seek, const char **values) +{ + int *len, *fmt; + const char **val; + + if (sql->trans && sql->trans->errnum) { + return sql->trans->errnum; + } + + val = apr_palloc(pool, sizeof(*val) * statement->nargs); + len = apr_pcalloc(pool, sizeof(*len) * statement->nargs); + fmt = apr_pcalloc(pool, sizeof(*fmt) * statement->nargs); + + dbd_pgsql_bind(statement, values, val, len, fmt); + + return dbd_pgsql_pselect_internal(pool, sql, results, statement, + seek, val, len, fmt); +} + +static int dbd_pgsql_pvselect(apr_pool_t *pool, apr_dbd_t *sql, + apr_dbd_results_t **results, + apr_dbd_prepared_t *statement, + int seek, va_list args) +{ + const char **values; + int i; + + if (sql->trans && sql->trans->errnum) { + return sql->trans->errnum; + } + + values = apr_palloc(pool, sizeof(*values) * statement->nvals); + + for (i = 0; i < statement->nvals; i++) { + values[i] = va_arg(args, const char*); + } + + return dbd_pgsql_pselect(pool, sql, results, statement, seek, values); +} + +static void dbd_pgsql_bbind(apr_pool_t *pool, apr_dbd_prepared_t * statement, + const void **values, + const char **val, int *len, int *fmt) +{ + int i, j; + apr_dbd_type_e type; + + for (i = 0, j = 0; i < statement->nargs; i++, j++) { + type = (values[j] == NULL ? APR_DBD_TYPE_NULL : statement->types[i]); + + switch (type) { + case APR_DBD_TYPE_TINY: + val[i] = apr_itoa(pool, *(char*)values[j]); + break; + case APR_DBD_TYPE_UTINY: + val[i] = apr_itoa(pool, *(unsigned char*)values[j]); + break; + case APR_DBD_TYPE_SHORT: + val[i] = apr_itoa(pool, *(short*)values[j]); + break; + case APR_DBD_TYPE_USHORT: + val[i] = apr_itoa(pool, *(unsigned short*)values[j]); + break; + case APR_DBD_TYPE_INT: + val[i] = apr_itoa(pool, *(int*)values[j]); + break; + case APR_DBD_TYPE_UINT: + val[i] = apr_itoa(pool, *(unsigned int*)values[j]); + break; + case APR_DBD_TYPE_LONG: + val[i] = apr_ltoa(pool, *(long*)values[j]); + break; + case APR_DBD_TYPE_ULONG: + val[i] = apr_ltoa(pool, *(unsigned long*)values[j]); + break; + case APR_DBD_TYPE_LONGLONG: + val[i] = apr_psprintf(pool, "%" APR_INT64_T_FMT, + *(apr_int64_t*)values[j]); + break; + case APR_DBD_TYPE_ULONGLONG: + val[i] = apr_psprintf(pool, "%" APR_UINT64_T_FMT, + *(apr_uint64_t*)values[j]); + break; + case APR_DBD_TYPE_FLOAT: + val[i] = apr_psprintf(pool, "%f", *(float*)values[j]); + break; + case APR_DBD_TYPE_DOUBLE: + val[i] = apr_psprintf(pool, "%lf", *(double*)values[j]); + break; + case APR_DBD_TYPE_STRING: + case APR_DBD_TYPE_TEXT: + case APR_DBD_TYPE_TIME: + case APR_DBD_TYPE_DATE: + case APR_DBD_TYPE_DATETIME: + case APR_DBD_TYPE_TIMESTAMP: + case APR_DBD_TYPE_ZTIMESTAMP: + val[i] = values[j]; + break; + case APR_DBD_TYPE_BLOB: + case APR_DBD_TYPE_CLOB: + val[i] = (char*)values[j]; + len[i] = *(apr_size_t*)values[++j]; + fmt[i] = 1; + + /* skip table and column */ + j += 2; + break; + case APR_DBD_TYPE_NULL: + default: + val[i] = NULL; + break; + } + } + + return; +} + +static int dbd_pgsql_pbquery(apr_pool_t * pool, apr_dbd_t * sql, + int *nrows, apr_dbd_prepared_t * statement, + const void **values) +{ + int *len, *fmt; + const char **val; + + if (sql->trans && sql->trans->errnum) { + return sql->trans->errnum; + } + + val = apr_palloc(pool, sizeof(*val) * statement->nargs); + len = apr_pcalloc(pool, sizeof(*len) * statement->nargs); + fmt = apr_pcalloc(pool, sizeof(*fmt) * statement->nargs); + + dbd_pgsql_bbind(pool, statement, values, val, len, fmt); + + return dbd_pgsql_pquery_internal(pool, sql, nrows, statement, + val, len, fmt); +} + +static int dbd_pgsql_pvbquery(apr_pool_t * pool, apr_dbd_t * sql, + int *nrows, apr_dbd_prepared_t * statement, + va_list args) +{ + const void **values; + int i; + + if (sql->trans && sql->trans->errnum) { + return sql->trans->errnum; + } + + values = apr_palloc(pool, sizeof(*values) * statement->nvals); + + for (i = 0; i < statement->nvals; i++) { + values[i] = va_arg(args, const void*); + } + + return dbd_pgsql_pbquery(pool, sql, nrows, statement, values); +} + +static int dbd_pgsql_pbselect(apr_pool_t * pool, apr_dbd_t * sql, + apr_dbd_results_t ** results, + apr_dbd_prepared_t * statement, + int seek, const void **values) +{ + int *len, *fmt; + const char **val; + + if (sql->trans && sql->trans->errnum) { + return sql->trans->errnum; + } + + val = apr_palloc(pool, sizeof(*val) * statement->nargs); + len = apr_pcalloc(pool, sizeof(*len) * statement->nargs); + fmt = apr_pcalloc(pool, sizeof(*fmt) * statement->nargs); + + dbd_pgsql_bbind(pool, statement, values, val, len, fmt); + + return dbd_pgsql_pselect_internal(pool, sql, results, statement, + seek, val, len, fmt); +} + +static int dbd_pgsql_pvbselect(apr_pool_t * pool, apr_dbd_t * sql, + apr_dbd_results_t ** results, + apr_dbd_prepared_t * statement, int seek, + va_list args) +{ + const void **values; + int i; + + if (sql->trans && sql->trans->errnum) { + return sql->trans->errnum; + } + + values = apr_palloc(pool, sizeof(*values) * statement->nvals); + + for (i = 0; i < statement->nvals; i++) { + values[i] = va_arg(args, const void*); + } + + return dbd_pgsql_pbselect(pool, sql, results, statement, seek, values); +} + +static int dbd_pgsql_start_transaction(apr_pool_t *pool, apr_dbd_t *handle, + apr_dbd_transaction_t **trans) +{ + int ret = 0; + PGresult *res; + + /* XXX handle recursive transactions here */ + + res = PQexec(handle->conn, "BEGIN TRANSACTION"); + if (res) { + ret = PQresultStatus(res); + if (dbd_pgsql_is_success(ret)) { + ret = 0; + if (!*trans) { + *trans = apr_pcalloc(pool, sizeof(apr_dbd_transaction_t)); + } + } + PQclear(res); + (*trans)->handle = handle; + handle->trans = *trans; + } + else { + ret = PGRES_FATAL_ERROR; + } + return ret; +} + +static int dbd_pgsql_end_transaction(apr_dbd_transaction_t *trans) +{ + PGresult *res; + int ret = -1; /* no transaction is an error cond */ + if (trans) { + /* rollback on error or explicit rollback request */ + if (trans->errnum || TXN_DO_ROLLBACK(trans)) { + trans->errnum = 0; + res = PQexec(trans->handle->conn, "ROLLBACK"); + } + else { + res = PQexec(trans->handle->conn, "COMMIT"); + } + if (res) { + ret = PQresultStatus(res); + if (dbd_pgsql_is_success(ret)) { + ret = 0; + } + PQclear(res); + } + else { + ret = PGRES_FATAL_ERROR; + } + trans->handle->trans = NULL; + } + return ret; +} + +static int dbd_pgsql_transaction_mode_get(apr_dbd_transaction_t *trans) +{ + if (!trans) + return APR_DBD_TRANSACTION_COMMIT; + + return trans->mode; +} + +static int dbd_pgsql_transaction_mode_set(apr_dbd_transaction_t *trans, + int mode) +{ + if (!trans) + return APR_DBD_TRANSACTION_COMMIT; + + return trans->mode = (mode & TXN_MODE_BITS); +} + +static void null_notice_receiver(void *arg, const PGresult *res) +{ + /* nothing */ +} + +static void null_notice_processor(void *arg, const char *message) +{ + /* nothing */ +} + +static apr_dbd_t *dbd_pgsql_open(apr_pool_t *pool, const char *params, + const char **error) +{ + apr_dbd_t *sql; + + PGconn *conn = PQconnectdb(params); + + /* if there's an error in the connect string or something we get + * back a * bogus connection object, and things like PQreset are + * liable to segfault, so just close it out now. it would be nice + * if we could give an indication of why we failed to connect... */ + if (PQstatus(conn) != CONNECTION_OK) { + if (error) { + *error = apr_pstrdup(pool, PQerrorMessage(conn)); + } + PQfinish(conn); + return NULL; + } + + PQsetNoticeReceiver(conn, null_notice_receiver, NULL); + PQsetNoticeProcessor(conn, null_notice_processor, NULL); + + sql = apr_pcalloc (pool, sizeof (*sql)); + + sql->conn = conn; + + return sql; +} + +static apr_status_t dbd_pgsql_close(apr_dbd_t *handle) +{ + PQfinish(handle->conn); + return APR_SUCCESS; +} + +static apr_status_t dbd_pgsql_check_conn(apr_pool_t *pool, + apr_dbd_t *handle) +{ + if (PQstatus(handle->conn) != CONNECTION_OK) { + PQreset(handle->conn); + if (PQstatus(handle->conn) != CONNECTION_OK) { + return APR_EGENERAL; + } + } + return APR_SUCCESS; +} + +static int dbd_pgsql_select_db(apr_pool_t *pool, apr_dbd_t *handle, + const char *name) +{ + return APR_ENOTIMPL; +} + +static void *dbd_pgsql_native(apr_dbd_t *handle) +{ + return handle->conn; +} + +static int dbd_pgsql_num_cols(apr_dbd_results_t* res) +{ + return res->sz; +} + +static int dbd_pgsql_num_tuples(apr_dbd_results_t* res) +{ + if (res->random) { + return res->ntuples; + } + else { + return -1; + } +} + +APR_MODULE_DECLARE_DATA const apr_dbd_driver_t apr_dbd_pgsql_driver = { + "pgsql", + NULL, + dbd_pgsql_native, + dbd_pgsql_open, + dbd_pgsql_check_conn, + dbd_pgsql_close, + dbd_pgsql_select_db, + dbd_pgsql_start_transaction, + dbd_pgsql_end_transaction, + dbd_pgsql_query, + dbd_pgsql_select, + dbd_pgsql_num_cols, + dbd_pgsql_num_tuples, + dbd_pgsql_get_row, + dbd_pgsql_get_entry, + dbd_pgsql_error, + dbd_pgsql_escape, + dbd_pgsql_prepare, + dbd_pgsql_pvquery, + dbd_pgsql_pvselect, + dbd_pgsql_pquery, + dbd_pgsql_pselect, + dbd_pgsql_get_name, + dbd_pgsql_transaction_mode_get, + dbd_pgsql_transaction_mode_set, + "$%d", + dbd_pgsql_pvbquery, + dbd_pgsql_pvbselect, + dbd_pgsql_pbquery, + dbd_pgsql_pbselect, + dbd_pgsql_datum_get +}; +#endif diff --git a/dbd/apr_dbd_pgsql.dsp b/dbd/apr_dbd_pgsql.dsp new file mode 100644 index 00000000000..03526576fd3 --- /dev/null +++ b/dbd/apr_dbd_pgsql.dsp @@ -0,0 +1,207 @@ +# Microsoft Developer Studio Project File - Name="apr_dbd_pgsql" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=apr_dbd_pgsql - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "apr_dbd_pgsql.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "apr_dbd_pgsql.mak" CFG="apr_dbd_pgsql - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "apr_dbd_pgsql - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "apr_dbd_pgsql - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "apr_dbd_pgsql - x64 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "apr_dbd_pgsql - x64 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "apr_dbd_pgsql - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c +# ADD CPP /nologo /MD /W3 /Zi /O2 /Oy- /I "../include" /I "../include/arch/win32" /I "../include/private" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "APU_DSO_MODULE_BUILD" /D APU_HAVE_PGSQL=1 /D "HAVE_LIBPQ_FE_H" /Fo"$(INTDIR)\" /Fd"$(INTDIR)\apr_dbd_pgsql_src" /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o /win32 "NUL" +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o /win32 "NUL" +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /fo"Release/apr_dbd_pgsql-1.res" /d DLL_NAME="apr_dbd_pgsql" /d "NDEBUG" /d "APU_VERSION_ONLY" /I "../include" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib libpq.lib /nologo /base:"0x6EF30000" /subsystem:windows /dll /incremental:no /debug /opt:ref +# ADD LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib libpq.lib /nologo /base:"0x6EF30000" /subsystem:windows /dll /incremental:no /debug /out:"Release\apr_dbd_pgsql-1.dll" /pdb:"Release\apr_dbd_pgsql-1.pdb" /implib:"Release\apr_dbd_pgsql-1.lib" /MACHINE:X86 /opt:ref +# Begin Special Build Tool +TargetPath=Release\apr_dbd_pgsql-1.dll +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2 +# End Special Build Tool + +!ELSEIF "$(CFG)" == "apr_dbd_pgsql - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /EHsc /c +# ADD CPP /nologo /MDd /W3 /Zi /Od /I "../include" /I "../include/arch/win32" /I "../include/private" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "APU_DSO_MODULE_BUILD" /D APU_HAVE_PGSQL=1 /D "HAVE_LIBPQ_FE_H" /Fo"$(INTDIR)\" /Fd"$(INTDIR)\apr_dbd_pgsql_src" /FD /EHsc /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o /win32 "NUL" +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o /win32 "NUL" +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /fo"Debug/apr_dbd_pgsql-1.res" /d DLL_NAME="apr_dbd_pgsql" /d "_DEBUG" /d "APU_VERSION_ONLY" /I "../include" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib libpq.lib /nologo /base:"0x6EF30000" /subsystem:windows /dll /incremental:no /debug +# ADD LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib libpq.lib /nologo /base:"0x6EF30000" /subsystem:windows /dll /incremental:no /debug /out:"Debug\apr_dbd_pgsql-1.dll" /pdb:"Debug\apr_dbd_pgsql-1.pdb" /implib:"Debug\apr_dbd_pgsql-1.lib" /MACHINE:X86 +# Begin Special Build Tool +TargetPath=Debug\apr_dbd_pgsql-1.dll +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2 +# End Special Build Tool + +!ELSEIF "$(CFG)" == "apr_dbd_pgsql - x64 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "x64\Release" +# PROP BASE Intermediate_Dir "x64\Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "x64\Release" +# PROP Intermediate_Dir "x64\Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c +# ADD CPP /nologo /MD /W3 /Zi /O2 /Oy- /I "../include" /I "../include/arch/win32" /I "../include/private" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "APU_DSO_MODULE_BUILD" /D APU_HAVE_PGSQL=1 /D "HAVE_LIBPQ_FE_H" /Fo"$(INTDIR)\" /Fd"$(INTDIR)\apr_dbd_pgsql_src" /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o /win32 "NUL" +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o /win32 "NUL" +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /fo"x64/Release/apr_dbd_pgsql-1.res" /d DLL_NAME="apr_dbd_pgsql" /d "NDEBUG" /d "APU_VERSION_ONLY" /I "../include" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib libpq.lib /nologo /base:"0x6EF30000" /subsystem:windows /dll /incremental:no /debug /opt:ref +# ADD LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib libpq.lib /nologo /base:"0x6EF30000" /subsystem:windows /dll /incremental:no /debug /out:"x64\Release\apr_dbd_pgsql-1.dll" /pdb:"x64\Release\apr_dbd_pgsql-1.pdb" /implib:"x64\Release\apr_dbd_pgsql-1.lib" /MACHINE:X64 /opt:ref +# Begin Special Build Tool +TargetPath=x64\Release\apr_dbd_pgsql-1.dll +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2 +# End Special Build Tool + +!ELSEIF "$(CFG)" == "apr_dbd_pgsql - x64 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "x64\Debug" +# PROP BASE Intermediate_Dir "x64\Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "x64\Debug" +# PROP Intermediate_Dir "x64\Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /EHsc /c +# ADD CPP /nologo /MDd /W3 /Zi /Od /I "../include" /I "../include/arch/win32" /I "../include/private" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "APU_DSO_MODULE_BUILD" /D APU_HAVE_PGSQL=1 /D "HAVE_LIBPQ_FE_H" /Fo"$(INTDIR)\" /Fd"$(INTDIR)\apr_dbd_pgsql_src" /FD /EHsc /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o /win32 "NUL" +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o /win32 "NUL" +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /fo"x64/Debug/apr_dbd_pgsql-1.res" /d DLL_NAME="apr_dbd_pgsql" /d "_DEBUG" /d "APU_VERSION_ONLY" /I "../include" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib libpq.lib /nologo /base:"0x6EF30000" /subsystem:windows /dll /incremental:no /debug +# ADD LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib libpq.lib /nologo /base:"0x6EF30000" /subsystem:windows /dll /incremental:no /debug /out:"x64\Debug\apr_dbd_pgsql-1.dll" /pdb:"x64\Debug\apr_dbd_pgsql-1.pdb" /implib:"x64\Debug\apr_dbd_pgsql-1.lib" /MACHINE:X64 +# Begin Special Build Tool +TargetPath=x64\Debug\apr_dbd_pgsql-1.dll +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2 +# End Special Build Tool + +!ENDIF + +# Begin Target + +# Name "apr_dbd_pgsql - Win32 Release" +# Name "apr_dbd_pgsql - Win32 Debug" +# Name "apr_dbd_pgsql - x64 Release" +# Name "apr_dbd_pgsql - x64 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\apr_dbd_pgsql.c +# End Source File +# End Group +# Begin Group "Public Header Files" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\include\apr_dbd.h +# End Source File +# End Group +# Begin Group "Internal Header Files" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\include\private\apu_config.h +# End Source File +# Begin Source File + +SOURCE=..\include\private\apu_dbd_internal.h +# End Source File +# Begin Source File + +SOURCE=..\include\private\apu_internal.h +# End Source File +# End Group +# Begin Source File + +SOURCE=..\libapr.rc +# End Source File +# End Target +# End Project diff --git a/dbd/apr_dbd_sqlite2.c b/dbd/apr_dbd_sqlite2.c new file mode 100644 index 00000000000..af72b931fbd --- /dev/null +++ b/dbd/apr_dbd_sqlite2.c @@ -0,0 +1,567 @@ +/* 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 "apu.h" +#include "apr_private.h" + +#if APU_HAVE_SQLITE2 + +#include <ctype.h> +#include <stdlib.h> + +#include <sqlite.h> + +#include "apr_strings.h" +#include "apr_time.h" +#include "apr_buckets.h" + +#include "apr_dbd_internal.h" + +struct apr_dbd_transaction_t { + int mode; + int errnum; + apr_dbd_t *handle; +}; + +struct apr_dbd_t { + sqlite *conn; + char *errmsg; + apr_dbd_transaction_t *trans; +}; + +struct apr_dbd_results_t { + int random; + sqlite *handle; + char **res; + size_t ntuples; + size_t sz; + size_t index; + apr_pool_t *pool; +}; + +struct apr_dbd_row_t { + int n; + char **data; + apr_dbd_results_t *res; +}; + +struct apr_dbd_prepared_t { + const char *name; + int prepared; +}; + +#define FREE_ERROR_MSG(dbd) \ + do { \ + if(dbd && dbd->errmsg) { \ + free(dbd->errmsg); \ + dbd->errmsg = NULL; \ + } \ + } while(0); + +static apr_status_t free_table(void *data) +{ + sqlite_free_table(data); + return APR_SUCCESS; +} + +static int dbd_sqlite_select(apr_pool_t * pool, apr_dbd_t * sql, + apr_dbd_results_t ** results, const char *query, + int seek) +{ + char **result; + int ret = 0; + int tuples = 0; + int fields = 0; + + if (sql->trans && sql->trans->errnum) { + return sql->trans->errnum; + } + + FREE_ERROR_MSG(sql); + + ret = sqlite_get_table(sql->conn, query, &result, &tuples, &fields, + &sql->errmsg); + + if (ret == SQLITE_OK) { + if (!*results) { + *results = apr_pcalloc(pool, sizeof(apr_dbd_results_t)); + } + + (*results)->res = result; + (*results)->ntuples = tuples; + (*results)->sz = fields; + (*results)->random = seek; + (*results)->pool = pool; + + if (tuples > 0) + apr_pool_cleanup_register(pool, result, free_table, + apr_pool_cleanup_null); + + ret = 0; + } + else { + if (TXN_NOTICE_ERRORS(sql->trans)) { + sql->trans->errnum = ret; + } + } + + return ret; +} + +static const char *dbd_sqlite_get_name(const apr_dbd_results_t *res, int n) +{ + if ((n < 0) || (n >= res->sz)) { + return NULL; + } + + return res->res[n]; +} + +static int dbd_sqlite_get_row(apr_pool_t * pool, apr_dbd_results_t * res, + apr_dbd_row_t ** rowp, int rownum) +{ + apr_dbd_row_t *row = *rowp; + int sequential = ((rownum >= 0) && res->random) ? 0 : 1; + + if (row == NULL) { + row = apr_palloc(pool, sizeof(apr_dbd_row_t)); + *rowp = row; + row->res = res; + row->n = sequential ? 0 : rownum - 1; + } + else { + if (sequential) { + ++row->n; + } + else { + row->n = rownum - 1; + } + } + + if (row->n >= res->ntuples) { + *rowp = NULL; + apr_pool_cleanup_run(res->pool, res->res, free_table); + res->res = NULL; + return -1; + } + + /* Pointer magic explanation: + * The sqlite result is an array such that the first res->sz elements are + * the column names and each tuple follows afterwards + * ex: (from the sqlite2 documentation) + SELECT employee_name, login, host FROM users WHERE login LIKE * 'd%'; + + nrow = 2 + ncolumn = 3 + result[0] = "employee_name" + result[1] = "login" + result[2] = "host" + result[3] = "dummy" + result[4] = "No such user" + result[5] = 0 + result[6] = "D. Richard Hipp" + result[7] = "drh" + result[8] = "zadok" + */ + + row->data = res->res + res->sz + (res->sz * row->n); + + return 0; +} + +static const char *dbd_sqlite_get_entry(const apr_dbd_row_t * row, int n) +{ + if ((n < 0) || (n >= row->res->sz)) { + return NULL; + } + + return row->data[n]; +} + +static apr_status_t dbd_sqlite_datum_get(const apr_dbd_row_t *row, int n, + apr_dbd_type_e type, void *data) +{ + if ((n < 0) || (n >= row->res->sz)) { + return APR_EGENERAL; + } + + if (row->data[n] == NULL) { + return APR_ENOENT; + } + + switch (type) { + case APR_DBD_TYPE_TINY: + *(char*)data = atoi(row->data[n]); + break; + case APR_DBD_TYPE_UTINY: + *(unsigned char*)data = atoi(row->data[n]); + break; + case APR_DBD_TYPE_SHORT: + *(short*)data = atoi(row->data[n]); + break; + case APR_DBD_TYPE_USHORT: + *(unsigned short*)data = atoi(row->data[n]); + break; + case APR_DBD_TYPE_INT: + *(int*)data = atoi(row->data[n]); + break; + case APR_DBD_TYPE_UINT: + *(unsigned int*)data = atoi(row->data[n]); + break; + case APR_DBD_TYPE_LONG: + *(long*)data = atol(row->data[n]); + break; + case APR_DBD_TYPE_ULONG: + *(unsigned long*)data = atol(row->data[n]); + break; + case APR_DBD_TYPE_LONGLONG: + *(apr_int64_t*)data = apr_atoi64(row->data[n]); + break; + case APR_DBD_TYPE_ULONGLONG: + *(apr_uint64_t*)data = apr_atoi64(row->data[n]); + break; + case APR_DBD_TYPE_FLOAT: + *(float*)data = atof(row->data[n]); + break; + case APR_DBD_TYPE_DOUBLE: + *(double*)data = atof(row->data[n]); + break; + case APR_DBD_TYPE_STRING: + case APR_DBD_TYPE_TEXT: + case APR_DBD_TYPE_TIME: + case APR_DBD_TYPE_DATE: + case APR_DBD_TYPE_DATETIME: + case APR_DBD_TYPE_TIMESTAMP: + case APR_DBD_TYPE_ZTIMESTAMP: + *(char**)data = row->data[n]; + break; + case APR_DBD_TYPE_BLOB: + case APR_DBD_TYPE_CLOB: + { + apr_bucket *e; + apr_bucket_brigade *b = (apr_bucket_brigade*)data; + + e = apr_bucket_pool_create(row->data[n],strlen(row->data[n]), + row->res->pool, b->bucket_alloc); + APR_BRIGADE_INSERT_TAIL(b, e); + } + break; + case APR_DBD_TYPE_NULL: + *(void**)data = NULL; + break; + default: + return APR_EGENERAL; + } + + return APR_SUCCESS; +} + +static const char *dbd_sqlite_error(apr_dbd_t * sql, int n) +{ + return sql->errmsg; +} + +static int dbd_sqlite_query(apr_dbd_t * sql, int *nrows, const char *query) +{ + char **result; + int ret; + int tuples = 0; + int fields = 0; + + if (sql->trans && sql->trans->errnum) { + return sql->trans->errnum; + } + + FREE_ERROR_MSG(sql); + + ret = + sqlite_get_table(sql->conn, query, &result, &tuples, &fields, + &sql->errmsg); + if (ret == SQLITE_OK) { + *nrows = sqlite_changes(sql->conn); + + if (tuples > 0) + free(result); + + ret = 0; + } + + if (TXN_NOTICE_ERRORS(sql->trans)) { + sql->trans->errnum = ret; + } + + return ret; +} + +static apr_status_t free_mem(void *data) +{ + sqlite_freemem(data); + return APR_SUCCESS; +} + +static const char *dbd_sqlite_escape(apr_pool_t * pool, const char *arg, + apr_dbd_t * sql) +{ + char *ret = sqlite_mprintf("%q", arg); + apr_pool_cleanup_register(pool, ret, free_mem, apr_pool_cleanup_null); + return ret; +} + +static int dbd_sqlite_prepare(apr_pool_t * pool, apr_dbd_t * sql, + const char *query, const char *label, + int nargs, int nvals, apr_dbd_type_e *types, + apr_dbd_prepared_t ** statement) +{ + return APR_ENOTIMPL; +} + +static int dbd_sqlite_pquery(apr_pool_t * pool, apr_dbd_t * sql, + int *nrows, apr_dbd_prepared_t * statement, + const char **values) +{ + return APR_ENOTIMPL; +} + +static int dbd_sqlite_pvquery(apr_pool_t * pool, apr_dbd_t * sql, + int *nrows, apr_dbd_prepared_t * statement, + va_list args) +{ + return APR_ENOTIMPL; +} + +static int dbd_sqlite_pselect(apr_pool_t * pool, apr_dbd_t * sql, + apr_dbd_results_t ** results, + apr_dbd_prepared_t * statement, + int seek, const char **values) +{ + return APR_ENOTIMPL; +} + +static int dbd_sqlite_pvselect(apr_pool_t * pool, apr_dbd_t * sql, + apr_dbd_results_t ** results, + apr_dbd_prepared_t * statement, int seek, + va_list args) +{ + return APR_ENOTIMPL; +} + +static int dbd_sqlite_pbquery(apr_pool_t * pool, apr_dbd_t * sql, + int *nrows, apr_dbd_prepared_t * statement, + const void **values) +{ + return APR_ENOTIMPL; +} + +static int dbd_sqlite_pvbquery(apr_pool_t * pool, apr_dbd_t * sql, + int *nrows, apr_dbd_prepared_t * statement, + va_list args) +{ + return APR_ENOTIMPL; +} + +static int dbd_sqlite_pbselect(apr_pool_t * pool, apr_dbd_t * sql, + apr_dbd_results_t ** results, + apr_dbd_prepared_t * statement, + int seek, const void **values) +{ + return APR_ENOTIMPL; +} + +static int dbd_sqlite_pvbselect(apr_pool_t * pool, apr_dbd_t * sql, + apr_dbd_results_t ** results, + apr_dbd_prepared_t * statement, int seek, + va_list args) +{ + return APR_ENOTIMPL; +} + +static int dbd_sqlite_start_transaction(apr_pool_t * pool, apr_dbd_t * handle, + apr_dbd_transaction_t ** trans) +{ + int ret, rows; + + ret = dbd_sqlite_query(handle, &rows, "BEGIN TRANSACTION"); + if (ret == 0) { + if (!*trans) { + *trans = apr_pcalloc(pool, sizeof(apr_dbd_transaction_t)); + } + (*trans)->handle = handle; + handle->trans = *trans; + } + else { + ret = -1; + } + return ret; +} + +static int dbd_sqlite_end_transaction(apr_dbd_transaction_t * trans) +{ + int rows; + int ret = -1; /* no transaction is an error cond */ + + if (trans) { + /* rollback on error or explicit rollback request */ + if (trans->errnum || TXN_DO_ROLLBACK(trans)) { + trans->errnum = 0; + ret = + dbd_sqlite_query(trans->handle, &rows, + "ROLLBACK TRANSACTION"); + } + else { + ret = + dbd_sqlite_query(trans->handle, &rows, "COMMIT TRANSACTION"); + } + trans->handle->trans = NULL; + } + + return ret; +} + +static int dbd_sqlite_transaction_mode_get(apr_dbd_transaction_t *trans) +{ + if (!trans) + return APR_DBD_TRANSACTION_COMMIT; + + return trans->mode; +} + +static int dbd_sqlite_transaction_mode_set(apr_dbd_transaction_t *trans, + int mode) +{ + if (!trans) + return APR_DBD_TRANSACTION_COMMIT; + + return trans->mode = (mode & TXN_MODE_BITS); +} + +static apr_status_t error_free(void *data) +{ + free(data); + return APR_SUCCESS; +} + +static apr_dbd_t *dbd_sqlite_open(apr_pool_t * pool, const char *params_, + const char **error) +{ + apr_dbd_t *sql; + sqlite *conn = NULL; + char *perm; + int iperms = 600; + char* params = apr_pstrdup(pool, params_); + /* params = "[filename]:[permissions]" + * example: "shopping.db:600" + */ + + perm = strstr(params, ":"); + if (perm) { + *(perm++) = '\x00'; /* split the filename and permissions */ + + if (strlen(perm) > 0) + iperms = atoi(perm); + } + + if (error) { + *error = NULL; + + conn = sqlite_open(params, iperms, (char **)error); + + if (*error) { + apr_pool_cleanup_register(pool, *error, error_free, + apr_pool_cleanup_null); + } + } + else { + conn = sqlite_open(params, iperms, NULL); + } + + sql = apr_pcalloc(pool, sizeof(*sql)); + sql->conn = conn; + + return sql; +} + +static apr_status_t dbd_sqlite_close(apr_dbd_t * handle) +{ + if (handle->conn) { + sqlite_close(handle->conn); + handle->conn = NULL; + } + return APR_SUCCESS; +} + +static apr_status_t dbd_sqlite_check_conn(apr_pool_t * pool, + apr_dbd_t * handle) +{ + if (handle->conn == NULL) + return -1; + return APR_SUCCESS; +} + +static int dbd_sqlite_select_db(apr_pool_t * pool, apr_dbd_t * handle, + const char *name) +{ + return APR_ENOTIMPL; +} + +static void *dbd_sqlite_native(apr_dbd_t * handle) +{ + return handle->conn; +} + +static int dbd_sqlite_num_cols(apr_dbd_results_t * res) +{ + return res->sz; +} + +static int dbd_sqlite_num_tuples(apr_dbd_results_t * res) +{ + return res->ntuples; +} + +APR_MODULE_DECLARE_DATA const apr_dbd_driver_t apr_dbd_sqlite2_driver = { + "sqlite2", + NULL, + dbd_sqlite_native, + dbd_sqlite_open, + dbd_sqlite_check_conn, + dbd_sqlite_close, + dbd_sqlite_select_db, + dbd_sqlite_start_transaction, + dbd_sqlite_end_transaction, + dbd_sqlite_query, + dbd_sqlite_select, + dbd_sqlite_num_cols, + dbd_sqlite_num_tuples, + dbd_sqlite_get_row, + dbd_sqlite_get_entry, + dbd_sqlite_error, + dbd_sqlite_escape, + dbd_sqlite_prepare, + dbd_sqlite_pvquery, + dbd_sqlite_pvselect, + dbd_sqlite_pquery, + dbd_sqlite_pselect, + dbd_sqlite_get_name, + dbd_sqlite_transaction_mode_get, + dbd_sqlite_transaction_mode_set, + NULL, + dbd_sqlite_pvbquery, + dbd_sqlite_pvbselect, + dbd_sqlite_pbquery, + dbd_sqlite_pbselect, + dbd_sqlite_datum_get +}; +#endif diff --git a/dbd/apr_dbd_sqlite2.dsp b/dbd/apr_dbd_sqlite2.dsp new file mode 100644 index 00000000000..8a0047e678a --- /dev/null +++ b/dbd/apr_dbd_sqlite2.dsp @@ -0,0 +1,207 @@ +# Microsoft Developer Studio Project File - Name="apr_dbd_sqlite2" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=apr_dbd_sqlite2 - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "apr_dbd_sqlite2.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "apr_dbd_sqlite2.mak" CFG="apr_dbd_sqlite2 - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "apr_dbd_sqlite2 - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "apr_dbd_sqlite2 - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "apr_dbd_sqlite2 - x64 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "apr_dbd_sqlite2 - x64 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "apr_dbd_sqlite2 - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c +# ADD CPP /nologo /MD /W3 /Zi /O2 /Oy- /I "../include" /I "../include/arch/win32" /I "../include/private" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "APU_DSO_MODULE_BUILD" /D APU_HAVE_SQLITE2=1 /Fo"$(INTDIR)\" /Fd"$(INTDIR)\apr_dbd_sqlite2_src" /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o /win32 "NUL" +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o /win32 "NUL" +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /fo"Release/apr_dbd_sqlite2-1.res" /d DLL_NAME="apr_dbd_sqlite2" /d "NDEBUG" /d "APU_VERSION_ONLY" /I "../include" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib sqlite2.lib /nologo /base:"0x6EF10000" /subsystem:windows /dll /incremental:no /debug /opt:ref +# ADD LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib sqlite2.lib /nologo /base:"0x6EF10000" /subsystem:windows /dll /incremental:no /debug /out:"Release\apr_dbd_sqlite2-1.dll" /pdb:"Release\apr_dbd_sqlite2-1.pdb" /implib:"Release\apr_dbd_sqlite2-1.lib" /MACHINE:X86 /opt:ref +# Begin Special Build Tool +TargetPath=Release\apr_dbd_sqlite2-1.dll +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2 +# End Special Build Tool + +!ELSEIF "$(CFG)" == "apr_dbd_sqlite2 - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /EHsc /c +# ADD CPP /nologo /MDd /W3 /Zi /Od /I "../include" /I "../include/arch/win32" /I "../include/private" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "APU_DSO_MODULE_BUILD" /D APU_HAVE_SQLITE2=1 /Fo"$(INTDIR)\" /Fd"$(INTDIR)\apr_dbd_sqlite2_src" /FD /EHsc /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o /win32 "NUL" +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o /win32 "NUL" +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /fo"Debug/apr_dbd_sqlite2-1.res" /d DLL_NAME="apr_dbd_sqlite2" /d "_DEBUG" /d "APU_VERSION_ONLY" /I "../include" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib sqlite2.lib /nologo /base:"0x6EF10000" /subsystem:windows /dll /incremental:no /debug +# ADD LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib sqlite2.lib /nologo /base:"0x6EF10000" /subsystem:windows /dll /incremental:no /debug /out:"Debug\apr_dbd_sqlite2-1.dll" /pdb:"Debug\apr_dbd_sqlite2-1.pdb" /implib:"Debug\apr_dbd_sqlite2-1.lib" /MACHINE:X86 +# Begin Special Build Tool +TargetPath=Debug\apr_dbd_sqlite2-1.dll +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2 +# End Special Build Tool + +!ELSEIF "$(CFG)" == "apr_dbd_sqlite2 - x64 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "x64\Release" +# PROP BASE Intermediate_Dir "x64\Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "x64\Release" +# PROP Intermediate_Dir "x64\Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c +# ADD CPP /nologo /MD /W3 /Zi /O2 /Oy- /I "../include" /I "../include/arch/win32" /I "../include/private" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "APU_DSO_MODULE_BUILD" /D APU_HAVE_SQLITE2=1 /Fo"$(INTDIR)\" /Fd"$(INTDIR)\apr_dbd_sqlite2_src" /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o /win32 "NUL" +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o /win32 "NUL" +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /fo"x64/Release/apr_dbd_sqlite2-1.res" /d DLL_NAME="apr_dbd_sqlite2" /d "NDEBUG" /d "APU_VERSION_ONLY" /I "../include" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib sqlite2.lib /nologo /base:"0x6EF10000" /subsystem:windows /dll /incremental:no /debug /opt:ref +# ADD LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib sqlite2.lib /nologo /base:"0x6EF10000" /subsystem:windows /dll /incremental:no /debug /out:"x64\Release\apr_dbd_sqlite2-1.dll" /pdb:"x64\Release\apr_dbd_sqlite2-1.pdb" /implib:"x64\Release\apr_dbd_sqlite2-1.lib" /MACHINE:X64 /opt:ref +# Begin Special Build Tool +TargetPath=x64\Release\apr_dbd_sqlite2-1.dll +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2 +# End Special Build Tool + +!ELSEIF "$(CFG)" == "apr_dbd_sqlite2 - x64 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "x64\Debug" +# PROP BASE Intermediate_Dir "x64\Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "x64\Debug" +# PROP Intermediate_Dir "x64\Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /EHsc /c +# ADD CPP /nologo /MDd /W3 /Zi /Od /I "../include" /I "../include/arch/win32" /I "../include/private" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "APU_DSO_MODULE_BUILD" /D APU_HAVE_SQLITE2=1 /Fo"$(INTDIR)\" /Fd"$(INTDIR)\apr_dbd_sqlite2_src" /FD /EHsc /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o /win32 "NUL" +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o /win32 "NUL" +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /fo"x64/Debug/apr_dbd_sqlite2-1.res" /d DLL_NAME="apr_dbd_sqlite2" /d "_DEBUG" /d "APU_VERSION_ONLY" /I "../include" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib sqlite2.lib /nologo /base:"0x6EF10000" /subsystem:windows /dll /incremental:no /debug +# ADD LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib sqlite2.lib /nologo /base:"0x6EF10000" /subsystem:windows /dll /incremental:no /debug /out:"x64\Debug\apr_dbd_sqlite2-1.dll" /pdb:"x64\Debug\apr_dbd_sqlite2-1.pdb" /implib:"x64\Debug\apr_dbd_sqlite2-1.lib" /MACHINE:X64 +# Begin Special Build Tool +TargetPath=x64\Debug\apr_dbd_sqlite2-1.dll +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2 +# End Special Build Tool + +!ENDIF + +# Begin Target + +# Name "apr_dbd_sqlite2 - Win32 Release" +# Name "apr_dbd_sqlite2 - Win32 Debug" +# Name "apr_dbd_sqlite2 - x64 Release" +# Name "apr_dbd_sqlite2 - x64 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\apr_dbd_sqlite2.c +# End Source File +# End Group +# Begin Group "Public Header Files" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\include\apr_dbd.h +# End Source File +# End Group +# Begin Group "Internal Header Files" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\include\private\apu_config.h +# End Source File +# Begin Source File + +SOURCE=..\include\private\apu_dbd_internal.h +# End Source File +# Begin Source File + +SOURCE=..\include\private\apu_internal.h +# End Source File +# End Group +# Begin Source File + +SOURCE=..\libapr.rc +# End Source File +# End Target +# End Project diff --git a/dbd/apr_dbd_sqlite3.c b/dbd/apr_dbd_sqlite3.c new file mode 100644 index 00000000000..33f3034f787 --- /dev/null +++ b/dbd/apr_dbd_sqlite3.c @@ -0,0 +1,915 @@ +/* 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 "apu.h" +#include "apr_private.h" + +#if APU_HAVE_SQLITE3 + +#include <ctype.h> +#include <stdlib.h> + +#include <sqlite3.h> + +#include "apr_strings.h" +#include "apr_time.h" +#include "apr_buckets.h" + +#include "apr_dbd_internal.h" + +#define MAX_RETRY_COUNT 15 +#define MAX_RETRY_SLEEP 100000 + +struct apr_dbd_transaction_t { + int mode; + int errnum; + apr_dbd_t *handle; +}; + +struct apr_dbd_t { + sqlite3 *conn; + apr_dbd_transaction_t *trans; + apr_pool_t *pool; + apr_dbd_prepared_t *prep; +}; + +typedef struct { + char *name; + char *value; + int size; + int type; +} apr_dbd_column_t; + +struct apr_dbd_row_t { + apr_dbd_results_t *res; + apr_dbd_column_t **columns; + apr_dbd_row_t *next_row; + int columnCount; + int rownum; +}; + +struct apr_dbd_results_t { + int random; + sqlite3 *handle; + sqlite3_stmt *stmt; + apr_dbd_row_t *next_row; + size_t sz; + int tuples; + char **col_names; + apr_pool_t *pool; +}; + +struct apr_dbd_prepared_t { + sqlite3_stmt *stmt; + apr_dbd_prepared_t *next; + int nargs; + int nvals; + apr_dbd_type_e *types; +}; + +#define dbd_sqlite3_is_success(x) (((x) == SQLITE_DONE) || ((x) == SQLITE_OK)) + +static int dbd_sqlite3_select_internal(apr_pool_t *pool, + apr_dbd_t *sql, + apr_dbd_results_t **results, + sqlite3_stmt *stmt, int seek) +{ + int ret, retry_count = 0, column_count; + size_t i, num_tuples = 0; + int increment = 0; + apr_dbd_row_t *row = NULL; + apr_dbd_row_t *lastrow = NULL; + apr_dbd_column_t *column; + char *hold = NULL; + + column_count = sqlite3_column_count(stmt); + if (!*results) { + *results = apr_pcalloc(pool, sizeof(apr_dbd_results_t)); + } + (*results)->stmt = stmt; + (*results)->sz = column_count; + (*results)->random = seek; + (*results)->next_row = 0; + (*results)->tuples = 0; + (*results)->col_names = apr_pcalloc(pool, column_count * sizeof(char *)); + (*results)->pool = pool; + do { + ret = sqlite3_step(stmt); + if (ret == SQLITE_BUSY) { + if (retry_count++ > MAX_RETRY_COUNT) { + ret = SQLITE_ERROR; + } else { + apr_dbd_mutex_unlock(); + apr_sleep(MAX_RETRY_SLEEP); + apr_dbd_mutex_lock(); + } + } else if (ret == SQLITE_ROW) { + int length; + row = apr_palloc(pool, sizeof(apr_dbd_row_t)); + row->res = *results; + increment = sizeof(apr_dbd_column_t *); + length = increment * (*results)->sz; + row->columns = apr_palloc(pool, length); + row->columnCount = column_count; + for (i = 0; i < (*results)->sz; i++) { + column = apr_palloc(pool, sizeof(apr_dbd_column_t)); + row->columns[i] = column; + /* copy column name once only */ + if ((*results)->col_names[i] == NULL) { + (*results)->col_names[i] = + apr_pstrdup(pool, sqlite3_column_name(stmt, i)); + } + column->name = (*results)->col_names[i]; + column->size = sqlite3_column_bytes(stmt, i); + column->type = sqlite3_column_type(stmt, i); + column->value = NULL; + switch (column->type) { + case SQLITE_FLOAT: + case SQLITE_INTEGER: + case SQLITE_TEXT: + hold = (char *) sqlite3_column_text(stmt, i); + if (hold) { + column->value = apr_pstrmemdup(pool, hold, + column->size); + } + break; + case SQLITE_BLOB: + hold = (char *) sqlite3_column_blob(stmt, i); + if (hold) { + column->value = apr_pstrmemdup(pool, hold, + column->size); + } + break; + case SQLITE_NULL: + break; + } + } + row->rownum = num_tuples++; + row->next_row = 0; + (*results)->tuples = num_tuples; + if ((*results)->next_row == 0) { + (*results)->next_row = row; + } + if (lastrow != 0) { + lastrow->next_row = row; + } + lastrow = row; + } + } while (ret == SQLITE_ROW || ret == SQLITE_BUSY); + + if (dbd_sqlite3_is_success(ret)) { + ret = 0; + } + return ret; +} + +static int dbd_sqlite3_select(apr_pool_t *pool, apr_dbd_t *sql, + apr_dbd_results_t **results, const char *query, + int seek) +{ + sqlite3_stmt *stmt = NULL; + const char *tail = NULL; + int ret; + + if (sql->trans && sql->trans->errnum) { + return sql->trans->errnum; + } + + apr_dbd_mutex_lock(); + + ret = sqlite3_prepare(sql->conn, query, strlen(query), &stmt, &tail); + if (dbd_sqlite3_is_success(ret)) { + ret = dbd_sqlite3_select_internal(pool, sql, results, stmt, seek); + } + sqlite3_finalize(stmt); + + apr_dbd_mutex_unlock(); + + if (TXN_NOTICE_ERRORS(sql->trans)) { + sql->trans->errnum = ret; + } + return ret; +} + +static const char *dbd_sqlite3_get_name(const apr_dbd_results_t *res, int n) +{ + if ((n < 0) || ((size_t)n >= res->sz)) { + return NULL; + } + + return res->col_names[n]; +} + +static int dbd_sqlite3_get_row(apr_pool_t *pool, apr_dbd_results_t *res, + apr_dbd_row_t **rowp, int rownum) +{ + int i = 0; + + if (rownum == -1) { + *rowp = res->next_row; + if (*rowp == 0) + return -1; + res->next_row = (*rowp)->next_row; + return 0; + } + if (rownum > res->tuples) { + return -1; + } + rownum--; + *rowp = res->next_row; + for (; *rowp != 0; i++, *rowp = (*rowp)->next_row) { + if (i == rownum) { + return 0; + } + } + + return -1; + +} + +static const char *dbd_sqlite3_get_entry(const apr_dbd_row_t *row, int n) +{ + apr_dbd_column_t *column; + const char *value; + if ((n < 0) || (n >= row->columnCount)) { + return NULL; + } + column = row->columns[n]; + value = column->value; + return value; +} + +static apr_status_t dbd_sqlite3_datum_get(const apr_dbd_row_t *row, int n, + apr_dbd_type_e type, void *data) +{ + if ((n < 0) || ((size_t)n >= row->res->sz)) { + return APR_EGENERAL; + } + + if (row->columns[n]->type == SQLITE_NULL) { + return APR_ENOENT; + } + + switch (type) { + case APR_DBD_TYPE_TINY: + *(char*)data = atoi(row->columns[n]->value); + break; + case APR_DBD_TYPE_UTINY: + *(unsigned char*)data = atoi(row->columns[n]->value); + break; + case APR_DBD_TYPE_SHORT: + *(short*)data = atoi(row->columns[n]->value); + break; + case APR_DBD_TYPE_USHORT: + *(unsigned short*)data = atoi(row->columns[n]->value); + break; + case APR_DBD_TYPE_INT: + *(int*)data = atoi(row->columns[n]->value); + break; + case APR_DBD_TYPE_UINT: + *(unsigned int*)data = atoi(row->columns[n]->value); + break; + case APR_DBD_TYPE_LONG: + *(long*)data = atol(row->columns[n]->value); + break; + case APR_DBD_TYPE_ULONG: + *(unsigned long*)data = atol(row->columns[n]->value); + break; + case APR_DBD_TYPE_LONGLONG: + *(apr_int64_t*)data = apr_atoi64(row->columns[n]->value); + break; + case APR_DBD_TYPE_ULONGLONG: + *(apr_uint64_t*)data = apr_atoi64(row->columns[n]->value); + break; + case APR_DBD_TYPE_FLOAT: + *(float*)data = (float)atof(row->columns[n]->value); + break; + case APR_DBD_TYPE_DOUBLE: + *(double*)data = atof(row->columns[n]->value); + break; + case APR_DBD_TYPE_STRING: + case APR_DBD_TYPE_TEXT: + case APR_DBD_TYPE_TIME: + case APR_DBD_TYPE_DATE: + case APR_DBD_TYPE_DATETIME: + case APR_DBD_TYPE_TIMESTAMP: + case APR_DBD_TYPE_ZTIMESTAMP: + *(char**)data = row->columns[n]->value; + break; + case APR_DBD_TYPE_BLOB: + case APR_DBD_TYPE_CLOB: + { + apr_bucket *e; + apr_bucket_brigade *b = (apr_bucket_brigade*)data; + + e = apr_bucket_pool_create(row->columns[n]->value, + row->columns[n]->size, + row->res->pool, b->bucket_alloc); + APR_BRIGADE_INSERT_TAIL(b, e); + } + break; + case APR_DBD_TYPE_NULL: + *(void**)data = NULL; + break; + default: + return APR_EGENERAL; + } + + return APR_SUCCESS; +} + +static const char *dbd_sqlite3_error(apr_dbd_t *sql, int n) +{ + return sqlite3_errmsg(sql->conn); +} + +static int dbd_sqlite3_query_internal(apr_dbd_t *sql, sqlite3_stmt *stmt, + int *nrows) +{ + int ret = -1, retry_count = 0; + + while(retry_count++ <= MAX_RETRY_COUNT) { + ret = sqlite3_step(stmt); + if (ret != SQLITE_BUSY) + break; + + apr_dbd_mutex_unlock(); + apr_sleep(MAX_RETRY_SLEEP); + apr_dbd_mutex_lock(); + } + + *nrows = sqlite3_changes(sql->conn); + + if (dbd_sqlite3_is_success(ret)) { + ret = 0; + } + return ret; +} + +static int dbd_sqlite3_query(apr_dbd_t *sql, int *nrows, const char *query) +{ + sqlite3_stmt *stmt = NULL; + const char *tail = NULL; + int ret = -1, length = 0; + + if (sql->trans && sql->trans->errnum) { + return sql->trans->errnum; + } + + length = strlen(query); + apr_dbd_mutex_lock(); + + do { + ret = sqlite3_prepare(sql->conn, query, length, &stmt, &tail); + if (ret != SQLITE_OK) { + sqlite3_finalize(stmt); + break; + } + + ret = dbd_sqlite3_query_internal(sql, stmt, nrows); + + sqlite3_finalize(stmt); + length -= (tail - query); + query = tail; + } while (length > 0); + + apr_dbd_mutex_unlock(); + + if (TXN_NOTICE_ERRORS(sql->trans)) { + sql->trans->errnum = ret; + } + return ret; +} + +static apr_status_t free_mem(void *data) +{ + sqlite3_free(data); + return APR_SUCCESS; +} + +static const char *dbd_sqlite3_escape(apr_pool_t *pool, const char *arg, + apr_dbd_t *sql) +{ + char *ret = sqlite3_mprintf("%q", arg); + apr_pool_cleanup_register(pool, ret, free_mem, + apr_pool_cleanup_null); + return ret; +} + +static int dbd_sqlite3_prepare(apr_pool_t *pool, apr_dbd_t *sql, + const char *query, const char *label, + int nargs, int nvals, apr_dbd_type_e *types, + apr_dbd_prepared_t **statement) +{ + sqlite3_stmt *stmt; + const char *tail = NULL; + int ret; + + apr_dbd_mutex_lock(); + + ret = sqlite3_prepare(sql->conn, query, strlen(query), &stmt, &tail); + if (ret == SQLITE_OK) { + apr_dbd_prepared_t *prep; + + prep = apr_pcalloc(sql->pool, sizeof(*prep)); + prep->stmt = stmt; + prep->next = sql->prep; + prep->nargs = nargs; + prep->nvals = nvals; + prep->types = types; + + /* link new statement to the handle */ + sql->prep = prep; + + *statement = prep; + } else { + sqlite3_finalize(stmt); + } + + apr_dbd_mutex_unlock(); + + return ret; +} + +static void dbd_sqlite3_bind(apr_dbd_prepared_t *statement, const char **values) +{ + sqlite3_stmt *stmt = statement->stmt; + int i, j; + + for (i = 0, j = 0; i < statement->nargs; i++, j++) { + if (values[j] == NULL) { + sqlite3_bind_null(stmt, i + 1); + } + else { + switch (statement->types[i]) { + case APR_DBD_TYPE_BLOB: + case APR_DBD_TYPE_CLOB: + { + char *data = (char *)values[j]; + int size = atoi((char*)values[++j]); + + /* skip table and column */ + j += 2; + + sqlite3_bind_blob(stmt, i + 1, data, size, SQLITE_STATIC); + } + break; + default: + sqlite3_bind_text(stmt, i + 1, values[j], + strlen(values[j]), SQLITE_STATIC); + break; + } + } + } + + return; +} + +static int dbd_sqlite3_pquery(apr_pool_t *pool, apr_dbd_t *sql, + int *nrows, apr_dbd_prepared_t *statement, + const char **values) +{ + sqlite3_stmt *stmt = statement->stmt; + int ret = -1; + + if (sql->trans && sql->trans->errnum) { + return sql->trans->errnum; + } + + apr_dbd_mutex_lock(); + + ret = sqlite3_reset(stmt); + if (ret == SQLITE_OK) { + dbd_sqlite3_bind(statement, values); + + ret = dbd_sqlite3_query_internal(sql, stmt, nrows); + + sqlite3_reset(stmt); + } + + apr_dbd_mutex_unlock(); + + if (TXN_NOTICE_ERRORS(sql->trans)) { + sql->trans->errnum = ret; + } + return ret; +} + +static int dbd_sqlite3_pvquery(apr_pool_t *pool, apr_dbd_t *sql, int *nrows, + apr_dbd_prepared_t *statement, va_list args) +{ + const char **values; + int i; + + if (sql->trans && sql->trans->errnum) { + return sql->trans->errnum; + } + + values = apr_palloc(pool, sizeof(*values) * statement->nvals); + + for (i = 0; i < statement->nvals; i++) { + values[i] = va_arg(args, const char*); + } + + return dbd_sqlite3_pquery(pool, sql, nrows, statement, values); +} + +static int dbd_sqlite3_pselect(apr_pool_t *pool, apr_dbd_t *sql, + apr_dbd_results_t **results, + apr_dbd_prepared_t *statement, int seek, + const char **values) +{ + sqlite3_stmt *stmt = statement->stmt; + int ret; + + if (sql->trans && sql->trans->errnum) { + return sql->trans->errnum; + } + + apr_dbd_mutex_lock(); + + ret = sqlite3_reset(stmt); + if (ret == SQLITE_OK) { + dbd_sqlite3_bind(statement, values); + + ret = dbd_sqlite3_select_internal(pool, sql, results, stmt, seek); + + sqlite3_reset(stmt); + } + + apr_dbd_mutex_unlock(); + + if (TXN_NOTICE_ERRORS(sql->trans)) { + sql->trans->errnum = ret; + } + return ret; +} + +static int dbd_sqlite3_pvselect(apr_pool_t *pool, apr_dbd_t *sql, + apr_dbd_results_t **results, + apr_dbd_prepared_t *statement, int seek, + va_list args) +{ + const char **values; + int i; + + if (sql->trans && sql->trans->errnum) { + return sql->trans->errnum; + } + + values = apr_palloc(pool, sizeof(*values) * statement->nvals); + + for (i = 0; i < statement->nvals; i++) { + values[i] = va_arg(args, const char*); + } + + return dbd_sqlite3_pselect(pool, sql, results, statement, seek, values); +} + +static void dbd_sqlite3_bbind(apr_dbd_prepared_t * statement, + const void **values) +{ + sqlite3_stmt *stmt = statement->stmt; + int i, j; + apr_dbd_type_e type; + + for (i = 0, j = 0; i < statement->nargs; i++, j++) { + type = (values[j] == NULL ? APR_DBD_TYPE_NULL : statement->types[i]); + + switch (type) { + case APR_DBD_TYPE_TINY: + sqlite3_bind_int(stmt, i + 1, *(char*)values[j]); + break; + case APR_DBD_TYPE_UTINY: + sqlite3_bind_int(stmt, i + 1, *(unsigned char*)values[j]); + break; + case APR_DBD_TYPE_SHORT: + sqlite3_bind_int(stmt, i + 1, *(short*)values[j]); + break; + case APR_DBD_TYPE_USHORT: + sqlite3_bind_int(stmt, i + 1, *(unsigned short*)values[j]); + break; + case APR_DBD_TYPE_INT: + sqlite3_bind_int(stmt, i + 1, *(int*)values[j]); + break; + case APR_DBD_TYPE_UINT: + sqlite3_bind_int(stmt, i + 1, *(unsigned int*)values[j]); + break; + case APR_DBD_TYPE_LONG: + sqlite3_bind_int64(stmt, i + 1, *(long*)values[j]); + break; + case APR_DBD_TYPE_ULONG: + sqlite3_bind_int64(stmt, i + 1, *(unsigned long*)values[j]); + break; + case APR_DBD_TYPE_LONGLONG: + sqlite3_bind_int64(stmt, i + 1, *(apr_int64_t*)values[j]); + break; + case APR_DBD_TYPE_ULONGLONG: + sqlite3_bind_int64(stmt, i + 1, *(apr_uint64_t*)values[j]); + break; + case APR_DBD_TYPE_FLOAT: + sqlite3_bind_double(stmt, i + 1, *(float*)values[j]); + break; + case APR_DBD_TYPE_DOUBLE: + sqlite3_bind_double(stmt, i + 1, *(double*)values[j]); + break; + case APR_DBD_TYPE_STRING: + case APR_DBD_TYPE_TEXT: + case APR_DBD_TYPE_TIME: + case APR_DBD_TYPE_DATE: + case APR_DBD_TYPE_DATETIME: + case APR_DBD_TYPE_TIMESTAMP: + case APR_DBD_TYPE_ZTIMESTAMP: + sqlite3_bind_text(stmt, i + 1, values[j], strlen(values[j]), + SQLITE_STATIC); + break; + case APR_DBD_TYPE_BLOB: + case APR_DBD_TYPE_CLOB: + { + char *data = (char*)values[j]; + apr_size_t size = *(apr_size_t*)values[++j]; + + sqlite3_bind_blob(stmt, i + 1, data, size, SQLITE_STATIC); + + /* skip table and column */ + j += 2; + } + break; + case APR_DBD_TYPE_NULL: + default: + sqlite3_bind_null(stmt, i + 1); + break; + } + } + + return; +} + +static int dbd_sqlite3_pbquery(apr_pool_t * pool, apr_dbd_t * sql, + int *nrows, apr_dbd_prepared_t * statement, + const void **values) +{ + sqlite3_stmt *stmt = statement->stmt; + int ret = -1; + + if (sql->trans && sql->trans->errnum) { + return sql->trans->errnum; + } + + apr_dbd_mutex_lock(); + + ret = sqlite3_reset(stmt); + if (ret == SQLITE_OK) { + dbd_sqlite3_bbind(statement, values); + + ret = dbd_sqlite3_query_internal(sql, stmt, nrows); + + sqlite3_reset(stmt); + } + + apr_dbd_mutex_unlock(); + + if (TXN_NOTICE_ERRORS(sql->trans)) { + sql->trans->errnum = ret; + } + return ret; +} + +static int dbd_sqlite3_pvbquery(apr_pool_t * pool, apr_dbd_t * sql, + int *nrows, apr_dbd_prepared_t * statement, + va_list args) +{ + const void **values; + int i; + + if (sql->trans && sql->trans->errnum) { + return sql->trans->errnum; + } + + values = apr_palloc(pool, sizeof(*values) * statement->nvals); + + for (i = 0; i < statement->nvals; i++) { + values[i] = va_arg(args, const void*); + } + + return dbd_sqlite3_pbquery(pool, sql, nrows, statement, values); +} + +static int dbd_sqlite3_pbselect(apr_pool_t * pool, apr_dbd_t * sql, + apr_dbd_results_t ** results, + apr_dbd_prepared_t * statement, + int seek, const void **values) +{ + sqlite3_stmt *stmt = statement->stmt; + int ret; + + if (sql->trans && sql->trans->errnum) { + return sql->trans->errnum; + } + + apr_dbd_mutex_lock(); + + ret = sqlite3_reset(stmt); + if (ret == SQLITE_OK) { + dbd_sqlite3_bbind(statement, values); + + ret = dbd_sqlite3_select_internal(pool, sql, results, stmt, seek); + + sqlite3_reset(stmt); + } + + apr_dbd_mutex_unlock(); + + if (TXN_NOTICE_ERRORS(sql->trans)) { + sql->trans->errnum = ret; + } + return ret; +} + +static int dbd_sqlite3_pvbselect(apr_pool_t * pool, apr_dbd_t * sql, + apr_dbd_results_t ** results, + apr_dbd_prepared_t * statement, int seek, + va_list args) +{ + const void **values; + int i; + + if (sql->trans && sql->trans->errnum) { + return sql->trans->errnum; + } + + values = apr_palloc(pool, sizeof(*values) * statement->nvals); + + for (i = 0; i < statement->nvals; i++) { + values[i] = va_arg(args, const void*); + } + + return dbd_sqlite3_pbselect(pool, sql, results, statement, seek, values); +} + +static int dbd_sqlite3_start_transaction(apr_pool_t *pool, + apr_dbd_t *handle, + apr_dbd_transaction_t **trans) +{ + int ret = 0; + int nrows = 0; + + ret = dbd_sqlite3_query(handle, &nrows, "BEGIN IMMEDIATE"); + if (!*trans) { + *trans = apr_pcalloc(pool, sizeof(apr_dbd_transaction_t)); + (*trans)->handle = handle; + handle->trans = *trans; + } + + return ret; +} + +static int dbd_sqlite3_end_transaction(apr_dbd_transaction_t *trans) +{ + int ret = -1; /* ending transaction that was never started is an error */ + int nrows = 0; + + if (trans) { + /* rollback on error or explicit rollback request */ + if (trans->errnum || TXN_DO_ROLLBACK(trans)) { + trans->errnum = 0; + ret = dbd_sqlite3_query(trans->handle, &nrows, "ROLLBACK"); + } else { + ret = dbd_sqlite3_query(trans->handle, &nrows, "COMMIT"); + } + trans->handle->trans = NULL; + } + + return ret; +} + +static int dbd_sqlite3_transaction_mode_get(apr_dbd_transaction_t *trans) +{ + if (!trans) + return APR_DBD_TRANSACTION_COMMIT; + + return trans->mode; +} + +static int dbd_sqlite3_transaction_mode_set(apr_dbd_transaction_t *trans, + int mode) +{ + if (!trans) + return APR_DBD_TRANSACTION_COMMIT; + + return trans->mode = (mode & TXN_MODE_BITS); +} + +static apr_dbd_t *dbd_sqlite3_open(apr_pool_t *pool, const char *params, + const char **error) +{ + apr_dbd_t *sql = NULL; + sqlite3 *conn = NULL; + int sqlres; + if (!params) + return NULL; + sqlres = sqlite3_open(params, &conn); + if (sqlres != SQLITE_OK) { + if (error) { + *error = apr_pstrdup(pool, sqlite3_errmsg(conn)); + } + sqlite3_close(conn); + return NULL; + } + /* should we register rand or power functions to the sqlite VM? */ + sql = apr_pcalloc(pool, sizeof(*sql)); + sql->conn = conn; + sql->pool = pool; + sql->trans = NULL; + + return sql; +} + +static apr_status_t dbd_sqlite3_close(apr_dbd_t *handle) +{ + apr_dbd_prepared_t *prep = handle->prep; + + /* finalize all prepared statements, or we'll get SQLITE_BUSY on close */ + while (prep) { + sqlite3_finalize(prep->stmt); + prep = prep->next; + } + + sqlite3_close(handle->conn); + return APR_SUCCESS; +} + +static apr_status_t dbd_sqlite3_check_conn(apr_pool_t *pool, + apr_dbd_t *handle) +{ + return (handle->conn != NULL) ? APR_SUCCESS : APR_EGENERAL; +} + +static int dbd_sqlite3_select_db(apr_pool_t *pool, apr_dbd_t *handle, + const char *name) +{ + return APR_ENOTIMPL; +} + +static void *dbd_sqlite3_native(apr_dbd_t *handle) +{ + return handle->conn; +} + +static int dbd_sqlite3_num_cols(apr_dbd_results_t *res) +{ + return res->sz; +} + +static int dbd_sqlite3_num_tuples(apr_dbd_results_t *res) +{ + return res->tuples; +} + +APR_MODULE_DECLARE_DATA const apr_dbd_driver_t apr_dbd_sqlite3_driver = { + "sqlite3", + NULL, + dbd_sqlite3_native, + dbd_sqlite3_open, + dbd_sqlite3_check_conn, + dbd_sqlite3_close, + dbd_sqlite3_select_db, + dbd_sqlite3_start_transaction, + dbd_sqlite3_end_transaction, + dbd_sqlite3_query, + dbd_sqlite3_select, + dbd_sqlite3_num_cols, + dbd_sqlite3_num_tuples, + dbd_sqlite3_get_row, + dbd_sqlite3_get_entry, + dbd_sqlite3_error, + dbd_sqlite3_escape, + dbd_sqlite3_prepare, + dbd_sqlite3_pvquery, + dbd_sqlite3_pvselect, + dbd_sqlite3_pquery, + dbd_sqlite3_pselect, + dbd_sqlite3_get_name, + dbd_sqlite3_transaction_mode_get, + dbd_sqlite3_transaction_mode_set, + "?", + dbd_sqlite3_pvbquery, + dbd_sqlite3_pvbselect, + dbd_sqlite3_pbquery, + dbd_sqlite3_pbselect, + dbd_sqlite3_datum_get +}; +#endif diff --git a/dbd/apr_dbd_sqlite3.dsp b/dbd/apr_dbd_sqlite3.dsp new file mode 100644 index 00000000000..961461de8c7 --- /dev/null +++ b/dbd/apr_dbd_sqlite3.dsp @@ -0,0 +1,207 @@ +# Microsoft Developer Studio Project File - Name="apr_dbd_sqlite3" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=apr_dbd_sqlite3 - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "apr_dbd_sqlite3.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "apr_dbd_sqlite3.mak" CFG="apr_dbd_sqlite3 - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "apr_dbd_sqlite3 - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "apr_dbd_sqlite3 - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "apr_dbd_sqlite3 - x64 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "apr_dbd_sqlite3 - x64 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "apr_dbd_sqlite3 - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c +# ADD CPP /nologo /MD /W3 /Zi /O2 /Oy- /I "../include" /I "../include/arch/win32" /I "../include/private" /I "../../sqlite3" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "APU_DSO_MODULE_BUILD" /D APU_HAVE_SQLITE3=1 /Fo"$(INTDIR)\" /Fd"$(INTDIR)\apr_dbd_sqlite3_src" /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o /win32 "NUL" +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o /win32 "NUL" +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /fo"Release/apr_dbd_sqlite3-1.res" /d DLL_NAME="apr_dbd_sqlite3" /d "NDEBUG" /d "APU_VERSION_ONLY" /I "../include" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib sqlite3.lib /nologo /base:"0x6EF20000" /subsystem:windows /dll /incremental:no /debug /opt:ref +# ADD LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib sqlite3.lib /nologo /base:"0x6EF20000" /subsystem:windows /dll /incremental:no /debug /libpath:"..\..\sqlite3" /out:"Release\apr_dbd_sqlite3-1.dll" /pdb:"Release\apr_dbd_sqlite3-1.pdb" /implib:"Release\apr_dbd_sqlite3-1.lib" /MACHINE:X86 /opt:ref +# Begin Special Build Tool +TargetPath=Release\apr_dbd_sqlite3-1.dll +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2 +# End Special Build Tool + +!ELSEIF "$(CFG)" == "apr_dbd_sqlite3 - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /EHsc /c +# ADD CPP /nologo /MDd /W3 /Zi /Od /I "../include" /I "../include/arch/win32" /I "../include/private" /I "../../sqlite3" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "APU_DSO_MODULE_BUILD" /D APU_HAVE_SQLITE3=1 /Fo"$(INTDIR)\" /Fd"$(INTDIR)\apr_dbd_sqlite3_src" /FD /EHsc /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o /win32 "NUL" +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o /win32 "NUL" +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /fo"Debug/apr_dbd_sqlite3-1.res" /d DLL_NAME="apr_dbd_sqlite3" /d "_DEBUG" /d "APU_VERSION_ONLY" /I "../include" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib sqlite3.lib /nologo /base:"0x6EF20000" /subsystem:windows /dll /incremental:no /debug +# ADD LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib sqlite3.lib /nologo /base:"0x6EF20000" /subsystem:windows /dll /incremental:no /debug /libpath:"..\..\sqlite3" /out:"Debug\apr_dbd_sqlite3-1.dll" /pdb:"Debug\apr_dbd_sqlite3-1.pdb" /implib:"Debug\apr_dbd_sqlite3-1.lib" /MACHINE:X86 +# Begin Special Build Tool +TargetPath=Debug\apr_dbd_sqlite3-1.dll +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2 +# End Special Build Tool + +!ELSEIF "$(CFG)" == "apr_dbd_sqlite3 - x64 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "x64\Release" +# PROP BASE Intermediate_Dir "x64\Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "x64\Release" +# PROP Intermediate_Dir "x64\Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c +# ADD CPP /nologo /MD /W3 /Zi /O2 /Oy- /I "../include" /I "../include/arch/win32" /I "../include/private" /I "../../sqlite3" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "APU_DSO_MODULE_BUILD" /D APU_HAVE_SQLITE3=1 /Fo"$(INTDIR)\" /Fd"$(INTDIR)\apr_dbd_sqlite3_src" /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o /win32 "NUL" +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o /win32 "NUL" +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /fo"x64/Release/apr_dbd_sqlite3-1.res" /d DLL_NAME="apr_dbd_sqlite3" /d "NDEBUG" /d "APU_VERSION_ONLY" /I "../include" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib sqlite3.lib /nologo /base:"0x6EF20000" /subsystem:windows /dll /incremental:no /debug /opt:ref +# ADD LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib sqlite3.lib /nologo /base:"0x6EF20000" /subsystem:windows /dll /incremental:no /libpath:"..\..\sqlite3" /debug /out:"x64\Release\apr_dbd_sqlite3-1.dll" /pdb:"x64\Release\apr_dbd_sqlite3-1.pdb" /implib:"x64\Release\apr_dbd_sqlite3-1.lib" /MACHINE:X64 /opt:ref +# Begin Special Build Tool +TargetPath=x64\Release\apr_dbd_sqlite3-1.dll +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2 +# End Special Build Tool + +!ELSEIF "$(CFG)" == "apr_dbd_sqlite3 - x64 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "x64\Debug" +# PROP BASE Intermediate_Dir "x64\Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "x64\Debug" +# PROP Intermediate_Dir "x64\Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /EHsc /c +# ADD CPP /nologo /MDd /W3 /Zi /Od /I "../include" /I "../include/arch/win32" /I "../include/private" /I "../../sqlite3" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "APU_DSO_MODULE_BUILD" /D APU_HAVE_SQLITE3=1 /Fo"$(INTDIR)\" /Fd"$(INTDIR)\apr_dbd_sqlite3_src" /FD /EHsc /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o /win32 "NUL" +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o /win32 "NUL" +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /fo"x64/Debug/apr_dbd_sqlite3-1.res" /d DLL_NAME="apr_dbd_sqlite3" /d "_DEBUG" /d "APU_VERSION_ONLY" /I "../include" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib sqlite3.lib /nologo /base:"0x6EF20000" /subsystem:windows /dll /incremental:no /debug +# ADD LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib sqlite3.lib /nologo /base:"0x6EF20000" /subsystem:windows /dll /incremental:no /libpath:"..\..\sqlite3" /debug /out:"x64\Debug\apr_dbd_sqlite3-1.dll" /pdb:"x64\Debug\apr_dbd_sqlite3-1.pdb" /implib:"x64\Debug\apr_dbd_sqlite3-1.lib" /MACHINE:X64 +# Begin Special Build Tool +TargetPath=x64\Debug\apr_dbd_sqlite3-1.dll +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2 +# End Special Build Tool + +!ENDIF + +# Begin Target + +# Name "apr_dbd_sqlite3 - Win32 Release" +# Name "apr_dbd_sqlite3 - Win32 Debug" +# Name "apr_dbd_sqlite3 - x64 Release" +# Name "apr_dbd_sqlite3 - x64 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\apr_dbd_sqlite3.c +# End Source File +# End Group +# Begin Group "Public Header Files" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\include\apr_dbd.h +# End Source File +# End Group +# Begin Group "Internal Header Files" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\include\private\apu_config.h +# End Source File +# Begin Source File + +SOURCE=..\include\private\apu_dbd_internal.h +# End Source File +# Begin Source File + +SOURCE=..\include\private\apu_internal.h +# End Source File +# End Group +# Begin Source File + +SOURCE=..\libapr.rc +# End Source File +# End Target +# End Project diff --git a/dbd/unsupported/NWGNUdbdfreetds b/dbd/unsupported/NWGNUdbdfreetds new file mode 100644 index 00000000000..71af8d15159 --- /dev/null +++ b/dbd/unsupported/NWGNUdbdfreetds @@ -0,0 +1,288 @@ +# +# Declare the sub-directories to be built here +# + +SUBDIRS = \ + $(EOLIST) + +# +# Get the 'head' of the build environment. This includes default targets and +# paths to tools +# + +ifndef EnvironmentDefined +include $(APR_WORK)/build/NWGNUhead.inc +endif + +# +# build this level's files + +# +# Make sure all needed macro's are defined +# + +# LINK_STATIC = 1 + +# for now defined here - should finally go into build/NWGNUenvironment.inc +FREETDS_INC = $(FREETDSSDK)/include +FREETDS_IMP = $(FREETDSSDK)/lib/libfreetds.imp +FREETDS_LIB = $(FREETDSSDK)/lib/libfreetds.lib +FREETDS_NLM = libfreetds + +# +# These directories will be at the beginning of the include list, followed by +# INCDIRS +# +XINCDIRS += \ + $(APR)/include \ + $(APR)/include/private \ + $(APR)/include/arch/netware \ + $(FREETDS_INC) \ + $(EOLIST) + +# +# These flags will come after CFLAGS +# +XCFLAGS += \ + $(EOLIST) + +# +# These defines will come after DEFINES +# +XDEFINES += \ + -DAPU_HAVE_FREETDS=1 \ + -DAPU_DSO_MODULE_BUILD \ + -DHAVE_SYBDB_H=1 \ + -DSYBDBLIB \ + $(EOLIST) + +# +# These flags will be added to the link.opt file +# +XLFLAGS += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) + +# +# These values will be appended to the correct variables based on the value of +# RELEASE +# +ifeq "$(RELEASE)" "debug" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +ifeq "$(RELEASE)" "noopt" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +ifeq "$(RELEASE)" "release" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +# +# These are used by the link target if an NLM is being generated +# This is used by the link 'name' directive to name the nlm. If left blank +# TARGET_nlm (see below) will be used. +# +NLM_NAME = dbdfreetds + +# +# This is used by the link '-desc ' directive. +# If left blank, NLM_NAME will be used. +# +NLM_DESCRIPTION = Apache Portability Runtime Library $(VERSION_STR) DBD FreeTDS Driver Module + +# +# This is used by the '-threadname' directive. If left blank, +# NLM_NAME Thread will be used. +# +NLM_THREAD_NAME = dbdfreetds + +# +# If this is specified, it will override VERSION value in +# $(APR_WORK)/build/NWGNUenvironment.inc +# +NLM_VERSION = + +# +# If this is specified, it will override the default of 64K +# +NLM_STACK_SIZE = + +# +# If this is specified it will be used by the link '-entry' directive +# +NLM_ENTRY_SYM = + +# +# If this is specified it will be used by the link '-exit' directive +# +NLM_EXIT_SYM = + +# +# If this is specified it will be used by the link '-check' directive +# +NLM_CHECK_SYM = + +# +# If these are specified it will be used by the link '-flags' directive +# +NLM_FLAGS = + +# +# If this is specified it will be linked in with the XDCData option in the def +# file instead of the default of $(NWOS)/apache.xdc. XDCData can be disabled +# by setting APACHE_UNIPROC in the environment +# +XDCDATA = + +# +# If there is an NLM target, put it here +# +TARGET_nlm = \ + $(OBJDIR)/$(NLM_NAME).nlm \ + $(EOLIST) + +# +# If there is an LIB target, put it here +# +TARGET_lib = \ + $(EOLIST) + +# +# These are the OBJ files needed to create the NLM target above. +# Paths must all use the '/' character +# +FILES_nlm_objs = \ + $(OBJDIR)/apr_dbd_freetds.o \ + $(EOLIST) + +# +# These are the LIB files needed to create the NLM target above. +# These will be added as a library command in the link.opt file. +# +FILES_nlm_libs = \ + $(PRELUDE) \ + $(EOLIST) + +ifeq ($(LINK_STATIC),1) +FILES_nlm_libs += \ + $(FREETDS_LIB) \ + $(EOLIST) +endif + +# +# These are the modules that the above NLM target depends on to load. +# These will be added as a module command in the link.opt file. +# +FILES_nlm_modules = \ + aprlib \ + libc \ + $(EOLIST) + +ifneq ($(LINK_STATIC),1) +FILES_nlm_modules += \ + $(FREETDS_NLM) \ + $(EOLIST) +endif + +# +# If the nlm has a msg file, put it's path here +# +FILE_nlm_msg = + +# +# If the nlm has a hlp file put it's path here +# +FILE_nlm_hlp = + +# +# If this is specified, it will override $(NWOS)\copyright.txt. +# +FILE_nlm_copyright = + +# +# Any additional imports go here +# +FILES_nlm_Ximports = \ + @$(APR)/aprlib.imp \ + @$(NOVI)/libc.imp \ + $(EOLIST) + +ifneq ($(LINK_STATIC),1) +FILES_nlm_Ximports += \ + @$(FREETDS_IMP) \ + $(EOLIST) +endif + +# +# Any symbols exported to here +# +FILES_nlm_exports = \ + apr_dbd_freetds_driver \ + $(EOLIST) + +# +# These are the OBJ files needed to create the LIB target above. +# Paths must all use the '/' character +# +FILES_lib_objs = \ + $(EOLIST) + +# +# implement targets and dependancies (leave this section alone) +# + +libs :: $(OBJDIR) $(TARGET_lib) + +nlms :: libs $(TARGET_nlm) + +# +# Updated this target to create necessary directories and copy files to the +# correct place. (See $(APR_WORK)/build/NWGNUhead.inc for examples) +# +install :: nlms FORCE + +# +# Any specialized rules here +# + +# +# Include the 'tail' makefile that has targets that depend on variables defined +# in this makefile +# + +include $(APRBUILD)/NWGNUtail.inc + diff --git a/dbd/unsupported/apr_dbd_freetds.c b/dbd/unsupported/apr_dbd_freetds.c new file mode 100644 index 00000000000..ba952e95b49 --- /dev/null +++ b/dbd/unsupported/apr_dbd_freetds.c @@ -0,0 +1,809 @@ +/* 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. + */ + +#ifdef I_CAN_DEAL_WITH_THIS_PARTIAL_DRIVER_AND_UNMAINTAINED_CODE_FOR_FREETDS + +#include "apu.h" +#include "apr_private.h" + +/* COMPILE_STUBS: compile stubs for unimplemented functions. + * + * This is required to compile in /trunk/, but can be + * undefined to compile a driver for httpd-2.2 and other + * APR-1.2 applications + */ +#define COMPILE_STUBS + +#if APU_HAVE_FREETDS + +#include <ctype.h> +#include <stdlib.h> + +#include "apr_strings.h" +#include "apr_lib.h" + +#include "apr_pools.h" +#include "apr_dbd_internal.h" + +#ifdef HAVE_FREETDS_SYBDB_H +#include <freetds/sybdb.h> +#endif +#ifdef HAVE_SYBDB_H +#include <sybdb.h> +#endif + +#include <stdio.h> +#include <sys/types.h> +#include <regex.h> + +/* This probably needs to change for different applications */ +#define MAX_COL_LEN 256 + +typedef struct freetds_cell_t { + int type; + DBINT len; + BYTE *data; +} freetds_cell_t; + +struct apr_dbd_transaction_t { + int mode; + int errnum; + apr_dbd_t *handle; +}; + +struct apr_dbd_t { + DBPROCESS *proc; + apr_dbd_transaction_t *trans; + apr_pool_t *pool; + const char *params; + RETCODE err; +}; + +struct apr_dbd_results_t { + int random; + size_t ntuples; + size_t sz; + apr_pool_t *pool; + DBPROCESS *proc; +}; + +struct apr_dbd_row_t { + apr_dbd_results_t *res; + BYTE buf[MAX_COL_LEN]; +}; + +struct apr_dbd_prepared_t { + int nargs; + regex_t **taint; + int *sz; + char *fmt; +}; + +#define dbd_freetds_is_success(x) (x == SUCCEED) + +static int labelnum = 0; /* FIXME */ +static regex_t dbd_freetds_find_arg; + +/* execute a query that doesn't return a result set, mop up, + * and return and APR-flavoured status + */ +static RETCODE freetds_exec(DBPROCESS *proc, const char *query, + int want_results, int *nrows) +{ + /* TBD */ + RETCODE rv = dbcmd(proc, query); + if (rv != SUCCEED) { + return rv; + } + rv = dbsqlexec(proc); + if (rv != SUCCEED) { + return rv; + } + if (!want_results) { + while (dbresults(proc) != NO_MORE_RESULTS) { + ++*nrows; + } + } + return SUCCEED; +} +static apr_status_t clear_result(void *data) +{ + /* clear cursor */ + return (dbcanquery((DBPROCESS*)data) == SUCCEED) + ? APR_SUCCESS + : APR_EGENERAL; +} + +static int dbd_freetds_select(apr_pool_t *pool, apr_dbd_t *sql, + apr_dbd_results_t **results, + const char *query, int seek) +{ + apr_dbd_results_t *res; + if (sql->trans && (sql->trans->errnum != SUCCEED)) { + return 1; + } + /* the core of this is + * dbcmd(proc, query); + * dbsqlexec(proc); + * while (dbnextrow(dbproc) != NO_MORE_ROWS) { + * do things + * } + * + * Ignore seek + */ + + sql->err = freetds_exec(sql->proc, query, 1, NULL); + if (!dbd_freetds_is_success(sql->err)) { + if (sql->trans) { + sql->trans->errnum = sql->err; + } + return 1; + } + + sql->err = dbresults(sql->proc); + if (sql->err != SUCCEED) { + if (sql->trans) { + sql->trans->errnum = sql->err; + } + return 1; + } + + if (!*results) { + *results = apr_pcalloc(pool, sizeof(apr_dbd_results_t)); + } + res = *results; + res->proc = sql->proc; + res->random = seek; + res->pool = pool; + res->ntuples = dblastrow(sql->proc); + res->sz = dbnumcols(sql->proc); + apr_pool_cleanup_register(pool, sql->proc, clear_result, + apr_pool_cleanup_null); + +#if 0 + /* Now we have a result set. We need to bind to its vars */ + res->vars = apr_palloc(pool, res->sz * sizeof(freetds_cell_t*)); + for (i=1; i <= res->sz; ++i) { + freetds_cell_t *cell = &res->vars[i-1]; + cell->type = dbcoltype(sql->proc, i); + cell->len = dbcollen(sql->proc, i); + cell->data = apr_palloc(pool, cell->len); + sql->err = dbbind(sql->proc, i, /*cell->type */ STRINGBIND, cell->len, cell->data); + if (sql->err != SUCCEED) { + fprintf(stderr, "dbbind error: %d, %d, %d", i, cell->type, cell->len); + } + if ((sql->err != SUCCEED) && (sql->trans != NULL)) { + sql->trans->errnum = sql->err; + } + } +#endif + return (sql->err == SUCCEED) ? 0 : 1; +} +static const char *dbd_untaint(apr_pool_t *pool, regex_t *rx, const char *val) +{ + regmatch_t match[1]; + if (rx == NULL) { + /* no untaint expression */ + return val; + } + if (regexec(rx, val, 1, match, 0) == 0) { + return apr_pstrndup(pool, val+match[0].rm_so, + match[0].rm_eo - match[0].rm_so); + } + return ""; +} +static const char *dbd_statement(apr_pool_t *pool, + apr_dbd_prepared_t *stmt, + int nargs, const char **args) +{ + int i; + int len; + const char *var; + char *ret; + const char *p_in; + char *p_out; + char *q; + + /* compute upper bound on length (since untaint shrinks) */ + len = strlen(stmt->fmt) +1; + for (i=0; i<nargs; ++i) { + len += strlen(args[i]) - 2; + } + i = 0; + p_in = stmt->fmt; + p_out = ret = apr_palloc(pool, len); + /* FIXME silly bug - this'll catch %%s */ + while (q = strstr(p_in, "%s"), q != NULL) { + len = q-p_in; + strncpy(p_out, p_in, len); + p_in += len; + p_out += len; + var = dbd_untaint(pool, stmt->taint[i], args[i]); + len = strlen(var); + strncpy(p_out, var, len); + p_in += 2; + p_out += len; + ++i; + } + strcpy(p_out, p_in); + return ret; +} +static int dbd_freetds_pselect(apr_pool_t *pool, apr_dbd_t *sql, + apr_dbd_results_t **results, + apr_dbd_prepared_t *statement, + int seek, const char **values) +{ + const char *query = dbd_statement(pool, statement, + statement->nargs, values); + return dbd_freetds_select(pool, sql, results, query, seek); +} +static int dbd_freetds_pvselect(apr_pool_t *pool, apr_dbd_t *sql, + apr_dbd_results_t **results, + apr_dbd_prepared_t *statement, + int seek, va_list args) +{ + const char **values; + int i; + + if (sql->trans && sql->trans->errnum) { + return sql->trans->errnum; + } + + values = apr_palloc(pool, sizeof(*values) * statement->nargs); + + for (i = 0; i < statement->nargs; i++) { + values[i] = va_arg(args, const char*); + } + + return dbd_freetds_pselect(pool, sql, results, statement, seek, values); +} +static int dbd_freetds_query(apr_dbd_t *sql, int *nrows, const char *query); +static int dbd_freetds_pquery(apr_pool_t *pool, apr_dbd_t *sql, + int *nrows, apr_dbd_prepared_t *statement, + const char **values) +{ + const char *query = dbd_statement(pool, statement, + statement->nargs, values); + return dbd_freetds_query(sql, nrows, query); +} +static int dbd_freetds_pvquery(apr_pool_t *pool, apr_dbd_t *sql, int *nrows, + apr_dbd_prepared_t *statement, va_list args) +{ + const char **values; + int i; + + if (sql->trans && sql->trans->errnum) { + return sql->trans->errnum; + } + + values = apr_palloc(pool, sizeof(*values) * statement->nargs); + + for (i = 0; i < statement->nargs; i++) { + values[i] = va_arg(args, const char*); + } + return dbd_freetds_pquery(pool, sql, nrows, statement, values); +} + +static int dbd_freetds_get_row(apr_pool_t *pool, apr_dbd_results_t *res, + apr_dbd_row_t **rowp, int rownum) +{ + RETCODE rv = 0; + apr_dbd_row_t *row = *rowp; + int sequential = ((rownum >= 0) && res->random) ? 0 : 1; + + if (row == NULL) { + row = apr_palloc(pool, sizeof(apr_dbd_row_t)); + *rowp = row; + row->res = res; + } + /* + else { + if ( sequential ) { + ++row->n; + } + else { + row->n = rownum; + } + } + */ + if (sequential) { + rv = dbnextrow(res->proc); + } + else { + rv = (rownum >= 0) ? dbgetrow(res->proc, rownum) : NO_MORE_ROWS; + } + switch (rv) { + case SUCCEED: return 0; + case REG_ROW: return 0; + case NO_MORE_ROWS: + apr_pool_cleanup_run(res->pool, res->proc, clear_result); + *rowp = NULL; + return -1; + case FAIL: return 1; + case BUF_FULL: return 2; /* FIXME */ + default: return 3; + } + + return 0; +} + +static const char *dbd_freetds_get_entry(const apr_dbd_row_t *row, int n) +{ + /* FIXME: support different data types */ + /* this fails - bind gets some vars but not others + return (const char*)row->res->vars[n].data; + */ + DBPROCESS* proc = row->res->proc; + BYTE *ptr = dbdata(proc, n+1); + int t = dbcoltype(proc, n+1); + int l = dbcollen(proc, n+1); + if (dbwillconvert(t, SYBCHAR)) { + dbconvert(proc, t, ptr, l, SYBCHAR, (BYTE *)row->buf, -1); + return (const char*)row->buf; + } + return (char*)ptr; +} + +static const char *dbd_freetds_error(apr_dbd_t *sql, int n) +{ + /* XXX this doesn't seem to exist in the API ??? */ + return apr_psprintf(sql->pool, "Error %d", sql->err); +} + +static int dbd_freetds_query(apr_dbd_t *sql, int *nrows, const char *query) +{ + if (sql->trans && sql->trans->errnum) { + return sql->trans->errnum; + } + *nrows = 0; + sql->err = freetds_exec(sql->proc, query, 0, nrows); + + if (sql->err != SUCCEED) { + if (sql->trans) { + sql->trans->errnum = sql->err; + } + return 1; + } + return 0; +} + +static const char *dbd_freetds_escape(apr_pool_t *pool, const char *arg, + apr_dbd_t *sql) +{ + return arg; +} + +static apr_status_t freetds_regfree(void *rx) +{ + regfree((regex_t*)rx); + return APR_SUCCESS; +} +static int recurse_args(apr_pool_t *pool, int n, const char *query, + apr_dbd_prepared_t *stmt, int offs) +{ + + /* we only support %s arguments for now */ + int ret; + char arg[256]; + regmatch_t matches[3]; + if (regexec(&dbd_freetds_find_arg, query, 3, matches, 0) != 0) { + /* No more args */ + stmt->nargs = n; + stmt->taint = apr_palloc(pool, n*sizeof(regex_t*)); + stmt->sz = apr_palloc(pool, n*sizeof(int)); + ret = 0; + } + else { + int i; + int sz = 0; + int len = matches[1].rm_eo - matches[1].rm_so - 2; + if (len > 255) { + return 9999; + } + + ret = recurse_args(pool, n+1, query+matches[0].rm_eo, + stmt, offs+matches[0].rm_eo); + + memmove(stmt->fmt + offs + matches[1].rm_so, + stmt->fmt + offs + matches[0].rm_eo-1, + strlen(stmt->fmt+offs+matches[0].rm_eo)+2); + + /* compile untaint to a regex if found */ + if (matches[1].rm_so == -1) { + stmt->taint[n] = NULL; + } + else { + strncpy(arg, query+matches[1].rm_so+1, + matches[1].rm_eo - matches[1].rm_so - 2); + arg[matches[1].rm_eo - matches[1].rm_so - 2] = '\0'; + stmt->taint[n] = apr_palloc(pool, sizeof(regex_t)); + if (regcomp(stmt->taint[n], arg, REG_ICASE|REG_EXTENDED) != 0) { + ++ret; + } + else { + apr_pool_cleanup_register(pool, stmt->taint[n], freetds_regfree, + apr_pool_cleanup_null); + } + } + + /* record length if specified */ + for (i=matches[2].rm_so; i<matches[2].rm_eo; ++i) { + sz = 10*sz + (query[i]-'\0'); + } + } + return ret; +} + +static int dbd_freetds_prepare(apr_pool_t *pool, apr_dbd_t *sql, + const char *query, const char *label, + int nargs, int nvals, apr_dbd_type_e *types, + apr_dbd_prepared_t **statement) +{ + apr_dbd_prepared_t *stmt; + + if (label == NULL) { + label = apr_psprintf(pool, "%d", labelnum++); + } + + if (!*statement) { + *statement = apr_palloc(pool, sizeof(apr_dbd_prepared_t)); + } + stmt = *statement; + +#if 0 + /* count args */ + stmt->fmt = apr_pstrdup(pool, query); + stmt->fmt = recurse_args(pool, 0, query, stmt, stmt->fmt); + + /* overestimate by a byte or two to simplify */ + len = strlen("CREATE PROC apr.") + + strlen(label) + + stmt->nargs * strlen(" @arg1 varchar(len1),") + + strlen(" AS begin ") + + strlen(stmt->fmt) + + strlen(" end "); /* extra byte for terminator */ + + pquery = apr_pcalloc(pool, len); + sprintf(pquery, "CREATE PROC apr.%s", label); + for (i=0; i<stmt->nargs; ++i) { + sprintf(pquery+strlen(pquery), " @arg%d varchar(%d)", i, stmt->sz[i]); + if (i < stmt->nargs-1) { + pquery[strlen(pquery)] = ','; + } + } + strcat(pquery, " AS BEGIN "); + strcat(pquery, stmt->fmt); + strcat(pquery, " END"); + + return (freetds_exec(sql->proc, pquery, 0, &i) == SUCCEED) ? 0 : 1; +#else + stmt->fmt = apr_pstrdup(pool, query); + return recurse_args(pool, 0, query, stmt, 0); +#endif + +} + +static int dbd_freetds_start_transaction(apr_pool_t *pool, apr_dbd_t *handle, + apr_dbd_transaction_t **trans) +{ + int dummy; + + /* XXX handle recursive transactions here */ + + handle->err = freetds_exec(handle->proc, "BEGIN TRANSACTION", 0, &dummy); + + if (dbd_freetds_is_success(handle->err)) { + if (!*trans) { + *trans = apr_pcalloc(pool, sizeof(apr_dbd_transaction_t)); + } + (*trans)->handle = handle; + handle->trans = *trans; + return 0; + } + + return 1; +} + +static int dbd_freetds_end_transaction(apr_dbd_transaction_t *trans) +{ + int dummy; + if (trans) { + /* rollback on error or explicit rollback request */ + if (trans->errnum) { + trans->errnum = 0; + trans->handle->err = freetds_exec(trans->handle->proc, + "ROLLBACK", 0, &dummy); + } + else { + trans->handle->err = freetds_exec(trans->handle->proc, + "COMMIT", 0, &dummy); + } + trans->handle->trans = NULL; + } + return (trans->handle->err == SUCCEED) ? 0 : 1; +} + +static DBPROCESS *freetds_open(apr_pool_t *pool, const char *params, + const char **error) +{ + char *server = NULL; + DBPROCESS *process; + LOGINREC *login; + static const char *delims = " \r\n\t;|,"; + char *ptr; + char *key; + char *value; + int vlen; + int klen; + char *buf; + char *databaseName = NULL; + + /* FIXME - this uses malloc */ + /* FIXME - pass error message back to the caller in case of failure */ + login = dblogin(); + if (login == NULL) { + return NULL; + } + /* now set login properties */ + for (ptr = strchr(params, '='); ptr; ptr = strchr(ptr, '=')) { + /* don't dereference memory that may not belong to us */ + if (ptr == params) { + ++ptr; + continue; + } + for (key = ptr-1; apr_isspace(*key); --key); + klen = 0; + while (apr_isalpha(*key)) { + --key; + ++klen; + } + ++key; + for (value = ptr+1; apr_isspace(*value); ++value); + + vlen = strcspn(value, delims); + buf = apr_pstrndup(pool, value, vlen); /* NULL-terminated copy */ + + if (!strncasecmp(key, "username", klen)) { + DBSETLUSER(login, buf); + } + else if (!strncasecmp(key, "password", klen)) { + DBSETLPWD(login, buf); + } + else if (!strncasecmp(key, "appname", klen)) { + DBSETLAPP(login, buf); + } + else if (!strncasecmp(key, "dbname", klen)) { + databaseName = buf; + } + else if (!strncasecmp(key, "host", klen)) { + DBSETLHOST(login, buf); + } + else if (!strncasecmp(key, "charset", klen)) { + DBSETLCHARSET(login, buf); + } + else if (!strncasecmp(key, "lang", klen)) { + DBSETLNATLANG(login, buf); + } + else if (!strncasecmp(key, "server", klen)) { + server = buf; + } + else { + /* unknown param */ + } + ptr = value+vlen; + } + + process = dbopen(login, server); + + if (process != NULL && databaseName != NULL) + { + dbuse(process, databaseName); + } + + dbloginfree(login); + if (process == NULL) { + return NULL; + } + + return process; +} +static apr_dbd_t *dbd_freetds_open(apr_pool_t *pool, const char *params, + const char **error) +{ + apr_dbd_t *sql; + /* FIXME - pass error message back to the caller in case of failure */ + DBPROCESS *process = freetds_open(pool, params, error); + if (process == NULL) { + return NULL; + } + sql = apr_pcalloc(pool, sizeof (apr_dbd_t)); + sql->pool = pool; + sql->proc = process; + sql->params = params; + return sql; +} + +static apr_status_t dbd_freetds_close(apr_dbd_t *handle) +{ + dbclose(handle->proc); + return APR_SUCCESS; +} + +static apr_status_t dbd_freetds_check_conn(apr_pool_t *pool, + apr_dbd_t *handle) +{ + if (dbdead(handle->proc)) { + /* try again */ + dbclose(handle->proc); + handle->proc = freetds_open(handle->pool, handle->params, NULL); + if (!handle->proc || dbdead(handle->proc)) { + return APR_EGENERAL; + } + } + /* clear it, in case this is called in error handling */ + dbcancel(handle->proc); + return APR_SUCCESS; +} + +static int dbd_freetds_select_db(apr_pool_t *pool, apr_dbd_t *handle, + const char *name) +{ + /* ouch, it's declared int. But we can use APR 0/nonzero */ + return (dbuse(handle->proc, (char*)name) == SUCCEED) ? APR_SUCCESS : APR_EGENERAL; +} + +static void *dbd_freetds_native(apr_dbd_t *handle) +{ + return handle->proc; +} + +static int dbd_freetds_num_cols(apr_dbd_results_t* res) +{ + return res->sz; +} + +static int dbd_freetds_num_tuples(apr_dbd_results_t* res) +{ + if (res->random) { + return res->ntuples; + } + else { + return -1; + } +} + +static apr_status_t freetds_term(void *dummy) +{ + dbexit(); + regfree(&dbd_freetds_find_arg); + return APR_SUCCESS; +} +static int freetds_err_handler(DBPROCESS *dbproc, int severity, int dberr, + int oserr, char *dberrstr, char *oserrstr) +{ + return INT_CANCEL; /* never exit */ +} +static void dbd_freetds_init(apr_pool_t *pool) +{ + int rv = regcomp(&dbd_freetds_find_arg, + "%(\\{[^}]*\\})?([0-9]*)[A-Za-z]", REG_EXTENDED); + if (rv != 0) { + char errmsg[256]; + regerror(rv, &dbd_freetds_find_arg, errmsg, 256); + fprintf(stderr, "regcomp failed: %s\n", errmsg); + } + dbinit(); + dberrhandle(freetds_err_handler); + apr_pool_cleanup_register(pool, NULL, freetds_term, apr_pool_cleanup_null); +} + +#ifdef COMPILE_STUBS +/* get_name is the only one of these that is implemented */ +static const char *dbd_freetds_get_name(const apr_dbd_results_t *res, int n) +{ + return (const char*) dbcolname(res->proc, n+1); /* numbering starts at 1 */ +} + +/* These are stubs: transaction modes not implemented here */ +#define DBD_NOTIMPL APR_ENOTIMPL; +static int dbd_freetds_transaction_mode_get(apr_dbd_transaction_t *trans) +{ + return trans ? trans->mode : APR_DBD_TRANSACTION_COMMIT; +} + +static int dbd_freetds_transaction_mode_set(apr_dbd_transaction_t *trans, + int mode) +{ + if (trans) { + trans->mode = mode & TXN_MODE_BITS; + return trans->mode; + } + return APR_DBD_TRANSACTION_COMMIT; +} +static int dbd_freetds_pvbquery(apr_pool_t *pool, apr_dbd_t *sql, int *nrows, + apr_dbd_prepared_t *statement, va_list args) +{ + return DBD_NOTIMPL; +} +static int dbd_freetds_pbquery(apr_pool_t *pool, apr_dbd_t *sql, int *nrows, + apr_dbd_prepared_t * statement, + const void **values) +{ + return DBD_NOTIMPL; +} + +static int dbd_freetds_pvbselect(apr_pool_t *pool, apr_dbd_t *sql, + apr_dbd_results_t **results, + apr_dbd_prepared_t *statement, + int seek, va_list args) +{ + return DBD_NOTIMPL; +} +static int dbd_freetds_pbselect(apr_pool_t *pool, apr_dbd_t *sql, + apr_dbd_results_t **results, + apr_dbd_prepared_t *statement, + int seek, const void **values) +{ + return DBD_NOTIMPL; +} +static apr_status_t dbd_freetds_datum_get(const apr_dbd_row_t *row, int n, + apr_dbd_type_e type, void *data) +{ + return APR_ENOTIMPL; +} +#endif + +APR_MODULE_DECLARE_DATA const apr_dbd_driver_t apr_dbd_freetds_driver = { + "freetds", + dbd_freetds_init, + dbd_freetds_native, + dbd_freetds_open, + dbd_freetds_check_conn, + dbd_freetds_close, + dbd_freetds_select_db, + dbd_freetds_start_transaction, + dbd_freetds_end_transaction, + dbd_freetds_query, + dbd_freetds_select, + dbd_freetds_num_cols, + dbd_freetds_num_tuples, + dbd_freetds_get_row, + dbd_freetds_get_entry, + dbd_freetds_error, + dbd_freetds_escape, + dbd_freetds_prepare, + dbd_freetds_pvquery, + dbd_freetds_pvselect, + dbd_freetds_pquery, + dbd_freetds_pselect, + /* this is only implemented to support httpd/2.2 standard usage, + * as in the original DBD implementation. Everything else is NOTIMPL. + */ +#ifdef COMPILE_STUBS + dbd_freetds_get_name, + dbd_freetds_transaction_mode_get, + dbd_freetds_transaction_mode_set, + "", + dbd_freetds_pvbquery, + dbd_freetds_pvbselect, + dbd_freetds_pbquery, + dbd_freetds_pbselect, + dbd_freetds_datum_get +#endif +}; +#endif + +#endif diff --git a/dbd/unsupported/apr_dbd_freetds.dsp b/dbd/unsupported/apr_dbd_freetds.dsp new file mode 100644 index 00000000000..f69ffac4bba --- /dev/null +++ b/dbd/unsupported/apr_dbd_freetds.dsp @@ -0,0 +1,207 @@ +# Microsoft Developer Studio Project File - Name="apr_dbd_freetds" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=apr_dbd_freetds - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "apr_dbd_freetds.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "apr_dbd_freetds.mak" CFG="apr_dbd_freetds - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "apr_dbd_freetds - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "apr_dbd_freetds - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "apr_dbd_freetds - x64 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "apr_dbd_freetds - x64 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "apr_dbd_freetds - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c +# ADD CPP /nologo /MD /W3 /Zi /O2 /Oy- /I "../include" /I "../include/arch/win32" /I "../include/private" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "APU_DSO_MODULE_BUILD" /D APU_HAVE_FREETDS=1 /Fo"$(INTDIR)\" /Fd"$(INTDIR)\apr_dbd_freetds_src" /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o /win32 "NUL" +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o /win32 "NUL" +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /fo"Release/apr_dbd_freetds-1.res" /d DLL_NAME="apr_dbd_freetds" /d "NDEBUG" /d "APU_VERSION_ONLY" /I "../include" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib libTDS.lib /nologo /base:"0x6EF60000" /subsystem:windows /dll /incremental:no /debug /opt:ref +# ADD LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib libTDS.lib /nologo /base:"0x6EF60000" /subsystem:windows /dll /incremental:no /debug /out:"Release\apr_dbd_freetds-1.dll" /pdb:"Release\apr_dbd_freetds-1.pdb" /implib:"Release\apr_dbd_freetds-1.lib" /MACHINE:X86 /opt:ref +# Begin Special Build Tool +TargetPath=Release\apr_dbd_freetds-1.dll +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2 +# End Special Build Tool + +!ELSEIF "$(CFG)" == "apr_dbd_freetds - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /EHsc /c +# ADD CPP /nologo /MDd /W3 /Zi /Od /I "../include" /I "../include/arch/win32" /I "../include/private" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "APU_DSO_MODULE_BUILD" /D APU_HAVE_FREETDS=1 /Fo"$(INTDIR)\" /Fd"$(INTDIR)\apr_dbd_freetds_src" /FD /EHsc /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o /win32 "NUL" +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o /win32 "NUL" +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /fo"Debug/apr_dbd_freetds-1.res" /d DLL_NAME="apr_dbd_freetds" /d "_DEBUG" /d "APU_VERSION_ONLY" /I "../include" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib libTDS.lib /nologo /base:"0x6EF60000" /subsystem:windows /dll /incremental:no /debug +# ADD LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib libTDS.lib /nologo /base:"0x6EF60000" /subsystem:windows /dll /incremental:no /debug /out:"Debug\apr_dbd_freetds-1.dll" /pdb:"Debug\apr_dbd_freetds-1.pdb" /implib:"Debug\apr_dbd_freetds-1.lib" /MACHINE:X86 +# Begin Special Build Tool +TargetPath=Debug\apr_dbd_freetds-1.dll +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2 +# End Special Build Tool + +!ELSEIF "$(CFG)" == "apr_dbd_freetds - x64 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "x64\Release" +# PROP BASE Intermediate_Dir "x64\Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "x64\Release" +# PROP Intermediate_Dir "x64\Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c +# ADD CPP /nologo /MD /W3 /Zi /O2 /Oy- /I "../include" /I "../include/arch/win32" /I "../include/private" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "APU_DSO_MODULE_BUILD" /D APU_HAVE_FREETDS=1 /Fo"$(INTDIR)\" /Fd"$(INTDIR)\apr_dbd_freetds_src" /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o /win32 "NUL" +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o /win32 "NUL" +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /fo"x64/Release/apr_dbd_freetds-1.res" /d DLL_NAME="apr_dbd_freetds" /d "NDEBUG" /d "APU_VERSION_ONLY" /I "../include" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib libTDS.lib /nologo /base:"0x6EF60000" /subsystem:windows /dll /incremental:no /debug /opt:ref +# ADD LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib libTDS.lib /nologo /base:"0x6EF60000" /subsystem:windows /dll /incremental:no /debug /out:"x64\Release\apr_dbd_freetds-1.dll" /pdb:"x64\Release\apr_dbd_freetds-1.pdb" /implib:"x64\Release\apr_dbd_freetds-1.lib" /MACHINE:X64 /opt:ref +# Begin Special Build Tool +TargetPath=x64\Release\apr_dbd_freetds-1.dll +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2 +# End Special Build Tool + +!ELSEIF "$(CFG)" == "apr_dbd_freetds - x64 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "x64\Debug" +# PROP BASE Intermediate_Dir "x64\Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "x64\Debug" +# PROP Intermediate_Dir "x64\Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /EHsc /c +# ADD CPP /nologo /MDd /W3 /Zi /Od /I "../include" /I "../include/arch/win32" /I "../include/private" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "APU_DSO_MODULE_BUILD" /D APU_HAVE_FREETDS=1 /Fo"$(INTDIR)\" /Fd"$(INTDIR)\apr_dbd_freetds_src" /FD /EHsc /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o /win32 "NUL" +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o /win32 "NUL" +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /fo"x64/Debug/apr_dbd_freetds-1.res" /d DLL_NAME="apr_dbd_freetds" /d "_DEBUG" /d "APU_VERSION_ONLY" /I "../include" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib libTDS.lib /nologo /base:"0x6EF60000" /subsystem:windows /dll /incremental:no /debug +# ADD LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib libTDS.lib /nologo /base:"0x6EF60000" /subsystem:windows /dll /incremental:no /debug /out:"x64\Debug\apr_dbd_freetds-1.dll" /pdb:"x64\Debug\apr_dbd_freetds-1.pdb" /implib:"x64\Debug\apr_dbd_freetds-1.lib" /MACHINE:X64 +# Begin Special Build Tool +TargetPath=x64\Debug\apr_dbd_freetds-1.dll +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2 +# End Special Build Tool + +!ENDIF + +# Begin Target + +# Name "apr_dbd_freetds - Win32 Release" +# Name "apr_dbd_freetds - Win32 Debug" +# Name "apr_dbd_freetds - x64 Release" +# Name "apr_dbd_freetds - x64 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\apr_dbd_freetds.c +# End Source File +# End Group +# Begin Group "Public Header Files" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\include\apr_dbd.h +# End Source File +# End Group +# Begin Group "Internal Header Files" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\include\private\apu_config.h +# End Source File +# Begin Source File + +SOURCE=..\include\private\apu_dbd_internal.h +# End Source File +# Begin Source File + +SOURCE=..\include\private\apu_internal.h +# End Source File +# End Group +# Begin Source File + +SOURCE=..\libapr.rc +# End Source File +# End Target +# End Project diff --git a/dbm/NWGNUdbmdb b/dbm/NWGNUdbmdb new file mode 100644 index 00000000000..266d0d06730 --- /dev/null +++ b/dbm/NWGNUdbmdb @@ -0,0 +1,293 @@ +# +# Declare the sub-directories to be built here +# + +SUBDIRS = \ + $(EOLIST) + +# +# Get the 'head' of the build environment. This includes default targets and +# paths to tools +# + +ifndef EnvironmentDefined +include $(APR_WORK)/build/NWGNUhead.inc +endif + +# +# build this level's files + +# +# Make sure all needed macro's are defined +# + +# LINK_STATIC = 1 + +# for now defined here - should finally go into build/NWGNUenvironment.inc +DB_INC = $(DBSDK)/inc +DB_IMP = $(DBSDK)/imp/libdb47.imp +DB_LIB = $(DBSDK)/lib/libdb47.lib +DB_NLM = libdb47 + +# +# These directories will be at the beginning of the include list, followed by +# INCDIRS +# +XINCDIRS += \ + $(APR)/include/arch/netware \ + $(APR)/include \ + $(APR)/include/private \ + $(APR) \ + $(DB_INC) \ + $(EOLIST) + +# +# These flags will come after CFLAGS +# +XCFLAGS += \ + $(EOLIST) + +# +# These defines will come after DEFINES +# +XDEFINES += \ + -DAPU_DSO_MODULE_BUILD \ + -DAPU_HAVE_DB=1 \ + -DAPU_HAVE_DB_VERSION=4 \ + $(EOLIST) + +# +# These flags will be added to the link.opt file +# +XLFLAGS += \ + $(EOLIST) + +ifdef LINK_STATIC +XLFLAGS += \ + $(EOLIST) +else +XLFLAGS += \ + $(EOLIST) +endif + +# +# These values will be appended to the correct variables based on the value of +# RELEASE +# +ifeq "$(RELEASE)" "debug" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +ifeq "$(RELEASE)" "noopt" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +ifeq "$(RELEASE)" "release" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +# +# These are used by the link target if an NLM is being generated +# This is used by the link 'name' directive to name the nlm. If left blank +# TARGET_nlm (see below) will be used. +# +NLM_NAME = dbmdb + +# +# This is used by the link '-desc ' directive. +# If left blank, NLM_NAME will be used. +# +NLM_DESCRIPTION = Apache Portability Runtime Library $(VERSION_STR) DBM Berkeley DB Driver Module + +# +# This is used by the '-threadname' directive. If left blank, +# NLM_NAME Thread will be used. +# +NLM_THREAD_NAME = dbmdb + +# +# If this is specified, it will override VERSION value in +# $(APR_WORK)/build/NWGNUenvironment.inc +# +NLM_VERSION = + +# +# If this is specified, it will override the default of 64K +# +NLM_STACK_SIZE = + +# +# If this is specified it will be used by the link '-entry' directive +# +NLM_ENTRY_SYM = + +# +# If this is specified it will be used by the link '-exit' directive +# +NLM_EXIT_SYM = + +# +# If this is specified it will be used by the link '-check' directive +# +NLM_CHECK_SYM = + +# +# If these are specified it will be used by the link '-flags' directive +# +NLM_FLAGS = + +# +# If this is specified it will be linked in with the XDCData option in the def +# file instead of the default of $(NWOS)/apache.xdc. XDCData can be disabled +# by setting APACHE_UNIPROC in the environment +# +XDCDATA = + +# +# If there is an NLM target, put it here +# +TARGET_nlm = \ + $(OBJDIR)\$(NLM_NAME).nlm \ + $(EOLIST) + +# +# If there is an LIB target, put it here +# +TARGET_lib = \ + $(EOLIST) + +# +# These are the OBJ files needed to create the NLM target above. +# Paths must all use the '/' character +# +FILES_nlm_objs = \ + $(OBJDIR)/apr_dbm_berkeleydb.o \ + $(EOLIST) + +# +# These are the LIB files needed to create the NLM target above. +# These will be added as a library command in the link.opt file. +# +FILES_nlm_libs = \ + $(PRELUDE) \ + $(EOLIST) + +ifeq ($(LINK_STATIC),1) +FILES_nlm_libs += \ + $(DB_LIB) \ + $(EOLIST) +endif + +# +# These are the modules that the above NLM target depends on to load. +# These will be added as a module command in the link.opt file. +# +FILES_nlm_modules = \ + aprlib \ + libc \ + $(EOLIST) + +ifneq ($(LINK_STATIC),1) +FILES_nlm_modules += \ + $(DB_NLM) \ + $(EOLIST) +endif + +# +# If the nlm has a msg file, put it's path here +# +FILE_nlm_msg = + +# +# If the nlm has a hlp file put it's path here +# +FILE_nlm_hlp = + +# +# If this is specified, it will override $(NWOS)\copyright.txt. +# +FILE_nlm_copyright = + +# +# Any additional imports go here +# +FILES_nlm_Ximports = \ + @$(APR)/aprlib.imp \ + @$(NOVI)/libc.imp \ + $(EOLIST) + +ifneq ($(LINK_STATIC),1) +FILES_nlm_Ximports += \ + @$(DB_IMP) \ + $(EOLIST) +endif + +# +# Any symbols exported to here +# +FILES_nlm_exports = \ + apr_dbm_type_db \ + $(EOLIST) + +# +# These are the OBJ files needed to create the LIB target above. +# Paths must all use the '/' character +# +FILES_lib_objs = \ + $(EOLIST) + +# +# implement targets and dependancies (leave this section alone) +# + +libs :: $(OBJDIR) $(TARGET_lib) + +nlms :: libs $(TARGET_nlm) + +# +# Updated this target to create necessary directories and copy files to the +# correct place. (See $(APR_WORK)/build/NWGNUhead.inc for examples) +# +install :: nlms FORCE + +# +# Any specialized rules here +# + +# +# Include the 'tail' makefile that has targets that depend on variables defined +# in this makefile +# + +include $(APRBUILD)/NWGNUtail.inc + diff --git a/dbm/NWGNUdbmgdbm b/dbm/NWGNUdbmgdbm new file mode 100644 index 00000000000..f72ce53e634 --- /dev/null +++ b/dbm/NWGNUdbmgdbm @@ -0,0 +1,292 @@ +# +# Declare the sub-directories to be built here +# + +SUBDIRS = \ + $(EOLIST) + +# +# Get the 'head' of the build environment. This includes default targets and +# paths to tools +# + +ifndef EnvironmentDefined +include $(APR_WORK)/build/NWGNUhead.inc +endif + +# +# build this level's files + +# +# Make sure all needed macro's are defined +# + +# LINK_STATIC = 1 + +# for now defined here - should finally go into build/NWGNUenvironment.inc +GDBM_INC = $(GDBMSDK)/inc +GDBM_IMP = $(GDBMSDK)/imp/libgdbm.imp +GDBM_LIB = $(GDBMSDK)/lib/libgdbm.lib +GDBM_NLM = libgdbm + +# +# These directories will be at the beginning of the include list, followed by +# INCDIRS +# +XINCDIRS += \ + $(APR)/include/arch/netware \ + $(APR)/include \ + $(APR)/include/private \ + $(APR) \ + $(GDBM_INC) \ + $(EOLIST) + +# +# These flags will come after CFLAGS +# +XCFLAGS += \ + $(EOLIST) + +# +# These defines will come after DEFINES +# +XDEFINES += \ + -DAPU_DSO_MODULE_BUILD \ + -DAPU_HAVE_GDBM=1 \ + $(EOLIST) + +# +# These flags will be added to the link.opt file +# +XLFLAGS += \ + $(EOLIST) + +ifdef LINK_STATIC +XLFLAGS += \ + $(EOLIST) +else +XLFLAGS += \ + $(EOLIST) +endif + +# +# These values will be appended to the correct variables based on the value of +# RELEASE +# +ifeq "$(RELEASE)" "debug" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +ifeq "$(RELEASE)" "noopt" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +ifeq "$(RELEASE)" "release" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +# +# These are used by the link target if an NLM is being generated +# This is used by the link 'name' directive to name the nlm. If left blank +# TARGET_nlm (see below) will be used. +# +NLM_NAME = dbmgdbm + +# +# This is used by the link '-desc ' directive. +# If left blank, NLM_NAME will be used. +# +NLM_DESCRIPTION = Apache Portability Runtime Library $(VERSION_STR) GDBM Driver Module + +# +# This is used by the '-threadname' directive. If left blank, +# NLM_NAME Thread will be used. +# +NLM_THREAD_NAME = dbmgdbm + +# +# If this is specified, it will override VERSION value in +# $(APR_WORK)/build/NWGNUenvironment.inc +# +NLM_VERSION = + +# +# If this is specified, it will override the default of 64K +# +NLM_STACK_SIZE = + +# +# If this is specified it will be used by the link '-entry' directive +# +NLM_ENTRY_SYM = + +# +# If this is specified it will be used by the link '-exit' directive +# +NLM_EXIT_SYM = + +# +# If this is specified it will be used by the link '-check' directive +# +NLM_CHECK_SYM = + +# +# If these are specified it will be used by the link '-flags' directive +# +NLM_FLAGS = + +# +# If this is specified it will be linked in with the XDCData option in the def +# file instead of the default of $(NWOS)/apache.xdc. XDCData can be disabled +# by setting APACHE_UNIPROC in the environment +# +XDCDATA = + +# +# If there is an NLM target, put it here +# +TARGET_nlm = \ + $(OBJDIR)\$(NLM_NAME).nlm \ + $(EOLIST) + +# +# If there is an LIB target, put it here +# +TARGET_lib = \ + $(EOLIST) + +# +# These are the OBJ files needed to create the NLM target above. +# Paths must all use the '/' character +# +FILES_nlm_objs = \ + $(OBJDIR)/apr_dbm_gdbm.o \ + $(EOLIST) + +# +# These are the LIB files needed to create the NLM target above. +# These will be added as a library command in the link.opt file. +# +FILES_nlm_libs = \ + $(PRELUDE) \ + $(EOLIST) + +ifeq ($(LINK_STATIC),1) +FILES_nlm_libs += \ + $(GDBM_LIB) \ + $(EOLIST) +endif + +# +# These are the modules that the above NLM target depends on to load. +# These will be added as a module command in the link.opt file. +# +FILES_nlm_modules = \ + aprlib \ + libc \ + $(EOLIST) + +ifneq ($(LINK_STATIC),1) +FILES_nlm_modules += \ + $(GDBM_NLM) \ + $(EOLIST) +endif + +# +# If the nlm has a msg file, put it's path here +# +FILE_nlm_msg = + +# +# If the nlm has a hlp file put it's path here +# +FILE_nlm_hlp = + +# +# If this is specified, it will override $(NWOS)\copyright.txt. +# +FILE_nlm_copyright = + +# +# Any additional imports go here +# +FILES_nlm_Ximports = \ + @$(APR)/aprlib.imp \ + @$(NOVI)/libc.imp \ + $(EOLIST) + +ifneq ($(LINK_STATIC),1) +FILES_nlm_Ximports += \ + @$(GDBM_IMP) \ + $(EOLIST) +endif + +# +# Any symbols exported to here +# +FILES_nlm_exports = \ + apr_dbm_type_gdbm \ + $(EOLIST) + +# +# These are the OBJ files needed to create the LIB target above. +# Paths must all use the '/' character +# +FILES_lib_objs = \ + $(EOLIST) + +# +# implement targets and dependancies (leave this section alone) +# + +libs :: $(OBJDIR) $(TARGET_lib) + +nlms :: libs $(TARGET_nlm) + +# +# Updated this target to create necessary directories and copy files to the +# correct place. (See $(APR_WORK)/build/NWGNUhead.inc for examples) +# +install :: nlms FORCE + +# +# Any specialized rules here +# + +# +# Include the 'tail' makefile that has targets that depend on variables defined +# in this makefile +# + +include $(APRBUILD)/NWGNUtail.inc + diff --git a/dbm/NWGNUmakefile b/dbm/NWGNUmakefile new file mode 100644 index 00000000000..228a45d11d2 --- /dev/null +++ b/dbm/NWGNUmakefile @@ -0,0 +1,251 @@ +# +# Declare the sub-directories to be built here +# + +SUBDIRS = \ + $(EOLIST) + +# +# Get the 'head' of the build environment. This includes default targets and +# paths to tools +# + +include $(APR_WORK)/build/NWGNUhead.inc + +# +# build this level's files + +# +# Make sure all needed macro's are defined +# + +# +# These directories will be at the beginning of the include list, followed by +# INCDIRS +# +XINCDIRS += \ + $(EOLIST) + +# +# These flags will come after CFLAGS +# +XCFLAGS += \ + $(EOLIST) + +# +# These defines will come after DEFINES +# +XDEFINES += \ + $(EOLIST) + +# +# These flags will be added to the link.opt file +# +XLFLAGS += \ + $(EOLIST) + +# +# These values will be appended to the correct variables based on the value of +# RELEASE +# +ifeq "$(RELEASE)" "debug" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +ifeq "$(RELEASE)" "noopt" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +ifeq "$(RELEASE)" "release" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +# +# These are used by the link target if an NLM is being generated +# This is used by the link 'name' directive to name the nlm. If left blank +# TARGET_nlm (see below) will be used. +# +NLM_NAME = + +# +# This is used by the link '-desc ' directive. +# If left blank, NLM_NAME will be used. +# +NLM_DESCRIPTION = + +# +# This is used by the '-threadname' directive. If left blank, +# NLM_NAME Thread will be used. +# +NLM_THREAD_NAME = + +# +# If this is specified, it will override VERSION value in +# $(APR_WORK)/build/NWGNUenvironment.inc +# +NLM_VERSION = + +# +# If this is specified, it will override the default of 64K +# +NLM_STACK_SIZE = + + +# +# If this is specified it will be used by the link '-entry' directive +# +NLM_ENTRY_SYM = + +# +# If this is specified it will be used by the link '-exit' directive +# +NLM_EXIT_SYM = + +# +# If this is specified it will be used by the link '-check' directive +# +NLM_CHECK_SYM = + +# +# If these are specified it will be used by the link '-flags' directive +# +NLM_FLAGS = + +# +# If this is specified it will be linked in with the XDCData option in the def +# file instead of the default of $(NWOS)/apache.xdc. XDCData can be disabled +# by setting APACHE_UNIPROC in the environment +# +XDCDATA = + +# +# If there is an NLM target, put it here +# +TARGET_nlm = \ + $(EOLIST) + +ifeq "$(APU_HAVE_DB)" "1" +TARGET_nlm += $(OBJDIR)/dbmdb.nlm $(OBJDIR)/dbmdb.nlm $(EOLIST) +endif +ifeq "$(APU_HAVE_GDBM)" "1" +TARGET_nlm += $(OBJDIR)/dbmgdbm.nlm $(OBJDIR)/dbmgdbm.nlm $(EOLIST) +endif + +# +# If there is an LIB target, put it here +# +TARGET_lib = \ + $(EOLIST) + +# +# These are the OBJ files needed to create the NLM target above. +# Paths must all use the '/' character +# +FILES_nlm_objs = \ + $(EOLIST) + +# +# These are the LIB files needed to create the NLM target above. +# These will be added as a library command in the link.opt file. +# +FILES_nlm_libs = \ + $(EOLIST) + +# +# These are the modules that the above NLM target depends on to load. +# These will be added as a module command in the link.opt file. +# +FILES_nlm_modules = \ + $(EOLIST) + +# +# If the nlm has a msg file, put it's path here +# +FILE_nlm_msg = + +# +# If the nlm has a hlp file put it's path here +# +FILE_nlm_hlp = + +# +# If this is specified, it will override $(NWOS)\copyright.txt. +# +FILE_nlm_copyright = + +# +# Any additional imports go here +# +FILES_nlm_Ximports = \ + $(EOLIST) + +# +# Any symbols exported to here +# +FILES_nlm_exports = \ + $(EOLIST) + +# +# These are the OBJ files needed to create the LIB target above. +# Paths must all use the '/' character +# +FILES_lib_objs = \ + $(EOLIST) + +# +# implement targets and dependancies (leave this section alone) +# + +libs :: $(OBJDIR) $(TARGET_lib) + +nlms :: libs $(TARGET_nlm) + +# +# Updated this target to create necessary directories and copy files to the +# correct place. (See $(APR_WORK)/build/NWGNUhead.inc for examples) +# +install :: nlms $(INSTDIRS) FORCE + $(call COPY,$(OBJDIR)/*.nlm,$(INSTALLBASE)/) + +# +# Any specialized rules here +# + +# +# Include the 'tail' makefile that has targets that depend on variables defined +# in this makefile +# + +include $(APRBUILD)/NWGNUtail.inc + + diff --git a/dbm/apr_dbm.c b/dbm/apr_dbm.c new file mode 100644 index 00000000000..71ba113ec47 --- /dev/null +++ b/dbm/apr_dbm.c @@ -0,0 +1,307 @@ +/* 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_dso.h" +#include "apr_hash.h" +#include "apr_errno.h" +#include "apr_pools.h" +#include "apr_strings.h" +#define APR_WANT_MEMFUNC +#define APR_WANT_STRFUNC +#include "apr_want.h" +#include "apr_general.h" +#include "apr_atomic.h" + +#include "apu.h" +#include "apr_private.h" +#include "apu_internal.h" +#include "apr_version.h" +#include "apr_dbm_private.h" +#include "apu_select_dbm.h" +#include "apr_dbm.h" +#include "apr_dbm_private.h" + +/* ### note: the setting of DBM_VTABLE will go away once we have multiple + ### DBMs in here. + ### Well, that day is here. So, do we remove DBM_VTABLE and the old + ### API entirely? Oh, what to do. We need an APU_DEFAULT_DBM #define. + ### Sounds like a job for autoconf. */ + +#if APU_USE_DB +#define DBM_VTABLE apr_dbm_type_db +#define DBM_NAME "db" +#elif APU_USE_GDBM +#define DBM_VTABLE apr_dbm_type_gdbm +#define DBM_NAME "gdbm" +#elif APU_USE_NDBM +#define DBM_VTABLE apr_dbm_type_ndbm +#define DBM_NAME "ndbm" +#elif APU_USE_SDBM +#define DBM_VTABLE apr_dbm_type_sdbm +#define DBM_NAME "sdbm" +#else /* Not in the USE_xDBM list above */ +#error a DBM implementation was not specified +#endif + +#if APR_HAVE_MODULAR_DSO + +static apr_hash_t *drivers = NULL; +static apr_uint32_t initialised = 0, in_init = 1; + +static apr_status_t dbm_term(void *ptr) +{ + /* set drivers to NULL so init can work again */ + drivers = NULL; + + /* Everything else we need is handled by cleanups registered + * when we created mutexes and loaded DSOs + */ + return APR_SUCCESS; +} + +#endif /* APR_HAVE_MODULAR_DSO */ + +static apr_status_t dbm_open_type(apr_dbm_type_t const* * vtable, + const char *type, + apr_pool_t *pool) +{ +#if !APR_HAVE_MODULAR_DSO + + *vtable = NULL; + if (!strcasecmp(type, "default")) *vtable = &DBM_VTABLE; +#if APU_HAVE_DB + else if (!strcasecmp(type, "db")) *vtable = &apr_dbm_type_db; +#endif + else if (*type && !strcasecmp(type + 1, "dbm")) { +#if APU_HAVE_GDBM + if (*type == 'G' || *type == 'g') *vtable = &apr_dbm_type_gdbm; +#endif +#if APU_HAVE_NDBM + if (*type == 'N' || *type == 'n') *vtable = &apr_dbm_type_ndbm; +#endif +#if APU_HAVE_SDBM + if (*type == 'S' || *type == 's') *vtable = &apr_dbm_type_sdbm; +#endif + /* avoid empty block */ ; + } + if (*vtable) + return APR_SUCCESS; + return APR_ENOTIMPL; + +#else /* APR_HAVE_MODULAR_DSO */ + + char modname[32]; + char symname[34]; + apr_dso_handle_sym_t symbol; + apr_status_t rv; + int usertype = 0; + + if (!strcasecmp(type, "default")) type = DBM_NAME; + else if (!strcasecmp(type, "db")) type = "db"; + else if (*type && !strcasecmp(type + 1, "dbm")) { + if (*type == 'G' || *type == 'g') type = "gdbm"; + else if (*type == 'N' || *type == 'n') type = "ndbm"; + else if (*type == 'S' || *type == 's') type = "sdbm"; + } + else usertype = 1; + + if (apr_atomic_inc32(&initialised)) { + apr_atomic_set32(&initialised, 1); /* prevent wrap-around */ + + while (apr_atomic_read32(&in_init)) /* wait until we get fully inited */ + ; + } + else { + apr_pool_t *parent; + + /* Top level pool scope, need process-scope lifetime */ + for (parent = apr_pool_parent_get(pool); + parent && parent != pool; + parent = apr_pool_parent_get(pool)) + pool = parent; + + /* deprecate in 2.0 - permit implicit initialization */ + apu_dso_init(pool); + + drivers = apr_hash_make(pool); + apr_hash_set(drivers, "sdbm", APR_HASH_KEY_STRING, &apr_dbm_type_sdbm); + + apr_pool_cleanup_register(pool, NULL, dbm_term, + apr_pool_cleanup_null); + + apr_atomic_dec32(&in_init); + } + + rv = apu_dso_mutex_lock(); + if (rv) { + *vtable = NULL; + return rv; + } + + *vtable = apr_hash_get(drivers, type, APR_HASH_KEY_STRING); + if (*vtable) { + apu_dso_mutex_unlock(); + return APR_SUCCESS; + } + + /* The driver DSO must have exactly the same lifetime as the + * drivers hash table; ignore the passed-in pool */ + pool = apr_hash_pool_get(drivers); + +#if defined(NETWARE) + apr_snprintf(modname, sizeof(modname), "dbm%s.nlm", type); +#elif defined(WIN32) || defined (__CYGWIN__) + apr_snprintf(modname, sizeof(modname), + "apr_dbm_%s-" APR_STRINGIFY(APR_MAJOR_VERSION) ".dll", type); +#else + apr_snprintf(modname, sizeof(modname), + "apr_dbm_%s-" APR_STRINGIFY(APR_MAJOR_VERSION) ".so", type); +#endif + apr_snprintf(symname, sizeof(symname), "apr_dbm_type_%s", type); + + rv = apu_dso_load(NULL, &symbol, modname, symname, pool); + if (rv == APR_SUCCESS || rv == APR_EINIT) { /* previously loaded?!? */ + *vtable = symbol; + if (usertype) + type = apr_pstrdup(pool, type); + apr_hash_set(drivers, type, APR_HASH_KEY_STRING, *vtable); + rv = APR_SUCCESS; + } + else + *vtable = NULL; + + apu_dso_mutex_unlock(); + return rv; + +#endif /* APR_HAVE_MODULAR_DSO */ +} + +APR_DECLARE(apr_status_t) apr_dbm_open_ex(apr_dbm_t **pdb, const char *type, + const char *pathname, + apr_int32_t mode, + apr_fileperms_t perm, + apr_pool_t *pool) +{ + apr_dbm_type_t const* vtable = NULL; + apr_status_t rv = dbm_open_type(&vtable, type, pool); + + if (rv == APR_SUCCESS) { + rv = (vtable->open)(pdb, pathname, mode, perm, pool); + } + return rv; +} + +APR_DECLARE(apr_status_t) apr_dbm_open(apr_dbm_t **pdb, const char *pathname, + apr_int32_t mode, apr_fileperms_t perm, + apr_pool_t *pool) +{ + return apr_dbm_open_ex(pdb, DBM_NAME, pathname, mode, perm, pool); +} + +APR_DECLARE(void) apr_dbm_close(apr_dbm_t *dbm) +{ + (*dbm->type->close)(dbm); +} + +APR_DECLARE(apr_status_t) apr_dbm_fetch(apr_dbm_t *dbm, apr_datum_t key, + apr_datum_t *pvalue) +{ + return (*dbm->type->fetch)(dbm, key, pvalue); +} + +APR_DECLARE(apr_status_t) apr_dbm_store(apr_dbm_t *dbm, apr_datum_t key, + apr_datum_t value) +{ + return (*dbm->type->store)(dbm, key, value); +} + +APR_DECLARE(apr_status_t) apr_dbm_delete(apr_dbm_t *dbm, apr_datum_t key) +{ + return (*dbm->type->del)(dbm, key); +} + +APR_DECLARE(int) apr_dbm_exists(apr_dbm_t *dbm, apr_datum_t key) +{ + return (*dbm->type->exists)(dbm, key); +} + +APR_DECLARE(apr_status_t) apr_dbm_firstkey(apr_dbm_t *dbm, apr_datum_t *pkey) +{ + return (*dbm->type->firstkey)(dbm, pkey); +} + +APR_DECLARE(apr_status_t) apr_dbm_nextkey(apr_dbm_t *dbm, apr_datum_t *pkey) +{ + return (*dbm->type->nextkey)(dbm, pkey); +} + +APR_DECLARE(void) apr_dbm_freedatum(apr_dbm_t *dbm, apr_datum_t data) +{ + (*dbm->type->freedatum)(dbm, data); +} + +APR_DECLARE(char *) apr_dbm_geterror(apr_dbm_t *dbm, int *errcode, + char *errbuf, apr_size_t errbufsize) +{ + if (errcode != NULL) + *errcode = dbm->errcode; + + /* assert: errbufsize > 0 */ + + if (dbm->errmsg == NULL) + *errbuf = '\0'; + else + (void) apr_cpystrn(errbuf, dbm->errmsg, errbufsize); + return errbuf; +} + +APR_DECLARE(apr_status_t) apr_dbm_get_usednames_ex(apr_pool_t *p, + const char *type, + const char *pathname, + const char **used1, + const char **used2) +{ + apr_dbm_type_t const* vtable; + apr_status_t rv = dbm_open_type(&vtable, type, p); + + if (rv == APR_SUCCESS) { + (vtable->getusednames)(p, pathname, used1, used2); + return APR_SUCCESS; + } + return rv; +} + +APR_DECLARE(void) apr_dbm_get_usednames(apr_pool_t *p, + const char *pathname, + const char **used1, + const char **used2) +{ + apr_dbm_get_usednames_ex(p, DBM_NAME, pathname, used1, used2); +} + +/* Most DBM libraries take a POSIX mode for creating files. Don't trust + * the mode_t type, some platforms may not support it, int is safe. + */ +APR_DECLARE(int) apr_posix_perms2mode(apr_fileperms_t perm) +{ + int mode = 0; + + mode |= 0700 & (perm >> 2); /* User is off-by-2 bits */ + mode |= 0070 & (perm >> 1); /* Group is off-by-1 bit */ + mode |= 0007 & (perm); /* World maps 1 for 1 */ + return mode; +} diff --git a/dbm/apr_dbm_berkeleydb.c b/dbm/apr_dbm_berkeleydb.c new file mode 100644 index 00000000000..37e36bd22e0 --- /dev/null +++ b/dbm/apr_dbm_berkeleydb.c @@ -0,0 +1,404 @@ +/* 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_strings.h" +#define APR_WANT_MEMFUNC +#include "apr_want.h" + +#define APU_WANT_DB +#include "apu_want.h" + +#if APR_HAVE_STDLIB_H +#include <stdlib.h> /* for abort() */ +#endif + +#include "apu.h" +#include "apr_private.h" + +#if APU_HAVE_DB +#include "apr_dbm_private.h" + +/* + * We pick up all varieties of Berkeley DB through db.h (included through + * apu_select_dbm.h). This code has been compiled/tested against DB1, + * DB_185, DB2, DB3, and DB4. + */ + +#if defined(DB_VERSION_MAJOR) && (DB_VERSION_MAJOR >= 4) +/* We will treat anything greater than 4.1 as DB4. + * We can treat 4.0 as DB3. + */ +#if DB_VERSION_MAJOR > 4 || (defined(DB_VERSION_MINOR) && (DB_VERSION_MINOR >= 1)) +#define DB_VER 4 +#elif DB_VERSION_MAJOR == 4 +#define DB_VER 3 +#endif +#elif defined(DB_VERSION_MAJOR) && (DB_VERSION_MAJOR == 3) +#define DB_VER 3 +#elif defined(DB_VERSION_MAJOR) && (DB_VERSION_MAJOR == 2) +#define DB_VER 2 +#else +#define DB_VER 1 +#endif + +typedef struct { + DB *bdb; +#if DB_VER != 1 + DBC *curs; +#endif +} real_file_t; + + +#if DB_VER == 1 +#define TXN_ARG +#else +#define TXN_ARG NULL, +#endif + +#define GET_BDB(f) (((real_file_t *)(f))->bdb) + +#define do_fetch(bdb, k, v) ((*(bdb)->get)(bdb, TXN_ARG &(k), &(v), 0)) + +#if DB_VER == 1 +#include <sys/fcntl.h> +#define APR_DBM_DBMODE_RO O_RDONLY +#define APR_DBM_DBMODE_RW O_RDWR +#define APR_DBM_DBMODE_RWCREATE (O_CREAT | O_RDWR) +#define APR_DBM_DBMODE_RWTRUNC (O_CREAT | O_RDWR | O_TRUNC) +#else +#define APR_DBM_DBMODE_RO DB_RDONLY +#define APR_DBM_DBMODE_RW 0 +#define APR_DBM_DBMODE_RWCREATE DB_CREATE +#define APR_DBM_DBMODE_RWTRUNC DB_TRUNCATE +#endif /* DBVER == 1 */ + +/* -------------------------------------------------------------------------- +** +** UTILITY FUNCTIONS +*/ + +/* map a DB error to an apr_status_t */ +static apr_status_t db2s(int dberr) +{ + if (dberr != 0) { + /* ### need to fix this */ + return APR_OS_START_USEERR + dberr; + } + + return APR_SUCCESS; +} + + +static apr_status_t set_error(apr_dbm_t *dbm, apr_status_t dbm_said) +{ + apr_status_t rv = APR_SUCCESS; + + /* ### ignore whatever the DBM said (dbm_said); ask it explicitly */ + + if (dbm_said == APR_SUCCESS) { + dbm->errcode = 0; + dbm->errmsg = NULL; + } + else { + /* ### need to fix. dberr was tossed in db2s(). */ + /* ### use db_strerror() */ + dbm->errcode = dbm_said; +#if DB_VER == 1 || DB_VER == 2 + dbm->errmsg = NULL; +#else + dbm->errmsg = db_strerror(dbm_said - APR_OS_START_USEERR); +#endif + rv = dbm_said; + } + + return rv; +} + +/* -------------------------------------------------------------------------- +** +** DEFINE THE VTABLE FUNCTIONS FOR BERKELEY DB +** +** ### we may need three sets of these: db1, db2, db3 +*/ + +static apr_status_t vt_db_open(apr_dbm_t **pdb, const char *pathname, + apr_int32_t mode, apr_fileperms_t perm, + apr_pool_t *pool) +{ + real_file_t file; + int dbmode; + + *pdb = NULL; + + switch (mode) { + case APR_DBM_READONLY: + dbmode = APR_DBM_DBMODE_RO; + break; + case APR_DBM_READWRITE: + dbmode = APR_DBM_DBMODE_RW; + break; + case APR_DBM_RWCREATE: + dbmode = APR_DBM_DBMODE_RWCREATE; + break; + case APR_DBM_RWTRUNC: + dbmode = APR_DBM_DBMODE_RWTRUNC; + break; + default: + return APR_EINVAL; + } + + { + int dberr; + +#if DB_VER >= 3 + if ((dberr = db_create(&file.bdb, NULL, 0)) == 0) { + if ((dberr = (*file.bdb->open)(file.bdb, +#if DB_VER == 4 + NULL, +#endif + pathname, NULL, + DB_HASH, dbmode, + apr_posix_perms2mode(perm))) != 0) { + /* close the DB handler */ + (void) (*file.bdb->close)(file.bdb, 0); + } + } + file.curs = NULL; +#elif DB_VER == 2 + dberr = db_open(pathname, DB_HASH, dbmode, apr_posix_perms2mode(perm), + NULL, NULL, &file.bdb); + file.curs = NULL; +#else + file.bdb = dbopen(pathname, dbmode, apr_posix_perms2mode(perm), + DB_HASH, NULL); + if (file.bdb == NULL) + return APR_EGENERAL; /* ### need a better error */ + dberr = 0; +#endif + if (dberr != 0) + return db2s(dberr); + } + + /* we have an open database... return it */ + *pdb = apr_pcalloc(pool, sizeof(**pdb)); + (*pdb)->pool = pool; + (*pdb)->type = &apr_dbm_type_db; + (*pdb)->file = apr_pmemdup(pool, &file, sizeof(file)); + + /* ### register a cleanup to close the DBM? */ + + return APR_SUCCESS; +} + +static void vt_db_close(apr_dbm_t *dbm) +{ + (*GET_BDB(dbm->file)->close)(GET_BDB(dbm->file) +#if DB_VER != 1 + , 0 +#endif + ); +} + +static apr_status_t vt_db_fetch(apr_dbm_t *dbm, apr_datum_t key, + apr_datum_t * pvalue) +{ + DBT ckey = { 0 }; + DBT rd = { 0 }; + int dberr; + + ckey.data = key.dptr; + ckey.size = key.dsize; + + dberr = do_fetch(GET_BDB(dbm->file), ckey, rd); + + /* "not found" is not an error. return zero'd value. */ + if (dberr == +#if DB_VER == 1 + RET_SPECIAL +#else + DB_NOTFOUND +#endif + ) { + memset(&rd, 0, sizeof(rd)); + dberr = 0; + } + + pvalue->dptr = rd.data; + pvalue->dsize = rd.size; + + /* store the error info into DBM, and return a status code. Also, note + that *pvalue should have been cleared on error. */ + return set_error(dbm, db2s(dberr)); +} + +static apr_status_t vt_db_store(apr_dbm_t *dbm, apr_datum_t key, + apr_datum_t value) +{ + apr_status_t rv; + DBT ckey = { 0 }; + DBT cvalue = { 0 }; + + ckey.data = key.dptr; + ckey.size = key.dsize; + + cvalue.data = value.dptr; + cvalue.size = value.dsize; + + rv = db2s((*GET_BDB(dbm->file)->put)(GET_BDB(dbm->file), + TXN_ARG + &ckey, + &cvalue, + 0)); + + /* store any error info into DBM, and return a status code. */ + return set_error(dbm, rv); +} + +static apr_status_t vt_db_del(apr_dbm_t *dbm, apr_datum_t key) +{ + apr_status_t rv; + DBT ckey = { 0 }; + + ckey.data = key.dptr; + ckey.size = key.dsize; + + rv = db2s((*GET_BDB(dbm->file)->del)(GET_BDB(dbm->file), + TXN_ARG + &ckey, + 0)); + + /* store any error info into DBM, and return a status code. */ + return set_error(dbm, rv); +} + +static int vt_db_exists(apr_dbm_t *dbm, apr_datum_t key) +{ + DBT ckey = { 0 }; /* converted key */ + DBT data = { 0 }; + int dberr; + + ckey.data = key.dptr; + ckey.size = key.dsize; + + dberr = do_fetch(GET_BDB(dbm->file), ckey, data); + + /* note: the result data is "loaned" to us; we don't need to free it */ + + /* DB returns DB_NOTFOUND if it doesn't exist. but we want to say + that *any* error means it doesn't exist. */ + return dberr == 0; +} + +static apr_status_t vt_db_firstkey(apr_dbm_t *dbm, apr_datum_t * pkey) +{ + real_file_t *f = dbm->file; + DBT first = { 0 }; + DBT data = { 0 }; + int dberr; + +#if DB_VER == 1 + dberr = (*f->bdb->seq)(f->bdb, &first, &data, R_FIRST); +#else + if ((dberr = (*f->bdb->cursor)(f->bdb, NULL, &f->curs +#if DB_VER >= 3 || ((DB_VERSION_MAJOR == 2) && (DB_VERSION_MINOR > 5)) + , 0 +#endif + )) == 0) { + dberr = (*f->curs->c_get)(f->curs, &first, &data, DB_FIRST); + if (dberr == DB_NOTFOUND) { + memset(&first, 0, sizeof(first)); + (*f->curs->c_close)(f->curs); + f->curs = NULL; + dberr = 0; + } + } +#endif + + pkey->dptr = first.data; + pkey->dsize = first.size; + + /* store any error info into DBM, and return a status code. */ + return set_error(dbm, db2s(dberr)); +} + +static apr_status_t vt_db_nextkey(apr_dbm_t *dbm, apr_datum_t * pkey) +{ + real_file_t *f = dbm->file; + DBT ckey = { 0 }; + DBT data = { 0 }; + int dberr; + + ckey.data = pkey->dptr; + ckey.size = pkey->dsize; + +#if DB_VER == 1 + dberr = (*f->bdb->seq)(f->bdb, &ckey, &data, R_NEXT); + if (dberr == RET_SPECIAL) { + dberr = 0; + ckey.data = NULL; + ckey.size = 0; + } +#else + if (f->curs == NULL) + return APR_EINVAL; + + dberr = (*f->curs->c_get)(f->curs, &ckey, &data, DB_NEXT); + if (dberr == DB_NOTFOUND) { + (*f->curs->c_close)(f->curs); + f->curs = NULL; + dberr = 0; + ckey.data = NULL; + ckey.size = 0; + } +#endif + + pkey->dptr = ckey.data; + pkey->dsize = ckey.size; + + /* store any error info into DBM, and return a status code. */ + /* ### or use db2s(dberr) instead of APR_SUCCESS? */ + return set_error(dbm, APR_SUCCESS); +} + +static void vt_db_freedatum(apr_dbm_t *dbm, apr_datum_t data) +{ + /* nothing to do */ +} + +static void vt_db_usednames(apr_pool_t *pool, const char *pathname, + const char **used1, const char **used2) +{ + *used1 = apr_pstrdup(pool, pathname); + *used2 = NULL; +} + + +APR_MODULE_DECLARE_DATA const apr_dbm_type_t apr_dbm_type_db = { + "db", + + vt_db_open, + vt_db_close, + vt_db_fetch, + vt_db_store, + vt_db_del, + vt_db_exists, + vt_db_firstkey, + vt_db_nextkey, + vt_db_freedatum, + vt_db_usednames +}; + +#endif /* APU_HAVE_DB */ diff --git a/dbm/apr_dbm_db.dsp b/dbm/apr_dbm_db.dsp new file mode 100644 index 00000000000..78d7fde7e6e --- /dev/null +++ b/dbm/apr_dbm_db.dsp @@ -0,0 +1,215 @@ +# Microsoft Developer Studio Project File - Name="apr_dbm_db" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=apr_dbm_db - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "apr_dbm_db.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "apr_dbm_db.mak" CFG="apr_dbm_db - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "apr_dbm_db - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "apr_dbm_db - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "apr_dbm_db - x64 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "apr_dbm_db - x64 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "apr_dbm_db - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c +# ADD CPP /nologo /MD /W3 /Zi /O2 /Oy- /I "../include" /I "../include/arch/win32" /I "../include/private" /I "../../db" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "APU_DSO_MODULE_BUILD" /D APU_HAVE_DB=1 /D APU_HAVE_DB_VERSION=4 /Fo"$(INTDIR)\" /Fd"$(INTDIR)\apr_dbm_db_src" /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o /win32 "NUL" +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o /win32 "NUL" +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /fo"Release/apr_dbm_db-1.res" /d DLL_NAME="apr_dbm_db" /d "NDEBUG" /d "APU_VERSION_ONLY" /I "../include" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib libdb47.lib /nologo /base:"0x6F000000" /subsystem:windows /dll /incremental:no /debug /opt:ref +# ADD LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib libdb47.lib /nologo /base:"0x6F000000" /subsystem:windows /dll /incremental:no /libpath:"..\..\db" /debug /out:"Release\apr_dbm_db-1.dll" /pdb:"Release\apr_dbm_db-1.pdb" /implib:"Release\apr_dbm_db-1.lib" /MACHINE:X86 /opt:ref +# Begin Special Build Tool +TargetPath=Release\apr_dbm_db-1.dll +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2 +# End Special Build Tool + +!ELSEIF "$(CFG)" == "apr_dbm_db - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /EHsc /c +# ADD CPP /nologo /MDd /W3 /Zi /Od /I "../include" /I "../include/arch/win32" /I "../include/private" /I "../../db" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "APU_DSO_MODULE_BUILD" /D APU_HAVE_DB=1 /D APU_HAVE_DB_VERSION=4 /Fo"$(INTDIR)\" /Fd"$(INTDIR)\apr_dbm_db_src" /FD /EHsc /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o /win32 "NUL" +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o /win32 "NUL" +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /fo"Debug/apr_dbm_db-1.res" /d DLL_NAME="apr_dbm_db" /d "_DEBUG" /d "APU_VERSION_ONLY" /I "../include" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib libdb47.lib /nologo /base:"0x6F000000" /subsystem:windows /dll /incremental:no /debug +# ADD LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib libdb47.lib /nologo /base:"0x6F000000" /subsystem:windows /dll /incremental:no /libpath:"..\..\db" /debug /out:"Debug\apr_dbm_db-1.dll" /pdb:"Debug\apr_dbm_db-1.pdb" /implib:"Debug\apr_dbm_db-1.lib" /MACHINE:X86 +# Begin Special Build Tool +TargetPath=Debug\apr_dbm_db-1.dll +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2 +# End Special Build Tool + +!ELSEIF "$(CFG)" == "apr_dbm_db - x64 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "x64\Release" +# PROP BASE Intermediate_Dir "x64\Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "x64\Release" +# PROP Intermediate_Dir "x64\Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c +# ADD CPP /nologo /MD /W3 /Zi /O2 /Oy- /I "../include" /I "../include/arch/win32" /I "../include/private" /I "../../db" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "APU_DSO_MODULE_BUILD" /D APU_HAVE_DB=1 /D APU_HAVE_DB_VERSION=4 /Fo"$(INTDIR)\" /Fd"$(INTDIR)\apr_dbm_db_src" /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o /win32 "NUL" +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o /win32 "NUL" +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /fo"x64/Release/apr_dbm_db-1.res" /d DLL_NAME="apr_dbm_db" /d "NDEBUG" /d "APU_VERSION_ONLY" /I "../include" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib libdb47.lib /nologo /base:"0x6F000000" /subsystem:windows /dll /incremental:no /debug /opt:ref +# ADD LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib libdb47.lib /nologo /base:"0x6F000000" /subsystem:windows /dll /incremental:no /libpath:"..\..\db" /debug /out:"x64\Release\apr_dbm_db-1.dll" /pdb:"x64\Release\apr_dbm_db-1.pdb" /implib:"x64\Release\apr_dbm_db-1.lib" /MACHINE:X64 /opt:ref +# Begin Special Build Tool +TargetPath=x64\Release\apr_dbm_db-1.dll +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2 +# End Special Build Tool + +!ELSEIF "$(CFG)" == "apr_dbm_db - x64 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "x64\Debug" +# PROP BASE Intermediate_Dir "x64\Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "x64\Debug" +# PROP Intermediate_Dir "x64\Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /EHsc /c +# ADD CPP /nologo /MDd /W3 /Zi /Od /I "../include" /I "../include/arch/win32" /I "../include/private" /I "../../db" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "APU_DSO_MODULE_BUILD" /D APU_HAVE_DB=1 /D APU_HAVE_DB_VERSION=4 /Fo"$(INTDIR)\" /Fd"$(INTDIR)\apr_dbm_db_src" /FD /EHsc /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o /win32 "NUL" +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o /win32 "NUL" +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /fo"x64/Debug/apr_dbm_db-1.res" /d DLL_NAME="apr_dbm_db" /d "_DEBUG" /d "APU_VERSION_ONLY" /I "../include" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib libdb47.lib /nologo /base:"0x6F000000" /subsystem:windows /dll /incremental:no /debug +# ADD LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib libdb47.lib /nologo /base:"0x6F000000" /subsystem:windows /dll /incremental:no /libpath:"..\..\db" /debug /out:"x64\Debug\apr_dbm_db-1.dll" /pdb:"x64\Debug\apr_dbm_db-1.pdb" /implib:"x64\Debug\apr_dbm_db-1.lib" /MACHINE:X64 +# Begin Special Build Tool +TargetPath=x64\Debug\apr_dbm_db-1.dll +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2 +# End Special Build Tool + +!ENDIF + +# Begin Target + +# Name "apr_dbm_db - Win32 Release" +# Name "apr_dbm_db - Win32 Debug" +# Name "apr_dbm_db - x64 Release" +# Name "apr_dbm_db - x64 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\apr_dbm_berkeleydb.c +# End Source File +# End Group +# Begin Group "Public Header Files" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\include\apr_dbm.h +# End Source File +# End Group +# Begin Group "Internal Header Files" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\include\private\apu_dbm_private.h +# End Source File +# Begin Source File + +SOURCE=..\include\private\apu_config.h +# End Source File +# Begin Source File + +SOURCE=..\include\private\apu_dbd_internal.h +# End Source File +# Begin Source File + +SOURCE=..\include\private\apu_internal.h +# End Source File +# Begin Source File + +SOURCE=..\include\private\apu_select_dbm.h +# End Source File +# End Group +# Begin Source File + +SOURCE=..\libapr.rc +# End Source File +# End Target +# End Project diff --git a/dbm/apr_dbm_gdbm.c b/dbm/apr_dbm_gdbm.c new file mode 100644 index 00000000000..1d8c96a6398 --- /dev/null +++ b/dbm/apr_dbm_gdbm.c @@ -0,0 +1,255 @@ +/* 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 "apu.h" +#include "apr_private.h" +#include "apr_strings.h" + +#if APR_HAVE_STDLIB_H +#include <stdlib.h> /* for free() */ +#endif + +#if APU_HAVE_GDBM +#include "apr_dbm_private.h" + +#include <gdbm.h> + +#define APR_DBM_DBMODE_RO GDBM_READER +#define APR_DBM_DBMODE_RW GDBM_WRITER +#define APR_DBM_DBMODE_RWCREATE GDBM_WRCREAT +#define APR_DBM_DBMODE_RWTRUNC GDBM_NEWDB + +/* map a GDBM error to an apr_status_t */ +static apr_status_t g2s(int gerr) +{ + if (gerr == -1) { + /* ### need to fix this */ + return APR_EGENERAL; + } + + return APR_SUCCESS; +} + +static apr_status_t datum_cleanup(void *dptr) +{ + if (dptr) + free(dptr); + + return APR_SUCCESS; +} + +static apr_status_t set_error(apr_dbm_t *dbm, apr_status_t dbm_said) +{ + apr_status_t rv = APR_SUCCESS; + + /* ### ignore whatever the DBM said (dbm_said); ask it explicitly */ + + if ((dbm->errcode = gdbm_errno) == GDBM_NO_ERROR) { + dbm->errmsg = NULL; + } + else { + dbm->errmsg = gdbm_strerror(gdbm_errno); + rv = APR_EGENERAL; /* ### need something better */ + } + + /* captured it. clear it now. */ + gdbm_errno = GDBM_NO_ERROR; + + return rv; +} + +/* -------------------------------------------------------------------------- +** +** DEFINE THE VTABLE FUNCTIONS FOR GDBM +*/ + +static apr_status_t vt_gdbm_open(apr_dbm_t **pdb, const char *pathname, + apr_int32_t mode, apr_fileperms_t perm, + apr_pool_t *pool) +{ + GDBM_FILE file; + int dbmode; + + *pdb = NULL; + + switch (mode) { + case APR_DBM_READONLY: + dbmode = APR_DBM_DBMODE_RO; + break; + case APR_DBM_READWRITE: + dbmode = APR_DBM_DBMODE_RW; + break; + case APR_DBM_RWCREATE: + dbmode = APR_DBM_DBMODE_RWCREATE; + break; + case APR_DBM_RWTRUNC: + dbmode = APR_DBM_DBMODE_RWTRUNC; + break; + default: + return APR_EINVAL; + } + + /* Note: stupid cast to get rid of "const" on the pathname */ + file = gdbm_open((char *) pathname, 0, dbmode, apr_posix_perms2mode(perm), + NULL); + + if (file == NULL) + return APR_EGENERAL; /* ### need a better error */ + + /* we have an open database... return it */ + *pdb = apr_pcalloc(pool, sizeof(**pdb)); + (*pdb)->pool = pool; + (*pdb)->type = &apr_dbm_type_gdbm; + (*pdb)->file = file; + + /* ### register a cleanup to close the DBM? */ + + return APR_SUCCESS; +} + +static void vt_gdbm_close(apr_dbm_t *dbm) +{ + gdbm_close(dbm->file); +} + +static apr_status_t vt_gdbm_fetch(apr_dbm_t *dbm, apr_datum_t key, + apr_datum_t *pvalue) +{ + datum kd, rd; + + kd.dptr = key.dptr; + kd.dsize = key.dsize; + + rd = gdbm_fetch(dbm->file, kd); + + pvalue->dptr = rd.dptr; + pvalue->dsize = rd.dsize; + + if (pvalue->dptr) + apr_pool_cleanup_register(dbm->pool, pvalue->dptr, datum_cleanup, + apr_pool_cleanup_null); + + /* store the error info into DBM, and return a status code. Also, note + that *pvalue should have been cleared on error. */ + return set_error(dbm, APR_SUCCESS); +} + +static apr_status_t vt_gdbm_store(apr_dbm_t *dbm, apr_datum_t key, + apr_datum_t value) +{ + int rc; + datum kd, vd; + + kd.dptr = key.dptr; + kd.dsize = key.dsize; + + vd.dptr = value.dptr; + vd.dsize = value.dsize; + + rc = gdbm_store(dbm->file, kd, vd, GDBM_REPLACE); + + /* store any error info into DBM, and return a status code. */ + return set_error(dbm, g2s(rc)); +} + +static apr_status_t vt_gdbm_del(apr_dbm_t *dbm, apr_datum_t key) +{ + int rc; + datum kd; + + kd.dptr = key.dptr; + kd.dsize = key.dsize; + + rc = gdbm_delete(dbm->file, kd); + + /* store any error info into DBM, and return a status code. */ + return set_error(dbm, g2s(rc)); +} + +static int vt_gdbm_exists(apr_dbm_t *dbm, apr_datum_t key) +{ + datum kd; + + kd.dptr = key.dptr; + kd.dsize = key.dsize; + + return gdbm_exists(dbm->file, kd) != 0; +} + +static apr_status_t vt_gdbm_firstkey(apr_dbm_t *dbm, apr_datum_t *pkey) +{ + datum rd; + + rd = gdbm_firstkey(dbm->file); + + pkey->dptr = rd.dptr; + pkey->dsize = rd.dsize; + + if (pkey->dptr) + apr_pool_cleanup_register(dbm->pool, pkey->dptr, datum_cleanup, + apr_pool_cleanup_null); + + /* store any error info into DBM, and return a status code. */ + return set_error(dbm, APR_SUCCESS); +} + +static apr_status_t vt_gdbm_nextkey(apr_dbm_t *dbm, apr_datum_t *pkey) +{ + datum kd, rd; + + kd.dptr = pkey->dptr; + kd.dsize = pkey->dsize; + + rd = gdbm_nextkey(dbm->file, kd); + + pkey->dptr = rd.dptr; + pkey->dsize = rd.dsize; + + if (pkey->dptr) + apr_pool_cleanup_register(dbm->pool, pkey->dptr, datum_cleanup, + apr_pool_cleanup_null); + + /* store any error info into DBM, and return a status code. */ + return set_error(dbm, APR_SUCCESS); +} + +static void vt_gdbm_freedatum(apr_dbm_t *dbm, apr_datum_t data) +{ + (void) apr_pool_cleanup_run(dbm->pool, data.dptr, datum_cleanup); +} + +static void vt_gdbm_usednames(apr_pool_t *pool, const char *pathname, + const char **used1, const char **used2) +{ + *used1 = apr_pstrdup(pool, pathname); + *used2 = NULL; +} + +APR_MODULE_DECLARE_DATA const apr_dbm_type_t apr_dbm_type_gdbm = { + "gdbm", + vt_gdbm_open, + vt_gdbm_close, + vt_gdbm_fetch, + vt_gdbm_store, + vt_gdbm_del, + vt_gdbm_exists, + vt_gdbm_firstkey, + vt_gdbm_nextkey, + vt_gdbm_freedatum, + vt_gdbm_usednames +}; + +#endif /* APU_HAVE_GDBM */ diff --git a/dbm/apr_dbm_gdbm.dsp b/dbm/apr_dbm_gdbm.dsp new file mode 100644 index 00000000000..eaa51ca515b --- /dev/null +++ b/dbm/apr_dbm_gdbm.dsp @@ -0,0 +1,215 @@ +# Microsoft Developer Studio Project File - Name="apr_dbm_gdbm" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=apr_dbm_gdbm - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "apr_dbm_gdbm.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "apr_dbm_gdbm.mak" CFG="apr_dbm_gdbm - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "apr_dbm_gdbm - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "apr_dbm_gdbm - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "apr_dbm_gdbm - x64 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "apr_dbm_gdbm - x64 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "apr_dbm_gdbm - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c +# ADD CPP /nologo /MD /W3 /Zi /O2 /Oy- /I "../include" /I "../include/arch/win32" /I "../include/private" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "APU_DSO_MODULE_BUILD" /D APU_HAVE_GDBM=1 /Fo"$(INTDIR)\" /Fd"$(INTDIR)\apr_dbm_gdbm_src" /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o /win32 "NUL" +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o /win32 "NUL" +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /fo"Release/apr_dbm_gdbm-1.res" /d DLL_NAME="apr_dbm_gdbm" /d "NDEBUG" /d "APU_VERSION_ONLY" /I "../include" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib libgdbm.lib /nologo /base:"0x6F010000" /subsystem:windows /dll /incremental:no /debug /opt:ref +# ADD LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib libgdbm.lib /nologo /base:"0x6F010000" /subsystem:windows /dll /incremental:no /debug /out:"Release\apr_dbm_gdbm-1.dll" /pdb:"Release\apr_dbm_gdbm-1.pdb" /implib:"Release\apr_dbm_gdbm-1.lib" /MACHINE:X86 /opt:ref +# Begin Special Build Tool +TargetPath=Release\apr_dbm_gdbm-1.dll +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2 +# End Special Build Tool + +!ELSEIF "$(CFG)" == "apr_dbm_gdbm - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /EHsc /c +# ADD CPP /nologo /MDd /W3 /Zi /Od /I "../include" /I "../include/arch/win32" /I "../include/private" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "APU_DSO_MODULE_BUILD" /D APU_HAVE_GDBM=1 /Fo"$(INTDIR)\" /Fd"$(INTDIR)\apr_dbm_gdbm_src" /FD /EHsc /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o /win32 "NUL" +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o /win32 "NUL" +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /fo"Debug/apr_dbm_gdbm-1.res" /d DLL_NAME="apr_dbm_gdbm" /d "_DEBUG" /d "APU_VERSION_ONLY" /I "../include" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib libgdbm.lib /nologo /base:"0x6F010000" /subsystem:windows /dll /incremental:no /debug +# ADD LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib libgdbm.lib /nologo /base:"0x6F010000" /subsystem:windows /dll /incremental:no /debug /out:"Debug\apr_dbm_gdbm-1.dll" /pdb:"Debug\apr_dbm_gdbm-1.pdb" /implib:"Debug\apr_dbm_gdbm-1.lib" /MACHINE:X86 +# Begin Special Build Tool +TargetPath=Debug\apr_dbm_gdbm-1.dll +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2 +# End Special Build Tool + +!ELSEIF "$(CFG)" == "apr_dbm_gdbm - x64 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "x64\Release" +# PROP BASE Intermediate_Dir "x64\Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "x64\Release" +# PROP Intermediate_Dir "x64\Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c +# ADD CPP /nologo /MD /W3 /Zi /O2 /Oy- /I "../include" /I "../include/arch/win32" /I "../include/private" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "APU_DSO_MODULE_BUILD" /D APU_HAVE_GDBM=1 /Fo"$(INTDIR)\" /Fd"$(INTDIR)\apr_dbm_gdbm_src" /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o /win32 "NUL" +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o /win32 "NUL" +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /fo"x64/Release/apr_dbm_gdbm-1.res" /d DLL_NAME="apr_dbm_gdbm" /d "NDEBUG" /d "APU_VERSION_ONLY" /I "../include" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib libgdbm.lib /nologo /base:"0x6F010000" /subsystem:windows /dll /incremental:no /debug /opt:ref +# ADD LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib libgdbm.lib /nologo /base:"0x6F010000" /subsystem:windows /dll /incremental:no /debug /out:"x64\Release\apr_dbm_gdbm-1.dll" /pdb:"x64\Release\apr_dbm_gdbm-1.pdb" /implib:"x64\Release\apr_dbm_gdbm-1.lib" /MACHINE:X64 /opt:ref +# Begin Special Build Tool +TargetPath=x64\Release\apr_dbm_gdbm-1.dll +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2 +# End Special Build Tool + +!ELSEIF "$(CFG)" == "apr_dbm_gdbm - x64 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "x64\Debug" +# PROP BASE Intermediate_Dir "x64\Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "x64\Debug" +# PROP Intermediate_Dir "x64\Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /EHsc /c +# ADD CPP /nologo /MDd /W3 /Zi /Od /I "../include" /I "../include/arch/win32" /I "../include/private" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "APU_DSO_MODULE_BUILD" /D APU_HAVE_GDBM=1 /Fo"$(INTDIR)\" /Fd"$(INTDIR)\apr_dbm_gdbm_src" /FD /EHsc /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o /win32 "NUL" +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o /win32 "NUL" +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /fo"x64/Debug/apr_dbm_gdbm-1.res" /d DLL_NAME="apr_dbm_gdbm" /d "_DEBUG" /d "APU_VERSION_ONLY" /I "../include" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib libgdbm.lib /nologo /base:"0x6F010000" /subsystem:windows /dll /incremental:no /debug +# ADD LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib libgdbm.lib /nologo /base:"0x6F010000" /subsystem:windows /dll /incremental:no /debug /out:"x64\Debug\apr_dbm_gdbm-1.dll" /pdb:"x64\Debug\apr_dbm_gdbm-1.pdb" /implib:"x64\Debug\apr_dbm_gdbm-1.lib" /MACHINE:X64 +# Begin Special Build Tool +TargetPath=x64\Debug\apr_dbm_gdbm-1.dll +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2 +# End Special Build Tool + +!ENDIF + +# Begin Target + +# Name "apr_dbm_gdbm - Win32 Release" +# Name "apr_dbm_gdbm - Win32 Debug" +# Name "apr_dbm_gdbm - x64 Release" +# Name "apr_dbm_gdbm - x64 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\apr_dbm_gdbm.c +# End Source File +# End Group +# Begin Group "Public Header Files" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\include\apr_dbm.h +# End Source File +# End Group +# Begin Group "Internal Header Files" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\include\private\apu_dbm_private.h +# End Source File +# Begin Source File + +SOURCE=..\include\private\apu_config.h +# End Source File +# Begin Source File + +SOURCE=..\include\private\apu_dbd_internal.h +# End Source File +# Begin Source File + +SOURCE=..\include\private\apu_internal.h +# End Source File +# Begin Source File + +SOURCE=..\include\private\apu_select_dbm.h +# End Source File +# End Group +# Begin Source File + +SOURCE=..\libapr.rc +# End Source File +# End Target +# End Project diff --git a/dbm/apr_dbm_ndbm.c b/dbm/apr_dbm_ndbm.c new file mode 100644 index 00000000000..a69ac526255 --- /dev/null +++ b/dbm/apr_dbm_ndbm.c @@ -0,0 +1,238 @@ +/* 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_strings.h" + +#if APR_HAVE_STDLIB_H +#include <stdlib.h> /* for free() */ +#endif + +#include "apu.h" +#include "apr_private.h" + +#if APU_HAVE_NDBM +#include "apr_dbm_private.h" + +#include <ndbm.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> + +#define APR_DBM_DBMODE_RO O_RDONLY +#define APR_DBM_DBMODE_RW O_RDWR +#define APR_DBM_DBMODE_RWCREATE (O_RDWR|O_CREAT) +#define APR_DBM_DBMODE_RWTRUNC (O_RDWR|O_CREAT|O_TRUNC) + +/* map a NDBM error to an apr_status_t */ +static apr_status_t ndbm2s(int ndbmerr) +{ + if (ndbmerr == -1) { + /* ### need to fix this */ + return APR_EGENERAL; + } + + return APR_SUCCESS; +} + +static apr_status_t set_error(apr_dbm_t *dbm, apr_status_t dbm_said) +{ + apr_status_t rv = APR_SUCCESS; + + /* ### ignore whatever the DBM said (dbm_said); ask it explicitly */ + + dbm->errmsg = NULL; + if (dbm_error((DBM*)dbm->file)) { + dbm->errmsg = NULL; + rv = APR_EGENERAL; /* ### need something better */ + } + + /* captured it. clear it now. */ + dbm_clearerr((DBM*)dbm->file); + + return rv; +} + +/* -------------------------------------------------------------------------- +** +** DEFINE THE VTABLE FUNCTIONS FOR NDBM +*/ + +static apr_status_t vt_ndbm_open(apr_dbm_t **pdb, const char *pathname, + apr_int32_t mode, apr_fileperms_t perm, + apr_pool_t *pool) +{ + DBM *file; + int dbmode; + + *pdb = NULL; + + switch (mode) { + case APR_DBM_READONLY: + dbmode = APR_DBM_DBMODE_RO; + break; + case APR_DBM_READWRITE: + dbmode = APR_DBM_DBMODE_RW; + break; + case APR_DBM_RWCREATE: + dbmode = APR_DBM_DBMODE_RWCREATE; + break; + case APR_DBM_RWTRUNC: + dbmode = APR_DBM_DBMODE_RWTRUNC; + break; + default: + return APR_EINVAL; + } + + { + file = dbm_open(pathname, dbmode, apr_posix_perms2mode(perm)); + if (file == NULL) + return APR_EGENERAL; /* ### need a better error */ + } + + /* we have an open database... return it */ + *pdb = apr_pcalloc(pool, sizeof(**pdb)); + (*pdb)->pool = pool; + (*pdb)->type = &apr_dbm_type_ndbm; + (*pdb)->file = file; + + /* ### register a cleanup to close the DBM? */ + + return APR_SUCCESS; +} + +static void vt_ndbm_close(apr_dbm_t *dbm) +{ + dbm_close(dbm->file); +} + +static apr_status_t vt_ndbm_fetch(apr_dbm_t *dbm, apr_datum_t key, + apr_datum_t *pvalue) +{ + datum kd, rd; + + kd.dptr = key.dptr; + kd.dsize = key.dsize; + + rd = dbm_fetch(dbm->file, kd); + + pvalue->dptr = rd.dptr; + pvalue->dsize = rd.dsize; + + /* store the error info into DBM, and return a status code. Also, note + that *pvalue should have been cleared on error. */ + return set_error(dbm, APR_SUCCESS); +} + +static apr_status_t vt_ndbm_store(apr_dbm_t *dbm, apr_datum_t key, + apr_datum_t value) +{ + int rc; + datum kd, vd; + + kd.dptr = key.dptr; + kd.dsize = key.dsize; + + vd.dptr = value.dptr; + vd.dsize = value.dsize; + + rc = dbm_store(dbm->file, kd, vd, DBM_REPLACE); + + /* store any error info into DBM, and return a status code. */ + return set_error(dbm, ndbm2s(rc)); +} + +static apr_status_t vt_ndbm_del(apr_dbm_t *dbm, apr_datum_t key) +{ + int rc; + datum kd; + + kd.dptr = key.dptr; + kd.dsize = key.dsize; + + rc = dbm_delete(dbm->file, kd); + + /* store any error info into DBM, and return a status code. */ + return set_error(dbm, ndbm2s(rc)); +} + +static int vt_ndbm_exists(apr_dbm_t *dbm, apr_datum_t key) +{ + datum kd, rd; + + kd.dptr = key.dptr; + kd.dsize = key.dsize; + + rd = dbm_fetch(dbm->file, kd); + + return rd.dptr != NULL; +} + +static apr_status_t vt_ndbm_firstkey(apr_dbm_t *dbm, apr_datum_t *pkey) +{ + datum rd; + + rd = dbm_firstkey(dbm->file); + + pkey->dptr = rd.dptr; + pkey->dsize = rd.dsize; + + /* store any error info into DBM, and return a status code. */ + return set_error(dbm, APR_SUCCESS); +} + +static apr_status_t vt_ndbm_nextkey(apr_dbm_t *dbm, apr_datum_t *pkey) +{ + datum kd, rd; + + kd.dptr = pkey->dptr; + kd.dsize = pkey->dsize; + + rd = dbm_nextkey(dbm->file); + + pkey->dptr = rd.dptr; + pkey->dsize = rd.dsize; + + /* store any error info into DBM, and return a status code. */ + return set_error(dbm, APR_SUCCESS); +} + +static void vt_ndbm_freedatum(apr_dbm_t *dbm, apr_datum_t data) +{ + /* nothing to do */ +} + +static void vt_ndbm_usednames(apr_pool_t *pool, const char *pathname, + const char **used1, const char **used2) +{ + *used1 = apr_pstrdup(pool, pathname); + *used2 = NULL; +} + +APR_MODULE_DECLARE_DATA const apr_dbm_type_t apr_dbm_type_ndbm = { + "ndbm", + vt_ndbm_open, + vt_ndbm_close, + vt_ndbm_fetch, + vt_ndbm_store, + vt_ndbm_del, + vt_ndbm_exists, + vt_ndbm_firstkey, + vt_ndbm_nextkey, + vt_ndbm_freedatum, + vt_ndbm_usednames +}; + +#endif /* APU_HAVE_NDBM */ diff --git a/dbm/apr_dbm_sdbm.c b/dbm/apr_dbm_sdbm.c new file mode 100644 index 00000000000..ac3192e632c --- /dev/null +++ b/dbm/apr_dbm_sdbm.c @@ -0,0 +1,226 @@ +/* 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_strings.h" +#define APR_WANT_MEMFUNC +#define APR_WANT_STRFUNC +#include "apr_want.h" + +#include "apu.h" +#include "apr_private.h" + +#if APU_HAVE_SDBM + +#include "apr_dbm_private.h" +#include "apr_sdbm.h" + +#define APR_DBM_DBMODE_RO (APR_FOPEN_READ | APR_FOPEN_BUFFERED) +#define APR_DBM_DBMODE_RW (APR_FOPEN_READ | APR_FOPEN_WRITE) +#define APR_DBM_DBMODE_RWCREATE (APR_FOPEN_READ | APR_FOPEN_WRITE | APR_FOPEN_CREATE) +#define APR_DBM_DBMODE_RWTRUNC (APR_FOPEN_READ | APR_FOPEN_WRITE | APR_FOPEN_CREATE | \ + APR_FOPEN_TRUNCATE) + +static apr_status_t set_error(apr_dbm_t *dbm, apr_status_t dbm_said) +{ + dbm->errcode = dbm_said; + + if (dbm_said != APR_SUCCESS) { + dbm->errmsg = apr_psprintf(dbm->pool, "%pm", &dbm_said); + } else { + dbm->errmsg = NULL; + } + + return dbm_said; +} + +/* -------------------------------------------------------------------------- +** +** DEFINE THE VTABLE FUNCTIONS FOR SDBM +*/ + +static apr_status_t vt_sdbm_open(apr_dbm_t **pdb, const char *pathname, + apr_int32_t mode, apr_fileperms_t perm, + apr_pool_t *pool) +{ + apr_sdbm_t *file; + int dbmode; + + *pdb = NULL; + + switch (mode) { + case APR_DBM_READONLY: + dbmode = APR_DBM_DBMODE_RO; + break; + case APR_DBM_READWRITE: + dbmode = APR_DBM_DBMODE_RW; + break; + case APR_DBM_RWCREATE: + dbmode = APR_DBM_DBMODE_RWCREATE; + break; + case APR_DBM_RWTRUNC: + dbmode = APR_DBM_DBMODE_RWTRUNC; + break; + default: + return APR_EINVAL; + } + + { + apr_status_t rv; + + rv = apr_sdbm_open(&file, pathname, dbmode, perm, pool); + if (rv != APR_SUCCESS) + return rv; + } + + /* we have an open database... return it */ + *pdb = apr_pcalloc(pool, sizeof(**pdb)); + (*pdb)->pool = pool; + (*pdb)->type = &apr_dbm_type_sdbm; + (*pdb)->file = file; + + /* ### register a cleanup to close the DBM? */ + + return APR_SUCCESS; +} + +static void vt_sdbm_close(apr_dbm_t *dbm) +{ + apr_sdbm_close(dbm->file); +} + +static apr_status_t vt_sdbm_fetch(apr_dbm_t *dbm, apr_datum_t key, + apr_datum_t *pvalue) +{ + apr_status_t rv; + apr_sdbm_datum_t kd, rd; + + kd.dptr = key.dptr; + kd.dsize = (int)key.dsize; + + rv = apr_sdbm_fetch(dbm->file, &rd, kd); + + pvalue->dptr = rd.dptr; + pvalue->dsize = rd.dsize; + + /* store the error info into DBM, and return a status code. Also, note + that *pvalue should have been cleared on error. */ + return set_error(dbm, rv); +} + +static apr_status_t vt_sdbm_store(apr_dbm_t *dbm, apr_datum_t key, + apr_datum_t value) +{ + apr_status_t rv; + apr_sdbm_datum_t kd, vd; + + kd.dptr = key.dptr; + kd.dsize = (int)key.dsize; + + vd.dptr = value.dptr; + vd.dsize = (int)value.dsize; + + rv = apr_sdbm_store(dbm->file, kd, vd, APR_SDBM_REPLACE); + + /* store any error info into DBM, and return a status code. */ + return set_error(dbm, rv); +} + +static apr_status_t vt_sdbm_del(apr_dbm_t *dbm, apr_datum_t key) +{ + apr_status_t rv; + apr_sdbm_datum_t kd; + + kd.dptr = key.dptr; + kd.dsize = (int)key.dsize; + + rv = apr_sdbm_delete(dbm->file, kd); + + /* store any error info into DBM, and return a status code. */ + return set_error(dbm, rv); +} + +static int vt_sdbm_exists(apr_dbm_t *dbm, apr_datum_t key) +{ + int exists; + apr_sdbm_datum_t vd, kd; + + kd.dptr = key.dptr; + kd.dsize = (int)key.dsize; + + if (apr_sdbm_fetch(dbm->file, &vd, kd) != APR_SUCCESS) + exists = 0; + else + exists = vd.dptr != NULL; + + return exists; +} + +static apr_status_t vt_sdbm_firstkey(apr_dbm_t *dbm, apr_datum_t *pkey) +{ + apr_status_t rv; + apr_sdbm_datum_t rd; + + rv = apr_sdbm_firstkey(dbm->file, &rd); + + pkey->dptr = rd.dptr; + pkey->dsize = rd.dsize; + + /* store any error info into DBM, and return a status code. */ + return set_error(dbm, rv); +} + +static apr_status_t vt_sdbm_nextkey(apr_dbm_t *dbm, apr_datum_t *pkey) +{ + apr_sdbm_datum_t rd; + + (void)apr_sdbm_nextkey(dbm->file, &rd); + + pkey->dptr = rd.dptr; + pkey->dsize = rd.dsize; + + /* + * XXX: This discards any error but apr_sdbm_nextkey currently returns + * XXX: an error for the last key + */ + return set_error(dbm, APR_SUCCESS); +} + +static void vt_sdbm_freedatum(apr_dbm_t *dbm, apr_datum_t data) +{ +} + +static void vt_sdbm_usednames(apr_pool_t *pool, const char *pathname, + const char **used1, const char **used2) +{ + *used1 = apr_pstrcat(pool, pathname, APR_SDBM_DIRFEXT, NULL); + *used2 = apr_pstrcat(pool, pathname, APR_SDBM_PAGFEXT, NULL); +} + +APR_MODULE_DECLARE_DATA const apr_dbm_type_t apr_dbm_type_sdbm = { + "sdbm", + vt_sdbm_open, + vt_sdbm_close, + vt_sdbm_fetch, + vt_sdbm_store, + vt_sdbm_del, + vt_sdbm_exists, + vt_sdbm_firstkey, + vt_sdbm_nextkey, + vt_sdbm_freedatum, + vt_sdbm_usednames +}; + +#endif /* APU_HAVE_SDBM */ diff --git a/dbm/sdbm/sdbm.c b/dbm/sdbm/sdbm.c new file mode 100644 index 00000000000..9ad9d20ff5f --- /dev/null +++ b/dbm/sdbm/sdbm.c @@ -0,0 +1,584 @@ +/* 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. + */ + +/* + * sdbm - ndbm work-alike hashed database library + * based on Per-Aake Larson's Dynamic Hashing algorithms. BIT 18 (1978). + * author: oz@nexus.yorku.ca + * ex-public domain, ported to APR for Apache 2 + * core routines + */ + +#include "apr.h" +#include "apr_file_io.h" +#include "apr_strings.h" +#include "apr_errno.h" +#include "apr_sdbm.h" + +#include "sdbm_tune.h" +#include "sdbm_pair.h" +#include "sdbm_private.h" + +#include <string.h> /* for memset() */ +#include <stdlib.h> /* for malloc() and free() */ + +/* + * forward + */ +static int getdbit (apr_sdbm_t *, long); +static apr_status_t setdbit(apr_sdbm_t *, long); +static apr_status_t getpage(apr_sdbm_t *db, long, int, int); +static apr_status_t getnext(apr_sdbm_datum_t *key, apr_sdbm_t *db); +static apr_status_t makroom(apr_sdbm_t *, long, int); + +/* + * useful macros + */ +#define bad(x) ((x).dptr == NULL || (x).dsize <= 0) +#define exhash(item) sdbm_hash((item).dptr, (item).dsize) + +#define OFF_PAG(off) (apr_off_t) (off) * PBLKSIZ +#define OFF_DIR(off) (apr_off_t) (off) * DBLKSIZ + +static const long masks[] = { + 000000000000, 000000000001, 000000000003, 000000000007, + 000000000017, 000000000037, 000000000077, 000000000177, + 000000000377, 000000000777, 000000001777, 000000003777, + 000000007777, 000000017777, 000000037777, 000000077777, + 000000177777, 000000377777, 000000777777, 000001777777, + 000003777777, 000007777777, 000017777777, 000037777777, + 000077777777, 000177777777, 000377777777, 000777777777, + 001777777777, 003777777777, 007777777777, 017777777777 +}; + +const apr_sdbm_datum_t sdbm_nullitem = { NULL, 0 }; + +static apr_status_t database_cleanup(void *data) +{ + apr_sdbm_t *db = data; + + /* + * Can't rely on apr_sdbm_unlock, since it will merely + * decrement the refcnt if several locks are held. + */ + if (db->flags & (SDBM_SHARED_LOCK | SDBM_EXCLUSIVE_LOCK)) + (void) apr_file_unlock(db->dirf); + (void) apr_file_close(db->dirf); + (void) apr_file_close(db->pagf); + free(db); + + return APR_SUCCESS; +} + +static apr_status_t prep(apr_sdbm_t **pdb, const char *dirname, const char *pagname, + apr_int32_t flags, apr_fileperms_t perms, apr_pool_t *p) +{ + apr_sdbm_t *db; + apr_status_t status; + + *pdb = NULL; + + db = malloc(sizeof(*db)); + memset(db, 0, sizeof(*db)); + db->pagbno = -1L; + + db->pool = p; + + /* + * adjust user flags so that WRONLY becomes RDWR, + * as required by this package. Also set our internal + * flag for RDONLY if needed. + */ + if (!(flags & APR_FOPEN_WRITE)) { + db->flags |= SDBM_RDONLY; + } + + /* + * adjust the file open flags so that we handle locking + * on our own (don't rely on any locking behavior within + * an apr_file_t, in case it's ever introduced, and set + * our own flag. + */ + if (flags & APR_FOPEN_SHARELOCK) { + db->flags |= SDBM_SHARED; + flags &= ~APR_FOPEN_SHARELOCK; + } + + flags |= APR_FOPEN_BINARY | APR_FOPEN_READ; + + /* + * open the files in sequence, and stat the dirfile. + * If we fail anywhere, undo everything, return NULL. + */ + + if ((status = apr_file_open(&db->dirf, dirname, flags, perms, p)) + != APR_SUCCESS) + goto error; + + if ((status = apr_file_open(&db->pagf, pagname, flags, perms, p)) + != APR_SUCCESS) + goto error; + + if ((status = apr_sdbm_lock(db, (db->flags & SDBM_RDONLY) + ? APR_FLOCK_SHARED + : APR_FLOCK_EXCLUSIVE)) + != APR_SUCCESS) + goto error; + + /* apr_pcalloc zeroed the buffers + * apr_sdbm_lock stated the dirf->size and invalidated the cache + */ + + /* + * if we are opened in SHARED mode, unlock ourself + */ + if (db->flags & SDBM_SHARED) + if ((status = apr_sdbm_unlock(db)) != APR_SUCCESS) + goto error; + + /* make sure that we close the database at some point */ + apr_pool_cleanup_register(p, db, database_cleanup, apr_pool_cleanup_null); + + /* Done! */ + *pdb = db; + return APR_SUCCESS; + +error: + if (db->dirf && db->pagf) + (void) apr_sdbm_unlock(db); + if (db->dirf != NULL) + (void) apr_file_close(db->dirf); + if (db->pagf != NULL) { + (void) apr_file_close(db->pagf); + } + free(db); + return status; +} + +APR_DECLARE(apr_status_t) apr_sdbm_open(apr_sdbm_t **db, const char *file, + apr_int32_t flags, + apr_fileperms_t perms, apr_pool_t *p) +{ + char *dirname = apr_pstrcat(p, file, APR_SDBM_DIRFEXT, NULL); + char *pagname = apr_pstrcat(p, file, APR_SDBM_PAGFEXT, NULL); + + return prep(db, dirname, pagname, flags, perms, p); +} + +APR_DECLARE(apr_status_t) apr_sdbm_close(apr_sdbm_t *db) +{ + return apr_pool_cleanup_run(db->pool, db, database_cleanup); +} + +APR_DECLARE(apr_status_t) apr_sdbm_fetch(apr_sdbm_t *db, apr_sdbm_datum_t *val, + apr_sdbm_datum_t key) +{ + apr_status_t status; + + if (db == NULL || bad(key)) + return APR_EINVAL; + + if ((status = apr_sdbm_lock(db, APR_FLOCK_SHARED)) != APR_SUCCESS) + return status; + + if ((status = getpage(db, exhash(key), 0, 1)) == APR_SUCCESS) { + *val = getpair(db->pagbuf, key); + /* ### do we want a not-found result? */ + } + + (void) apr_sdbm_unlock(db); + + return status; +} + +static apr_status_t write_page(apr_sdbm_t *db, const char *buf, long pagno) +{ + apr_status_t status; + apr_off_t off = OFF_PAG(pagno); + + if ((status = apr_file_seek(db->pagf, APR_SET, &off)) == APR_SUCCESS) + status = apr_file_write_full(db->pagf, buf, PBLKSIZ, NULL); + + return status; +} + +APR_DECLARE(apr_status_t) apr_sdbm_delete(apr_sdbm_t *db, + const apr_sdbm_datum_t key) +{ + apr_status_t status; + + if (db == NULL || bad(key)) + return APR_EINVAL; + if (apr_sdbm_rdonly(db)) + return APR_EINVAL; + + if ((status = apr_sdbm_lock(db, APR_FLOCK_EXCLUSIVE)) != APR_SUCCESS) + return status; + + if ((status = getpage(db, exhash(key), 0, 1)) == APR_SUCCESS) { + if (!delpair(db->pagbuf, key)) + /* ### should we define some APRUTIL codes? */ + status = APR_EGENERAL; + else + status = write_page(db, db->pagbuf, db->pagbno); + } + + (void) apr_sdbm_unlock(db); + + return status; +} + +APR_DECLARE(apr_status_t) apr_sdbm_store(apr_sdbm_t *db, apr_sdbm_datum_t key, + apr_sdbm_datum_t val, int flags) +{ + int need; + register long hash; + apr_status_t status; + + if (db == NULL || bad(key)) + return APR_EINVAL; + if (apr_sdbm_rdonly(db)) + return APR_EINVAL; + need = key.dsize + val.dsize; + /* + * is the pair too big (or too small) for this database ?? + */ + if (need < 0 || need > PAIRMAX) + return APR_EINVAL; + + if ((status = apr_sdbm_lock(db, APR_FLOCK_EXCLUSIVE)) != APR_SUCCESS) + return status; + + if ((status = getpage(db, (hash = exhash(key)), 0, 1)) == APR_SUCCESS) { + + /* + * if we need to replace, delete the key/data pair + * first. If it is not there, ignore. + */ + if (flags == APR_SDBM_REPLACE) + (void) delpair(db->pagbuf, key); + else if (!(flags & APR_SDBM_INSERTDUP) && duppair(db->pagbuf, key)) { + status = APR_EEXIST; + goto error; + } + /* + * if we do not have enough room, we have to split. + */ + if (!fitpair(db->pagbuf, need)) + if ((status = makroom(db, hash, need)) != APR_SUCCESS) + goto error; + /* + * we have enough room or split is successful. insert the key, + * and update the page file. + */ + (void) putpair(db->pagbuf, key, val); + + status = write_page(db, db->pagbuf, db->pagbno); + } + +error: + (void) apr_sdbm_unlock(db); + + return status; +} + +/* + * makroom - make room by splitting the overfull page + * this routine will attempt to make room for SPLTMAX times before + * giving up. + */ +static apr_status_t makroom(apr_sdbm_t *db, long hash, int need) +{ + long newp; + char twin[PBLKSIZ]; + char *pag = db->pagbuf; + char *new = twin; + register int smax = SPLTMAX; + apr_status_t status; + + do { + /* + * split the current page + */ + (void) splpage(pag, new, db->hmask + 1); + /* + * address of the new page + */ + newp = (hash & db->hmask) | (db->hmask + 1); + + /* + * write delay, read avoidence/cache shuffle: + * select the page for incoming pair: if key is to go to the new page, + * write out the previous one, and copy the new one over, thus making + * it the current page. If not, simply write the new page, and we are + * still looking at the page of interest. current page is not updated + * here, as sdbm_store will do so, after it inserts the incoming pair. + */ + if (hash & (db->hmask + 1)) { + if ((status = write_page(db, db->pagbuf, db->pagbno)) + != APR_SUCCESS) + return status; + + db->pagbno = newp; + (void) memcpy(pag, new, PBLKSIZ); + } + else { + if ((status = write_page(db, new, newp)) != APR_SUCCESS) + return status; + } + + if ((status = setdbit(db, db->curbit)) != APR_SUCCESS) + return status; + /* + * see if we have enough room now + */ + if (fitpair(pag, need)) + return APR_SUCCESS; + /* + * try again... update curbit and hmask as getpage would have + * done. because of our update of the current page, we do not + * need to read in anything. BUT we have to write the current + * [deferred] page out, as the window of failure is too great. + */ + db->curbit = 2 * db->curbit + + ((hash & (db->hmask + 1)) ? 2 : 1); + db->hmask |= db->hmask + 1; + + if ((status = write_page(db, db->pagbuf, db->pagbno)) + != APR_SUCCESS) + return status; + + } while (--smax); + + /* + * if we are here, this is real bad news. After SPLTMAX splits, + * we still cannot fit the key. say goodnight. + */ +#if 0 + (void) write(2, "sdbm: cannot insert after SPLTMAX attempts.\n", 44); +#endif + /* ### ENOSPC not really appropriate but better than nothing */ + return APR_ENOSPC; + +} + +/* Reads 'len' bytes from file 'f' at offset 'off' into buf. + * 'off' is given relative to the start of the file. + * If 'create' is asked and EOF is returned while reading, this is taken + * as success (i.e. a cleared buffer is returned). + */ +static apr_status_t read_from(apr_file_t *f, void *buf, + apr_off_t off, apr_size_t len, + int create) +{ + apr_status_t status; + + if ((status = apr_file_seek(f, APR_SET, &off)) != APR_SUCCESS || + ((status = apr_file_read_full(f, buf, len, NULL)) != APR_SUCCESS)) { + /* if EOF is reached, pretend we read all zero's */ + if (status == APR_EOF && create) { + memset(buf, 0, len); + status = APR_SUCCESS; + } + } + + return status; +} + +/* + * the following two routines will break if + * deletions aren't taken into account. (ndbm bug) + */ +APR_DECLARE(apr_status_t) apr_sdbm_firstkey(apr_sdbm_t *db, + apr_sdbm_datum_t *key) +{ + apr_status_t status; + + if ((status = apr_sdbm_lock(db, APR_FLOCK_SHARED)) != APR_SUCCESS) + return status; + + /* + * start at page 0 + */ + if ((status = getpage(db, 0, 1, 1)) == APR_SUCCESS) { + db->blkptr = 0; + db->keyptr = 0; + status = getnext(key, db); + } + + (void) apr_sdbm_unlock(db); + + return status; +} + +APR_DECLARE(apr_status_t) apr_sdbm_nextkey(apr_sdbm_t *db, + apr_sdbm_datum_t *key) +{ + apr_status_t status; + + if ((status = apr_sdbm_lock(db, APR_FLOCK_SHARED)) != APR_SUCCESS) + return status; + + status = getnext(key, db); + + (void) apr_sdbm_unlock(db); + + return status; +} + +/* + * all important binary tree traversal + */ +static apr_status_t getpage(apr_sdbm_t *db, long hash, int by_num, int create) +{ + apr_status_t status; + register long pagb; + + if (by_num) { + pagb = hash; + } + else { + register int hbit = 0; + register long dbit = 0; + + while (dbit < db->maxbno && getdbit(db, dbit)) + dbit = 2 * dbit + ((hash & (1 << hbit++)) ? 2 : 1); + debug(("dbit: %d...", dbit)); + + db->curbit = dbit; + db->hmask = masks[hbit]; + + pagb = hash & db->hmask; + } + + /* + * see if the block we need is already in memory. + * note: this lookaside cache has about 10% hit rate. + */ + if (pagb != db->pagbno) { + /* + * note: here, we assume a "hole" is read as 0s. + * if not, must zero pagbuf first. + * ### joe: this assumption was surely never correct? but + * ### we make it so in read_from anyway. + */ + if ((status = read_from(db->pagf, db->pagbuf, + OFF_PAG(pagb), PBLKSIZ, + create)) != APR_SUCCESS) + return status; + + if (!chkpage(db->pagbuf)) + return APR_ENOSPC; /* ### better error? */ + + db->pagbno = pagb; + + debug(("pag read: %d\n", pagb)); + } + return APR_SUCCESS; +} + +static int getdbit(apr_sdbm_t *db, long dbit) +{ + register long c; + register long dirb; + + c = dbit / BYTESIZ; + dirb = c / DBLKSIZ; + + if (dirb != db->dirbno) { + if (read_from(db->dirf, db->dirbuf, + OFF_DIR(dirb), DBLKSIZ, + 1) != APR_SUCCESS) + return 0; + + db->dirbno = dirb; + + debug(("dir read: %d\n", dirb)); + } + + return db->dirbuf[c % DBLKSIZ] & (1 << dbit % BYTESIZ); +} + +static apr_status_t setdbit(apr_sdbm_t *db, long dbit) +{ + register long c; + register long dirb; + apr_status_t status; + apr_off_t off; + + c = dbit / BYTESIZ; + dirb = c / DBLKSIZ; + + if (dirb != db->dirbno) { + if ((status = read_from(db->dirf, db->dirbuf, + OFF_DIR(dirb), DBLKSIZ, + 1)) != APR_SUCCESS) + return status; + + db->dirbno = dirb; + + debug(("dir read: %d\n", dirb)); + } + + db->dirbuf[c % DBLKSIZ] |= (1 << dbit % BYTESIZ); + + if (dbit >= db->maxbno) + db->maxbno += DBLKSIZ * BYTESIZ; + + off = OFF_DIR(dirb); + if ((status = apr_file_seek(db->dirf, APR_SET, &off)) == APR_SUCCESS) + status = apr_file_write_full(db->dirf, db->dirbuf, DBLKSIZ, NULL); + + return status; +} + +/* +* getnext - get the next key in the page, and if done with +* the page, try the next page in sequence +*/ +static apr_status_t getnext(apr_sdbm_datum_t *key, apr_sdbm_t *db) +{ + apr_status_t status; + for (;;) { + db->keyptr++; + *key = getnkey(db->pagbuf, db->keyptr); + if (key->dptr != NULL) + return APR_SUCCESS; + /* + * we either run out, or there is nothing on this page.. + * try the next one... If we lost our position on the + * file, we will have to seek. + */ + db->blkptr++; + db->keyptr = 0; + + /* ### EOF acceptable here too? */ + if ((status = getpage(db, db->blkptr, 1, 0)) != APR_SUCCESS) + return status; + } + + /* NOTREACHED */ +} + + +APR_DECLARE(int) apr_sdbm_rdonly(apr_sdbm_t *db) +{ + /* ### Should we return true if the first lock is a share lock, + * to reflect that apr_sdbm_store and apr_sdbm_delete will fail? + */ + return (db->flags & SDBM_RDONLY) != 0; +} + diff --git a/dbm/sdbm/sdbm_hash.c b/dbm/sdbm/sdbm_hash.c new file mode 100644 index 00000000000..e4d75179451 --- /dev/null +++ b/dbm/sdbm/sdbm_hash.c @@ -0,0 +1,63 @@ +/* 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. + */ + +/* + * sdbm - ndbm work-alike hashed database library + * based on Per-Aake Larson's Dynamic Hashing algorithms. BIT 18 (1978). + * author: oz@nexus.yorku.ca + * status: ex-public domain. keep it that way. + * + * hashing routine + */ + +#include "apr_sdbm.h" +#include "sdbm_private.h" + +/* + * polynomial conversion ignoring overflows + * [this seems to work remarkably well, in fact better + * then the ndbm hash function. Replace at your own risk] + * use: 65599 nice. + * 65587 even better. + */ +long sdbm_hash(const char *str, int len) +{ + register unsigned long n = 0; + +#define DUFF /* go ahead and use the loop-unrolled version */ +#ifdef DUFF + +#define HASHC n = *str++ + 65599 * n + + if (len > 0) { + register int loop = (len + 8 - 1) >> 3; + + switch(len & (8 - 1)) { + case 0: do { + HASHC; case 7: HASHC; + case 6: HASHC; case 5: HASHC; + case 4: HASHC; case 3: HASHC; + case 2: HASHC; case 1: HASHC; + } while (--loop); + } + + } +#else + while (len--) + n = *str++ + 65599 * n; +#endif + return n; +} diff --git a/dbm/sdbm/sdbm_lock.c b/dbm/sdbm/sdbm_lock.c new file mode 100644 index 00000000000..9241c1fb647 --- /dev/null +++ b/dbm/sdbm/sdbm_lock.c @@ -0,0 +1,79 @@ +/* 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_file_info.h" +#include "apr_file_io.h" +#include "apr_sdbm.h" + +#include "sdbm_private.h" +#include "sdbm_tune.h" + +/* NOTE: this function may block until it acquires the lock */ +APR_DECLARE(apr_status_t) apr_sdbm_lock(apr_sdbm_t *db, int type) +{ + apr_status_t status; + int lock_type = type & APR_FLOCK_TYPEMASK; + + if (!(lock_type == APR_FLOCK_SHARED || lock_type == APR_FLOCK_EXCLUSIVE)) + return APR_EINVAL; + + if (db->flags & SDBM_EXCLUSIVE_LOCK) { + ++db->lckcnt; + return APR_SUCCESS; + } + else if (db->flags & SDBM_SHARED_LOCK) { + /* + * Cannot promote a shared lock to an exlusive lock + * in a cross-platform compatibile manner. + */ + if (type == APR_FLOCK_EXCLUSIVE) + return APR_EINVAL; + ++db->lckcnt; + return APR_SUCCESS; + } + /* + * zero size: either a fresh database, or one with a single, + * unsplit data page: dirpage is all zeros. + */ + if ((status = apr_file_lock(db->dirf, type)) == APR_SUCCESS) + { + apr_finfo_t finfo; + if ((status = apr_file_info_get(&finfo, APR_FINFO_SIZE, db->dirf)) + != APR_SUCCESS) { + (void) apr_file_unlock(db->dirf); + return status; + } + + SDBM_INVALIDATE_CACHE(db, finfo); + + ++db->lckcnt; + if (type == APR_FLOCK_SHARED) + db->flags |= SDBM_SHARED_LOCK; + else if (type == APR_FLOCK_EXCLUSIVE) + db->flags |= SDBM_EXCLUSIVE_LOCK; + } + return status; +} + +APR_DECLARE(apr_status_t) apr_sdbm_unlock(apr_sdbm_t *db) +{ + if (!(db->flags & (SDBM_SHARED_LOCK | SDBM_EXCLUSIVE_LOCK))) + return APR_EINVAL; + if (--db->lckcnt > 0) + return APR_SUCCESS; + db->flags &= ~(SDBM_SHARED_LOCK | SDBM_EXCLUSIVE_LOCK); + return apr_file_unlock(db->dirf); +} diff --git a/dbm/sdbm/sdbm_pair.c b/dbm/sdbm/sdbm_pair.c new file mode 100644 index 00000000000..50d7965b141 --- /dev/null +++ b/dbm/sdbm/sdbm_pair.c @@ -0,0 +1,320 @@ +/* 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. + */ + +/* + * sdbm - ndbm work-alike hashed database library + * based on Per-Aake Larson's Dynamic Hashing algorithms. BIT 18 (1978). + * author: oz@nexus.yorku.ca + * status: ex-public domain. + * + * page-level routines + */ + +#include "apr_sdbm.h" + +#include "sdbm_tune.h" +#include "sdbm_pair.h" +#include "sdbm_private.h" + +#include <string.h> /* for memset() */ + + +#define exhash(item) sdbm_hash((item).dptr, (item).dsize) + +/* + * forward + */ +static int seepair(char *, int, char *, int); + +/* + * page format: + * +------------------------------+ + * ino | n | keyoff | datoff | keyoff | + * +------------+--------+--------+ + * | datoff | - - - ----> | + * +--------+---------------------+ + * | F R E E A R E A | + * +--------------+---------------+ + * | <---- - - - | data | + * +--------+-----+----+----------+ + * | key | data | key | + * +--------+----------+----------+ + * + * calculating the offsets for free area: if the number + * of entries (ino[0]) is zero, the offset to the END of + * the free area is the block size. Otherwise, it is the + * nth (ino[ino[0]]) entry's offset. + */ + +int +fitpair(pag, need) +char *pag; +int need; +{ + register int n; + register int off; + register int avail; + register short *ino = (short *) pag; + + off = ((n = ino[0]) > 0) ? ino[n] : PBLKSIZ; + avail = off - (n + 1) * sizeof(short); + need += 2 * sizeof(short); + + debug(("avail %d need %d\n", avail, need)); + + return need <= avail; +} + +void +putpair(pag, key, val) +char *pag; +apr_sdbm_datum_t key; +apr_sdbm_datum_t val; +{ + register int n; + register int off; + register short *ino = (short *) pag; + + off = ((n = ino[0]) > 0) ? ino[n] : PBLKSIZ; +/* + * enter the key first + */ + off -= key.dsize; + (void) memcpy(pag + off, key.dptr, key.dsize); + ino[n + 1] = off; +/* + * now the data + */ + off -= val.dsize; + (void) memcpy(pag + off, val.dptr, val.dsize); + ino[n + 2] = off; +/* + * adjust item count + */ + ino[0] += 2; +} + +apr_sdbm_datum_t +getpair(pag, key) +char *pag; +apr_sdbm_datum_t key; +{ + register int i; + register int n; + apr_sdbm_datum_t val; + register short *ino = (short *) pag; + + if ((n = ino[0]) == 0) + return sdbm_nullitem; + + if ((i = seepair(pag, n, key.dptr, key.dsize)) == 0) + return sdbm_nullitem; + + val.dptr = pag + ino[i + 1]; + val.dsize = ino[i] - ino[i + 1]; + return val; +} + +int +duppair(pag, key) +char *pag; +apr_sdbm_datum_t key; +{ + register short *ino = (short *) pag; + return ino[0] > 0 && seepair(pag, ino[0], key.dptr, key.dsize) > 0; +} + +apr_sdbm_datum_t +getnkey(pag, num) +char *pag; +int num; +{ + apr_sdbm_datum_t key; + register int off; + register short *ino = (short *) pag; + + num = num * 2 - 1; + if (ino[0] == 0 || num > ino[0]) + return sdbm_nullitem; + + off = (num > 1) ? ino[num - 1] : PBLKSIZ; + + key.dptr = pag + ino[num]; + key.dsize = off - ino[num]; + + return key; +} + +int +delpair(pag, key) +char *pag; +apr_sdbm_datum_t key; +{ + register int n; + register int i; + register short *ino = (short *) pag; + + if ((n = ino[0]) == 0) + return 0; + + if ((i = seepair(pag, n, key.dptr, key.dsize)) == 0) + return 0; +/* + * found the key. if it is the last entry + * [i.e. i == n - 1] we just adjust the entry count. + * hard case: move all data down onto the deleted pair, + * shift offsets onto deleted offsets, and adjust them. + * [note: 0 < i < n] + */ + if (i < n - 1) { + register int m; + register char *dst = pag + (i == 1 ? PBLKSIZ : ino[i - 1]); + register char *src = pag + ino[i + 1]; + register short zoo = (short) (dst - src); + + debug(("free-up %d ", zoo)); +/* + * shift data/keys down + */ + m = ino[i + 1] - ino[n]; + +#undef DUFF /* just use memmove. it should be plenty fast. */ +#ifdef DUFF +#define MOVB *--dst = *--src + + if (m > 0) { + register int loop = (m + 8 - 1) >> 3; + + switch (m & (8 - 1)) { + case 0: do { + MOVB; case 7: MOVB; + case 6: MOVB; case 5: MOVB; + case 4: MOVB; case 3: MOVB; + case 2: MOVB; case 1: MOVB; + } while (--loop); + } + } +#else + dst -= m; + src -= m; + memmove(dst, src, m); +#endif + +/* + * adjust offset index up + */ + while (i < n - 1) { + ino[i] = ino[i + 2] + zoo; + i++; + } + } + ino[0] -= 2; + return 1; +} + +/* + * search for the key in the page. + * return offset index in the range 0 < i < n. + * return 0 if not found. + */ +static int +seepair(pag, n, key, siz) +char *pag; +register int n; +register char *key; +register int siz; +{ + register int i; + register int off = PBLKSIZ; + register short *ino = (short *) pag; + + for (i = 1; i < n; i += 2) { + if (siz == off - ino[i] && + memcmp(key, pag + ino[i], siz) == 0) + return i; + off = ino[i + 1]; + } + return 0; +} + +void +splpage(pag, new, sbit) +char *pag; +char *new; +long sbit; +{ + apr_sdbm_datum_t key; + apr_sdbm_datum_t val; + + register int n; + register int off = PBLKSIZ; + char cur[PBLKSIZ]; + register short *ino = (short *) cur; + + (void) memcpy(cur, pag, PBLKSIZ); + (void) memset(pag, 0, PBLKSIZ); + (void) memset(new, 0, PBLKSIZ); + + n = ino[0]; + for (ino++; n > 0; ino += 2) { + key.dptr = cur + ino[0]; + key.dsize = off - ino[0]; + val.dptr = cur + ino[1]; + val.dsize = ino[0] - ino[1]; +/* + * select the page pointer (by looking at sbit) and insert + */ + (void) putpair((exhash(key) & sbit) ? new : pag, key, val); + + off = ino[1]; + n -= 2; + } + + debug(("%d split %d/%d\n", ((short *) cur)[0] / 2, + ((short *) new)[0] / 2, + ((short *) pag)[0] / 2)); +} + +/* + * check page sanity: + * number of entries should be something + * reasonable, and all offsets in the index should be in order. + * this could be made more rigorous. + */ +int +chkpage(pag) +char *pag; +{ + register int n; + register int off; + register short *ino = (short *) pag; + + if ((n = ino[0]) < 0 || n > PBLKSIZ / sizeof(short)) + return 0; + + if (n > 0) { + off = PBLKSIZ; + for (ino++; n > 0; ino += 2) { + if (ino[0] < 0 || ino[0] > off || + ino[1] < 0 || ino[1] > off || + ino[1] > ino[0]) + return 0; + off = ino[1]; + n -= 2; + } + } + return 1; +} diff --git a/dbm/sdbm/sdbm_pair.h b/dbm/sdbm/sdbm_pair.h new file mode 100644 index 00000000000..222c5e17f4b --- /dev/null +++ b/dbm/sdbm/sdbm_pair.h @@ -0,0 +1,40 @@ +/* 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. + */ + +#ifndef SDBM_PAIR_H +#define SDBM_PAIR_H + +/* Mini EMBED (pair.c) */ +#define chkpage apu__sdbm_chkpage +#define delpair apu__sdbm_delpair +#define duppair apu__sdbm_duppair +#define fitpair apu__sdbm_fitpair +#define getnkey apu__sdbm_getnkey +#define getpair apu__sdbm_getpair +#define putpair apu__sdbm_putpair +#define splpage apu__sdbm_splpage + +int fitpair(char *, int); +void putpair(char *, apr_sdbm_datum_t, apr_sdbm_datum_t); +apr_sdbm_datum_t getpair(char *, apr_sdbm_datum_t); +int delpair(char *, apr_sdbm_datum_t); +int chkpage (char *); +apr_sdbm_datum_t getnkey(char *, int); +void splpage(char *, char *, long); +int duppair(char *, apr_sdbm_datum_t); + +#endif /* SDBM_PAIR_H */ + diff --git a/dbm/sdbm/sdbm_private.h b/dbm/sdbm/sdbm_private.h new file mode 100644 index 00000000000..f5d1ae06b56 --- /dev/null +++ b/dbm/sdbm/sdbm_private.h @@ -0,0 +1,84 @@ +/* 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. + */ + +/* + * sdbm - ndbm work-alike hashed database library + * based on Per-Ake Larson's Dynamic Hashing algorithms. BIT 18 (1978). + * author: oz@nexus.yorku.ca + */ + +#ifndef SDBM_PRIVATE_H +#define SDBM_PRIVATE_H + +#include "apr.h" +#include "apr_pools.h" +#include "apr_file_io.h" +#include "apr_errno.h" /* for apr_status_t */ + +#if 0 +/* if the block/page size is increased, it breaks perl apr_sdbm_t compatibility */ +#define DBLKSIZ 16384 +#define PBLKSIZ 8192 +#define PAIRMAX 8008 /* arbitrary on PBLKSIZ-N */ +#else +#define DBLKSIZ 4096 +#define PBLKSIZ 1024 +#define PAIRMAX 1008 /* arbitrary on PBLKSIZ-N */ +#endif +#define SPLTMAX 10 /* maximum allowed splits */ + +/* for apr_sdbm_t.flags */ +#define SDBM_RDONLY 0x1 /* data base open read-only */ +#define SDBM_SHARED 0x2 /* data base open for sharing */ +#define SDBM_SHARED_LOCK 0x4 /* data base locked for shared read */ +#define SDBM_EXCLUSIVE_LOCK 0x8 /* data base locked for write */ + +struct apr_sdbm_t { + apr_pool_t *pool; + apr_file_t *dirf; /* directory file descriptor */ + apr_file_t *pagf; /* page file descriptor */ + apr_int32_t flags; /* status/error flags, see below */ + long maxbno; /* size of dirfile in bits */ + long curbit; /* current bit number */ + long hmask; /* current hash mask */ + long blkptr; /* current block for nextkey */ + int keyptr; /* current key for nextkey */ + long blkno; /* current page to read/write */ + long pagbno; /* current page in pagbuf */ + char pagbuf[PBLKSIZ]; /* page file block buffer */ + long dirbno; /* current block in dirbuf */ + char dirbuf[DBLKSIZ]; /* directory file block buffer */ + int lckcnt; /* number of calls to sdbm_lock */ +}; + + +#define sdbm_hash apu__sdbm_hash +#define sdbm_nullitem apu__sdbm_nullitem + +extern const apr_sdbm_datum_t sdbm_nullitem; + +long sdbm_hash(const char *str, int len); + +/* + * zero the cache + */ +#define SDBM_INVALIDATE_CACHE(db, finfo) \ + do { db->dirbno = (!finfo.size) ? 0 : -1; \ + db->pagbno = -1; \ + db->maxbno = (long)(finfo.size * BYTESIZ); \ + } while (0); + +#endif /* SDBM_PRIVATE_H */ diff --git a/dbm/sdbm/sdbm_tune.h b/dbm/sdbm/sdbm_tune.h new file mode 100644 index 00000000000..9bf3d09f288 --- /dev/null +++ b/dbm/sdbm/sdbm_tune.h @@ -0,0 +1,40 @@ +/* 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. + */ + +/* + * sdbm - ndbm work-alike hashed database library + * tuning and portability constructs [not nearly enough] + * author: oz@nexus.yorku.ca + */ + +#ifndef SDBM_TUNE_H +#define SDBM_TUNE_H + +#include "apr_errno.h" + +/* ### this might be better off as sizeof(char *) */ +#define BYTESIZ 8 + +/* + * misc + */ +#ifdef DEBUG +#define debug(x) printf x +#else +#define debug(x) +#endif + +#endif /* SDBM_TUNE_H */ diff --git a/docs/APRDesign.html b/docs/APRDesign.html new file mode 100644 index 00000000000..7d1caeb8d4e --- /dev/null +++ b/docs/APRDesign.html @@ -0,0 +1,399 @@ +<HTML> +<HEAD><TITLE>APR Design Document</TITLE></HEAD> +<BODY> +<h1>Design of APR</h1> + +<p>The Apache Portable Run-time libraries have been designed to provide a common +interface to low level routines across any platform. The original goal of APR +was to combine all code in Apache to one common code base. This is not the +correct approach however, so the goal of APR has changed. There are places +where common code is not a good thing. For example, how to map requests +to either threads or processes should be platform specific. APR's place +is now to combine any code that can be safely combined without sacrificing +performance.</p> + +<p>To this end we have created a set of operations that are required for cross +platform development. There may be other types that are desired and those +will be implemented in the future.</p> + +<p>This document will discuss the structure of APR, and how best to contribute +code to the effort.</p> + +<h2>APR On Windows and Netware</h2> + +<p>APR on Windows and Netware is different from APR on all other systems, +because those platforms don't use autoconf. On Unix, apr_private.h (private to +APR) and apr.h (public, used by applications that use APR) are generated by +autoconf from acconfig.h and apr.h.in respectively. On Windows (and Netware), +apr_private.h and apr.h are created from apr_private.hw (apr_private.hwn) +and apr.hw (apr.hwn) respectively.</p> + +<p> <strong> + If you add code to acconfig.h or tests to configure.in or aclocal.m4, + please give some thought to whether or not Windows and Netware need + these additions as well. A general rule of thumb, is that if it is + a feature macro, such as APR_HAS_THREADS, Windows and Netware need it. + In other words, if the definition is going to be used in a public APR + header file, such as apr_general.h, Windows needs it. + + The only time it is safe to add a macro or test without also adding + the macro to apr*.h[n]w, is if the macro tells APR how to build. For + example, a test for a header file does not need to be added to Windows. +</strong></p> + +<h2>APR Features</h2> + +<p>One of the goals of APR is to provide a common set of features across all +platforms. This is an admirable goal, it is also not realistic. We cannot +expect to be able to implement ALL features on ALL platforms. So we are +going to do the next best thing. Provide a common interface to ALL APR +features on MOST platforms.</p> + +<p>APR developers should create FEATURE MACROS for any feature that is not +available on ALL platforms. This should be a simple definition which has +the form:</p> + +<code>APR_HAS_FEATURE</code> + +<p>This macro should evaluate to true if APR has this feature on this platform. +For example, Linux and Windows have mmap'ed files, and APR is providing an +interface for mmapp'ing a file. On both Linux and Windows, APR_HAS_MMAP +should evaluate to one, and the ap_mmap_* functions should map files into +memory and return the appropriate status codes.</p> + +<p>If your OS of choice does not have mmap'ed files, APR_HAS_MMAP should +evaluate to zero, and all ap_mmap_* functions should not be defined. The +second step is a precaution that will allow us to break at compile time if a +programmer tries to use unsupported functions.</p> + +<h2>APR types</h2> + +<p>The base types in APR</p> + +<ul> +<li>dso<br> + Shared library routines +<li>mmap<br> + Memory-mapped files +<li>poll<br> + Polling I/O +<li>time<br> + Time +<li>user<br> + Users and groups +<li>locks<br> + Process and thread locks (critical sections) +<li>shmem<br> + Shared memory +<li>file_io<br> + File I/O, including pipes +<li>atomic<br> + Atomic integer operations +<li>strings<br> + String handling routines +<li>memory<br> + Pool-based memory allocation +<li>passwd<br> + Reading passwords from the terminal +<li>tables<br> + Tables and hashes +<li>network_io<br> + Network I/O +<li>threadproc<br> + Threads and processes +<li>misc<br> + Any APR type which doesn't have any other place to belong. This + should be used sparingly. +<li>support<br> + Functions meant to be used across multiple APR types. This area + is for internal functions only. If a function is exposed, it should + not be put here. +</ul> + +<h2>Directory Structure</h2> + +<p>Each type has a base directory. Inside this base directory, are +subdirectories, which contain the actual code. These subdirectories are named +after the platforms the are compiled on. Unix is also used as a common +directory. If the code you are writing is POSIX based, you should look at the +code in the unix directory. A good rule of thumb, is that if more than half +your code needs to be ifdef'ed out, and the structures required for your code +are substantively different from the POSIX code, you should create a new +directory.</p> + +<p>Currently, the APR code is written for Unix, BeOS, Windows, and OS/2. An +example of the directory structure is the file I/O directory:</p> + +<pre> +apr + | + -> file_io + | + -> unix The Unix and common base code + | + -> win32 The Windows code + | + -> os2 The OS/2 code +</pre> + +<p>Obviously, BeOS does not have a directory. This is because BeOS is currently +using the Unix directory for it's file_io.</p> + +<p>There are a few special top level directories. These are test and include. +Test is a directory which stores all test programs. It is expected +that if a new type is developed, there will also be a new test program, to +help people port this new type to different platforms. A small document +describing how to create new tests that integrate with the test suite can be +found in the test/ directory. Include is a directory which stores all +required APR header files for external use.</p> + +<h2>Creating an APR Type</h2> + +<p>The current design of APR requires that most APR types be incomplete. +It is not possible to write flexible portable code if programs can access +the internals of APR types. This is because different platforms are +likely to define different native types. There are only two execptions to +this rule:</p> + +<ul> +<li>The first exception to this rule is if the type can only reasonably be +implemented one way. For example, time is a complete type because there +is only one reasonable time implementation. + +<li>The second exception to the incomplete type rule can be found in +apr_portable.h. This file defines the native types for each platform. +Using these types, it is possible to extract native types for any APR type.</p> +</ul> + +<p>For this reason, each platform defines a structure in their own directories. +Those structures are then typedef'ed in an external header file. For example +in file_io/unix/fileio.h:</p> + +<pre> + struct ap_file_t { + apr_pool_t *cntxt; + int filedes; + FILE *filehand; + ... + } +</pre> + +<p>In include/apr_file_io.h:</p> + </pre> + typedef struct ap_file_t ap_file_t; + </pre> + +<p> This will cause a compiler error if somebody tries to access the filedes +field in this structure. Windows does not have a filedes field, so obviously, +it is important that programs not be able to access these.</p> + +<p>You may notice the apr_pool_t field. Most APR types have this field. This +type is used to allocate memory within APR. Because every APR type has a pool, +any APR function can allocate memory if it needs to. This is very important +and it is one of the reasons that APR works. If you create a new type, you +must add a pool to it. If you do not, then all functions that operate on that +type will need a pool argument.</p> + +<h2>New Function</h2> + +<p>When creating a new function, please try to adhere to these rules.</p> + +<ul> +<li> Result arguments should be the first arguments. +<li> If a function needs a pool, it should be the last argument. +<li> These rules are flexible, especially if it makes the code easier + to understand because it mimics a standard function. +</ul> + +<h2>Documentation</h2> + +<p>Whenever a new function is added to APR, it MUST be documented. New +functions will not be committed unless there are docs to go along with them. +The documentation should be a comment block above the function in the header +file.</p> + +<p>The format for the comment block is:</p> + +<pre> + /** + * Brief description of the function + * @param parma_1_name explanation + * @param parma_2_name explanation + * @param parma_n_name explanation + * @tip Any extra information people should know. + * @deffunc function prototype if required + */ +</pre> + +<p>For an actual example, look at any file in the include directory. The +reason the docs are in the header files is to ensure that the docs always +reflect the current code. If you change paramters or return values for a +function, please be sure to update the documentation.</p> + +<h2>APR Error reporting</h2> + +<p>Most APR functions should return an ap_status_t type. The only time an +APR function does not return an ap_status_t is if it absolutely CAN NOT +fail. Examples of this would be filling out an array when you know you are +not beyond the array's range. If it cannot fail on your platform, but it +could conceivably fail on another platform, it should return an ap_status_t. +Unless you are sure, return an ap_status_t.</p> + +<strong> + This includes functions that return TRUE/FALSE values. How that + is handled is discussed below +</strong> + +<p>All platforms return errno values unchanged. Each platform can also have +one system error type, which can be returned after an offset is added. +There are five types of error values in APR, each with it's own offset.</p> + +<!-- This should be turned into a table, but I am lazy today --> +<pre> + Name Purpose +0) This is 0 for all platforms and isn't really defined + anywhere, but it is the offset for errno values. + (This has no name because it isn't actually defined, + but for completeness we are discussing it here). + +1) APR_OS_START_ERROR This is platform dependent, and is the offset at which + APR errors start to be defined. Error values are + defined as anything which caused the APR function to + fail. APR errors in this range should be named + APR_E* (i.e. APR_ENOSOCKET) + +2) APR_OS_START_STATUS This is platform dependent, and is the offset at which + APR status values start. Status values do not indicate + success or failure, and should be returned if + APR_SUCCESS does not make sense. APR status codes in + this range should be name APR_* (i.e. APR_DETACH) + +4) APR_OS_START_USEERR This is platform dependent, and is the offset at which + APR apps can begin to add their own error codes. + +3) APR_OS_START_SYSERR This is platform dependent, and is the offset at which + system error values begin. +</pre> + +<strong>The difference in naming between APR_OS_START_ERROR and +APR_OS_START_STATUS mentioned above allows programmers to easily determine if +the error code indicates an error condition or a status codition.</strong> + +<p>If your function has multiple return codes that all indicate success, but +with different results, or if your function can only return PASS/FAIL, you +should still return an apr_status_t. In the first case, define one +APR status code for each return value, an example of this is +<code>apr_proc_wait</code>, which can only return APR_CHILDDONE, +APR_CHILDNOTDONE, or an error code. In the second case, please return +APR_SUCCESS for PASS, and define a new APR status code for failure, an +example of this is <code>apr_compare_users</code>, which can only return +APR_SUCCESS, APR_EMISMATCH, or an error code.</p> + +<p>All of these definitions can be found in apr_errno.h for all platforms. When +an error occurs in an APR function, the function must return an error code. +If the error occurred in a system call and that system call uses errno to +report an error, then the code is returned unchanged. For example: </p> + +<pre> + if (open(fname, oflags, 0777) < 0) + return errno; +</pre> + +<p>The next place an error can occur is a system call that uses some error value +other than the primary error value on a platform. This can also be handled +by APR applications. For example:</p> + +<pre> + if (CreateFile(fname, oflags, sharemod, NULL, + createflags, attributes, 0) == INVALID_HANDLE_VALUE + return (GetLAstError() + APR_OS_START_SYSERR); +</pre> + +<p>These two examples implement the same function for two different platforms. +Obviously even if the underlying problem is the same on both platforms, this +will result in two different error codes being returned. This is OKAY, and +is correct for APR. APR relies on the fact that most of the time an error +occurs, the program logs the error and continues, it does not try to +programatically solve the problem. This does not mean we have not provided +support for programmatically solving the problem, it just isn't the default +case. We'll get to how this problem is solved in a little while.</p> + +<p>If the error occurs in an APR function but it is not due to a system call, +but it is actually an APR error or just a status code from APR, then the +appropriate code should be returned. These codes are defined in apr_errno.h +and should be self explanatory.</p> + +<p>No APR code should ever return a code between APR_OS_START_USEERR and +APR_OS_START_SYSERR, those codes are reserved for APR applications.</p> + +<p>To programmatically correct an error in a running application, the error +codes need to be consistent across platforms. This should make sense. APR +has provided macros to test for status code equivalency. For example, to +determine if the code that you received from the APR function means EOF, you +would use the macro APR_STATUS_IS_EOF().</p> + +<p>Why did APR take this approach? There are two ways to deal with error +codes portably.</p> + +<ol type=1> +<li> Return the same error code across all platforms. +<li> Return platform specific error codes and convert them when necessary. +</ol> + +<p>The problem with option number one is that it takes time to convert error +codes to a common code, and most of the time programs want to just output +an error string. If we convert all errors to a common subset, we have four +steps to output an error string:</p> + +<p>The seocnd problem with option 1, is that it is a lossy conversion. For +example, Windows and OS/2 have a couple hundred error codes, but POSIX errno +only defines about 50 errno values. This means that if we convert to a +canonical error value immediately, there is no way for the programmer to +get the actual system error.</p> + +<pre> + make syscall that fails + convert to common error code step 1 + return common error code + check for success + call error output function step 2 + convert back to system error step 3 + output error string step 4 +</pre> + +<p>By keeping the errors platform specific, we can output error strings in two +steps.</p> + +<pre> + make syscall that fails + return error code + check for success + call error output function step 1 + output error string step 2 +</pre> + +<p>Less often, programs change their execution based on what error was returned. +This is no more expensive using option 2 than it is using option 1, but we +put the onus of converting the error code on the programmer themselves. +For example, using option 1:</p> + +<pre> + make syscall that fails + convert to common error code + return common error code + decide execution based on common error code +</pre> + +<p>Using option 2:</p> + +<pre> + make syscall that fails + return error code + convert to common error code (using ap_canonical_error) + decide execution based on common error code +</pre> + +<p>Finally, there is one more operation on error codes. You can get a string +that explains in human readable form what has happened. To do this using +APR, call ap_strerror().</p> + diff --git a/docs/canonical_filenames.html b/docs/canonical_filenames.html new file mode 100644 index 00000000000..2bd9bdba822 --- /dev/null +++ b/docs/canonical_filenames.html @@ -0,0 +1,156 @@ +<HTML> +<HEAD><TITLE>APR Canonical Filenames</TITLE></HEAD> +<BODY> +<h1>APR Canonical Filename</h1> + +<h2>Requirements</h2> + +<p>APR porters need to address the underlying discrepancies between +file systems. To achieve a reasonable degree of security, the +program depending upon APR needs to know that two paths may be +compared, and that a mismatch is guarenteed to reflect that the +two paths do not return the same resource</p>. + +<p>The first discrepancy is in volume roots. Unix and pure deriviates +have only one root path, "/". Win32 and OS2 share root paths of +the form "D:/", D: is the volume designation. However, this can +be specified as "//./D:/" as well, indicating D: volume of the +'this' machine. Win32 and OS2 also may employ a UNC root path, +of the form "//server/share/" where share is a share-point of the +specified network server. Finally, NetWare root paths are of the +form "server/volume:/", or the simpler "volume:/" syntax for 'this' +machine. All these non-Unix file systems accept volume:path, +without a slash following the colon, as a path relative to the +current working directory, which APR will treat as ambigious, that +is, neither an absolute nor a relative path per se.</p> + +<p>The second discrepancy is in the meaning of the 'this' directory. +In general, 'this' must be eliminated from the path where it occurs. +The syntax "path/./" and "path/" are both aliases to path. However, +this isn't file system independent, since the double slash "//" has +a special meaning on OS2 and Win32 at the start of the path name, +and is invalid on those platforms before the "//server/share/" UNC +root path is completed. Finally, as noted above, "//./volume/" is +legal root syntax on WinNT, and perhaps others.</p> + +<p>The third discrepancy is in the context of the 'parent' directory. +When "parent/path/.." occurs, the path must be unwound to "parent". +It's also critical to simply truncate leading "/../" paths to "/", +since the parent of the root is root. This gets tricky on the +Win32 and OS2 platforms, since the ".." element is invalid before +the "//server/share/" is complete, and the "//server/share/../" +seqence is the complete UNC root "//server/share/". In relative +paths, leading ".." elements are significant, until they are merged +with an absolute path. The relative form must only retain the ".." +segments as leading segments, to be resolved once merged to another +relative or an absolute path.</p> + +<p>The fourth discrepancy occurs with acceptance of alternate character +codes for the same element. Path seperators are not retained within +the APR canonical forms. The OS filesystem and APR (slashed) forms +can both be returned as strings, to be used in the proper context. +Unix, Win32 and Netware all accept slashes and backslashes as the +same path seperator symbol, although unix strictly accepts slashes. +While the APR form of the name strictly uses slashes, always consider +that there could be a platform that actually accepts slashes as a +character within a segment name.</p> + +<p>The fifth and worst discrepancy plauges Win32, OS2, Netware, and some +filesystems mounted in Unix. Case insensitivity can permit the same +file to slip through in both it's proper case and alternate cases. +Simply changing the case is insufficient for any character set beyond +ASCII, since various dilectic forms of characters suffer from one to +many or many to one translations. An example would be u-umlaut, which +might be accepted as a single character u-umlaut, a two character +sequence u and the zero-width umlaut, the upper case form of the same, +or perhaps even a captial U alone. This can be handled in different +ways depending on the purposes of the APR based program, but the one +requirement is that the path must be absolute in order to resolve these +ambiguities. Methods employed include comparison of device and inode +file uniqifiers, which is a fairly fast operation, or quering the OS +for the true form of the name, which can be much slower. Only the +acknowledgement of the file names by the OS can validate the equality +of two different cases of the same filename.</p> + +<p>The sixth discrepancy, illegal or insignificant characters, is especially +significant in non-unix file systems. Trailing periods are accepted +but never stored, therefore trailing periods must be ignored for any +form of comparison. And all OS's have certain expectations of what +characters are illegal (or undesireable due to confusion.)</p> + +<p>A final warning, canonical functions don't transform or resolve case +or character ambiguity issues until they are resolved into an absolute +path. The relative canonical path, while useful, while useful for URL +or similar identifiers, cannot be used for testing or comparison of file +system objects.</p> + +<hr> + +<h2>Canonical API</h2> + +Functions to manipulate the apr_canon_file_t (an opaque type) include: + +<ul> +<li>Create canon_file_t (from char* path and canon_file_t parent path) +<li>Merged canon_file_t (from path and parent, both canon_file_t) +<li>Get char* path of all or some segments +<li>Get path flags of IsRelative, IsVirtualRoot, and IsAbsolute +<li>Compare two canon_file_t structures for file equality +</ul> + +<p>The path is corrected to the file system case only if is in absolute +form. The apr_canon_file_t should be preserved as long as possible and +used as the parent to create child entries to reduce the number of expensive +stat and case canonicalization calls to the OS.</p> + +<p>The comparison operation provides that the APR can postpone correction +of case by simply relying upon the device and inode for equivalence. The +stat implementation provides that two files are the same, while their +strings are not equivalent, and eliminates the need for the operating +system to return the proper form of the name.</p> + +<p>In any case, returning the char* path, with a flag to request the proper +case, forces the OS calls to resolve the true names of each segment. Where +there is a penality for this operation and the stat device and inode test +is faster, case correction is postponed until the char* result is requested. +On platforms that identify the inode, device, or proper name interchangably +with no penalities, this may occur when the name is initially processed.</p> + +<hr> + +<h2>Unix Example</h2> + +<p>First the simplest case:</p> + +<pre> +Parse Canonical Name +accepts parent path as canonical_t + this path as string + +Split this path Segments on '/' + +For each of this path Segments + If first Segment + If this Segment is Empty ([nothing]/) + Append this Root Segment (don't merge) + Continue to next Segment + Else is relative + Append parent Segments (to merge) + Continue with this Segment + If Segment is '.' or empty (2 slashes) + Discard this Segment + Continue with next Segment + If Segment is '..' + If no previous Segment or previous Segment is '..' + Append this Segment + Continue with next Segment + If previous Segment and previous is not Root Segment + Discard previous Segment + Discard this Segment + Continue with next Segment + Append this Relative Segment + Continue with next Segment +</pre> + +</BODY> +</HTML> diff --git a/docs/doxygen.conf b/docs/doxygen.conf new file mode 100644 index 00000000000..86145a4d061 --- /dev/null +++ b/docs/doxygen.conf @@ -0,0 +1,42 @@ +PROJECT_NAME="Apache Portable Runtime" + +INPUT=. +QUIET=YES +RECURSIVE=YES +FILE_PATTERNS=*.h + +OUTPUT_DIRECTORY=docs/dox + +MACRO_EXPANSION=YES +EXPAND_ONLY_PREDEF=YES +#EXPAND_AS_DEFINED= +# not sure why this doesn't work as EXPAND_AS_DEFINED, it should! +PREDEFINED="APR_DECLARE(x)=x" \ + "APR_DECLARE_NONSTD(x)=x" \ + "APR_DECLARE_LDAP(x)=x" \ + "APR_DECLARE_DATA" \ + "APR_POOL_DECLARE_ACCESSOR(x)=apr_pool_t* apr_##x##_pool_get (const apr_##x##_t *the##x)" \ + "APR_DECLARE_INHERIT_SET(x)=apr_status_t apr_##x##_inherit_set(apr_##x##_t *the##x)" \ + "APR_DECLARE_INHERIT_UNSET(x)=apr_status_t apr_##x##_inherit_unset(apr_##x##_t *the##x)" \ + "APR_HAS_THREADS" \ + "APR_HAS_MMAP" \ + "APR_HAS_XLATE" \ + "APR_MODULE_DECLARE_DATA" \ + "__attribute__(x)=" \ + DOXYGEN= + +OPTIMIZE_OUTPUT_FOR_C=YES +STRIP_CODE_COMMENTS=NO + +FULL_PATH_NAMES=NO +CASE_SENSE_NAMES=NO +# some autoconf guru needs to make configure set this correctly... +# in the meantime, simply listing the headers should be alright +#STRIP_FROM_PATH=/buildpath/apr + +EXCLUDE_PATTERNS="*/acconfig.h" \ + "*/test/*" \ + "*/arch/*" + +GENERATE_TAGFILE=docs/dox/apr.tag + diff --git a/docs/incomplete_types b/docs/incomplete_types new file mode 100644 index 00000000000..cbed7774232 --- /dev/null +++ b/docs/incomplete_types @@ -0,0 +1,84 @@ +The question has been asked multiple times, "Why is APR using Incomplete +types?" This document will try to explain that. + +Incomplete types are used in APR because they can enforce portability, and +they make the APR developers job easier, as well as allowing APR to use native +types on all platforms. Imagine a scenario where APR wasn't using incomplete +types. The ap_file_t type would have to be defined as: + +typedef struct ap_file_t { + ap_pool_t *pool + char *fname; + int eof_hit; + int pipe; + ap_interval_time_t timeout; +#ifdef WIN32 + HANDLE file_handle; + DWORD dwFileAttributes; +#elif defined(OS2) + HFILE filedes; + HEV PipeSem +#else + int filedes; + int ungetchar; +#endif + +#ifndef WIN32 + int buffered; + ap_int32_flags + int isopen; + + /* Stuff for buffered mode */ + char *buffer; + int bufpos; + unsigned long dataRead; + int direction; + unsigned long filePtr; + ap_lock_t *mutex; +#endif +} ap_file_t; + +This captures the essense of what is currently being defined for ap_file_t +using incomplete types. However, using this structure leads developers to +believe that they are safe accessing any of the fields in this structure. +This is not true. On some platforms, such as Windows, about half of the +structure disappears. We could combine some of these definitions with +macros, for example: + +#ifdef WIN32 +#define filetype HANDLE +#elif OS2 +#define filetype HFILE +#else +#define filetype int +#endif + +And then in the defintion for ap_file_t, we could say: + filetype filedes; + +This gets rid of some of the complexity, by moving it off to the side, but +it is still not safe for a programmers to access the filedes field directly +outside of APR, because the programmer has no way of knowing what the actual +type is. So for example printing the filedes using printf would yield wildly +varying results on Windows and OS2 when compared to Unix. + +Another option also presents itself. Stick strictly to POSIX. This means +that all code can be shared on any POSIX compliant platform. The problem +with this is performance. One of the benefits to APR, is that it allows +developers to easily use native types on all platforms with the same code. +This has proven to provide a substantial performance boost on most non-Unix +platforms. + +Having said all of that, sometimes incomplete types just don't make sense. +For example, the first implementation of time functions used incomplete types, +which added a layer of complexity that turned out to be unnecessary. If +a platform cannot provide a simple number that represents the number of seconds +elapsed since a specifed date and time, then APR doesn't really want to +provide support for that platform. + +APR is trying hard to provide a balance of incomplete and complete types, +but like all things, sometimes the developers make mistakes. If you are +using APR and find that there is an incomplete type that doesn't need to be +an incomplete type, please let us know, we are more than willing to listen +and design parts of APR that do not use incomplete types. + diff --git a/docs/non_apr_programs b/docs/non_apr_programs new file mode 100644 index 00000000000..5003a8bd550 --- /dev/null +++ b/docs/non_apr_programs @@ -0,0 +1,47 @@ +How do I use APR'ized programs in connection with programs that don't +use APR? These darn incomplete types don't let me fill out the APR types. + +The APR developers acknowledge that most programs are not using APR, and +we don't expect them to migrate to using APR just because APR has been +released. So, we have provided a way for non-APR'ized programs to interact +very cleanly with APR. + +There are a set of functions, all documented in apr_portable.h, which allow +a programmer to either get a native type from an APR type, or to setup an +APR type from a native type. + +For example, if you are writing an add-on to another program that does not use +APR for file I/O, but you (in your infinite wisdom) want to use APR to make +sure your section is portable. Assume the program provides a type foo_t with +a file descriptor in it (fd). + +void function_using_apr(foo_t non_apr_struct, ap_pool_t *p) +{ + ap_file_t *apr_file = NULL; + + ap_put_os_file(&apr_file, &non_apr_struct->fd, p); + + ... +} + +There are portable functions for each APR incomplete type. They are all +called ap_put_os_foobar(), and they each take the same basic arguments, a +pointer to a pointer to the incomplete type (the last pointer in that list +should be NULL), a pointer to the native type, and a pool. Each of these can +be found in apr_portable.h. + +If you have to do the exact opposite (take an APR type and convert it to a +native type, there are functions for that too. For example: + +void function_not_using_apr(apr_file_t *apr_file) +{ + int unix_file_desc; + + ap_get_os_file(&unix_file_desc, apr_file); + + ... +} + +For each ap_put_os_foobar, there is a corresponding ap_get_os_file. These are +also documented in apr_portable.h. + diff --git a/docs/pool-design.html b/docs/pool-design.html new file mode 100644 index 00000000000..46b63d62b2b --- /dev/null +++ b/docs/pool-design.html @@ -0,0 +1,96 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> +<html><head> + <title>Using APR Pools</title> + </head> + <body> + <h1>Using APR Pools</h1> + + <p> + From <a href="http://subversion.tigris.org/">Subversion</a>, we + have learned a <em>lot</em> about how to use pools in a heavily + structured/object-based environment. + <a href="http://httpd.apache.org/">Apache httpd</a> is a + completely different beast: "allocate a request pool. use + it. destroy it." + </p> + + <p> + In a complex app, that request-style of behavior is not + present. Luckily, the "proper" use of pools can be described in + just a few rules: + </p> + + <ul> + <li> + Objects should not have their own pools. An object is + allocated into a pool defined by the constructor's caller. The + <strong>caller</strong> knows the lifetime of the object and + will manage it via the pool. Generally, this also means that + objects will not have a "close" or a "free" since those + operations will happen implicitly as part of the destruction + of the pool the objects live within. + </li> + + <li> + <p> + Functions should not create/destroy pools for their + operation; they should use a pool provided by the + caller. Again, the <strong>caller</strong> knows more about + how the function will be used, how often, how many times, + etc. Thus, it should be in charge of the function's memory + usage. + </p> + <p> + As an example, the caller might know that the app will exit + upon the function's return. Thus, the function would be + creating extra work if it built and destroyed a + pool. Instead, it should use the passed-in pool, which the + caller is going to be tossing as part of app-exit anyways. + </p> + </li> + + <li> + <p> + Whenever an unbounded iteration occurs, a subpool should be + used. The general pattern is: + </p> + <blockquote> + <pre> +subpool = apr_create_subpool(pool); +for (i = 0; i < n; ++i) { + apr_pool_clear(subpool); + + do_operation(..., subpool); +} +apr_pool_destroy(subpool);</pre> + </blockquote> + <p> + This pattern prevents the 'pool' from growing unbounded and + consuming all of memory. Note that it is slightly more + optimal to clear the pool on loop-entry. This pattern also + allows for a '<tt>continue</tt>' to occur within the loop, + yet still ensure the pool will be cleared. + </p> + </li> + + <li> + Given all of the above, it is pretty well mandatory to pass a + pool to <em>every</em> function. Since objects are not + recording pools for themselves, and the caller is always + supposed to be managing memory, then each function needs a + pool, rather than relying on some hidden magic pool. In + limited cases, objects may record the pool used for their + construction so that they can construct sub-parts, but these + cases should be examined carefully. Internal pools can lead to + unbounded pool usage if the object is not careful. + </li> + </ul> + + <hr> + <address>Greg Stein</address> + <!-- Created: Wed Jun 25 14:39:57 PDT 2003 --> + <!-- hhmts start --> +Last modified: Wed Jun 25 14:50:19 PDT 2003 +<!-- hhmts end --> + +</body></html> diff --git a/docs/win32_builds.html b/docs/win32_builds.html new file mode 100644 index 00000000000..c835829824b --- /dev/null +++ b/docs/win32_builds.html @@ -0,0 +1,57 @@ +<HTML> +<HEAD><TITLE>APR Win32 Builds and Debugging</TITLE></HEAD> +<BODY> +<h1>APR Win32 Builds and Debugging</h1> + +<h2>Configuration and Flavors</h2> + +<p>The Win32 APR Developer Studio projects consist of</p> + +<dl> + <dt>apr/apr.dsp</dt> + <dd>Builds the static apr.lib library (-D APR_DECLARE_STATIC)</dd> + <dt>apr/libapr.dsp</dt> + <dd>Builds the dynamic libapr.dll library (no define required)</dd> + <dt>apr-util/aprutil.dsp</dt> + <dd>Builds the static aprutil.lib library (-D APR_DECLARE_STATIC)</dd> + <dt>apr-util/libaprutil.dsp</dt> + <dd>Builds the dynamic libaprutil.dll library (no define required)</dd> + <dt>apr-iconv/apriconv.dsp</dt> + <dd>Builds the static apriconv.lib library (-D API_DECLARE_STATIC)</dd> + <dt>apr-iconv/libapriconv.dsp</dt> + <dd>Builds the dynamic libapriconv.dll library (no define required)</dd> +</dl> + +<p>In order to prepare to use one of the <em>static</em> libraries above, + your application must be compiled with the define shown above, so that the + correct linkage is created. The APR authors intended the use of dynamic + libraries by default, so application authors do not need any special + defines in order to link to the dynamic library flavors.</p> + +<p>In order to build APR, you must use the proper dependencies. A good + example of those dependencies is given in the apr-util/aprutil.dsw + Developer Studio workspace. You can borrow the parts of that structure + your application needs, that workspace defines both the dynamic and static + library dependencies.</p> + +<p>The APR libraries (dynamic and static) are compiled with debugging symbols, + even in Release builds. The dynamic library symbols are always usable, + simply keep the correspond .pdb file in the same path as the library .dll. + (E.g. both libapr.dll and libapr.pdb should be copied to the same path.)</p> + +<p>The static symbols will only be fully usable if your application does <em>not<em> + link with the /pdbtype:sept flag! At the time your application links to + an APR library, the corresponding _src.pdb file should exist in the original + path the library was built, or it may be sufficient to keep the _src.pdb file + in the same path as the library file. (E.g. apr.lib and apr_src.pdb should + reside together in your lib directory.) The later option is unconfirmed.</p> + +<p>In order to keep the symbols compiled into the static library, your application + must use the linker's /debug flag. If you do not want the application to be + debuggable with its corresponding .pdb file, omit the /debug flag and all debug + symbolic information is discarded. Note that your application can only be + debugged with the corresponding .pdb file created by the linker, unless you use + /debugtype:coff or /debugtype:both in your link options.</p> + +</BODY> +</HTML> diff --git a/dso/aix/Makefile.in b/dso/aix/Makefile.in deleted file mode 100644 index 56714ed3aa5..00000000000 --- a/dso/aix/Makefile.in +++ /dev/null @@ -1,61 +0,0 @@ -#CFLAGS=$(OPTIM) $(CFLAGS1) $(EXTRA_CFLAGS) -#LIBS=$(EXTRA_LIBS) $(LIBS1) -#INCLUDES=$(INCLUDES1) $(INCLUDES0) $(EXTRA_INCLUDES) -#LDFLAGS=$(LDFLAGS1) $(EXTRA_LDFLAGS) - -RM=@RM@ -CC=@CC@ -RANLIB=@RANLIB@ -CFLAGS=@CFLAGS@ @OPTIM@ -LIBS=@LIBS@ -LDFLAGS=@LDFLAGS@ $(LIBS) -INCDIR=../../include -INCLUDES=-I$(INCDIR) -I$(INCDIR1) -I. - -LIB=libdso.a - -OBJS=dso.o - -.c.o: - $(CC) $(CFLAGS) -c $(INCLUDES) $< - -all: $(LIB) - -clean: - $(RM) -f *.o *.a *.so - -distclean: clean - -$(RM) -f Makefile - -$(OBJS): Makefile - -$(LIB): $(OBJS) - $(RM) -f $@ - $(AR) cr $@ $(OBJS) - $(RANLIB) $@ - -# -# We really don't expect end users to use this rule. It works only with -# gcc, and rebuilds Makefile.tmpl. You have to re-run Configure after -# using it. -# -depend: - cp Makefile.in Makefile.in.bak \ - && sed -ne '1,/^# DO NOT REMOVE/p' Makefile.in > Makefile.new \ - && gcc -MM $(INCLUDES) $(CFLAGS) *.c >> Makefile.new \ - && sed -e '1,$$s: $(INCDIR)/: $$(INCDIR)/:g' \ - -e '1,$$s: $(OSDIR)/: $$(OSDIR)/:g' Makefile.new \ - > Makefile.in \ - && rm Makefile.new - -# DO NOT REMOVE -getopt.o: getopt.c misc.h ../../include/apr_private.h \ - ../../include/apr_general.h ../../include/apr.h \ - ../../include/apr_errno.h ../../include/apr_pools.h \ - ../../include/apr_lib.h ../../include/apr_file_io.h \ - ../../include/apr_getopt.h -start.o: start.c misc.h ../../include/apr_private.h \ - ../../include/apr_general.h ../../include/apr.h \ - ../../include/apr_errno.h ../../include/apr_pools.h \ - ../../include/apr_lib.h ../../include/apr_file_io.h \ - ../../include/apr_getopt.h diff --git a/dso/aix/dso.c b/dso/aix/dso.c index d43c8fdd99d..25f6262af86 100644 --- a/dso/aix/dso.c +++ b/dso/aix/dso.c @@ -1,59 +1,23 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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. */ /* * dso.c -- DSO system function emulation for AIX + * + * This is *only* intended for AIX < 4.3. */ /* @@ -85,7 +49,10 @@ #include <sys/types.h> #include <sys/ldr.h> #include <a.out.h> -#include "dso.h" +#include "apr_arch_dso.h" +#include "apr_portable.h" + +#if APR_HAS_DSO #undef FREAD #undef FWRITE @@ -116,7 +83,7 @@ #define RTLD_GLOBAL 0x100 /* allow symbols to be global */ /* - * To be able to intialize, a library may provide a dl_info structure + * To be able to initialize, a library may provide a dl_info structure * that contains functions to be called to initialize and terminate. */ struct dl_info { @@ -130,45 +97,84 @@ struct dl_info { * add the basic "wrappers" here. */ -ap_status_t ap_dso_init(void){ +APR_DECLARE(apr_status_t) apr_os_dso_handle_put(apr_dso_handle_t **aprdso, + apr_os_dso_handle_t osdso, + apr_pool_t *pool) +{ + *aprdso = apr_pcalloc(pool, sizeof **aprdso); + (*aprdso)->handle = osdso; + (*aprdso)->pool = pool; return APR_SUCCESS; } -ap_status_t ap_dso_load(ap_dso_handle_t **res_handle, const char *path, - ap_pool_t *ctx) +APR_DECLARE(apr_status_t) apr_os_dso_handle_get(apr_os_dso_handle_t *osdso, + apr_dso_handle_t *aprdso) +{ + *osdso = aprdso->handle; + return APR_SUCCESS; +} + +static apr_status_t dso_cleanup(void *thedso) +{ + apr_dso_handle_t *dso = thedso; + + if (dso->handle != NULL && dlclose(dso->handle) != 0) + return APR_EINIT; + dso->handle = NULL; + + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_dso_load(apr_dso_handle_t **res_handle, + const char *path, apr_pool_t *ctx) { void *os_handle = dlopen((char *)path, RTLD_NOW | RTLD_GLOBAL); - if(os_handle == NULL) + *res_handle = apr_pcalloc(ctx, sizeof(*res_handle)); + + if(os_handle == NULL) { + (*res_handle)->errormsg = dlerror(); return APR_EDSOOPEN; + } - *res_handle = ap_pcalloc(ctx, sizeof(*res_handle)); (*res_handle)->handle = (void*)os_handle; - (*res_handle)->cont = ctx; + (*res_handle)->pool = ctx; + (*res_handle)->errormsg = NULL; + + apr_pool_cleanup_register(ctx, *res_handle, dso_cleanup, apr_pool_cleanup_null); + return APR_SUCCESS; } -ap_status_t ap_dso_unload(ap_dso_handle_t *handle) +APR_DECLARE(apr_status_t) apr_dso_unload(apr_dso_handle_t *handle) { - if (dlclose(handle->handle) != 0) - return APR_EINIT; - - return APR_SUCCESS; + return apr_pool_cleanup_run(handle->pool, handle, dso_cleanup); } -ap_status_t ap_dso_sym(ap_dso_handle_sym_t *ressym, - ap_dso_handle_t *handle, - const char *symname) +APR_DECLARE(apr_status_t) apr_dso_sym(apr_dso_handle_sym_t *ressym, + apr_dso_handle_t *handle, + const char *symname) { void *retval = dlsym(handle->handle, symname); - if (retval == NULL) - return APR_EINIT; - - ressym = retval; + if (retval == NULL) { + handle->errormsg = dlerror(); + return APR_ESYMNOTFOUND; + } + + *ressym = retval; return APR_SUCCESS; } +APR_DECLARE(const char *) apr_dso_error(apr_dso_handle_t *dso, char *buffer, apr_size_t buflen) +{ + if (dso->errormsg) { + apr_cpystrn(buffer, dso->errormsg, buflen); + return dso->errormsg; + } + return "No Error"; +} + /* @@ -273,7 +279,7 @@ void *dlopen(const char *path, int mode) * load should be declared load(const char *...). Thus we * cast the path to a normal char *. Ugly. */ - if ((mp->entry = (void *) load((char *) path, L_NOAUTODEFER, NULL)) == NULL) { + if ((mp->entry = (void *) loadAndInit((char *) path, L_NOAUTODEFER, NULL)) == NULL) { free(mp->name); free(mp); errvalid++; @@ -704,3 +710,5 @@ static void *findMain(void) free(buf); return ret; } + +#endif diff --git a/dso/aix/dso.h b/dso/aix/dso.h deleted file mode 100644 index 392a92015ab..00000000000 --- a/dso/aix/dso.h +++ /dev/null @@ -1,73 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#ifndef DSO_H -#define DSO_H - -#include "apr_private.h" -#include "apr_general.h" -#include "apr_pools.h" -#include "apr_dso.h" - -void *dlopen(const char *path, int mode); -void *dlsym(void *handle, const char *symbol); -const char *dlerror(void); -int dlclose(void *handle); - -struct ap_dso_handle_t { - ap_pool_t *cont; - void *handle; -}; - -#endif diff --git a/dso/beos/Makefile.in b/dso/beos/Makefile.in deleted file mode 100644 index 6c5788d86f1..00000000000 --- a/dso/beos/Makefile.in +++ /dev/null @@ -1,60 +0,0 @@ -#CFLAGS=$(OPTIM) $(CFLAGS1) $(EXTRA_CFLAGS) -#LIBS=$(EXTRA_LIBS) $(LIBS1) -#INCLUDES=$(INCLUDES1) $(INCLUDES0) $(EXTRA_INCLUDES) -#LDFLAGS=$(LDFLAGS1) $(EXTRA_LDFLAGS) - -CC=@CC@ -RANLIB=@RANLIB@ -CFLAGS=@CFLAGS@ @OPTIM@ -LIBS=@LIBS@ -LDFLAGS=@LDFLAGS@ $(LIBS) -INCDIR=../../include -INCLUDES=-I$(INCDIR) -I$(INCDIR1) -I. - -LIB=libdso.a - -OBJS=dso.o - -.c.o: - $(CC) $(CFLAGS) -c $(INCLUDES) $< - -all: $(LIB) - -clean: - $(RM) -f *.o *.a *.so - -distclean: clean - -$(RM) -f Makefile - -$(OBJS): Makefile - -$(LIB): $(OBJS) - $(RM) -f $@ - $(AR) cr $@ $(OBJS) - $(RANLIB) $@ - -# -# We really don't expect end users to use this rule. It works only with -# gcc, and rebuilds Makefile.tmpl. You have to re-run Configure after -# using it. -# -depend: - cp Makefile.in Makefile.in.bak \ - && sed -ne '1,/^# DO NOT REMOVE/p' Makefile.in > Makefile.new \ - && gcc -MM $(INCLUDES) $(CFLAGS) *.c >> Makefile.new \ - && sed -e '1,$$s: $(INCDIR)/: $$(INCDIR)/:g' \ - -e '1,$$s: $(OSDIR)/: $$(OSDIR)/:g' Makefile.new \ - > Makefile.in \ - && rm Makefile.new - -# DO NOT REMOVE -getopt.o: getopt.c misc.h ../../include/apr_private.h \ - ../../include/apr_general.h ../../include/apr.h \ - ../../include/apr_errno.h ../../include/apr_pools.h \ - ../../include/apr_lib.h ../../include/apr_file_io.h \ - ../../include/apr_getopt.h -start.o: start.c misc.h ../../include/apr_private.h \ - ../../include/apr_general.h ../../include/apr.h \ - ../../include/apr_errno.h ../../include/apr_pools.h \ - ../../include/apr_lib.h ../../include/apr_file_io.h \ - ../../include/apr_getopt.h diff --git a/dso/beos/dso.c b/dso/beos/dso.c index c63102739b5..91dd1b4e81c 100644 --- a/dso/beos/dso.c +++ b/dso/beos/dso.c @@ -1,99 +1,98 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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 "dso.h" +#include "apr_arch_dso.h" +#include "apr_portable.h" +#if APR_HAS_DSO + +static apr_status_t dso_cleanup(void *thedso) +{ + apr_dso_handle_t *dso = thedso; + + if (dso->handle > 0 && unload_add_on(dso->handle) < B_NO_ERROR) + return APR_EINIT; + dso->handle = -1; -ap_status_t ap_dso_init(void){ return APR_SUCCESS; } -ap_status_t ap_dso_load(ap_dso_handle_t **res_handle, const char *path, - ap_pool_t *ctx) +APR_DECLARE(apr_status_t) apr_dso_load(apr_dso_handle_t **res_handle, + const char *path, apr_pool_t *pool) { - image_id newid; + image_id newid = -1; - if((newid = load_add_on(path)) < B_NO_ERROR) - return APR_EINIT; + *res_handle = apr_pcalloc(pool, sizeof(*res_handle)); - *res_handle = ap_pcalloc(ctx, sizeof(*res_handle)); + if((newid = load_add_on(path)) < B_NO_ERROR) { + (*res_handle)->errormsg = strerror(newid); + return APR_EDSOOPEN; + } + + (*res_handle)->pool = pool; (*res_handle)->handle = newid; - (*res_handle)->cont = ctx; + + apr_pool_cleanup_register(pool, *res_handle, dso_cleanup, apr_pool_cleanup_null); + return APR_SUCCESS; } -ap_status_t ap_dso_unload(ap_dso_handle_t *handle) +APR_DECLARE(apr_status_t) apr_dso_unload(apr_dso_handle_t *handle) { - if(unload_add_on(handle->handle) < B_NO_ERROR) - return APR_EINIT; - - return APR_SUCCESS; + return apr_pool_cleanup_run(handle->pool, handle, dso_cleanup); } -ap_status_t ap_dso_sym(ap_dso_handle_sym_t *ressym, ap_dso_handle_t *handle, +APR_DECLARE(apr_status_t) apr_dso_sym(apr_dso_handle_sym_t *ressym, apr_dso_handle_t *handle, const char *symname) { int err; if (symname == NULL) - return APR_EINIT; + return APR_ESYMNOTFOUND; err = get_image_symbol(handle->handle, symname, B_SYMBOL_TYPE_ANY, ressym); if(err != B_OK) - return APR_EINIT; + return APR_ESYMNOTFOUND; return APR_SUCCESS; } + +APR_DECLARE(const char *) apr_dso_error(apr_dso_handle_t *dso, char *buffer, apr_size_t buflen) +{ + strncpy(buffer, strerror(errno), buflen); + return buffer; +} + +APR_DECLARE(apr_status_t) apr_os_dso_handle_put(apr_dso_handle_t **aprdso, + apr_os_dso_handle_t osdso, + apr_pool_t *pool) +{ + *aprdso = apr_pcalloc(pool, sizeof **aprdso); + (*aprdso)->handle = osdso; + (*aprdso)->pool = pool; + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_os_dso_handle_get(apr_os_dso_handle_t *osdso, + apr_dso_handle_t *aprdso) +{ + *osdso = aprdso->handle; + return APR_SUCCESS; +} + +#endif diff --git a/dso/beos/dso.h b/dso/beos/dso.h deleted file mode 100644 index 2666d779ad2..00000000000 --- a/dso/beos/dso.h +++ /dev/null @@ -1,70 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#ifndef DSO_H -#define DSO_H - -#include "apr_private.h" -#include "apr_general.h" -#include "apr_pools.h" -#include "apr_errno.h" -#include "apr_dso.h" -#include <kernel/image.h> - -struct ap_dso_handle_t { - image_id handle; /* Handle to the DSO loaded */ - ap_pool_t *cont; -}; - -#endif diff --git a/dso/netware/dso.c b/dso/netware/dso.c new file mode 100644 index 00000000000..4cd2ad611ed --- /dev/null +++ b/dso/netware/dso.c @@ -0,0 +1,137 @@ +/* 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_dso.h" +#include "apr_strings.h" +#include "apr_portable.h" + +#include <library.h> +#include <unistd.h> + +APR_DECLARE(apr_status_t) apr_os_dso_handle_put(apr_dso_handle_t **aprdso, + apr_os_dso_handle_t osdso, + apr_pool_t *pool) +{ + *aprdso = apr_pcalloc(pool, sizeof **aprdso); + (*aprdso)->handle = osdso; + (*aprdso)->pool = pool; + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_os_dso_handle_get(apr_os_dso_handle_t *osdso, + apr_dso_handle_t *aprdso) +{ + *osdso = aprdso->handle; + return APR_SUCCESS; +} + +static apr_status_t dso_cleanup(void *thedso) +{ + apr_dso_handle_t *dso = thedso; + sym_list *symbol = NULL; + void *NLMHandle = getnlmhandle(); + + if (dso->handle == NULL) + return APR_SUCCESS; + + if (dso->symbols != NULL) { + symbol = dso->symbols; + while (symbol) { + UnImportPublicObject(NLMHandle, symbol->symbol); + symbol = symbol->next; + } + } + + if (dlclose(dso->handle) != 0) + return APR_EINIT; + + dso->handle = NULL; + dso->symbols = NULL; + dso->path = NULL; + + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_dso_load(apr_dso_handle_t **res_handle, + const char *path, apr_pool_t *pool) +{ + + void *os_handle = NULL; + char *fullpath = NULL; + apr_status_t rv; + + if ((rv = apr_filepath_merge(&fullpath, NULL, path, + APR_FILEPATH_NATIVE, pool)) != APR_SUCCESS) { + return rv; + } + + os_handle = dlopen(fullpath, RTLD_NOW | RTLD_LOCAL); + + *res_handle = apr_pcalloc(pool, sizeof(**res_handle)); + + if(os_handle == NULL) { + (*res_handle)->errormsg = dlerror(); + return APR_EDSOOPEN; + } + + (*res_handle)->handle = (void*)os_handle; + (*res_handle)->pool = pool; + (*res_handle)->errormsg = NULL; + (*res_handle)->symbols = NULL; + (*res_handle)->path = apr_pstrdup(pool, fullpath); + + apr_pool_cleanup_register(pool, *res_handle, dso_cleanup, apr_pool_cleanup_null); + + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_dso_unload(apr_dso_handle_t *handle) +{ + return apr_pool_cleanup_run(handle->pool, handle, dso_cleanup); +} + +APR_DECLARE(apr_status_t) apr_dso_sym(apr_dso_handle_sym_t *ressym, + apr_dso_handle_t *handle, + const char *symname) +{ + sym_list *symbol = NULL; + void *retval = dlsym(handle->handle, symname); + + if (retval == NULL) { + handle->errormsg = dlerror(); + return APR_ESYMNOTFOUND; + } + + symbol = apr_pcalloc(handle->pool, sizeof(sym_list)); + symbol->next = handle->symbols; + handle->symbols = symbol; + symbol->symbol = apr_pstrdup(handle->pool, symname); + + *ressym = retval; + + return APR_SUCCESS; +} + +APR_DECLARE(const char *) apr_dso_error(apr_dso_handle_t *dso, char *buffer, + apr_size_t buflen) +{ + if (dso->errormsg) { + apr_cpystrn(buffer, dso->errormsg, buflen); + return dso->errormsg; + } + return "No Error"; +} + diff --git a/dso/os2/Makefile.in b/dso/os2/Makefile.in deleted file mode 100644 index 8fadaff4bb5..00000000000 --- a/dso/os2/Makefile.in +++ /dev/null @@ -1,57 +0,0 @@ -#CFLAGS=$(OPTIM) $(CFLAGS1) $(EXTRA_CFLAGS) -#LIBS=$(EXTRA_LIBS) $(LIBS1) -#INCLUDES=$(INCLUDES1) $(INCLUDES0) $(EXTRA_INCLUDES) -#LDFLAGS=$(LDFLAGS1) $(EXTRA_LDFLAGS) - -SHELL=@SH@ -CC=@CC@ -RANLIB=@RANLIB@ -CFLAGS=@CFLAGS@ @OPTIM@ -LIBS=@LIBS@ -LDFLAGS=@LDFLAGS@ $(LIBS) -INCDIR=../../include -INCLUDES=-I$(INCDIR) -I$(INCDIR1) -I. - -LIB=libdso.a - -OBJS=dso.o - -.c.o: - $(CC) $(CFLAGS) -c $(INCLUDES) $< - -all: $(LIB) - -clean: - $(RM) -f *.o *.a *.so - -distclean: clean - -$(RM) -f Makefile - -$(OBJS): Makefile - -$(LIB): $(OBJS) - $(RM) -f $@ - $(AR) cr $@ $(OBJS) - $(RANLIB) $@ - -# -# We really don't expect end users to use this rule. It works only with -# gcc, and rebuilds Makefile.tmpl. You have to re-run Configure after -# using it. -# -depend: - cp Makefile.in Makefile.in.bak \ - && sed -ne '1,/^# DO NOT REMOVE/p' Makefile.in > Makefile.new \ - && gcc -MM $(INCLUDES) $(CFLAGS) *.c | sed -e "s%\\\\\(.\)%/\\1%g" >> Makefile.new \ - && sed -e '1,$$s: $(INCDIR)/: $$(INCDIR)/:g' \ - -e '1,$$s: $(OSDIR)/: $$(OSDIR)/:g' Makefile.new \ - > Makefile.in \ - && rm Makefile.new - -# DO NOT REMOVE -dso.o: dso.c dso.h $(INCDIR)/apr_private.h \ - $(INCDIR)/apr_general.h $(INCDIR)/apr.h \ - $(INCDIR)/apr_errno.h $(INCDIR)/apr_pools.h \ - $(INCDIR)/apr_lib.h $(INCDIR)/apr_file_io.h \ - $(INCDIR)/apr_time.h $(INCDIR)/apr_thread_proc.h \ - $(INCDIR)/apr_dso.h diff --git a/dso/os2/dso.c b/dso/os2/dso.c index 25043c130d5..1a7f7de838a 100644 --- a/dso/os2/dso.c +++ b/dso/os2/dso.c @@ -1,128 +1,132 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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 "dso.h" -#define INCL_DOS -#include <os2.h> +#include "apr_arch_dso.h" +#include "apr_strings.h" +#include "apr_portable.h" #include <stdio.h> #include <string.h> -ap_status_t ap_dso_init() +#if APR_HAS_DSO + +static apr_status_t dso_cleanup(void *thedso) { - return APR_SUCCESS; -} + apr_dso_handle_t *dso = thedso; + int rc; + + if (dso->handle == 0) + return APR_SUCCESS; + + rc = DosFreeModule(dso->handle); + if (rc == 0) + dso->handle = 0; -static ap_status_t dso_cleanup(void *thedso) -{ - ap_dso_handle_t *dso = thedso; - return ap_dso_unload(dso); + return APR_FROM_OS_ERROR(rc); } -ap_status_t ap_dso_load(ap_dso_handle_t **res_handle, const char *path, ap_pool_t *ctx) +APR_DECLARE(apr_status_t) apr_dso_load(apr_dso_handle_t **res_handle, const char *path, apr_pool_t *ctx) { - char failed_module[1024]; + char failed_module[200]; HMODULE handle; int rc; - *res_handle = ap_pcalloc(ctx, sizeof(*res_handle)); + *res_handle = apr_pcalloc(ctx, sizeof(**res_handle)); + (*res_handle)->cont = ctx; + (*res_handle)->load_error = APR_SUCCESS; + (*res_handle)->failed_module = NULL; if ((rc = DosLoadModule(failed_module, sizeof(failed_module), path, &handle)) != 0) { - (*res_handle)->failed_module = ap_pstrdup(ctx, failed_module); - return APR_OS2_STATUS(rc); + (*res_handle)->load_error = APR_FROM_OS_ERROR(rc); + (*res_handle)->failed_module = apr_pstrdup(ctx, failed_module); + return APR_FROM_OS_ERROR(rc); } (*res_handle)->handle = handle; - (*res_handle)->cont = ctx; - (*res_handle)->failed_module = NULL; - ap_register_cleanup(ctx, *res_handle, dso_cleanup, ap_null_cleanup); + apr_pool_cleanup_register(ctx, *res_handle, dso_cleanup, apr_pool_cleanup_null); return APR_SUCCESS; } -ap_status_t ap_dso_unload(ap_dso_handle_t *handle) +APR_DECLARE(apr_status_t) apr_dso_unload(apr_dso_handle_t *handle) { - int rc; - - if (handle->handle == 0) - return APR_SUCCESS; - - rc = DosFreeModule(handle->handle); - - if (rc == 0) - handle->handle = 0; - - return APR_OS2_STATUS(rc); + return apr_pool_cleanup_run(handle->cont, handle, dso_cleanup); } -ap_status_t ap_dso_sym(ap_dso_handle_sym_t *ressym, - ap_dso_handle_t *handle, - const char *symname) +APR_DECLARE(apr_status_t) apr_dso_sym(apr_dso_handle_sym_t *ressym, + apr_dso_handle_t *handle, + const char *symname) { PFN func; int rc; if (symname == NULL || ressym == NULL) - return APR_EINIT; + return APR_ESYMNOTFOUND; - if ((rc = DosQueryProcAddr(handle->handle, 0, symname, &func)) != 0) - return APR_EINIT; + if ((rc = DosQueryProcAddr(handle->handle, 0, symname, &func)) != 0) { + handle->load_error = APR_FROM_OS_ERROR(rc); + return handle->load_error; + } *ressym = func; return APR_SUCCESS; } + + + +APR_DECLARE(const char *) apr_dso_error(apr_dso_handle_t *dso, char *buffer, apr_size_t buflen) +{ + char message[200]; + apr_strerror(dso->load_error, message, sizeof(message)); + + if (dso->failed_module != NULL) { + strcat(message, " ("); + strcat(message, dso->failed_module); + strcat(message, ")"); + } + + apr_cpystrn(buffer, message, buflen); + return buffer; +} + + + +APR_DECLARE(apr_status_t) apr_os_dso_handle_put(apr_dso_handle_t **aprdso, + apr_os_dso_handle_t osdso, + apr_pool_t *pool) +{ + *aprdso = apr_pcalloc(pool, sizeof **aprdso); + (*aprdso)->handle = osdso; + (*aprdso)->cont = pool; + (*aprdso)->load_error = APR_SUCCESS; + (*aprdso)->failed_module = NULL; + return APR_SUCCESS; +} + + + +APR_DECLARE(apr_status_t) apr_os_dso_handle_get(apr_os_dso_handle_t *osdso, + apr_dso_handle_t *aprdso) +{ + *osdso = aprdso->handle; + return APR_SUCCESS; +} + +#endif diff --git a/dso/os2/dso.h b/dso/os2/dso.h deleted file mode 100644 index 02855bb0c7b..00000000000 --- a/dso/os2/dso.h +++ /dev/null @@ -1,72 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#ifndef DSO_H -#define DSO_H - -#define INCL_DOS -#include <os2.h> - -#include "apr_private.h" -#include "apr_general.h" -#include "apr_pools.h" -#include "apr_dso.h" - -struct ap_dso_handle_t { - ap_pool_t *cont; /* Context for returning error strings */ - HMODULE handle; /* Handle to the DSO loaded */ - char *failed_module; -}; - -#endif diff --git a/dso/os390/dso.c b/dso/os390/dso.c new file mode 100644 index 00000000000..9344c71a154 --- /dev/null +++ b/dso/os390/dso.c @@ -0,0 +1,109 @@ +/* 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_portable.h" +#include "apr_strings.h" +#include "apr_arch_dso.h" +#include <errno.h> +#include <string.h> + +#if APR_HAS_DSO + +APR_DECLARE(apr_status_t) apr_os_dso_handle_put(apr_dso_handle_t **aprdso, + apr_os_dso_handle_t osdso, + apr_pool_t *pool) +{ + *aprdso = apr_pcalloc(pool, sizeof **aprdso); + (*aprdso)->handle = osdso; + (*aprdso)->pool = pool; + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_os_dso_handle_get(apr_os_dso_handle_t *osdso, + apr_dso_handle_t *aprdso) +{ + *osdso = aprdso->handle; + return APR_SUCCESS; +} + +static apr_status_t dso_cleanup(void *thedso) +{ + apr_dso_handle_t *dso = thedso; + int rc; + + if (dso->handle == 0) + return APR_SUCCESS; + + rc = dllfree(dso->handle); + + if (rc == 0) { + dso->handle = 0; + return APR_SUCCESS; + } + dso->failing_errno = errno; + return errno; +} + +APR_DECLARE(apr_status_t) apr_dso_load(apr_dso_handle_t **res_handle, + const char *path, apr_pool_t *ctx) +{ + dllhandle *handle; + int rc; + + *res_handle = apr_pcalloc(ctx, sizeof(**res_handle)); + (*res_handle)->pool = ctx; + if ((handle = dllload(path)) != NULL) { + (*res_handle)->handle = handle; + apr_pool_cleanup_register(ctx, *res_handle, dso_cleanup, apr_pool_cleanup_null); + return APR_SUCCESS; + } + + (*res_handle)->failing_errno = errno; + return APR_EDSOOPEN; +} + +APR_DECLARE(apr_status_t) apr_dso_unload(apr_dso_handle_t *handle) +{ + return apr_pool_cleanup_run(handle->pool, handle, dso_cleanup); +} + +APR_DECLARE(apr_status_t) apr_dso_sym(apr_dso_handle_sym_t *ressym, + apr_dso_handle_t *handle, + const char *symname) +{ + void *func_ptr; + void *var_ptr; + + if ((var_ptr = dllqueryvar(handle->handle, symname)) != NULL) { + *ressym = var_ptr; + return APR_SUCCESS; + } + if ((func_ptr = (void *)dllqueryfn(handle->handle, symname)) != NULL) { + *ressym = func_ptr; + return APR_SUCCESS; + } + handle->failing_errno = errno; + return APR_ESYMNOTFOUND; +} + +APR_DECLARE(const char *) apr_dso_error(apr_dso_handle_t *handle, char *buffer, + apr_size_t buflen) +{ + apr_cpystrn(buffer, strerror(handle->failing_errno), buflen); + return buffer; +} + +#endif diff --git a/dso/unix/.cvsignore b/dso/unix/.cvsignore deleted file mode 100644 index f3c7a7c5da6..00000000000 --- a/dso/unix/.cvsignore +++ /dev/null @@ -1 +0,0 @@ -Makefile diff --git a/dso/unix/Makefile.in b/dso/unix/Makefile.in deleted file mode 100644 index 0be9515cc43..00000000000 --- a/dso/unix/Makefile.in +++ /dev/null @@ -1,57 +0,0 @@ -#CFLAGS=$(OPTIM) $(CFLAGS1) $(EXTRA_CFLAGS) -#LIBS=$(EXTRA_LIBS) $(LIBS1) -#INCLUDES=$(INCLUDES1) $(INCLUDES0) $(EXTRA_INCLUDES) -#LDFLAGS=$(LDFLAGS1) $(EXTRA_LDFLAGS) - -RM=@RM@ -CC=@CC@ -RANLIB=@RANLIB@ -CFLAGS=@CFLAGS@ @OPTIM@ -LIBS=@LIBS@ -LDFLAGS=@LDFLAGS@ $(LIBS) -INCDIR=../../include -INCLUDES=-I$(INCDIR) -I$(INCDIR1) -I. - -LIB=libdso.a - -OBJS=dso.o - -.c.o: - $(CC) $(CFLAGS) -c $(INCLUDES) $< - -all: $(LIB) - -clean: - $(RM) -f *.o *.a *.so - -distclean: clean - -$(RM) -f Makefile - -$(OBJS): Makefile - -$(LIB): $(OBJS) - $(RM) -f $@ - $(AR) cr $@ $(OBJS) - $(RANLIB) $@ - -# -# We really don't expect end users to use this rule. It works only with -# gcc, and rebuilds Makefile.tmpl. You have to re-run Configure after -# using it. -# -depend: - cp Makefile.in Makefile.in.bak \ - && sed -ne '1,/^# DO NOT REMOVE/p' Makefile.in > Makefile.new \ - && gcc -MM $(INCLUDES) $(CFLAGS) *.c >> Makefile.new \ - && sed -e '1,$$s: $(INCDIR)/: $$(INCDIR)/:g' \ - -e '1,$$s: $(OSDIR)/: $$(OSDIR)/:g' Makefile.new \ - > Makefile.in \ - && rm Makefile.new - -# DO NOT REMOVE -dso.o: dso.c dso.h $(INCDIR)/apr_private.h \ - $(INCDIR)/apr_general.h $(INCDIR)/apr.h \ - $(INCDIR)/apr_errno.h $(INCDIR)/apr_pools.h \ - $(INCDIR)/apr_lib.h $(INCDIR)/apr_file_io.h \ - $(INCDIR)/apr_time.h $(INCDIR)/apr_thread_proc.h \ - $(INCDIR)/apr_dso.h diff --git a/dso/unix/dso.c b/dso/unix/dso.c index c25986b85e3..fdd56f1d338 100644 --- a/dso/unix/dso.c +++ b/dso/unix/dso.c @@ -1,131 +1,251 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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 "dso.h" +#include "apr_arch_dso.h" +#include "apr_strings.h" +#include "apr_portable.h" + +#if APR_HAS_DSO + +#if !defined(DSO_USE_DLFCN) && !defined(DSO_USE_SHL) && !defined(DSO_USE_DYLD) +#error No DSO implementation specified. +#endif + +#ifdef HAVE_STDDEF_H +#include <stddef.h> +#endif +#if APR_HAVE_STDLIB_H +#include <stdlib.h> /* malloc(), free() */ +#endif +#if APR_HAVE_STRING_H +#include <string.h> /* for strerror() on HP-UX */ +#endif + +#if defined(DSO_USE_DYLD) +#define DYLD_LIBRARY_HANDLE (void *)-1 +#endif -ap_status_t ap_dso_init(void){ +APR_DECLARE(apr_status_t) apr_os_dso_handle_put(apr_dso_handle_t **aprdso, + apr_os_dso_handle_t osdso, + apr_pool_t *pool) +{ + *aprdso = apr_pcalloc(pool, sizeof **aprdso); + (*aprdso)->handle = osdso; + (*aprdso)->pool = pool; + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_os_dso_handle_get(apr_os_dso_handle_t *osdso, + apr_dso_handle_t *aprdso) +{ + *osdso = aprdso->handle; return APR_SUCCESS; } -ap_status_t ap_dso_load(ap_dso_handle_t **res_handle, const char *path, - ap_pool_t *ctx) +static apr_status_t dso_cleanup(void *thedso) { -#if defined(HPUX) || defined(HPUX10) || defined(HPUX11) - shl_t os_handle = shl_load(path, BIND_IMMEDIATE|BIND_VERBOSE|BIND_NOSTART, 0L); -#elif defined(OSF1) || defined(SEQUENT) || defined(SNI) ||\ - (defined(__FreeBSD_version) && (__FreeBSD_version >= 220000)) + apr_dso_handle_t *dso = thedso; + + if (dso->handle == NULL) + return APR_SUCCESS; + +#if defined(DSO_USE_SHL) + shl_unload((shl_t)dso->handle); +#elif defined(DSO_USE_DYLD) + if (dso->handle != DYLD_LIBRARY_HANDLE) { + NSUnLinkModule(dso->handle, FALSE); + } +#elif defined(DSO_USE_DLFCN) + if (dlclose(dso->handle) != 0) + return APR_EINIT; +#endif + dso->handle = NULL; + + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_dso_load(apr_dso_handle_t **res_handle, + const char *path, apr_pool_t *pool) +{ +#if defined(DSO_USE_SHL) + shl_t os_handle = shl_load(path, BIND_IMMEDIATE, 0L); + +#elif defined(DSO_USE_DYLD) + NSObjectFileImage image; + NSModule os_handle = NULL; + NSObjectFileImageReturnCode dsoerr; + const char* err_msg = NULL; + dsoerr = NSCreateObjectFileImageFromFile(path, &image); + + if (dsoerr == NSObjectFileImageSuccess) { +#if defined(NSLINKMODULE_OPTION_RETURN_ON_ERROR) && defined(NSLINKMODULE_OPTION_NONE) + os_handle = NSLinkModule(image, path, + NSLINKMODULE_OPTION_RETURN_ON_ERROR | + NSLINKMODULE_OPTION_NONE); + /* If something went wrong, get the errors... */ + if (!os_handle) { + NSLinkEditErrors errors; + int errorNumber; + const char *fileName; + NSLinkEditError(&errors, &errorNumber, &fileName, &err_msg); + } +#else + os_handle = NSLinkModule(image, path, FALSE); +#endif + NSDestroyObjectFileImage(image); + } + else if ((dsoerr == NSObjectFileImageFormat || + dsoerr == NSObjectFileImageInappropriateFile) && + NSAddLibrary(path) == TRUE) { + os_handle = (NSModule)DYLD_LIBRARY_HANDLE; + } + else { + err_msg = "cannot create object file image or add library"; + } + +#elif defined(DSO_USE_DLFCN) +#if defined(OSF1) || defined(SEQUENT) || defined(SNI) ||\ + (defined(__FreeBSD_version) && (__FreeBSD_version >= 220000)) ||\ + defined(__DragonFly__) void *os_handle = dlopen((char *)path, RTLD_NOW | RTLD_GLOBAL); + #else - void *os_handle = dlopen(path, RTLD_NOW | RTLD_GLOBAL); + int flags = RTLD_NOW | RTLD_GLOBAL; + void *os_handle; +#ifdef _AIX + if (strchr(path + 1, '(') && path[strlen(path) - 1] == ')') + { + /* This special archive.a(dso.so) syntax is required for + * the way libtool likes to build shared libraries on AIX. + * dlopen() support for such a library requires that the + * RTLD_MEMBER flag be enabled. + */ + flags |= RTLD_MEMBER; + } +#endif + os_handle = dlopen(path, flags); #endif +#endif /* DSO_USE_x */ - if(os_handle == NULL) + *res_handle = apr_pcalloc(pool, sizeof(**res_handle)); + + if(os_handle == NULL) { +#if defined(DSO_USE_SHL) + (*res_handle)->errormsg = strerror(errno); + return APR_EDSOOPEN; +#elif defined(DSO_USE_DYLD) + (*res_handle)->errormsg = (err_msg) ? err_msg : "link failed"; return APR_EDSOOPEN; +#elif defined(DSO_USE_DLFCN) + (*res_handle)->errormsg = dlerror(); + return APR_EDSOOPEN; +#endif + } - *res_handle = ap_pcalloc(ctx, sizeof(*res_handle)); (*res_handle)->handle = (void*)os_handle; - (*res_handle)->cont = ctx; + (*res_handle)->pool = pool; + (*res_handle)->errormsg = NULL; + + apr_pool_cleanup_register(pool, *res_handle, dso_cleanup, apr_pool_cleanup_null); + return APR_SUCCESS; } -ap_status_t ap_dso_unload(ap_dso_handle_t *handle) +APR_DECLARE(apr_status_t) apr_dso_unload(apr_dso_handle_t *handle) { -#if defined(HPUX) || defined(HPUX10) || defined(HPUX11) - shl_unload((shl_t)handle->handle); -#else - if (dlclose(handle->handle) != 0) - return APR_EINIT; -#endif - handle->handle = NULL; - - return APR_SUCCESS; + return apr_pool_cleanup_run(handle->pool, handle, dso_cleanup); } -ap_status_t ap_dso_sym(ap_dso_handle_sym_t *ressym, - ap_dso_handle_t *handle, - const char *symname) +APR_DECLARE(apr_status_t) apr_dso_sym(apr_dso_handle_sym_t *ressym, + apr_dso_handle_t *handle, + const char *symname) { -#if defined(HPUX) || defined(HPUX10) || defined(HPUX11) +#if defined(DSO_USE_SHL) void *symaddr = NULL; int status; errno = 0; - status = shl_findsym((shl_t *)&handle->handle, symname, TYPE_PROCEDURE, &symaddr); + status = shl_findsym((void *)&handle->handle, symname, TYPE_PROCEDURE, &symaddr); if (status == -1 && errno == 0) /* try TYPE_DATA instead */ - status = shl_findsym((shl_t *)&handle->handle, symname, TYPE_DATA, &symaddr); - if (status = -1) - return APR_EINIT; - ressym = symaddr; + status = shl_findsym((void *)&handle->handle, symname, TYPE_DATA, &symaddr); + if (status == -1) + return APR_ESYMNOTFOUND; + *ressym = symaddr; + return APR_SUCCESS; +#elif defined(DSO_USE_DYLD) + void *retval = NULL; + NSSymbol symbol; + char *symname2 = (char*)malloc(sizeof(char)*(strlen(symname)+2)); + sprintf(symname2, "_%s", symname); +#ifdef NSLINKMODULE_OPTION_PRIVATE + if (handle->handle == DYLD_LIBRARY_HANDLE) { + symbol = NSLookupAndBindSymbol(symname2); + } + else { + symbol = NSLookupSymbolInModule((NSModule)handle->handle, symname2); + } +#else + symbol = NSLookupAndBindSymbol(symname2); +#endif + free(symname2); + if (symbol == NULL) { + handle->errormsg = "undefined symbol"; + return APR_ESYMNOTFOUND; + } + retval = NSAddressOfSymbol(symbol); + if (retval == NULL) { + handle->errormsg = "cannot resolve symbol"; + return APR_ESYMNOTFOUND; + } + *ressym = retval; + return APR_SUCCESS; +#elif defined(DSO_USE_DLFCN) -#elif defined(DLSYM_NEEDS_UNDERSCORE) +#if defined(DLSYM_NEEDS_UNDERSCORE) void *retval; char *symbol = (char*)malloc(sizeof(char)*(strlen(symname)+2)); sprintf(symbol, "_%s", symname); retval = dlsym(handle->handle, symbol); free(symbol); - #elif defined(SEQUENT) || defined(SNI) void *retval = dlsym(handle->handle, (char *)symname); #else void *retval = dlsym(handle->handle, symname); -#endif +#endif /* DLSYM_NEEDS_UNDERSCORE */ - if (retval == NULL) - return APR_EINIT; + if (retval == NULL) { + handle->errormsg = dlerror(); + return APR_ESYMNOTFOUND; + } *ressym = retval; return APR_SUCCESS; +#endif /* DSO_USE_x */ } + +APR_DECLARE(const char *) apr_dso_error(apr_dso_handle_t *dso, char *buffer, + apr_size_t buflen) +{ + if (dso->errormsg) { + apr_cpystrn(buffer, dso->errormsg, buflen); + return dso->errormsg; + } + return "No Error"; +} + +#endif diff --git a/dso/unix/dso.h b/dso/unix/dso.h deleted file mode 100644 index 67bf85104d2..00000000000 --- a/dso/unix/dso.h +++ /dev/null @@ -1,90 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#ifndef DSO_H -#define DSO_H - -#include "apr_private.h" -#include "apr_general.h" -#include "apr_pools.h" -#include "apr_dso.h" - -#ifdef HAVE_DLFCN_H -#include <dlfcn.h> -#endif - -#ifdef HAVE_DL_H -#include <dl.h> -#endif - -#ifndef RTLD_NOW -#define RTLD_NOW 1 -#endif - -#ifndef RTLD_GLOBAL -#define RTLD_GLOBAL 0 -#endif - -#if (defined(__FreeBSD__) ||\ - defined(__OpenBSD__) ||\ - defined(__NetBSD__) ) && !defined(__ELF__) -#define DLSYM_NEEDS_UNDERSCORE -#endif - -struct ap_dso_handle_t { - ap_pool_t *cont; - void *handle; -}; - -#endif diff --git a/dso/win32/dso.c b/dso/win32/dso.c index b8dde20e4a3..89885e5fa0f 100644 --- a/dso/win32/dso.c +++ b/dso/win32/dso.c @@ -1,95 +1,183 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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 "dso.h" +#include "apr_arch_dso.h" +#include "apr_strings.h" +#include "apr_private.h" +#include "apr_arch_file_io.h" +#include "apr_arch_utf8.h" + +#if APR_HAS_DSO -ap_status_t ap_dso_init(void){ +APR_DECLARE(apr_status_t) apr_os_dso_handle_put(apr_dso_handle_t **aprdso, + apr_os_dso_handle_t osdso, + apr_pool_t *pool) +{ + *aprdso = apr_pcalloc(pool, sizeof **aprdso); + (*aprdso)->handle = osdso; + (*aprdso)->cont = pool; return APR_SUCCESS; } -ap_status_t ap_dso_load(struct ap_dso_handle_t **res_handle, const char *path, - ap_pool_t *ctx) +APR_DECLARE(apr_status_t) apr_os_dso_handle_get(apr_os_dso_handle_t *osdso, + apr_dso_handle_t *aprdso) { - HINSTANCE os_handle = LoadLibraryEx(path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); - if(os_handle == NULL) { - return GetLastError(); + *osdso = aprdso->handle; + return APR_SUCCESS; +} + +static apr_status_t dso_cleanup(void *thedso) +{ + apr_dso_handle_t *dso = thedso; + + if (dso->handle != NULL && !FreeLibrary(dso->handle)) { + return apr_get_os_error(); } + dso->handle = NULL; - *res_handle = ap_pcalloc(ctx, sizeof(*res_handle)); - (*res_handle)->handle = (void*)os_handle; - (*res_handle)->cont = ctx; return APR_SUCCESS; } - -ap_status_t ap_dso_unload(struct ap_dso_handle_t *handle) + +APR_DECLARE(apr_status_t) apr_dso_load(struct apr_dso_handle_t **res_handle, + const char *path, apr_pool_t *ctx) { - if (!FreeLibrary(handle->handle)) { - return GetLastError(); + HINSTANCE os_handle; + apr_status_t rv; +#ifndef _WIN32_WCE + UINT em; +#endif + +#if APR_HAS_UNICODE_FS + IF_WIN_OS_IS_UNICODE + { + apr_wchar_t wpath[APR_PATH_MAX]; + if ((rv = utf8_to_unicode_path(wpath, sizeof(wpath) + / sizeof(apr_wchar_t), path)) + != APR_SUCCESS) { + *res_handle = apr_pcalloc(ctx, sizeof(**res_handle)); + return ((*res_handle)->load_error = rv); + } + /* Prevent ugly popups from killing our app */ +#ifndef _WIN32_WCE + em = SetErrorMode(SEM_FAILCRITICALERRORS); +#endif + os_handle = LoadLibraryExW(wpath, NULL, 0); + if (!os_handle) + os_handle = LoadLibraryExW(wpath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); + if (!os_handle) { +#ifndef _WIN32_WCE + apr_wchar_t *ignored; + apr_wchar_t fpath[APR_PATH_MAX]; + rv = apr_get_os_error(); + if (GetFullPathNameW(wpath, sizeof(fpath) / sizeof(apr_wchar_t), fpath, &ignored)) { + if (SetDllDirectoryW(fpath)) { + os_handle = LoadLibraryExW(wpath, NULL, 0); + if (!os_handle) + os_handle = LoadLibraryExW(wpath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); + if (os_handle) + rv = APR_SUCCESS; + } + } +#else + rv = apr_get_os_error(); +#endif + } +#ifndef _WIN32_WCE + SetErrorMode(em); +#endif } +#endif /* APR_HAS_UNICODE_FS */ +#if APR_HAS_ANSI_FS + ELSE_WIN_OS_IS_ANSI + { + char fspec[APR_PATH_MAX], *p = fspec; + /* Must convert path from / to \ notation. + * Per PR2555, the LoadLibraryEx function is very picky about slashes. + * Debugging on NT 4 SP 6a reveals First Chance Exception within NTDLL. + * LoadLibrary in the MS PSDK also reveals that it -explicitly- states + * that backslashes must be used for the LoadLibrary family of calls. + */ + apr_cpystrn(fspec, path, sizeof(fspec)); + while ((p = strchr(p, '/')) != NULL) + *p = '\\'; + + /* Prevent ugly popups from killing our app */ + em = SetErrorMode(SEM_FAILCRITICALERRORS); + os_handle = LoadLibraryEx(path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); + if (!os_handle) + os_handle = LoadLibraryEx(path, NULL, 0); + if (!os_handle) + rv = apr_get_os_error(); + else + rv = APR_SUCCESS; + SetErrorMode(em); + } +#endif + + *res_handle = apr_pcalloc(ctx, sizeof(**res_handle)); + (*res_handle)->cont = ctx; + + if (rv) { + return ((*res_handle)->load_error = rv); + } + + (*res_handle)->handle = (void*)os_handle; + (*res_handle)->load_error = APR_SUCCESS; + + apr_pool_cleanup_register(ctx, *res_handle, dso_cleanup, apr_pool_cleanup_null); + return APR_SUCCESS; } + +APR_DECLARE(apr_status_t) apr_dso_unload(struct apr_dso_handle_t *handle) +{ + return apr_pool_cleanup_run(handle->cont, handle, dso_cleanup); +} -ap_status_t ap_dso_sym(ap_dso_handle_sym_t *ressym, - struct ap_dso_handle_t *handle, - const char *symname) +APR_DECLARE(apr_status_t) apr_dso_sym(apr_dso_handle_sym_t *ressym, + struct apr_dso_handle_t *handle, + const char *symname) { - FARPROC retval = GetProcAddress(handle->handle, symname); - if (!retval) { - return GetLastError(); +#ifdef _WIN32_WCE + apr_size_t symlen = strlen(symname) + 1; + apr_size_t wsymlen = 256; + apr_wchar_t wsymname[256]; + apr_status_t rv; + + rv = apr_conv_utf8_to_ucs2(wsymname, &wsymlen, symname, &symlen); + if (rv != APR_SUCCESS) { + return rv; + } + else if (symlen) { + return APR_ENAMETOOLONG; + } + + *ressym = (apr_dso_handle_sym_t)GetProcAddressW(handle->handle, wsymname); +#else + *ressym = (apr_dso_handle_sym_t)GetProcAddress(handle->handle, symname); +#endif + if (!*ressym) { + return apr_get_os_error(); } - - *ressym = retval; - return APR_SUCCESS; } + +APR_DECLARE(const char *) apr_dso_error(apr_dso_handle_t *dso, char *buf, apr_size_t bufsize) +{ + return apr_strerror(dso->load_error, buf, bufsize); +} + +#endif diff --git a/dso/win32/dso.h b/dso/win32/dso.h deleted file mode 100644 index 745db192dce..00000000000 --- a/dso/win32/dso.h +++ /dev/null @@ -1,68 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#ifndef DSO_H -#define DSO_H - -#include "apr_private.h" -#include "apr_general.h" -#include "apr_pools.h" -#include "apr_dso.h" - -struct ap_dso_handle_t { - ap_pool_t *cont; - void *handle; -}; - -#endif diff --git a/emacs-mode b/emacs-mode new file mode 100644 index 00000000000..2c7abe98356 --- /dev/null +++ b/emacs-mode @@ -0,0 +1,15 @@ +;; M-x load-file <this file> +;; or emacs -l <this file> +;; to use this style: C-c . apache +(c-add-style "apache" + '((inclass . ++) + (defun-block-intro . ++) + (statement-block-intro . ++) + (substatement . ++) + (brace-list-intro . ++) + (statement-case-intro . ++) + (inextern-lang . 0) + )) +(setq-default indent-tabs-mode nil) +;; if you forgot to do this at startup, then M-x eval-expression +;; (setq indent-tabs-mode nil) on each buffer diff --git a/encoding/apr_base64.c b/encoding/apr_base64.c new file mode 100644 index 00000000000..b07aede010b --- /dev/null +++ b/encoding/apr_base64.c @@ -0,0 +1,293 @@ +/* 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. + */ + +/* base64 encoder/decoder. Originally part of main/util.c + * but moved here so that support/ab and apr_sha1.c could + * use it. This meant removing the apr_palloc()s and adding + * ugly 'len' functions, which is quite a nasty cost. + */ + +#include "apr_base64.h" +#if APR_CHARSET_EBCDIC +#include "apr_xlate.h" +#endif /* APR_CHARSET_EBCDIC */ + +/* aaaack but it's fast and const should make it shared text page. */ +static const unsigned char pr2six[256] = +{ +#if !APR_CHARSET_EBCDIC + /* ASCII table */ + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64, + 64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64, + 64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64 +#else /*APR_CHARSET_EBCDIC*/ + /* EBCDIC table */ + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 63, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 64, 64, 64, 64, 64, 64, + 64, 35, 36, 37, 38, 39, 40, 41, 42, 43, 64, 64, 64, 64, 64, 64, + 64, 64, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 64, 64, 64, 64, 64, 64, + 64, 9, 10, 11, 12, 13, 14, 15, 16, 17, 64, 64, 64, 64, 64, 64, + 64, 64, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64, 64, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64 +#endif /*APR_CHARSET_EBCDIC*/ +}; + +#if APR_CHARSET_EBCDIC +static apr_xlate_t *xlate_to_ebcdic; +static unsigned char os_toascii[256]; + +APR_DECLARE(apr_status_t) apr_base64init_ebcdic(apr_xlate_t *to_ascii, + apr_xlate_t *to_ebcdic) +{ + int i; + apr_size_t inbytes_left, outbytes_left; + apr_status_t rv; + int onoff; + + /* Only single-byte conversion is supported. + */ + rv = apr_xlate_sb_get(to_ascii, &onoff); + if (rv) { + return rv; + } + if (!onoff) { /* If conversion is not single-byte-only */ + return APR_EINVAL; + } + rv = apr_xlate_sb_get(to_ebcdic, &onoff); + if (rv) { + return rv; + } + if (!onoff) { /* If conversion is not single-byte-only */ + return APR_EINVAL; + } + xlate_to_ebcdic = to_ebcdic; + for (i = 0; i < sizeof(os_toascii); i++) { + os_toascii[i] = i; + } + inbytes_left = outbytes_left = sizeof(os_toascii); + apr_xlate_conv_buffer(to_ascii, os_toascii, &inbytes_left, + os_toascii, &outbytes_left); + + return APR_SUCCESS; +} +#endif /*APR_CHARSET_EBCDIC*/ + +APR_DECLARE(int) apr_base64_decode_len(const char *bufcoded) +{ + int nbytesdecoded; + register const unsigned char *bufin; + register apr_size_t nprbytes; + + bufin = (const unsigned char *) bufcoded; + while (pr2six[*(bufin++)] <= 63); + + nprbytes = (bufin - (const unsigned char *) bufcoded) - 1; + nbytesdecoded = (((int)nprbytes + 3) / 4) * 3; + + return nbytesdecoded + 1; +} + +APR_DECLARE(int) apr_base64_decode(char *bufplain, const char *bufcoded) +{ +#if APR_CHARSET_EBCDIC + apr_size_t inbytes_left, outbytes_left; +#endif /* APR_CHARSET_EBCDIC */ + int len; + + len = apr_base64_decode_binary((unsigned char *) bufplain, bufcoded); +#if APR_CHARSET_EBCDIC + inbytes_left = outbytes_left = len; + apr_xlate_conv_buffer(xlate_to_ebcdic, bufplain, &inbytes_left, + bufplain, &outbytes_left); +#endif /* APR_CHARSET_EBCDIC */ + bufplain[len] = '\0'; + return len; +} + +/* This is the same as apr_base64_decode() except: + * - no \0 is appended + * - on EBCDIC machines, the conversion of the output to ebcdic is left out + */ +APR_DECLARE(int) apr_base64_decode_binary(unsigned char *bufplain, + const char *bufcoded) +{ + int nbytesdecoded; + register const unsigned char *bufin; + register unsigned char *bufout; + register apr_size_t nprbytes; + + bufin = (const unsigned char *) bufcoded; + while (pr2six[*(bufin++)] <= 63); + nprbytes = (bufin - (const unsigned char *) bufcoded) - 1; + nbytesdecoded = (((int)nprbytes + 3) / 4) * 3; + + bufout = (unsigned char *) bufplain; + bufin = (const unsigned char *) bufcoded; + + while (nprbytes > 4) { + *(bufout++) = + (unsigned char) (pr2six[*bufin] << 2 | pr2six[bufin[1]] >> 4); + *(bufout++) = + (unsigned char) (pr2six[bufin[1]] << 4 | pr2six[bufin[2]] >> 2); + *(bufout++) = + (unsigned char) (pr2six[bufin[2]] << 6 | pr2six[bufin[3]]); + bufin += 4; + nprbytes -= 4; + } + + /* Note: (nprbytes == 1) would be an error, so just ingore that case */ + if (nprbytes > 1) { + *(bufout++) = + (unsigned char) (pr2six[*bufin] << 2 | pr2six[bufin[1]] >> 4); + } + if (nprbytes > 2) { + *(bufout++) = + (unsigned char) (pr2six[bufin[1]] << 4 | pr2six[bufin[2]] >> 2); + } + if (nprbytes > 3) { + *(bufout++) = + (unsigned char) (pr2six[bufin[2]] << 6 | pr2six[bufin[3]]); + } + + nbytesdecoded -= (4 - (int)nprbytes) & 3; + return nbytesdecoded; +} + +APR_DECLARE(char *) apr_pbase64_decode(apr_pool_t *p, const char *bufcoded) +{ + char *decoded; + int l; + + decoded = (char *) apr_palloc(p, 1 + apr_base64_decode_len(bufcoded)); + l = apr_base64_decode(decoded, bufcoded); + decoded[l] = '\0'; /* make binary sequence into string */ + + return decoded; +} + +static const char basis_64[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +APR_DECLARE(int) apr_base64_encode_len(int len) +{ + return ((len + 2) / 3 * 4) + 1; +} + +APR_DECLARE(int) apr_base64_encode(char *encoded, const char *string, int len) +{ +#if !APR_CHARSET_EBCDIC + return apr_base64_encode_binary(encoded, (const unsigned char *) string, len); +#else /* APR_CHARSET_EBCDIC */ + int i; + char *p; + + p = encoded; + for (i = 0; i < len - 2; i += 3) { + *p++ = basis_64[(os_toascii[string[i]] >> 2) & 0x3F]; + *p++ = basis_64[((os_toascii[string[i]] & 0x3) << 4) | + ((int) (os_toascii[string[i + 1]] & 0xF0) >> 4)]; + *p++ = basis_64[((os_toascii[string[i + 1]] & 0xF) << 2) | + ((int) (os_toascii[string[i + 2]] & 0xC0) >> 6)]; + *p++ = basis_64[os_toascii[string[i + 2]] & 0x3F]; + } + if (i < len) { + *p++ = basis_64[(os_toascii[string[i]] >> 2) & 0x3F]; + if (i == (len - 1)) { + *p++ = basis_64[((os_toascii[string[i]] & 0x3) << 4)]; + *p++ = '='; + } + else { + *p++ = basis_64[((os_toascii[string[i]] & 0x3) << 4) | + ((int) (os_toascii[string[i + 1]] & 0xF0) >> 4)]; + *p++ = basis_64[((os_toascii[string[i + 1]] & 0xF) << 2)]; + } + *p++ = '='; + } + + *p++ = '\0'; + return p - encoded; +#endif /* APR_CHARSET_EBCDIC */ +} + +/* This is the same as apr_base64_encode() except on EBCDIC machines, where + * the conversion of the input to ascii is left out. + */ +APR_DECLARE(int) apr_base64_encode_binary(char *encoded, + const unsigned char *string, int len) +{ + int i; + char *p; + + p = encoded; + for (i = 0; i < len - 2; i += 3) { + *p++ = basis_64[(string[i] >> 2) & 0x3F]; + *p++ = basis_64[((string[i] & 0x3) << 4) | + ((int) (string[i + 1] & 0xF0) >> 4)]; + *p++ = basis_64[((string[i + 1] & 0xF) << 2) | + ((int) (string[i + 2] & 0xC0) >> 6)]; + *p++ = basis_64[string[i + 2] & 0x3F]; + } + if (i < len) { + *p++ = basis_64[(string[i] >> 2) & 0x3F]; + if (i == (len - 1)) { + *p++ = basis_64[((string[i] & 0x3) << 4)]; + *p++ = '='; + } + else { + *p++ = basis_64[((string[i] & 0x3) << 4) | + ((int) (string[i + 1] & 0xF0) >> 4)]; + *p++ = basis_64[((string[i + 1] & 0xF) << 2)]; + } + *p++ = '='; + } + + *p++ = '\0'; + return (int)(p - encoded); +} + +APR_DECLARE(char *) apr_pbase64_encode(apr_pool_t *p, const char *string) +{ + char *encoded; + int l = strlen(string); + + encoded = (char *) apr_palloc(p, apr_base64_encode_len(l)); + l = apr_base64_encode(encoded, string, l); + encoded[l] = '\0'; /* make binary sequence into string */ + + return encoded; +} diff --git a/encoding/apr_escape.c b/encoding/apr_escape.c new file mode 100644 index 00000000000..3be9eb99ec1 --- /dev/null +++ b/encoding/apr_escape.c @@ -0,0 +1,1254 @@ +/* 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. + */ + +/* escape/unescape functions. + * + * These functions perform various escaping operations, and are provided in + * pairs, a function to query the length of and escape existing buffers, as + * well as companion functions to perform the same process to memory + * allocated from a pool. + * + * The API is designed to have the smallest possible RAM footprint, and so + * will only allocate the exact amount of RAM needed for each conversion. + */ + +#include "apr_escape.h" +#include "apr_escape_test_char.h" +#include "apr_lib.h" +#include "apr_strings.h" + +#if APR_CHARSET_EBCDIC +static int convert_a2e[256] = { + 0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F, 0x16, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x3C, 0x3D, 0x32, 0x26, 0x18, 0x19, 0x3F, 0x27, 0x1C, 0x1D, 0x1E, 0x1F, + 0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D, 0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61, + 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F, + 0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, + 0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xAD, 0xE0, 0xBD, 0x5F, 0x6D, + 0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, + 0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xC0, 0x4F, 0xD0, 0xA1, 0x07, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x06, 0x17, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x09, 0x0A, 0x1B, + 0x30, 0x31, 0x1A, 0x33, 0x34, 0x35, 0x36, 0x08, 0x38, 0x39, 0x3A, 0x3B, 0x04, 0x14, 0x3E, 0xFF, + 0x41, 0xAA, 0x4A, 0xB1, 0x9F, 0xB2, 0x6A, 0xB5, 0xBB, 0xB4, 0x9A, 0x8A, 0xB0, 0xCA, 0xAF, 0xBC, + 0x90, 0x8F, 0xEA, 0xFA, 0xBE, 0xA0, 0xB6, 0xB3, 0x9D, 0xDA, 0x9B, 0x8B, 0xB7, 0xB8, 0xB9, 0xAB, + 0x64, 0x65, 0x62, 0x66, 0x63, 0x67, 0x9E, 0x68, 0x74, 0x71, 0x72, 0x73, 0x78, 0x75, 0x76, 0x77, + 0xAC, 0x69, 0xED, 0xEE, 0xEB, 0xEF, 0xEC, 0xBF, 0x80, 0xFD, 0xFE, 0xFB, 0xFC, 0xBA, 0xAE, 0x59, + 0x44, 0x45, 0x42, 0x46, 0x43, 0x47, 0x9C, 0x48, 0x54, 0x51, 0x52, 0x53, 0x58, 0x55, 0x56, 0x57, + 0x8C, 0x49, 0xCD, 0xCE, 0xCB, 0xCF, 0xCC, 0xE1, 0x70, 0xDD, 0xDE, 0xDB, 0xDC, 0x8D, 0x8E, 0xDF }; + +static int convert_e2a[256] = { + 0x00, 0x01, 0x02, 0x03, 0x9C, 0x09, 0x86, 0x7F, 0x97, 0x8D, 0x8E, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x9D, 0x0A, 0x08, 0x87, 0x18, 0x19, 0x92, 0x8F, 0x1C, 0x1D, 0x1E, 0x1F, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x17, 0x1B, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x05, 0x06, 0x07, + 0x90, 0x91, 0x16, 0x93, 0x94, 0x95, 0x96, 0x04, 0x98, 0x99, 0x9A, 0x9B, 0x14, 0x15, 0x9E, 0x1A, + 0x20, 0xA0, 0xE2, 0xE4, 0xE0, 0xE1, 0xE3, 0xE5, 0xE7, 0xF1, 0xA2, 0x2E, 0x3C, 0x28, 0x2B, 0x7C, + 0x26, 0xE9, 0xEA, 0xEB, 0xE8, 0xED, 0xEE, 0xEF, 0xEC, 0xDF, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0x5E, + 0x2D, 0x2F, 0xC2, 0xC4, 0xC0, 0xC1, 0xC3, 0xC5, 0xC7, 0xD1, 0xA6, 0x2C, 0x25, 0x5F, 0x3E, 0x3F, + 0xF8, 0xC9, 0xCA, 0xCB, 0xC8, 0xCD, 0xCE, 0xCF, 0xCC, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22, + 0xD8, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0xAB, 0xBB, 0xF0, 0xFD, 0xFE, 0xB1, + 0xB0, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0xAA, 0xBA, 0xE6, 0xB8, 0xC6, 0xA4, + 0xB5, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0xA1, 0xBF, 0xD0, 0x5B, 0xDE, 0xAE, + 0xAC, 0xA3, 0xA5, 0xB7, 0xA9, 0xA7, 0xB6, 0xBC, 0xBD, 0xBE, 0xDD, 0xA8, 0xAF, 0x5D, 0xB4, 0xD7, + 0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0xAD, 0xF4, 0xF6, 0xF2, 0xF3, 0xF5, + 0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0xB9, 0xFB, 0xFC, 0xF9, 0xFA, 0xFF, + 0x5C, 0xF7, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0xB2, 0xD4, 0xD6, 0xD2, 0xD3, 0xD5, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0xB3, 0xDB, 0xDC, 0xD9, 0xDA, 0x9F }; +#define RAW_ASCII_CHAR(ch) convert_e2a[(unsigned char)ch] +#else /* APR_CHARSET_EBCDIC */ +#define RAW_ASCII_CHAR(ch) (ch) +#endif /* !APR_CHARSET_EBCDIC */ + +/* we assume the folks using this ensure 0 <= c < 256... which means + * you need a cast to (unsigned char) first, you can't just plug a + * char in here and get it to work, because if char is signed then it + * will first be sign extended. + */ +#define TEST_CHAR(c, f) (test_char_table[(unsigned)(c)] & (f)) + +APR_DECLARE(apr_status_t) apr_escape_shell(char *escaped, const char *str, + apr_ssize_t slen, apr_size_t *len) +{ + unsigned char *d; + const unsigned char *s; + apr_size_t size = 1; + int found = 0; + + d = (unsigned char *) escaped; + s = (const unsigned char *) str; + + if (s) { + if (d) { + for (; *s && slen; ++s, slen--) { +#if defined(OS2) || defined(WIN32) + /* + * Newlines to Win32/OS2 CreateProcess() are ill advised. + * Convert them to spaces since they are effectively white + * space to most applications + */ + if (*s == '\r' || *s == '\n') { + if (d) { + *d++ = ' '; + found = 1; + } + continue; + } +#endif + if (TEST_CHAR(*s, T_ESCAPE_SHELL_CMD)) { + *d++ = '\\'; + size++; + found = 1; + } + *d++ = *s; + size++; + } + *d = '\0'; + } + else { + for (; *s && slen; ++s, slen--) { + if (TEST_CHAR(*s, T_ESCAPE_SHELL_CMD)) { + size++; + found = 1; + } + size++; + } + } + } + + if (len) { + *len = size; + } + if (!found) { + return APR_NOTFOUND; + } + + return APR_SUCCESS; +} + +APR_DECLARE(const char *) apr_pescape_shell(apr_pool_t *p, const char *str) +{ + apr_size_t len; + + switch (apr_escape_shell(NULL, str, APR_ESCAPE_STRING, &len)) { + case APR_SUCCESS: { + char *cmd = apr_palloc(p, len); + apr_escape_shell(cmd, str, APR_ESCAPE_STRING, NULL); + return cmd; + } + case APR_NOTFOUND: { + break; + } + } + + return str; +} + +static char x2c(const char *what) +{ + register char digit; + +#if !APR_CHARSET_EBCDIC + digit = + ((what[0] >= 'A') ? ((what[0] & 0xdf) - 'A') + 10 : (what[0] - '0')); + digit *= 16; + digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A') + 10 : (what[1] - '0')); +#else /*APR_CHARSET_EBCDIC*/ + char xstr[5]; + xstr[0]='0'; + xstr[1]='x'; + xstr[2]=what[0]; + xstr[3]=what[1]; + xstr[4]='\0'; + digit = convert_a2e[0xFF & strtol(xstr, NULL, 16)]; +#endif /*APR_CHARSET_EBCDIC*/ + return (digit); +} + +APR_DECLARE(apr_status_t) apr_unescape_url(char *escaped, const char *url, + apr_ssize_t slen, const char *forbid, const char *reserved, int plus, + apr_size_t *len) +{ + apr_size_t size = 1; + int found = 0; + const char *s = (const char *) url; + char *d = (char *) escaped; + register int badesc, badpath; + + if (!url) { + return APR_NOTFOUND; + } + + badesc = 0; + badpath = 0; + if (s) { + if (d) { + for (; *s && slen; ++s, d++, slen--) { + if (plus && *s == '+') { + *d = ' '; + found = 1; + } + else if (*s != '%') { + *d = *s; + } + else { + if (!apr_isxdigit(*(s + 1)) || !apr_isxdigit(*(s + 2))) { + badesc = 1; + *d = '%'; + } + else { + char decoded; + decoded = x2c(s + 1); + if ((decoded == '\0') + || (forbid && strchr(forbid, decoded))) { + badpath = 1; + *d = decoded; + s += 2; + slen -= 2; + } + else if (reserved && strchr(reserved, decoded)) { + *d++ = *s++; + *d++ = *s++; + *d = *s; + size += 2; + } + else { + *d = decoded; + s += 2; + slen -= 2; + found = 1; + } + } + } + size++; + } + *d = '\0'; + } + else { + for (; *s && slen; ++s, slen--) { + if (plus && *s == '+') { + found = 1; + } + else if (*s != '%') { + /* character unchanged */ + } + else { + if (!apr_isxdigit(*(s + 1)) || !apr_isxdigit(*(s + 2))) { + badesc = 1; + } + else { + char decoded; + decoded = x2c(s + 1); + if ((decoded == '\0') + || (forbid && strchr(forbid, decoded))) { + badpath = 1; + s += 2; + slen -= 2; + } + else if (reserved && strchr(reserved, decoded)) { + s += 2; + slen -= 2; + size += 2; + } + else { + s += 2; + slen -= 2; + found = 1; + } + } + } + size++; + } + } + } + + if (len) { + *len = size; + } + if (badesc) { + return APR_EINVAL; + } + else if (badpath) { + return APR_BADCH; + } + else if (!found) { + return APR_NOTFOUND; + } + + return APR_SUCCESS; +} + +APR_DECLARE(const char *) apr_punescape_url(apr_pool_t *p, const char *url, + const char *forbid, const char *reserved, int plus) +{ + apr_size_t len; + + switch (apr_unescape_url(NULL, url, APR_ESCAPE_STRING, forbid, reserved, + plus, &len)) { + case APR_SUCCESS: { + char *buf = apr_palloc(p, len); + apr_unescape_url(buf, url, APR_ESCAPE_STRING, forbid, reserved, plus, + NULL); + return buf; + } + case APR_EINVAL: + case APR_BADCH: { + return NULL; + } + case APR_NOTFOUND: { + break; + } + } + + return url; +} + +/* c2x takes an unsigned, and expects the caller has guaranteed that + * 0 <= what < 256... which usually means that you have to cast to + * unsigned char first, because (unsigned)(char)(x) first goes through + * signed extension to an int before the unsigned cast. + * + * The reason for this assumption is to assist gcc code generation -- + * the unsigned char -> unsigned extension is already done earlier in + * both uses of this code, so there's no need to waste time doing it + * again. + */ +static const char c2x_table[] = "0123456789abcdef"; + +static APR_INLINE unsigned char *c2x(unsigned what, unsigned char prefix, + unsigned char *where) +{ +#if APR_CHARSET_EBCDIC + what = convert_e2a[(unsigned char)what]; +#endif /*APR_CHARSET_EBCDIC*/ + *where++ = prefix; + *where++ = c2x_table[what >> 4]; + *where++ = c2x_table[what & 0xf]; + return where; +} + +APR_DECLARE(apr_status_t) apr_escape_path_segment(char *escaped, + const char *str, apr_ssize_t slen, apr_size_t *len) +{ + apr_size_t size = 1; + int found = 0; + const unsigned char *s = (const unsigned char *) str; + unsigned char *d = (unsigned char *) escaped; + unsigned c; + + if (s) { + if (d) { + while ((c = *s) && slen) { + if (TEST_CHAR(c, T_ESCAPE_PATH_SEGMENT)) { + d = c2x(c, '%', d); + size += 2; + found = 1; + } + else { + *d++ = c; + } + ++s; + size++; + slen--; + } + *d = '\0'; + } + else { + while ((c = *s) && slen) { + if (TEST_CHAR(c, T_ESCAPE_PATH_SEGMENT)) { + size += 2; + found = 1; + } + ++s; + size++; + slen--; + } + } + } + + if (len) { + *len = size; + } + if (!found) { + return APR_NOTFOUND; + } + + return APR_SUCCESS; +} + +APR_DECLARE(const char *) apr_pescape_path_segment(apr_pool_t *p, + const char *str) +{ + apr_size_t len; + + switch (apr_escape_path_segment(NULL, str, APR_ESCAPE_STRING, &len)) { + case APR_SUCCESS: { + char *cmd = apr_palloc(p, len); + apr_escape_path_segment(cmd, str, APR_ESCAPE_STRING, NULL); + return cmd; + } + case APR_NOTFOUND: { + break; + } + } + + return str; +} + +APR_DECLARE(apr_status_t) apr_escape_path(char *escaped, const char *path, + apr_ssize_t slen, int partial, apr_size_t *len) +{ + apr_size_t size = 1; + int found = 0; + const unsigned char *s = (const unsigned char *) path; + unsigned char *d = (unsigned char *) escaped; + unsigned c; + + if (!path) { + return APR_NOTFOUND; + } + + if (!partial) { + const char *colon = strchr(path, ':'); + const char *slash = strchr(path, '/'); + + if (colon && (!slash || colon < slash)) { + if (d) { + *d++ = '.'; + *d++ = '/'; + } + size += 2; + found = 1; + } + } + if (d) { + while ((c = *s) && slen) { + if (TEST_CHAR(c, T_OS_ESCAPE_PATH)) { + d = c2x(c, '%', d); + size += 2; + found = 1; + } + else { + *d++ = c; + } + ++s; + size++; + slen--; + } + *d = '\0'; + } + else { + while ((c = *s) && slen) { + if (TEST_CHAR(c, T_OS_ESCAPE_PATH)) { + size += 2; + found = 1; + } + ++s; + size++; + slen--; + } + } + + if (len) { + *len = size; + } + if (!found) { + return APR_NOTFOUND; + } + + return APR_SUCCESS; +} + +APR_DECLARE(const char *) apr_pescape_path(apr_pool_t *p, const char *str, + int partial) +{ + apr_size_t len; + + switch (apr_escape_path(NULL, str, APR_ESCAPE_STRING, partial, &len)) { + case APR_SUCCESS: { + char *path = apr_palloc(p, len); + apr_escape_path(path, str, APR_ESCAPE_STRING, partial, NULL); + return path; + } + case APR_NOTFOUND: { + break; + } + } + + return str; +} + +APR_DECLARE(apr_status_t) apr_escape_urlencoded(char *escaped, const char *str, + apr_ssize_t slen, apr_size_t *len) +{ + apr_size_t size = 1; + int found = 0; + const unsigned char *s = (const unsigned char *) str; + unsigned char *d = (unsigned char *) escaped; + unsigned c; + + if (s) { + if (d) { + while ((c = *s) && slen) { + if (TEST_CHAR(c, T_ESCAPE_URLENCODED)) { + d = c2x(c, '%', d); + size += 2; + found = 1; + } + else if (c == ' ') { + *d++ = '+'; + found = 1; + } + else { + *d++ = c; + } + ++s; + size++; + slen--; + } + *d = '\0'; + } + else { + while ((c = *s) && slen) { + if (TEST_CHAR(c, T_ESCAPE_URLENCODED)) { + size += 2; + found = 1; + } + else if (c == ' ') { + found = 1; + } + ++s; + size++; + slen--; + } + } + } + + if (len) { + *len = size; + } + if (!found) { + return APR_NOTFOUND; + } + + return APR_SUCCESS; +} + +APR_DECLARE(const char *) apr_pescape_urlencoded(apr_pool_t *p, const char *str) +{ + apr_size_t len; + + switch (apr_escape_urlencoded(NULL, str, APR_ESCAPE_STRING, &len)) { + case APR_SUCCESS: { + char *encoded = apr_palloc(p, len); + apr_escape_urlencoded(encoded, str, APR_ESCAPE_STRING, NULL); + return encoded; + } + case APR_NOTFOUND: { + break; + } + } + + return str; +} + +APR_DECLARE(apr_status_t) apr_escape_entity(char *escaped, const char *str, + apr_ssize_t slen, int toasc, apr_size_t *len) +{ + apr_size_t size = 1; + int found = 0; + const unsigned char *s = (const unsigned char *) str; + unsigned char *d = (unsigned char *) escaped; + unsigned c; + + if (s) { + if (d) { + while ((c = *s) && slen) { + if (TEST_CHAR(c, T_ESCAPE_XML)) { + switch (c) { + case '>': { + memcpy(d, ">", 4); + size += 4; + d += 4; + break; + } + case '<': { + memcpy(d, "<", 4); + size += 4; + d += 4; + break; + } + case '&': { + memcpy(d, "&", 5); + size += 5; + d += 5; + break; + } + case '\"': { + memcpy(d, """, 6); + size += 6; + d += 6; + break; + } + case '\'': { + memcpy(d, "'", 6); + size += 6; + d += 6; + break; + } + } + found = 1; + } + else if (toasc && !apr_isascii(c)) { + int offset = apr_snprintf((char *) d, 6, "&#%3.3d;", c); + size += offset; + d += offset; + found = 1; + } + else { + *d++ = c; + size++; + } + ++s; + slen--; + } + *d = '\0'; + } + else { + while ((c = *s) && slen) { + if (TEST_CHAR(c, T_ESCAPE_XML)) { + switch (c) { + case '>': { + size += 4; + break; + } + case '<': { + size += 4; + break; + } + case '&': { + size += 5; + break; + } + case '\"': { + size += 6; + break; + } + case '\'': { + size += 6; + break; + } + } + found = 1; + } + else if (toasc && !apr_isascii(c)) { + char buf[8]; + size += apr_snprintf(buf, 6, "&#%3.3d;", c); + found = 1; + } + else { + size++; + } + ++s; + slen--; + } + } + } + + if (len) { + *len = size; + } + if (!found) { + return APR_NOTFOUND; + } + + return APR_SUCCESS; +} + +APR_DECLARE(const char *) apr_pescape_entity(apr_pool_t *p, const char *str, + int toasc) +{ + apr_size_t len; + + switch (apr_escape_entity(NULL, str, APR_ESCAPE_STRING, toasc, &len)) { + case APR_SUCCESS: { + char *cmd = apr_palloc(p, len); + apr_escape_entity(cmd, str, APR_ESCAPE_STRING, toasc, NULL); + return cmd; + } + case APR_NOTFOUND: { + break; + } + } + + return str; +} + +/* maximum length of any ISO-LATIN-1 HTML entity name. */ +#define MAXENTLEN (6) + +APR_DECLARE(apr_status_t) apr_unescape_entity(char *unescaped, const char *str, + apr_ssize_t slen, apr_size_t *len) +{ + int found = 0; + apr_size_t size = 1; + int val, i, j; + char *d = unescaped; + const char *s = str; + const char *ents; + static const char * const entlist[MAXENTLEN + 1] = + { + NULL, /* 0 */ + NULL, /* 1 */ + "lt\074gt\076", /* 2 */ + "amp\046ETH\320eth\360", /* 3 */ + "quot\042Auml\304Euml\313Iuml\317Ouml\326Uuml\334auml\344euml" + "\353iuml\357ouml\366uuml\374yuml\377", /* 4 */ + "Acirc\302Aring\305AElig\306Ecirc\312Icirc\316Ocirc\324Ucirc" + "\333THORN\336szlig\337acirc\342aring\345aelig\346ecirc\352" + "icirc\356ocirc\364ucirc\373thorn\376", /* 5 */ + "Agrave\300Aacute\301Atilde\303Ccedil\307Egrave\310Eacute\311" + "Igrave\314Iacute\315Ntilde\321Ograve\322Oacute\323Otilde" + "\325Oslash\330Ugrave\331Uacute\332Yacute\335agrave\340" + "aacute\341atilde\343ccedil\347egrave\350eacute\351igrave" + "\354iacute\355ntilde\361ograve\362oacute\363otilde\365" + "oslash\370ugrave\371uacute\372yacute\375" /* 6 */ + }; + + if (s) { + if (d) { + for (; *s != '\0' && slen; s++, d++, size++, slen--) { + if (*s != '&') { + *d = *s; + continue; + } + /* find end of entity */ + for (i = 1; s[i] != ';' && s[i] != '\0' && (slen - i) != 0; + i++) { + continue; + } + + if (s[i] == '\0' || (slen - i) == 0) { /* treat as normal data */ + *d = *s; + continue; + } + + /* is it numeric ? */ + if (s[1] == '#') { + for (j = 2, val = 0; j < i && apr_isdigit(s[j]); j++) { + val = val * 10 + s[j] - '0'; + } + s += i; + if (j < i || val <= 8 || (val >= 11 && val <= 31) + || (val >= 127 && val <= 160) || val >= 256) { + d--; /* no data to output */ + size--; + } + else { + *d = RAW_ASCII_CHAR(val); + found = 1; + } + } + else { + j = i - 1; + if (j > MAXENTLEN || entlist[j] == NULL) { + /* wrong length */ + *d = '&'; + continue; /* skip it */ + } + for (ents = entlist[j]; *ents != '\0'; ents += i) { + if (strncmp(s + 1, ents, j) == 0) { + break; + } + } + + if (*ents == '\0') { + *d = '&'; /* unknown */ + } + else { + *d = RAW_ASCII_CHAR(((const unsigned char *) ents)[j]); + s += i; + slen -= i; + found = 1; + } + } + } + *d = '\0'; + } + else { + for (; *s != '\0' && slen; s++, size++, slen--) { + if (*s != '&') { + continue; + } + /* find end of entity */ + for (i = 1; s[i] != ';' && s[i] != '\0' && (slen - i) != 0; + i++) { + continue; + } + + if (s[i] == '\0' || (slen - i) == 0) { /* treat as normal data */ + continue; + } + + /* is it numeric ? */ + if (s[1] == '#') { + for (j = 2, val = 0; j < i && apr_isdigit(s[j]); j++) { + val = val * 10 + s[j] - '0'; + } + s += i; + if (j < i || val <= 8 || (val >= 11 && val <= 31) + || (val >= 127 && val <= 160) || val >= 256) { + /* no data to output */ + size--; + } + else { + found = 1; + } + } + else { + j = i - 1; + if (j > MAXENTLEN || entlist[j] == NULL) { + /* wrong length */ + continue; /* skip it */ + } + for (ents = entlist[j]; *ents != '\0'; ents += i) { + if (strncmp(s + 1, ents, j) == 0) { + break; + } + } + + if (*ents == '\0') { + /* unknown */ + } + else { + s += i; + slen -= i; + found = 1; + } + } + } + } + } + + if (len) { + *len = size; + } + if (!found) { + return APR_NOTFOUND; + } + + return APR_SUCCESS; +} + +APR_DECLARE(const char *) apr_punescape_entity(apr_pool_t *p, const char *str) +{ + apr_size_t len; + + switch (apr_unescape_entity(NULL, str, APR_ESCAPE_STRING, &len)) { + case APR_SUCCESS: { + char *cmd = apr_palloc(p, len); + apr_unescape_entity(cmd, str, APR_ESCAPE_STRING, NULL); + return cmd; + } + case APR_NOTFOUND: { + break; + } + } + + return str; +} + +APR_DECLARE(apr_status_t) apr_escape_echo(char *escaped, const char *str, + apr_ssize_t slen, int quote, apr_size_t *len) +{ + apr_size_t size = 1; + int found = 0; + const unsigned char *s = (const unsigned char *) str; + unsigned char *d = (unsigned char *) escaped; + unsigned c; + + if (s) { + if (d) { + while ((c = *s) && slen) { + if (TEST_CHAR(c, T_ESCAPE_ECHO)) { + *d++ = '\\'; + size++; + switch (c) { + case '\a': + *d++ = 'a'; + size++; + found = 1; + break; + case '\b': + *d++ = 'b'; + size++; + found = 1; + break; + case '\f': + *d++ = 'f'; + size++; + found = 1; + break; + case '\n': + *d++ = 'n'; + size++; + found = 1; + break; + case '\r': + *d++ = 'r'; + size++; + found = 1; + break; + case '\t': + *d++ = 't'; + size++; + found = 1; + break; + case '\v': + *d++ = 'v'; + size++; + found = 1; + break; + case '\\': + *d++ = '\\'; + size++; + found = 1; + break; + case '"': + if (quote) { + *d++ = c; + size++; + found = 1; + } + else { + d[-1] = c; + } + break; + default: + c2x(c, 'x', d); + d += 3; + size += 3; + found = 1; + break; + } + } + else { + *d++ = c; + size++; + } + ++s; + slen--; + } + *d = '\0'; + } + else { + while ((c = *s) && slen) { + if (TEST_CHAR(c, T_ESCAPE_ECHO)) { + size++; + switch (c) { + case '\a': + case '\b': + case '\f': + case '\n': + case '\r': + case '\t': + case '\v': + case '\\': + size++; + found = 1; + break; + case '"': + if (quote) { + size++; + found = 1; + } + break; + default: + size += 3; + found = 1; + break; + } + } + else { + size++; + } + ++s; + slen--; + } + } + } + + if (len) { + *len = size; + } + if (!found) { + return APR_NOTFOUND; + } + + return APR_SUCCESS; +} + +APR_DECLARE(const char *) apr_pescape_echo(apr_pool_t *p, const char *str, + int quote) +{ + apr_size_t len; + + switch (apr_escape_echo(NULL, str, APR_ESCAPE_STRING, quote, &len)) { + case APR_SUCCESS: { + char *cmd = apr_palloc(p, len); + apr_escape_echo(cmd, str, APR_ESCAPE_STRING, quote, NULL); + return cmd; + } + case APR_NOTFOUND: { + break; + } + } + + return str; +} + +APR_DECLARE(apr_status_t) apr_escape_hex(char *dest, const void *src, + apr_size_t srclen, int colon, apr_size_t *len) +{ + const unsigned char *in = src; + apr_size_t size; + + if (!src) { + return APR_NOTFOUND; + } + + if (dest) { + for (size = 0; size < srclen; size++) { + if (colon && size) { + *dest++ = ':'; + } + *dest++ = c2x_table[in[size] >> 4]; + *dest++ = c2x_table[in[size] & 0xf]; + } + *dest = '\0'; + } + + if (len) { + if (colon && srclen) { + *len = srclen * 3; + } + else { + *len = srclen * 2 + 1; + } + } + + return APR_SUCCESS; +} + +APR_DECLARE(const char *) apr_pescape_hex(apr_pool_t *p, const void *src, + apr_size_t srclen, int colon) +{ + apr_size_t len; + + switch (apr_escape_hex(NULL, src, srclen, colon, &len)) { + case APR_SUCCESS: { + char *cmd = apr_palloc(p, len); + apr_escape_hex(cmd, src, srclen, colon, NULL); + return cmd; + } + case APR_NOTFOUND: { + break; + } + } + + return src; +} + +APR_DECLARE(apr_status_t) apr_unescape_hex(void *dest, const char *str, + apr_ssize_t slen, int colon, apr_size_t *len) +{ + apr_size_t size = 0; + int flip = 0; + const unsigned char *s = (const unsigned char *) str; + unsigned char *d = (unsigned char *) dest; + unsigned c; + unsigned char u = 0; + + if (s) { + if (d) { + while ((c = *s) && slen) { + + if (!flip) { + u = 0; + } + + if (colon && c == ':' && !flip) { + ++s; + slen--; + continue; + } + else if (apr_isdigit(c)) { + u |= c - '0'; + } + else if (apr_isupper(c) && c <= 'F') { + u |= c - ('A' - 10); + } + else if (apr_islower(c) && c <= 'f') { + u |= c - ('a' - 10); + } + else { + return APR_BADCH; + } + + if (flip) { + *d++ = u; + size++; + } + else { + u <<= 4; + *d = u; + } + flip = !flip; + + ++s; + slen--; + } + } + else { + while ((c = *s) && slen) { + + if (colon && c == ':' && !flip) { + ++s; + slen--; + continue; + } + else if (apr_isdigit(c)) { + /* valid */ + } + else if (apr_isupper(c) && c <= 'F') { + /* valid */ + } + else if (apr_islower(c) && c <= 'f') { + /* valid */ + } + else { + return APR_BADCH; + } + + if (flip) { + size++; + } + flip = !flip; + + ++s; + slen--; + } + } + } + + if (len) { + *len = size; + } + if (!s) { + return APR_NOTFOUND; + } + + return APR_SUCCESS; +} + +APR_DECLARE(const void *) apr_punescape_hex(apr_pool_t *p, const char *str, + int colon, apr_size_t *len) +{ + apr_size_t size; + + switch (apr_unescape_hex(NULL, str, APR_ESCAPE_STRING, colon, &size)) { + case APR_SUCCESS: { + void *cmd = apr_palloc(p, size); + apr_unescape_hex(cmd, str, APR_ESCAPE_STRING, colon, len); + return cmd; + } + case APR_BADCH: + case APR_NOTFOUND: { + break; + } + } + + return NULL; +} + +APR_DECLARE(apr_status_t) apr_escape_ldap(char *escaped, const void *str, + apr_ssize_t slen, int flags, apr_size_t *len) +{ + apr_size_t size = 1; + int found = 0; + const unsigned char *s = (const unsigned char *) str; + unsigned char *d = (unsigned char *) escaped; + unsigned c; + + if (s) { + if (d) { + while (((c = *s) && slen) || (slen > 0)) { + if (((flags & APR_ESCAPE_LDAP_DN) && TEST_CHAR(c, T_ESCAPE_LDAP_DN)) + || ((flags & APR_ESCAPE_LDAP_FILTER) && TEST_CHAR(c, T_ESCAPE_LDAP_FILTER))) { + d = c2x(c, '\\', d); + size += 2; + found = 1; + } + else { + *d++ = c; + } + ++s; + size++; + slen--; + } + *d = '\0'; + } + else { + while (((c = *s) && slen) || (slen > 0)) { + if (((flags & APR_ESCAPE_LDAP_DN) && TEST_CHAR(c, T_ESCAPE_LDAP_DN)) + || ((flags & APR_ESCAPE_LDAP_FILTER) && TEST_CHAR(c, T_ESCAPE_LDAP_FILTER))) { + size += 2; + found = 1; + } + ++s; + size++; + slen--; + } + } + } + + if (len) { + *len = size; + } + if (!found) { + return APR_NOTFOUND; + } + + return APR_SUCCESS; +} + +APR_DECLARE(const char *) apr_pescape_ldap(apr_pool_t *p, const void *src, + apr_ssize_t srclen, int flags) +{ + apr_size_t len; + + switch (apr_escape_ldap(NULL, src, srclen, flags, &len)) { + case APR_SUCCESS: { + char *encoded = apr_palloc(p, len); + apr_escape_ldap(encoded, src, srclen, flags, NULL); + return encoded; + } + case APR_NOTFOUND: { + break; + } + } + + return src; +} + diff --git a/file_io/beos/Makefile.in b/file_io/beos/Makefile.in deleted file mode 100644 index c06254b2da1..00000000000 --- a/file_io/beos/Makefile.in +++ /dev/null @@ -1,63 +0,0 @@ -#CFLAGS=$(OPTIM) $(CFLAGS1) $(EXTRA_CFLAGS) -#LIBS=$(EXTRA_LIBS) $(LIBS1) -#INCLUDES=$(INCLUDES1) $(INCLUDES0) $(EXTRA_INCLUDES) -#LDFLAGS=$(LDFLAGS1) $(EXTRA_LDFLAGS) - -RM=@RM@ -CC=@CC@ -RANLIB=@RANLIB@ -CFLAGS=@CFLAGS@ @OPTIM@ -LIBS=@LIBS@ -LDFLAGS=@LDFLAGS@ $(LIBS) -INCDIR=../../include -I../unix -INCLUDES=-I$(INCDIR) -I. - -LIB=libfile.a - -OBJS=file_io_common.o readwrite.o - -.c.o: - $(CC) $(CFLAGS) -c $(INCLUDES) $< - -all: $(LIB) - -clean: - $(RM) -f *.o *.a *.so - -distclean: clean - -$(RM) -f Makefile - -$(OBJS): Makefile - -$(LIB): $(OBJS) - $(RM) -f $@ - $(AR) cr $@ $(OBJS) - $(RANLIB) $@ - -# -# We really don't expect end users to use this rule. It works only with -# gcc, and rebuilds Makefile.tmpl. You have to re-run Configure after -# using it. -# -depend: - cp Makefile.in Makefile.in.bak \ - && sed -ne '1,/^# DO NOT REMOVE/p' Makefile.in > Makefile.new \ - && gcc -MM $(INCLUDES) $(CFLAGS) *.c >> Makefile.new \ - && sed -e '1,$$s: $(INCDIR)/: $$(INCDIR)/:g' \ - -e '1,$$s: $(OSDIR)/: $$(OSDIR)/:g' Makefile.new \ - > Makefile.in \ - && rm Makefile.new - -# DO NOT REMOVE -file_io_common.o: file_io_common.c ../unix/dir.c ../unix/fileio.h \ - ../../include/apr_private.h ../../include/apr_general.h \ - ../../include/apr.h ../../include/apr_errno.h \ - ../../include/apr_file_io.h ../../include/apr_lib.h \ - ../../include/apr_portable.h ../../include/apr_thread_proc.h \ - ../../include/apr_network_io.h ../../include/apr_lock.h \ - ../../include/apr_time.h ../unix/fileacc.c ../unix/filedup.c \ - ../unix/filestat.c ../unix/open.c ../unix/pipe.c ../unix/seek.c -readwrite.o: readwrite.c ../unix/fileio.h ../../include/apr_private.h \ - ../../include/apr_general.h ../../include/apr.h \ - ../../include/apr_errno.h ../../include/apr_file_io.h \ - ../../include/apr_lib.h diff --git a/file_io/beos/file_io_common.c b/file_io/beos/file_io_common.c deleted file mode 100644 index 63ffac03e9d..00000000000 --- a/file_io/beos/file_io_common.c +++ /dev/null @@ -1,73 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -/* common.c */ - -/* The code used in readwrite.c in the Unix directory won't work on - BeOS so I've moved to using a common.c file for all the common - code. */ - -#include "../unix/dir.c" - -#include "../unix/fileacc.c" - -#include "../unix/filedup.c" - -#include "../unix/filestat.c" - -#include "../unix/open.c" - -#include "../unix/pipe.c" - -#include "../unix/seek.c" diff --git a/file_io/beos/readwrite.c b/file_io/beos/readwrite.c deleted file mode 100644 index 96aaf5247db..00000000000 --- a/file_io/beos/readwrite.c +++ /dev/null @@ -1,334 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#include "../unix/fileio.h" - -ap_status_t ap_read(ap_file_t *thefile, void *buf, ap_ssize_t *nbytes) -{ - ap_ssize_t rv; - ap_ssize_t bytes_read; - - if(*nbytes <= 0) { - *nbytes = 0; - return APR_SUCCESS; - } - - if (thefile->buffered) { - char *pos = (char *)buf; - ap_uint64_t blocksize; - ap_uint64_t size = *nbytes; - - ap_lock(thefile->thlock); - - if (thefile->direction == 1) { - ap_flush(thefile); - thefile->bufpos = 0; - thefile->direction = 0; - thefile->dataRead = 0; - } - - rv = 0; - while (rv == 0 && size > 0) { - if (thefile->bufpos >= thefile->dataRead) { - thefile->dataRead = read(thefile->filedes, thefile->buffer, APR_FILE_BUFSIZE); - if (thefile->dataRead == 0) { - thefile->eof_hit = TRUE; - break; - } - thefile->filePtr += thefile->dataRead; - thefile->bufpos = 0; - } - - blocksize = size > thefile->dataRead - thefile->bufpos ? thefile->dataRead - thefile->bufpos : size; memcpy(pos, thefile->buffer + thefile->bufpos, blocksize); - thefile->bufpos += blocksize; - pos += blocksize; - size -= blocksize; - } - - *nbytes = rv == 0 ? pos - (char *)buf : 0; - ap_unlock(thefile->thlock); - return rv; - } - else { - bytes_read = 0; - if (thefile->ungetchar != -1) { - bytes_read = 1; - *(char *)buf = (char)thefile->ungetchar; - buf = (char *)buf + 1; - (*nbytes)--; - thefile->ungetchar = -1; - if (*nbytes == 0) { - *nbytes = bytes_read; - return APR_SUCCESS; - } - } - do { - rv = read(thefile->filedes, buf, *nbytes); - } while (rv == -1 && errno == EINTR); - *nbytes = bytes_read; - if (rv == 0) { - return APR_EOF; - } - if (rv > 0) { - *nbytes += rv; - return APR_SUCCESS; - } - return errno; - } -} - -ap_status_t ap_write(ap_file_t *thefile, void *buf, ap_ssize_t *nbytes) -{ - ap_size_t rv; - - if (thefile->buffered) { - char *pos = (char *)buf; - int blocksize; - int size = *nbytes; - - ap_lock(thefile->thlock); - - if ( thefile->direction == 0 ) { - /* Position file pointer for writing at the offset we are - * logically reading from - */ - ap_int64_t offset = thefile->filePtr - thefile->dataRead + thefile->bufpos; - if (offset != thefile->filePtr) - lseek(thefile->filedes, offset, SEEK_SET); - thefile->bufpos = thefile->dataRead = 0; - thefile->direction = 1; - } - - rv = 0; - while (rv == 0 && size > 0) { - if (thefile->bufpos == APR_FILE_BUFSIZE) /* write buffer is full*/ - ap_flush(thefile); - - blocksize = size > APR_FILE_BUFSIZE - thefile->bufpos ? - APR_FILE_BUFSIZE - thefile->bufpos : size; - memcpy(thefile->buffer + thefile->bufpos, pos, blocksize); thefile->bufpos += blocksize; - pos += blocksize; - size -= blocksize; - } - - ap_unlock(thefile->thlock); - return rv; - } - else { - do { - rv = write(thefile->filedes, buf, *nbytes); - } while (rv == (ap_size_t)-1 && errno == EINTR); - - if (rv == (ap_size_t)-1) { - (*nbytes) = 0; - return errno; - } - *nbytes = rv; - return APR_SUCCESS; - } -} - -ap_status_t ap_writev(ap_file_t *thefile, const struct iovec *vec, - ap_size_t nvec, ap_ssize_t *nbytes) -{ - int bytes; - - if ((bytes = writev(thefile->filedes, vec, nvec)) < 0) { - *nbytes = 0; - return errno; - } - else { - *nbytes = bytes; - return APR_SUCCESS; - } -} - -ap_status_t ap_putc(char ch, ap_file_t *thefile) -{ - if (write(thefile->filedes, &ch, 1) != 1) { - return errno; - } - return APR_SUCCESS; -} - -ap_status_t ap_ungetc(char ch, ap_file_t *thefile) -{ - thefile->ungetchar = (unsigned char)ch; - return APR_SUCCESS; -} - -ap_status_t ap_getc(char *ch, ap_file_t *thefile) -{ - ssize_t rv; - - if (thefile->ungetchar != -1) { - *ch = (char) thefile->ungetchar; - thefile->ungetchar = -1; - return APR_SUCCESS; - } - rv = read(thefile->filedes, ch, 1); - if (rv == 0) { - thefile->eof_hit = TRUE; - return APR_EOF; - } - else if (rv != 1) { - return errno; - } - return APR_SUCCESS; -} - -ap_status_t ap_puts(char *str, ap_file_t *thefile) -{ - ssize_t rv; - int len; - - len = strlen(str); - rv = write(thefile->filedes, str, len); - if (rv != len) { - return errno; - } - return APR_SUCCESS; -} - -ap_status_t ap_flush(ap_file_t *thefile) -{ - if (thefile->buffered) { - ap_int64_t written = 0; - int rc = 0; - - if (thefile->direction == 1 && thefile->bufpos) { - written= write(thefile->filedes, thefile->buffer, thefile->bufpos); - thefile->filePtr += written; - - if (rc == 0) - thefile->bufpos = 0; - } - - return rc; - } - /* There isn't anything to do if we aren't buffering the output - * so just return success. - */ - return APR_SUCCESS; -} - -ap_status_t ap_fgets(char *str, int len, ap_file_t *thefile) -{ - ssize_t rv; - int i, used_unget = FALSE, beg_idx; - - if(len <= 1) /* as per fgets() */ - return APR_SUCCESS; - - if(thefile->ungetchar != -1){ - str[0] = thefile->ungetchar; - used_unget = TRUE; - beg_idx = 1; - if(str[0] == '\n' || str[0] == '\r'){ - thefile->ungetchar = -1; - str[1] = '\0'; - return APR_SUCCESS; - } - } else - beg_idx = 0; - - for (i = beg_idx; i < len; i++) { - rv = read(thefile->filedes, &str[i], 1); - if (rv == 0) { - thefile->eof_hit = TRUE; - if(used_unget) thefile->filedes = -1; - str[i] = '\0'; - return APR_EOF; - } - else if (rv != 1) { - return errno; - } - if (str[i] == '\n' || str[i] == '\r') - break; - } - if (i < len-1) - str[i+1] = '\0'; - return APR_SUCCESS; -} - -#if 0 /* not currently used */ -static int printf_flush(ap_vformatter_buff_t *vbuff) -{ - /* I would love to print this stuff out to the file, but I will - * get that working later. :) For now, just return. - */ - return -1; -} -#endif - -API_EXPORT(int) ap_fprintf(ap_file_t *fptr, const char *format, ...) -{ - int cc; - va_list ap; - char *buf; - int len; - - buf = malloc(HUGE_STRING_LEN); - if (buf == NULL) { - return 0; - } - va_start(ap, format); - len = ap_vsnprintf(buf, HUGE_STRING_LEN, format, ap); - cc = ap_puts(buf, fptr); - va_end(ap); - free(buf); - return (cc == APR_SUCCESS) ? len : -1; -} - - diff --git a/file_io/netware/filestat.c b/file_io/netware/filestat.c new file mode 100644 index 00000000000..85d73c30d13 --- /dev/null +++ b/file_io/netware/filestat.c @@ -0,0 +1,417 @@ +/* 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_file_io.h" +#include "fsio.h" +#include "nks/dirio.h" +#include "apr_file_io.h" +#include "apr_general.h" +#include "apr_strings.h" +#include "apr_errno.h" +#include "apr_hash.h" +#include "apr_thread_rwlock.h" + +#ifdef HAVE_UTIME_H +#include <utime.h> +#endif + +#define APR_HAS_PSA + +static apr_filetype_e filetype_from_mode(mode_t mode) +{ + apr_filetype_e type = APR_NOFILE; + + if (S_ISREG(mode)) + type = APR_REG; + else if (S_ISDIR(mode)) + type = APR_DIR; + else if (S_ISCHR(mode)) + type = APR_CHR; + else if (S_ISBLK(mode)) + type = APR_BLK; + else if (S_ISFIFO(mode)) + type = APR_PIPE; + else if (S_ISLNK(mode)) + type = APR_LNK; + else if (S_ISSOCK(mode)) + type = APR_SOCK; + else + type = APR_UNKFILE; + return type; +} + +static void fill_out_finfo(apr_finfo_t *finfo, struct stat *info, + apr_int32_t wanted) +{ + finfo->valid = APR_FINFO_MIN | APR_FINFO_IDENT | APR_FINFO_NLINK + | APR_FINFO_OWNER | APR_FINFO_PROT; + + finfo->protection = apr_unix_mode2perms(info->st_mode); + finfo->filetype = filetype_from_mode(info->st_mode); + finfo->user = info->st_uid; + finfo->group = info->st_gid; + finfo->size = info->st_size; + finfo->inode = info->st_ino; + finfo->device = info->st_dev; + finfo->nlink = info->st_nlink; + + apr_time_ansi_put(&finfo->atime, info->st_atime.tv_sec); + apr_time_ansi_put(&finfo->mtime, info->st_mtime.tv_sec); + apr_time_ansi_put(&finfo->ctime, info->st_ctime.tv_sec); + +#ifdef HAVE_STRUCT_STAT_ST_BLOCKS +#ifdef DEV_BSIZE + finfo->csize = (apr_off_t)info->st_blocks * (apr_off_t)DEV_BSIZE; +#else + finfo->csize = (apr_off_t)info->st_blocks * (apr_off_t)512; +#endif + finfo->valid |= APR_FINFO_CSIZE; +#endif +} + +apr_status_t apr_file_info_get_locked(apr_finfo_t *finfo, apr_int32_t wanted, + apr_file_t *thefile) +{ + struct_stat info; + + if (thefile->buffered) { + apr_status_t rv = apr_file_flush_locked(thefile); + if (rv != APR_SUCCESS) + return rv; + } + + if (fstat(thefile->filedes, &info) == 0) { + finfo->pool = thefile->pool; + finfo->fname = thefile->fname; + fill_out_finfo(finfo, &info, wanted); + return (wanted & ~finfo->valid) ? APR_INCOMPLETE : APR_SUCCESS; + } + else { + return errno; + } +} + +APR_DECLARE(apr_status_t) apr_file_info_get(apr_finfo_t *finfo, + apr_int32_t wanted, + apr_file_t *thefile) +{ + struct stat info; + + if (thefile->buffered) { + /* XXX: flush here is not mutex protected */ + apr_status_t rv = apr_file_flush(thefile); + if (rv != APR_SUCCESS) + return rv; + } + + if (fstat(thefile->filedes, &info) == 0) { + finfo->pool = thefile->pool; + finfo->fname = thefile->fname; + fill_out_finfo(finfo, &info, wanted); + return (wanted & ~finfo->valid) ? APR_INCOMPLETE : APR_SUCCESS; + } + else { + return errno; + } +} + +APR_DECLARE(apr_status_t) apr_file_perms_set(const char *fname, + apr_fileperms_t perms) +{ + mode_t mode = apr_unix_perms2mode(perms); + + if (chmod(fname, mode) == -1) + return errno; + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_file_attrs_set(const char *fname, + apr_fileattrs_t attributes, + apr_fileattrs_t attr_mask, + apr_pool_t *pool) +{ + apr_status_t status; + apr_finfo_t finfo; + + /* Don't do anything if we can't handle the requested attributes */ + if (!(attr_mask & (APR_FILE_ATTR_READONLY + | APR_FILE_ATTR_EXECUTABLE))) + return APR_SUCCESS; + + status = apr_stat(&finfo, fname, APR_FINFO_PROT, pool); + if (status) + return status; + + /* ### TODO: should added bits be umask'd? */ + if (attr_mask & APR_FILE_ATTR_READONLY) + { + if (attributes & APR_FILE_ATTR_READONLY) + { + finfo.protection &= ~APR_FPROT_UWRITE; + finfo.protection &= ~APR_FPROT_GWRITE; + finfo.protection &= ~APR_FPROT_WWRITE; + } + else + { + /* ### umask this! */ + finfo.protection |= APR_FPROT_UWRITE; + finfo.protection |= APR_FPROT_GWRITE; + finfo.protection |= APR_FPROT_WWRITE; + } + } + + if (attr_mask & APR_FILE_ATTR_EXECUTABLE) + { + if (attributes & APR_FILE_ATTR_EXECUTABLE) + { + /* ### umask this! */ + finfo.protection |= APR_FPROT_UEXECUTE; + finfo.protection |= APR_FPROT_GEXECUTE; + finfo.protection |= APR_FPROT_WEXECUTE; + } + else + { + finfo.protection &= ~APR_FPROT_UEXECUTE; + finfo.protection &= ~APR_FPROT_GEXECUTE; + finfo.protection &= ~APR_FPROT_WEXECUTE; + } + } + + return apr_file_perms_set(fname, finfo.protection); +} + +#ifndef APR_HAS_PSA +static apr_status_t stat_cache_cleanup(void *data) +{ + apr_pool_t *p = (apr_pool_t *)getGlobalPool(); + apr_hash_index_t *hi; + apr_hash_t *statCache = (apr_hash_t*)data; + char *key; + apr_ssize_t keylen; + NXPathCtx_t pathctx; + + for (hi = apr_hash_first(p, statCache); hi; hi = apr_hash_next(hi)) { + apr_hash_this(hi, (const void**)&key, &keylen, (void**)&pathctx); + + if (pathctx) { + NXFreePathContext(pathctx); + } + } + + return APR_SUCCESS; +} + +int cstat (NXPathCtx_t ctx, char *path, struct stat *buf, unsigned long requestmap, apr_pool_t *p) +{ + apr_pool_t *gPool = (apr_pool_t *)getGlobalPool(); + apr_hash_t *statCache = NULL; + apr_thread_rwlock_t *rwlock = NULL; + + NXPathCtx_t pathctx = 0; + char *ptr = NULL, *tr; + int len = 0, x; + char *ppath; + char *pinfo; + + if (ctx == 1) { + + /* If there isn't a global pool then just stat the file + and return */ + if (!gPool) { + char poolname[50]; + + if (apr_pool_create(&gPool, NULL) != APR_SUCCESS) { + return getstat(ctx, path, buf, requestmap); + } + + setGlobalPool(gPool); + apr_pool_tag(gPool, apr_pstrdup(gPool, "cstat_mem_pool")); + + statCache = apr_hash_make(gPool); + apr_pool_userdata_set ((void*)statCache, "STAT_CACHE", stat_cache_cleanup, gPool); + + apr_thread_rwlock_create(&rwlock, gPool); + apr_pool_userdata_set ((void*)rwlock, "STAT_CACHE_LOCK", apr_pool_cleanup_null, gPool); + } + else { + apr_pool_userdata_get((void**)&statCache, "STAT_CACHE", gPool); + apr_pool_userdata_get((void**)&rwlock, "STAT_CACHE_LOCK", gPool); + } + + if (!gPool || !statCache || !rwlock) { + return getstat(ctx, path, buf, requestmap); + } + + for (x = 0,tr = path;*tr != '\0';tr++,x++) { + if (*tr == '\\' || *tr == '/') { + ptr = tr; + len = x; + } + if (*tr == ':') { + ptr = "\\"; + len = x; + } + } + + if (ptr) { + ppath = apr_pstrndup (p, path, len); + strlwr(ppath); + if (ptr[1] != '\0') { + ptr++; + } + /* If the path ended in a trailing slash then our result path + will be a single slash. To avoid stat'ing the root with a + slash, we need to make sure we stat the current directory + with a dot */ + if (((*ptr == '/') || (*ptr == '\\')) && (*(ptr+1) == '\0')) { + pinfo = apr_pstrdup (p, "."); + } + else { + pinfo = apr_pstrdup (p, ptr); + } + } + + /* If we have a statCache then try to pull the information + from the cache. Otherwise just stat the file and return.*/ + if (statCache) { + apr_thread_rwlock_rdlock(rwlock); + pathctx = (NXPathCtx_t) apr_hash_get(statCache, ppath, APR_HASH_KEY_STRING); + apr_thread_rwlock_unlock(rwlock); + if (pathctx) { + return getstat(pathctx, pinfo, buf, requestmap); + } + else { + int err; + + err = NXCreatePathContext(0, ppath, 0, NULL, &pathctx); + if (!err) { + apr_thread_rwlock_wrlock(rwlock); + apr_hash_set(statCache, apr_pstrdup(gPool,ppath) , APR_HASH_KEY_STRING, (void*)pathctx); + apr_thread_rwlock_unlock(rwlock); + return getstat(pathctx, pinfo, buf, requestmap); + } + } + } + } + return getstat(ctx, path, buf, requestmap); +} +#endif + +APR_DECLARE(apr_status_t) apr_stat(apr_finfo_t *finfo, + const char *fname, + apr_int32_t wanted, apr_pool_t *pool) +{ + struct stat info; + int srv; + NXPathCtx_t pathCtx = 0; + + getcwdpath(NULL, &pathCtx, CTX_ACTUAL_CWD); +#ifdef APR_HAS_PSA + srv = getstat(pathCtx, (char*)fname, &info, ST_STAT_BITS|ST_NAME_BIT); +#else + srv = cstat(pathCtx, (char*)fname, &info, ST_STAT_BITS|ST_NAME_BIT, pool); +#endif + errno = srv; + + if (srv == 0) { + finfo->pool = pool; + finfo->fname = fname; + fill_out_finfo(finfo, &info, wanted); + if (wanted & APR_FINFO_LINK) + wanted &= ~APR_FINFO_LINK; + if (wanted & APR_FINFO_NAME) { + finfo->name = apr_pstrdup(pool, info.st_name); + finfo->valid |= APR_FINFO_NAME; + } + return (wanted & ~finfo->valid) ? APR_INCOMPLETE : APR_SUCCESS; + } + else { +#if !defined(ENOENT) || !defined(ENOTDIR) +#error ENOENT || ENOTDIR not defined; please see the +#error comments at this line in the source for a workaround. + /* + * If ENOENT || ENOTDIR is not defined in one of the your OS's + * include files, APR cannot report a good reason why the stat() + * of the file failed; there are cases where it can fail even though + * the file exists. This opens holes in Apache, for example, because + * it becomes possible for someone to get a directory listing of a + * directory even though there is an index (eg. index.html) file in + * it. If you do not have a problem with this, delete the above + * #error lines and start the compile again. If you need to do this, + * please submit a bug report to http://www.apache.org/bug_report.html + * letting us know that you needed to do this. Please be sure to + * include the operating system you are using. + */ + /* WARNING: All errors will be handled as not found + */ +#if !defined(ENOENT) + return APR_ENOENT; +#else + /* WARNING: All errors but not found will be handled as not directory + */ + if (errno != ENOENT) + return APR_ENOENT; + else + return errno; +#endif +#else /* All was defined well, report the usual: */ + return errno; +#endif + } +} + +APR_DECLARE(apr_status_t) apr_file_mtime_set(const char *fname, + apr_time_t mtime, + apr_pool_t *pool) +{ + apr_status_t status; + apr_finfo_t finfo; + + status = apr_stat(&finfo, fname, APR_FINFO_ATIME, pool); + if (status) { + return status; + } + +#ifdef HAVE_UTIMES + { + struct timeval tvp[2]; + + tvp[0].tv_sec = apr_time_sec(finfo.atime); + tvp[0].tv_usec = apr_time_usec(finfo.atime); + tvp[1].tv_sec = apr_time_sec(mtime); + tvp[1].tv_usec = apr_time_usec(mtime); + + if (utimes(fname, tvp) == -1) { + return errno; + } + } +#elif defined(HAVE_UTIME) + { + struct utimbuf buf; + + buf.actime = (time_t) (finfo.atime / APR_USEC_PER_SEC); + buf.modtime = (time_t) (mtime / APR_USEC_PER_SEC); + + if (utime(fname, &buf) == -1) { + return errno; + } + } +#else + return APR_ENOTIMPL; +#endif + + return APR_SUCCESS; +} diff --git a/file_io/netware/filesys.c b/file_io/netware/filesys.c new file mode 100644 index 00000000000..05c44cecd57 --- /dev/null +++ b/file_io/netware/filesys.c @@ -0,0 +1,106 @@ +/* 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_file_io.h" +#include "apr_strings.h" + +apr_status_t filepath_root_case(char **rootpath, char *root, apr_pool_t *p) +{ +/* See the Windows code to figure out what to do here. + It probably checks to make sure that the root exists + and case it correctly according to the file system. +*/ + *rootpath = apr_pstrdup(p, root); + return APR_SUCCESS; +} + +apr_status_t filepath_has_drive(const char *rootpath, int only, apr_pool_t *p) +{ + char *s; + + if (rootpath) { + s = strchr (rootpath, ':'); + if (only) + /* Test if the path only has a drive/volume and nothing else + */ + return (s && (s != rootpath) && !s[1]); + else + /* Test if the path includes a drive/volume + */ + return (s && (s != rootpath)); + } + return 0; +} + +apr_status_t filepath_compare_drive(const char *path1, const char *path2, apr_pool_t *p) +{ + char *s1, *s2; + + if (path1 && path2) { + s1 = strchr (path1, ':'); + s2 = strchr (path2, ':'); + + /* Make sure that they both have a drive/volume delimiter + and are the same size. Then see if they match. + */ + if (s1 && s2 && ((s1-path1) == (s2-path2))) { + return strnicmp (s1, s2, s1-path1); + } + } + return -1; +} + +APR_DECLARE(apr_status_t) apr_filepath_get(char **rootpath, apr_int32_t flags, + apr_pool_t *p) +{ + char path[APR_PATH_MAX]; + char *ptr; + + /* use getcwdpath to make sure that we get the volume name*/ + if (!getcwdpath(path, NULL, 0)) { + if (errno == ERANGE) + return APR_ENAMETOOLONG; + else + return errno; + } + /* Strip off the server name if there is one*/ + ptr = strpbrk(path, "\\/:"); + if (!ptr) { + return APR_ENOENT; + } + if (*ptr == ':') { + ptr = path; + } + *rootpath = apr_pstrdup(p, ptr); + if (!(flags & APR_FILEPATH_NATIVE)) { + for (ptr = *rootpath; *ptr; ++ptr) { + if (*ptr == '\\') + *ptr = '/'; + } + } + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_filepath_set(const char *rootpath, + apr_pool_t *p) +{ + if (chdir2(rootpath) != 0) + return errno; + return APR_SUCCESS; +} + + diff --git a/file_io/netware/flock.c b/file_io/netware/flock.c new file mode 100644 index 00000000000..c083a0ed401 --- /dev/null +++ b/file_io/netware/flock.c @@ -0,0 +1,39 @@ +/* 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 <nks/fsio.h> +#include "apr_arch_file_io.h" + + +apr_status_t apr_file_lock(apr_file_t *thefile, int type) +{ + int fc; + + fc = (type & APR_FLOCK_NONBLOCK) ? NX_RANGE_LOCK_TRYLOCK : NX_RANGE_LOCK_CHECK; + + if(NXFileRangeLock(thefile->filedes,fc, 0, 0) == -1) + return errno; + + return APR_SUCCESS; +} + +apr_status_t apr_file_unlock(apr_file_t *thefile) +{ + if(NXFileRangeUnlock(thefile->filedes,NX_RANGE_LOCK_CANCEL,0 , 0) == -1) + return errno; + + return APR_SUCCESS; +} diff --git a/file_io/netware/mktemp.c b/file_io/netware/mktemp.c new file mode 100644 index 00000000000..f37cab85bdc --- /dev/null +++ b/file_io/netware/mktemp.c @@ -0,0 +1,64 @@ +/* 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_file_io.h" /* prototype of apr_mkstemp() */ +#include "apr_strings.h" /* prototype of apr_mkstemp() */ +#include "apr_arch_file_io.h" /* prototype of apr_mkstemp() */ +#include "apr_portable.h" /* for apr_os_file_put() */ +#include "apr_arch_inherit.h" + +#include <stdlib.h> /* for mkstemp() - Single Unix */ + +APR_DECLARE(apr_status_t) apr_file_mktemp(apr_file_t **fp, char *template, apr_int32_t flags, apr_pool_t *p) +{ + int fd; + apr_status_t rv; + + flags = (!flags) ? APR_FOPEN_CREATE | APR_FOPEN_READ | APR_FOPEN_WRITE | + APR_FOPEN_DELONCLOSE : flags & ~APR_FOPEN_EXCL; + + fd = mkstemp(template); + if (fd == -1) { + return errno; + } + /* We need to reopen the file to get rid of the o_excl flag. + * Otherwise file locking will not allow the file to be shared. + */ + close(fd); + if ((rv = apr_file_open(fp, template, flags|APR_FOPEN_NOCLEANUP, + APR_FPROT_UREAD | APR_FPROT_UWRITE, p)) == APR_SUCCESS) { + + + if (!(flags & APR_FOPEN_NOCLEANUP)) { + int flags; + + if ((flags = fcntl((*fp)->filedes, F_GETFD)) == -1) + return errno; + + flags |= FD_CLOEXEC; + if (fcntl((*fp)->filedes, F_SETFD, flags) == -1) + return errno; + + apr_pool_cleanup_register((*fp)->pool, (void *)(*fp), + apr_unix_file_cleanup, + apr_unix_child_file_cleanup); + } + } + + return rv; +} + diff --git a/file_io/netware/pipe.c b/file_io/netware/pipe.c new file mode 100644 index 00000000000..1a3a5e87932 --- /dev/null +++ b/file_io/netware/pipe.c @@ -0,0 +1,227 @@ +/* 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 <stdio.h> +#include <nks/fsio.h> +#include <nks/errno.h> + +#include "apr_arch_file_io.h" +#include "apr_strings.h" +#include "apr_portable.h" +#include "apr_arch_inherit.h" + +static apr_status_t pipeblock(apr_file_t *thepipe) +{ +#ifdef USE_FLAGS + unsigned long flags; + + if (fcntl(thepipe->filedes, F_GETFL, &flags) != -1) + { + flags &= ~FNDELAY; + fcntl(thepipe->filedes, F_SETFL, flags); + } +#else + errno = 0; + fcntl(thepipe->filedes, F_SETFL, 0); +#endif + + if (errno) + return errno; + + thepipe->blocking = BLK_ON; + return APR_SUCCESS; +} + +static apr_status_t pipenonblock(apr_file_t *thepipe) +{ +#ifdef USE_FLAGS + unsigned long flags; + + errno = 0; + if (fcntl(thepipe->filedes, F_GETFL, &flags) != -1) + { + flags |= FNDELAY; + fcntl(thepipe->filedes, F_SETFL, flags); + } +#else + errno = 0; + fcntl(thepipe->filedes, F_SETFL, FNDELAY); +#endif + + if (errno) + return errno; + + thepipe->blocking = BLK_OFF; + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_file_pipe_timeout_set(apr_file_t *thepipe, apr_interval_time_t timeout) +{ + if (thepipe->is_pipe == 1) { + thepipe->timeout = timeout; + if (timeout >= 0) { + if (thepipe->blocking != BLK_OFF) { /* blocking or unknown state */ + return pipenonblock(thepipe); + } + } + else { + if (thepipe->blocking != BLK_ON) { /* non-blocking or unknown state */ + return pipeblock(thepipe); + } + } + return APR_SUCCESS; + } + return APR_EINVAL; +} + +APR_DECLARE(apr_status_t) apr_file_pipe_timeout_get(apr_file_t *thepipe, apr_interval_time_t *timeout) +{ + if (thepipe->is_pipe == 1) { + *timeout = thepipe->timeout; + return APR_SUCCESS; + } + return APR_EINVAL; +} + +APR_DECLARE(apr_status_t) apr_os_pipe_put_ex(apr_file_t **file, + apr_os_file_t *thefile, + int register_cleanup, + apr_pool_t *pool) +{ + int *dafile = thefile; + + (*file) = apr_pcalloc(pool, sizeof(apr_file_t)); + (*file)->pool = pool; + (*file)->eof_hit = 0; + (*file)->is_pipe = 1; + (*file)->blocking = BLK_UNKNOWN; /* app needs to make a timeout call */ + (*file)->timeout = -1; + (*file)->ungetchar = -1; /* no char avail */ + (*file)->filedes = *dafile; + if (!register_cleanup) { + (*file)->flags = APR_FOPEN_NOCLEANUP; + } + (*file)->buffered = 0; +#if APR_HAS_THREADS + (*file)->thlock = NULL; +#endif + if (register_cleanup) { + apr_pool_cleanup_register((*file)->pool, (void *)(*file), + apr_unix_file_cleanup, + apr_pool_cleanup_null); + } + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_os_pipe_put(apr_file_t **file, + apr_os_file_t *thefile, + apr_pool_t *pool) +{ + return apr_os_pipe_put_ex(file, thefile, 0, pool); +} + +static apr_status_t file_pipe_create(apr_file_t **in, + apr_file_t **out, + apr_int32_t blocking, + apr_pool_t *pool_in, + apr_pool_t *pool_out) +{ + int filedes[2]; + + if (pipe(filedes) == -1) { + return errno; + } + + (*in) = (apr_file_t *)apr_pcalloc(pool_in, sizeof(apr_file_t)); + (*out) = (apr_file_t *)apr_pcalloc(pool_out, sizeof(apr_file_t)); + + (*in)->pool = pool_in; + (*out)->pool = pool_out; + (*in)->filedes = filedes[0]; + (*out)->filedes = filedes[1]; + (*in)->flags = APR_INHERIT; + (*out)->flags = APR_INHERIT; + (*in)->is_pipe = + (*out)->is_pipe = 1; + (*out)->fname = + (*in)->fname = NULL; + (*in)->buffered = + (*out)->buffered = 0; + (*in)->blocking = + (*out)->blocking = BLK_ON; + (*in)->timeout = + (*out)->timeout = -1; + (*in)->ungetchar = -1; + (*in)->thlock = + (*out)->thlock = NULL; + (void) apr_pollset_create(&(*in)->pollset, 1, pool_in, 0); + (void) apr_pollset_create(&(*out)->pollset, 1, pool_out, 0); + + apr_pool_cleanup_register((*in)->pool, (void *)(*in), apr_unix_file_cleanup, + apr_pool_cleanup_null); + apr_pool_cleanup_register((*out)->pool, (void *)(*out), apr_unix_file_cleanup, + apr_pool_cleanup_null); + + switch (blocking) { + case APR_FULL_BLOCK: + break; + case APR_READ_BLOCK: + apr_file_pipe_timeout_set(*out, 0); + break; + case APR_WRITE_BLOCK: + apr_file_pipe_timeout_set(*in, 0); + break; + default: + apr_file_pipe_timeout_set(*out, 0); + apr_file_pipe_timeout_set(*in, 0); + break; + } + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_file_pipe_create(apr_file_t **in, + apr_file_t **out, + apr_pool_t *pool) +{ + /* Default is full blocking pipes. */ + return file_pipe_create(in, out, APR_FULL_BLOCK, pool, pool); +} + +APR_DECLARE(apr_status_t) apr_file_pipe_create_ex(apr_file_t **in, + apr_file_t **out, + apr_int32_t blocking, + apr_pool_t *pool) +{ + return file_pipe_create(in, out, blocking, pool, pool); +} + +APR_DECLARE(apr_status_t) apr_file_pipe_create_pools(apr_file_t **in, + apr_file_t **out, + apr_int32_t blocking, + apr_pool_t *pool_in, + apr_pool_t *pool_out) +{ + return file_pipe_create(in, out, blocking, pool_in, pool_out); +} + +APR_DECLARE(apr_status_t) apr_file_namedpipe_create(const char *filename, + apr_fileperms_t perm, apr_pool_t *pool) +{ + return APR_ENOTIMPL; +} + + + diff --git a/file_io/os2/.cvsignore b/file_io/os2/.cvsignore deleted file mode 100644 index f3c7a7c5da6..00000000000 --- a/file_io/os2/.cvsignore +++ /dev/null @@ -1 +0,0 @@ -Makefile diff --git a/file_io/os2/Makefile.in b/file_io/os2/Makefile.in deleted file mode 100644 index 934134b5ee5..00000000000 --- a/file_io/os2/Makefile.in +++ /dev/null @@ -1,105 +0,0 @@ -#CFLAGS=$(OPTIM) $(CFLAGS1) $(EXTRA_CFLAGS) -#LIBS=$(EXTRA_LIBS) $(LIBS1) -#INCLUDES=$(INCLUDES1) $(INCLUDES0) $(EXTRA_INCLUDES) -#LDFLAGS=$(LDFLAGS1) $(EXTRA_LDFLAGS) - -CC=@CC@ -RANLIB=@RANLIB@ -CFLAGS=@CFLAGS@ @OPTIM@ -LIBS=@LIBS@ -LDFLAGS=@LDFLAGS@ $(LIBS) -INCDIR=../../inc -INCDIR1=../../include -INCLUDES=-I$(INCDIR) -I$(INCDIR1) -I. - -LIB=file.a - -OBJS=dir.o \ - fileacc.o \ - filedup.o \ - filestat.o \ - open.o \ - pipe.o \ - readwrite.o \ - seek.o \ - maperrorcode.o - -.c.o: - $(CC) $(CFLAGS) -c $(INCLUDES) $< - -all: $(LIB) - -clean: - $(RM) -f *.o *.a *.so - -distclean: clean - -$(RM) -f Makefile - -$(OBJS): Makefile - -$(LIB): $(OBJS) - $(RM) -f $@ - $(AR) cr $@ $(OBJS) - $(RANLIB) $@ - -# -# We really don't expect end users to use this rule. It works only with -# gcc, and rebuilds Makefile.tmpl. You have to re-run Configure after -# using it. -# -depend: - cp Makefile.in Makefile.in.bak \ - && sed -ne '1,/^# DO NOT REMOVE/p' Makefile.in > Makefile.new \ - && gcc -MM $(INCLUDES) $(CFLAGS) *.c | sed -e "s%\\\\\(.\)%/\\1%g" >> Makefile.new \ - && sed -e '1,$$s: $(INCDIR)/: $$(INCDIR)/:g' \ - -e '1,$$s: $(INCDIR1)/: $$(INCDIR1)/:g' \ - -e '1,$$s: $(OSDIR)/: $$(OSDIR)/:g' Makefile.new \ - > Makefile.in \ - && rm Makefile.new - -# DO NOT REMOVE -dir.o: dir.c fileio.h $(INCDIR1)/apr_private.h \ - $(INCDIR1)/apr_general.h $(INCDIR1)/apr.h \ - $(INCDIR1)/apr_errno.h $(INCDIR1)/apr_file_io.h \ - $(INCDIR1)/apr_time.h $(INCDIR1)/apr_lib.h \ - $(INCDIR1)/apr_thread_proc.h -fileacc.o: fileacc.c fileio.h $(INCDIR1)/apr_private.h \ - $(INCDIR1)/apr_general.h $(INCDIR1)/apr.h \ - $(INCDIR1)/apr_errno.h $(INCDIR1)/apr_file_io.h \ - $(INCDIR1)/apr_time.h $(INCDIR1)/apr_lib.h \ - $(INCDIR1)/apr_thread_proc.h -filedup.o: filedup.c fileio.h $(INCDIR1)/apr_private.h \ - $(INCDIR1)/apr_general.h $(INCDIR1)/apr.h \ - $(INCDIR1)/apr_errno.h $(INCDIR1)/apr_file_io.h \ - $(INCDIR1)/apr_time.h $(INCDIR1)/apr_lib.h \ - $(INCDIR1)/apr_thread_proc.h -filestat.o: filestat.c fileio.h $(INCDIR1)/apr_private.h \ - $(INCDIR1)/apr_general.h $(INCDIR1)/apr.h \ - $(INCDIR1)/apr_errno.h $(INCDIR1)/apr_file_io.h \ - $(INCDIR1)/apr_time.h $(INCDIR1)/apr_lib.h \ - $(INCDIR1)/apr_thread_proc.h -maperrorcode.o: maperrorcode.c fileio.h $(INCDIR1)/apr_private.h \ - $(INCDIR1)/apr_general.h $(INCDIR1)/apr.h \ - $(INCDIR1)/apr_errno.h $(INCDIR1)/apr_file_io.h \ - $(INCDIR1)/apr_time.h ../../network_io/os2/os2calls.h -open.o: open.c fileio.h $(INCDIR1)/apr_private.h \ - $(INCDIR1)/apr_general.h $(INCDIR1)/apr.h \ - $(INCDIR1)/apr_errno.h $(INCDIR1)/apr_file_io.h \ - $(INCDIR1)/apr_time.h $(INCDIR1)/apr_lib.h \ - $(INCDIR1)/apr_thread_proc.h $(INCDIR1)/apr_portable.h \ - $(INCDIR1)/apr_network_io.h $(INCDIR1)/apr_lock.h -pipe.o: pipe.c fileio.h $(INCDIR1)/apr_private.h \ - $(INCDIR1)/apr_general.h $(INCDIR1)/apr.h \ - $(INCDIR1)/apr_errno.h $(INCDIR1)/apr_file_io.h \ - $(INCDIR1)/apr_time.h $(INCDIR1)/apr_lib.h \ - $(INCDIR1)/apr_thread_proc.h -readwrite.o: readwrite.c fileio.h $(INCDIR1)/apr_private.h \ - $(INCDIR1)/apr_general.h $(INCDIR1)/apr.h \ - $(INCDIR1)/apr_errno.h $(INCDIR1)/apr_file_io.h \ - $(INCDIR1)/apr_time.h $(INCDIR1)/apr_lib.h \ - $(INCDIR1)/apr_thread_proc.h -seek.o: seek.c fileio.h $(INCDIR1)/apr_private.h \ - $(INCDIR1)/apr_general.h $(INCDIR1)/apr.h \ - $(INCDIR1)/apr_errno.h $(INCDIR1)/apr_file_io.h \ - $(INCDIR1)/apr_time.h $(INCDIR1)/apr_lib.h \ - $(INCDIR1)/apr_thread_proc.h diff --git a/file_io/os2/buffer.c b/file_io/os2/buffer.c new file mode 100644 index 00000000000..8edc606187b --- /dev/null +++ b/file_io/os2/buffer.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_arch_file_io.h" +#include "apr_thread_mutex.h" + +APR_DECLARE(apr_status_t) apr_file_buffer_set(apr_file_t *file, + char * buffer, + apr_size_t bufsize) +{ + apr_status_t rv = APR_SUCCESS; + int do_locking = file->mutex != NULL && file->buffered; + + if (do_locking) { + apr_thread_mutex_lock(file->mutex); + } + + if (file->buffered) { + /* Flush the existing buffer */ + rv = apr_file_flush(file); + if (rv != APR_SUCCESS) { + if (do_locking) { + apr_thread_mutex_unlock(file->mutex); + } + + return rv; + } + } + + file->buffer = buffer; + file->bufsize = bufsize; + file->bufpos = 0; + file->direction = 0; + file->dataRead = 0; + + if (bufsize > 0 && file->mutex == NULL && (file->flags & APR_FOPEN_XTHREAD)) { + /* buffering is being turned on but we have no mutex, make one */ + rv = apr_thread_mutex_create(&file->mutex, 0, file->pool); + } + + /* Setting the buffer size to zero is equivalent to turning + * buffering off. + */ + file->buffered = file->bufsize > 0; + + if (do_locking) { + apr_thread_mutex_unlock(file->mutex); + } + + return rv; +} + +APR_DECLARE(apr_size_t) apr_file_buffer_size_get(apr_file_t *file) +{ + return file->bufsize; +} diff --git a/file_io/os2/copy.c b/file_io/os2/copy.c new file mode 100644 index 00000000000..f4ce010f8f7 --- /dev/null +++ b/file_io/os2/copy.c @@ -0,0 +1 @@ +#include "../unix/copy.c" diff --git a/file_io/os2/dir.c b/file_io/os2/dir.c index 34f973ec63c..f1554b6f35c 100644 --- a/file_io/os2/dir.c +++ b/file_io/os2/dir.c @@ -1,82 +1,45 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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 "fileio.h" +#include "apr_arch_file_io.h" #include "apr_file_io.h" #include "apr_lib.h" +#include "apr_strings.h" +#include "apr_portable.h" #include <string.h> -#define INCL_DOS -#include <os2.h> - -static ap_status_t dir_cleanup(void *thedir) +static apr_status_t dir_cleanup(void *thedir) { - ap_dir_t *dir = thedir; - return ap_closedir(dir); + apr_dir_t *dir = thedir; + return apr_dir_close(dir); } -ap_status_t ap_opendir(ap_dir_t **new, const char *dirname, ap_pool_t *cntxt) +APR_DECLARE(apr_status_t) apr_dir_open(apr_dir_t **new, const char *dirname, apr_pool_t *pool) { - ap_dir_t *thedir = (ap_dir_t *)ap_palloc(cntxt, sizeof(ap_dir_t)); + FILESTATUS3 filestatus; + int rv; + apr_dir_t *thedir = (apr_dir_t *)apr_palloc(pool, sizeof(apr_dir_t)); if (thedir == NULL) return APR_ENOMEM; - thedir->cntxt = cntxt; - thedir->dirname = ap_pstrdup(cntxt, dirname); + thedir->pool = pool; + thedir->dirname = apr_pstrdup(pool, dirname); if (thedir->dirname == NULL) return APR_ENOMEM; @@ -84,13 +47,24 @@ ap_status_t ap_opendir(ap_dir_t **new, const char *dirname, ap_pool_t *cntxt) thedir->handle = 0; thedir->validentry = FALSE; *new = thedir; - ap_register_cleanup(cntxt, thedir, dir_cleanup, ap_null_cleanup); + apr_pool_cleanup_register(pool, thedir, dir_cleanup, apr_pool_cleanup_null); + + rv = DosQueryPathInfo(dirname, FIL_STANDARD, &filestatus, sizeof(filestatus)); + + if (rv != 0) { + return APR_FROM_OS_ERROR(rv); + } + + if ((filestatus.attrFile & FILE_DIRECTORY) == 0) { + return APR_ENOTDIR; + } + return APR_SUCCESS; } -ap_status_t ap_closedir(ap_dir_t *thedir) +APR_DECLARE(apr_status_t) apr_dir_close(apr_dir_t *thedir) { int rv = 0; @@ -102,126 +76,105 @@ ap_status_t ap_closedir(ap_dir_t *thedir) } } - return APR_OS2_STATUS(rv); + return APR_FROM_OS_ERROR(rv); } -ap_status_t ap_readdir(ap_dir_t *thedir) +APR_DECLARE(apr_status_t) apr_dir_read(apr_finfo_t *finfo, apr_int32_t wanted, + apr_dir_t *thedir) { int rv; ULONG entries = 1; if (thedir->handle == 0) { thedir->handle = HDIR_CREATE; - rv = DosFindFirst(ap_pstrcat(thedir->cntxt, thedir->dirname, "/*", NULL), &thedir->handle, + rv = DosFindFirst(apr_pstrcat(thedir->pool, thedir->dirname, "/*", NULL), &thedir->handle, FILE_ARCHIVED|FILE_DIRECTORY|FILE_SYSTEM|FILE_HIDDEN|FILE_READONLY, &thedir->entry, sizeof(thedir->entry), &entries, FIL_STANDARD); } else { rv = DosFindNext(thedir->handle, &thedir->entry, sizeof(thedir->entry), &entries); } + finfo->pool = thedir->pool; + finfo->fname = NULL; + finfo->valid = 0; + if (rv == 0 && entries == 1) { thedir->validentry = TRUE; - return APR_SUCCESS; - } - - thedir->validentry = FALSE; - - if (rv) - return APR_OS2_STATUS(rv); - - return APR_ENOENT; -} + /* We passed a name off the stack that has popped */ + finfo->fname = NULL; + finfo->size = thedir->entry.cbFile; + finfo->csize = thedir->entry.cbFileAlloc; + /* Only directories & regular files show up in directory listings */ + finfo->filetype = (thedir->entry.attrFile & FILE_DIRECTORY) ? APR_DIR : APR_REG; -ap_status_t ap_rewinddir(ap_dir_t *thedir) -{ - return ap_closedir(thedir); -} + apr_os2_time_to_apr_time(&finfo->mtime, thedir->entry.fdateLastWrite, + thedir->entry.ftimeLastWrite); + apr_os2_time_to_apr_time(&finfo->atime, thedir->entry.fdateLastAccess, + thedir->entry.ftimeLastAccess); + apr_os2_time_to_apr_time(&finfo->ctime, thedir->entry.fdateCreation, + thedir->entry.ftimeCreation); + finfo->name = thedir->entry.achName; + finfo->valid = APR_FINFO_NAME | APR_FINFO_MTIME | APR_FINFO_ATIME | + APR_FINFO_CTIME | APR_FINFO_TYPE | APR_FINFO_SIZE | + APR_FINFO_CSIZE; + return APR_SUCCESS; + } -ap_status_t ap_make_dir(const char *path, ap_fileperms_t perm, ap_pool_t *cont) -{ - return APR_OS2_STATUS(DosCreateDir(path, NULL)); + thedir->validentry = FALSE; + + if (rv) + return APR_FROM_OS_ERROR(rv); + + return APR_ENOENT; } -ap_status_t ap_remove_dir(const char *path, ap_pool_t *cont) +APR_DECLARE(apr_status_t) apr_dir_rewind(apr_dir_t *thedir) { - return APR_OS2_STATUS(DosDeleteDir(path)); + return apr_dir_close(thedir); } -ap_status_t ap_dir_entry_size(ap_ssize_t *size, ap_dir_t *thedir) +APR_DECLARE(apr_status_t) apr_dir_make(const char *path, apr_fileperms_t perm, apr_pool_t *pool) { - if (thedir->validentry) { - *size = thedir->entry.cbFile; - return APR_SUCCESS; - } - - return APR_ENOFILE; + return APR_FROM_OS_ERROR(DosCreateDir(path, NULL)); } -ap_status_t ap_dir_entry_mtime(ap_time_t *time, ap_dir_t *thedir) +APR_DECLARE(apr_status_t) apr_dir_remove(const char *path, apr_pool_t *pool) { - if (thedir->validentry) { - ap_os2_time_to_ap_time(time, thedir->entry.fdateLastWrite, thedir->entry.ftimeLastWrite); - return APR_SUCCESS; - } - - return APR_ENOFILE; + return APR_FROM_OS_ERROR(DosDeleteDir(path)); } -ap_status_t ap_dir_entry_ftype(ap_filetype_e *type, ap_dir_t *thedir) +APR_DECLARE(apr_status_t) apr_os_dir_get(apr_os_dir_t **thedir, apr_dir_t *dir) { - int rc; - HFILE hFile; - ULONG action, Type, Attr; - ap_filetype_e typemap[8] = { APR_REG, APR_CHR, APR_PIPE }; - - if (thedir->validentry) { - if (thedir->entry.attrFile & FILE_DIRECTORY) { - *type = APR_DIR; - return APR_SUCCESS; - } else { - rc = DosOpen(ap_pstrcat(thedir->cntxt, thedir->dirname, "/", thedir->entry.achName, NULL) , - &hFile, &action, 0, 0, - OPEN_ACTION_FAIL_IF_NEW|OPEN_ACTION_OPEN_IF_EXISTS, OPEN_SHARE_DENYNONE|OPEN_ACCESS_READONLY, - NULL); - - if ( rc == 0 ) { - rc = DosQueryHType( hFile, &Type, &Attr ); - - if ( rc == 0 ) { - *type = typemap[(Type & 0x0007)]; - } - DosClose( hFile ); - } - - return APR_OS2_STATUS(rc); - } + if (dir == NULL) { + return APR_ENODIR; } - - return APR_ENOFILE; + *thedir = &dir->handle; + return APR_SUCCESS; } -ap_status_t ap_get_dir_filename(char **new, ap_dir_t *thedir) +APR_DECLARE(apr_status_t) apr_os_dir_put(apr_dir_t **dir, apr_os_dir_t *thedir, + apr_pool_t *pool) { - if (thedir->validentry) { - *new = thedir->entry.achName; - return APR_SUCCESS; + if ((*dir) == NULL) { + (*dir) = (apr_dir_t *)apr_pcalloc(pool, sizeof(apr_dir_t)); + (*dir)->pool = pool; } - - return APR_ENOFILE; + (*dir)->handle = *thedir; + return APR_SUCCESS; } diff --git a/file_io/os2/dir_make_recurse.c b/file_io/os2/dir_make_recurse.c new file mode 100644 index 00000000000..602a621ae7e --- /dev/null +++ b/file_io/os2/dir_make_recurse.c @@ -0,0 +1,90 @@ +/* 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_file_io.h" +#include "apr_lib.h" +#include "apr_strings.h" +#include <string.h> + +#define IS_SEP(c) (c == '/' || c == '\\') + +/* Remove trailing separators that don't affect the meaning of PATH. */ +static const char *path_canonicalize(const char *path, apr_pool_t *pool) +{ + /* At some point this could eliminate redundant components. For + * now, it just makes sure there is no trailing slash. */ + apr_size_t len = strlen(path); + apr_size_t orig_len = len; + + while ((len > 0) && IS_SEP(path[len - 1])) { + len--; + } + + if (len != orig_len) { + return apr_pstrndup(pool, path, len); + } + else { + return path; + } +} + + + +/* Remove one component off the end of PATH. */ +static char *path_remove_last_component(const char *path, apr_pool_t *pool) +{ + const char *newpath = path_canonicalize(path, pool); + int i; + + for (i = strlen(newpath) - 1; i >= 0; i--) { + if (IS_SEP(path[i])) { + break; + } + } + + return apr_pstrndup(pool, path, (i < 0) ? 0 : i); +} + + + +apr_status_t apr_dir_make_recursive(const char *path, apr_fileperms_t perm, + apr_pool_t *pool) +{ + apr_status_t apr_err = APR_SUCCESS; + + apr_err = apr_dir_make(path, perm, pool); /* Try to make PATH right out */ + + if (APR_STATUS_IS_ENOENT(apr_err)) { /* Missing an intermediate dir */ + char *dir; + + dir = path_remove_last_component(path, pool); + apr_err = apr_dir_make_recursive(dir, perm, pool); + + if (!apr_err) { + apr_err = apr_dir_make(path, perm, pool); + } + } + + /* + * It's OK if PATH exists. Timing issues can lead to the second + * apr_dir_make being called on existing dir, therefore this check + * has to come last. + */ + if (APR_STATUS_IS_EEXIST(apr_err)) + return APR_SUCCESS; + + return apr_err; +} diff --git a/file_io/os2/fileacc.c b/file_io/os2/fileacc.c index 0dfee57f02b..b5c1afd5031 100644 --- a/file_io/os2/fileacc.c +++ b/file_io/os2/fileacc.c @@ -1,102 +1,18 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. +/* 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 "fileio.h" -#include "apr_file_io.h" -#include "apr_general.h" -#include "apr_lib.h" -#include <errno.h> -#include <string.h> -#include <sys/types.h> - -/* A file to put ALL of the accessor functions for ap_file_t types. */ - -ap_status_t ap_get_filename(char **new, ap_file_t *thefile) -{ - if (thefile != NULL) { - *new = ap_pstrdup(thefile->cntxt, thefile->fname); - return APR_SUCCESS; - } else { - *new = NULL; - return APR_ENOFILE; - } -} - - - -ap_status_t ap_get_filedata(void **data, char *key, ap_file_t *file) -{ - if (file != NULL) { - return ap_get_userdata(data, key, file->cntxt); - } - else { - data = NULL; - return APR_ENOFILE; - } -} - - - -ap_status_t ap_set_filedata(ap_file_t *file, void *data, char *key, - ap_status_t (*cleanup) (void *)) -{ - if (file != NULL) { - return ap_set_userdata(data, key, cleanup, file->cntxt); - } - else { - data = NULL; - return APR_ENOFILE; - } -} +#include "../unix/fileacc.c" diff --git a/file_io/os2/filedup.c b/file_io/os2/filedup.c index d3cedd6a70f..ff937eb686c 100644 --- a/file_io/os2/filedup.c +++ b/file_io/os2/filedup.c @@ -1,72 +1,33 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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 "fileio.h" +#include "apr_arch_file_io.h" #include "apr_file_io.h" #include "apr_lib.h" +#include "apr_strings.h" #include <string.h> +#include "apr_arch_inherit.h" -#define INCL_DOS -#include <os2.h> - -ap_status_t ap_dupfile(ap_file_t **new_file, ap_file_t *old_file, ap_pool_t *p) +static apr_status_t file_dup(apr_file_t **new_file, apr_file_t *old_file, apr_pool_t *p) { int rv; - ap_file_t *dup_file; + apr_file_t *dup_file; if (*new_file == NULL) { - dup_file = (ap_file_t *)ap_palloc(p, sizeof(ap_file_t)); + dup_file = (apr_file_t *)apr_palloc(p, sizeof(apr_file_t)); if (dup_file == NULL) { return APR_ENOMEM; @@ -77,25 +38,89 @@ ap_status_t ap_dupfile(ap_file_t **new_file, ap_file_t *old_file, ap_pool_t *p) dup_file = *new_file; } - dup_file->cntxt = p; + dup_file->pool = p; rv = DosDupHandle(old_file->filedes, &dup_file->filedes); if (rv) { - return APR_OS2_STATUS(rv); + return APR_FROM_OS_ERROR(rv); } - dup_file->fname = ap_pstrdup(dup_file->cntxt, old_file->fname); + dup_file->fname = apr_pstrdup(dup_file->pool, old_file->fname); dup_file->buffered = old_file->buffered; dup_file->isopen = old_file->isopen; - dup_file->flags = old_file->flags; + dup_file->flags = old_file->flags & ~APR_INHERIT; + dup_file->ungetchar = old_file->ungetchar; /* TODO - dup pipes correctly */ dup_file->pipe = old_file->pipe; if (*new_file == NULL) { - ap_register_cleanup(dup_file->cntxt, dup_file, apr_file_cleanup, - ap_null_cleanup); + apr_pool_cleanup_register(dup_file->pool, dup_file, apr_file_cleanup, + apr_pool_cleanup_null); *new_file = dup_file; } return APR_SUCCESS; } + + + +APR_DECLARE(apr_status_t) apr_file_dup(apr_file_t **new_file, apr_file_t *old_file, apr_pool_t *p) +{ + if (*new_file) { + apr_file_close(*new_file); + (*new_file)->filedes = -1; + } + + return file_dup(new_file, old_file, p); +} + + + +APR_DECLARE(apr_status_t) apr_file_dup2(apr_file_t *new_file, apr_file_t *old_file, apr_pool_t *p) +{ + return file_dup(&new_file, old_file, p); +} + + + +APR_DECLARE(apr_status_t) apr_file_setaside(apr_file_t **new_file, + apr_file_t *old_file, + apr_pool_t *p) +{ + *new_file = (apr_file_t *)apr_pmemdup(p, old_file, sizeof(apr_file_t)); + (*new_file)->pool = p; + + if (old_file->buffered) { + (*new_file)->buffer = apr_palloc(p, old_file->bufsize); + (*new_file)->bufsize = old_file->bufsize; + + if (old_file->direction == 1) { + memcpy((*new_file)->buffer, old_file->buffer, old_file->bufpos); + } + else { + memcpy((*new_file)->buffer, old_file->buffer, old_file->dataRead); + } + + if (old_file->mutex) { + apr_thread_mutex_create(&((*new_file)->mutex), + APR_THREAD_MUTEX_DEFAULT, p); + apr_thread_mutex_destroy(old_file->mutex); + } + } + + if (old_file->fname) { + (*new_file)->fname = apr_pstrdup(p, old_file->fname); + } + + if (!(old_file->flags & APR_FOPEN_NOCLEANUP)) { + apr_pool_cleanup_register(p, (void *)(*new_file), + apr_file_cleanup, + apr_file_cleanup); + } + + old_file->filedes = -1; + apr_pool_cleanup_kill(old_file->pool, (void *)old_file, + apr_file_cleanup); + + return APR_SUCCESS; +} diff --git a/file_io/os2/fileio.h b/file_io/os2/fileio.h deleted file mode 100644 index b2d6d6d2ef0..00000000000 --- a/file_io/os2/fileio.h +++ /dev/null @@ -1,102 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#ifndef FILE_IO_H -#define FILE_IO_H - -#define INCL_DOS -#include <os2.h> - -#include "apr_private.h" -#include "apr_general.h" -#include "apr_lock.h" -#include "apr_file_io.h" -#include "apr_errno.h" - -#define APR_FILE_BUFSIZE 4096 - -struct ap_file_t { - ap_pool_t *cntxt; - HFILE filedes; - char * fname; - int isopen; - int buffered; - int eof_hit; - ap_int32_t flags; - int timeout; - int pipe; - HEV pipeSem; - - /* Stuff for buffered mode */ - char *buffer; - int bufpos; // Read/Write position in buffer - unsigned long dataRead; // amount of valid data read into buffer - int direction; // buffer being used for 0 = read, 1 = write - unsigned long filePtr; // position in file of handle - ap_lock_t *mutex; // mutex semaphore, must be owned to access the above fields -}; - -struct ap_dir_t { - ap_pool_t *cntxt; - char *dirname; - ULONG handle; - FILEFINDBUF3 entry; - int validentry; -}; - -ap_status_t apr_file_cleanup(void *); -ap_status_t ap_os2_time_to_ap_time(ap_time_t *result, FDATE os2date, FTIME os2time); - -#endif /* ! FILE_IO_H */ - diff --git a/file_io/os2/filepath.c b/file_io/os2/filepath.c new file mode 100644 index 00000000000..9422faa957c --- /dev/null +++ b/file_io/os2/filepath.c @@ -0,0 +1,16 @@ +/* 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 "../win32/filepath.c" diff --git a/file_io/os2/filepath_util.c b/file_io/os2/filepath_util.c new file mode 100644 index 00000000000..a89c173e54e --- /dev/null +++ b/file_io/os2/filepath_util.c @@ -0,0 +1 @@ +#include "../unix/filepath_util.c" diff --git a/file_io/os2/filestat.c b/file_io/os2/filestat.c index 429686c2822..8208eb4b7f3 100644 --- a/file_io/os2/filestat.c +++ b/file_io/os2/filestat.c @@ -1,69 +1,31 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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 INCL_DOS #define INCL_DOSERRORS -#include "fileio.h" +#include "apr_arch_file_io.h" #include "apr_file_io.h" #include "apr_lib.h" #include <sys/time.h> -#include <os2.h> +#include "apr_strings.h" -static void FS3_to_finfo(ap_finfo_t *finfo, FILESTATUS3 *fstatus) +static void FS3_to_finfo(apr_finfo_t *finfo, FILESTATUS3 *fstatus) { - finfo->protection = (fstatus->attrFile & FILE_READONLY) ? 0555 : 0777; + finfo->protection = (fstatus->attrFile & FILE_READONLY) ? 0x555 : 0x777; if (fstatus->attrFile & FILE_DIRECTORY) finfo->filetype = APR_DIR; @@ -73,15 +35,23 @@ static void FS3_to_finfo(ap_finfo_t *finfo, FILESTATUS3 *fstatus) finfo->user = 0; finfo->group = 0; finfo->inode = 0; + finfo->device = 0; finfo->size = fstatus->cbFile; - ap_os2_time_to_ap_time(&finfo->atime, fstatus->fdateLastAccess, fstatus->ftimeLastAccess ); - ap_os2_time_to_ap_time(&finfo->mtime, fstatus->fdateLastWrite, fstatus->ftimeLastWrite ); - ap_os2_time_to_ap_time(&finfo->ctime, fstatus->fdateCreation, fstatus->ftimeCreation ); + finfo->csize = fstatus->cbFileAlloc; + apr_os2_time_to_apr_time(&finfo->atime, fstatus->fdateLastAccess, + fstatus->ftimeLastAccess ); + apr_os2_time_to_apr_time(&finfo->mtime, fstatus->fdateLastWrite, + fstatus->ftimeLastWrite ); + apr_os2_time_to_apr_time(&finfo->ctime, fstatus->fdateCreation, + fstatus->ftimeCreation ); + finfo->valid = APR_FINFO_TYPE | APR_FINFO_PROT | APR_FINFO_SIZE + | APR_FINFO_CSIZE | APR_FINFO_MTIME + | APR_FINFO_CTIME | APR_FINFO_ATIME | APR_FINFO_LINK; } -static ap_status_t handle_type(ap_filetype_e *ftype, HFILE file) +static apr_status_t handle_type(apr_filetype_e *ftype, HFILE file) { ULONG filetype, fileattr, rc; @@ -100,27 +70,43 @@ static ap_status_t handle_type(ap_filetype_e *ftype, HFILE file) case 2: *ftype = APR_PIPE; break; + + default: + /* Values greater than 2 are reserved, this should never happen */ + *ftype = APR_UNKFILE; + break; } return APR_SUCCESS; } - return APR_OS2_STATUS(rc); + return APR_FROM_OS_ERROR(rc); } -ap_status_t ap_getfileinfo(ap_finfo_t *finfo, ap_file_t *thefile) +APR_DECLARE(apr_status_t) apr_file_info_get(apr_finfo_t *finfo, apr_int32_t wanted, + apr_file_t *thefile) { ULONG rc; FILESTATUS3 fstatus; - if (thefile->isopen) + if (thefile->isopen) { + if (thefile->buffered) { + apr_status_t rv = apr_file_flush(thefile); + + if (rv != APR_SUCCESS) { + return rv; + } + } + rc = DosQueryFileInfo(thefile->filedes, FIL_STANDARD, &fstatus, sizeof(fstatus)); + } else rc = DosQueryPathInfo(thefile->fname, FIL_STANDARD, &fstatus, sizeof(fstatus)); if (rc == 0) { FS3_to_finfo(finfo, &fstatus); + finfo->fname = thefile->fname; if (finfo->filetype == APR_REG) { if (thefile->isopen) { @@ -133,29 +119,120 @@ ap_status_t ap_getfileinfo(ap_finfo_t *finfo, ap_file_t *thefile) finfo->protection = 0; finfo->filetype = APR_NOFILE; - return APR_OS2_STATUS(rc); + return APR_FROM_OS_ERROR(rc); } +APR_DECLARE(apr_status_t) apr_file_perms_set(const char *fname, apr_fileperms_t perms) +{ + return APR_ENOTIMPL; +} -ap_status_t ap_stat(ap_finfo_t *finfo, const char *fname, ap_pool_t *cont) +APR_DECLARE(apr_status_t) apr_stat(apr_finfo_t *finfo, const char *fname, + apr_int32_t wanted, apr_pool_t *cont) { ULONG rc; FILESTATUS3 fstatus; finfo->protection = 0; finfo->filetype = APR_NOFILE; + finfo->name = NULL; rc = DosQueryPathInfo(fname, FIL_STANDARD, &fstatus, sizeof(fstatus)); if (rc == 0) { FS3_to_finfo(finfo, &fstatus); - return APR_SUCCESS; + finfo->fname = fname; + + if (wanted & APR_FINFO_NAME) { + ULONG count = 1; + HDIR hDir = HDIR_SYSTEM; + FILEFINDBUF3 ffb; + rc = DosFindFirst(fname, &hDir, + FILE_DIRECTORY|FILE_HIDDEN|FILE_SYSTEM|FILE_ARCHIVED, + &ffb, sizeof(ffb), &count, FIL_STANDARD); + if (rc == 0 && count == 1) { + finfo->name = apr_pstrdup(cont, ffb.achName); + finfo->valid |= APR_FINFO_NAME; + } + } } else if (rc == ERROR_INVALID_ACCESS) { - memset(finfo, 0, sizeof(ap_finfo_t)); - finfo->protection = 0444; + memset(finfo, 0, sizeof(apr_finfo_t)); + finfo->valid = APR_FINFO_TYPE | APR_FINFO_PROT; + finfo->protection = 0666; finfo->filetype = APR_CHR; + + if (wanted & APR_FINFO_NAME) { + finfo->name = apr_pstrdup(cont, fname); + finfo->valid |= APR_FINFO_NAME; + } + } else { + return APR_FROM_OS_ERROR(rc); + } + + return (wanted & ~finfo->valid) ? APR_INCOMPLETE : APR_SUCCESS; +} + + + +APR_DECLARE(apr_status_t) apr_file_attrs_set(const char *fname, + apr_fileattrs_t attributes, + apr_fileattrs_t attr_mask, + apr_pool_t *cont) +{ + FILESTATUS3 fs3; + ULONG rc; + + /* Don't do anything if we can't handle the requested attributes */ + if (!(attr_mask & (APR_FILE_ATTR_READONLY + | APR_FILE_ATTR_HIDDEN))) return APR_SUCCESS; + + rc = DosQueryPathInfo(fname, FIL_STANDARD, &fs3, sizeof(fs3)); + if (rc == 0) { + ULONG old_attr = fs3.attrFile; + + if (attr_mask & APR_FILE_ATTR_READONLY) + { + if (attributes & APR_FILE_ATTR_READONLY) { + fs3.attrFile |= FILE_READONLY; + } else { + fs3.attrFile &= ~FILE_READONLY; + } + } + + if (attr_mask & APR_FILE_ATTR_HIDDEN) + { + if (attributes & APR_FILE_ATTR_HIDDEN) { + fs3.attrFile |= FILE_HIDDEN; + } else { + fs3.attrFile &= ~FILE_HIDDEN; + } + } + + if (fs3.attrFile != old_attr) { + rc = DosSetPathInfo(fname, FIL_STANDARD, &fs3, sizeof(fs3), 0); + } } - - return APR_OS2_STATUS(rc); + + return APR_FROM_OS_ERROR(rc); +} + + +/* ### Somebody please write this! */ +APR_DECLARE(apr_status_t) apr_file_mtime_set(const char *fname, + apr_time_t mtime, + apr_pool_t *pool) +{ + FILESTATUS3 fs3; + ULONG rc; + rc = DosQueryPathInfo(fname, FIL_STANDARD, &fs3, sizeof(fs3)); + + if (rc) { + return APR_FROM_OS_ERROR(rc); + } + + apr_apr_time_to_os2_time(&fs3.fdateLastWrite, &fs3.ftimeLastWrite, mtime); + + rc = DosSetPathInfo(fname, FIL_STANDARD, &fs3, sizeof(fs3), 0); + return APR_FROM_OS_ERROR(rc); } diff --git a/file_io/os2/filesys.c b/file_io/os2/filesys.c new file mode 100644 index 00000000000..ae43bc0a0fc --- /dev/null +++ b/file_io/os2/filesys.c @@ -0,0 +1,148 @@ +/* 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_file_io.h" +#include "apr_strings.h" +#include "apr_lib.h" +#include <ctype.h> + +/* OS/2 Exceptions: + * + * Note that trailing spaces and trailing periods are never recorded + * in the file system. + * + * Leading spaces and periods are accepted, however. + * The * ? < > codes all have wildcard side effects + * The " / \ : are exclusively component separator tokens + * The system doesn't accept | for any (known) purpose + * Oddly, \x7f _is_ acceptable ;) + */ + +const char c_is_fnchar[256] = +{/* Reject all ctrl codes... */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + /* " * / : < > ? */ + 1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,0, 1,1,1,1,1,1,1,1,1,1,0,1,0,1,0,0, + /* \ */ + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1, + /* | */ + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1, + /* High bit codes are accepted */ + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 +}; + + +#define IS_SLASH(c) (c == '/' || c == '\\') + + +apr_status_t filepath_root_test(char *path, apr_pool_t *p) +{ + char drive = apr_toupper(path[0]); + + if (drive >= 'A' && drive <= 'Z' && path[1] == ':' && IS_SLASH(path[2])) + return APR_SUCCESS; + + return APR_EBADPATH; +} + + +apr_status_t filepath_drive_get(char **rootpath, char drive, + apr_int32_t flags, apr_pool_t *p) +{ + char path[APR_PATH_MAX]; + char *pos; + ULONG rc; + ULONG bufsize = sizeof(path) - 3; + + path[0] = drive; + path[1] = ':'; + path[2] = '/'; + + rc = DosQueryCurrentDir(apr_toupper(drive) - 'A', path+3, &bufsize); + + if (rc) { + return APR_FROM_OS_ERROR(rc); + } + + if (!(flags & APR_FILEPATH_NATIVE)) { + for (pos=path; *pos; pos++) { + if (*pos == '\\') + *pos = '/'; + } + } + + *rootpath = apr_pstrdup(p, path); + return APR_SUCCESS; +} + + +apr_status_t filepath_root_case(char **rootpath, char *root, apr_pool_t *p) +{ + if (root[0] && apr_islower(root[0]) && root[1] == ':') { + *rootpath = apr_pstrdup(p, root); + (*rootpath)[0] = apr_toupper((*rootpath)[0]); + } + else { + *rootpath = root; + } + return APR_SUCCESS; +} + + +APR_DECLARE(apr_status_t) apr_filepath_get(char **defpath, apr_int32_t flags, + apr_pool_t *p) +{ + char path[APR_PATH_MAX]; + ULONG drive; + ULONG drivemap; + ULONG rv, pathlen = sizeof(path) - 3; + char *pos; + + DosQueryCurrentDisk(&drive, &drivemap); + path[0] = '@' + drive; + strcpy(path+1, ":\\"); + rv = DosQueryCurrentDir(drive, path+3, &pathlen); + + *defpath = apr_pstrdup(p, path); + + if (!(flags & APR_FILEPATH_NATIVE)) { + for (pos=*defpath; *pos; pos++) { + if (*pos == '\\') + *pos = '/'; + } + } + + return APR_SUCCESS; +} + + + +APR_DECLARE(apr_status_t) apr_filepath_set(const char *path, apr_pool_t *p) +{ + ULONG rv = 0; + + if (path[1] == ':') + rv = DosSetDefaultDisk(apr_toupper(path[0]) - '@'); + + if (rv == 0) + rv = DosSetCurrentDir(path); + + return APR_FROM_OS_ERROR(rv); +} diff --git a/file_io/os2/flock.c b/file_io/os2/flock.c new file mode 100644 index 00000000000..ec94022081a --- /dev/null +++ b/file_io/os2/flock.c @@ -0,0 +1,37 @@ +/* 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_file_io.h" + +APR_DECLARE(apr_status_t) apr_file_lock(apr_file_t *thefile, int type) +{ + FILELOCK lockrange = { 0, 0x7fffffff }; + ULONG rc; + + rc = DosSetFileLocks(thefile->filedes, NULL, &lockrange, + (type & APR_FLOCK_NONBLOCK) ? 0 : (ULONG)-1, + (type & APR_FLOCK_TYPEMASK) == APR_FLOCK_SHARED); + return APR_FROM_OS_ERROR(rc); +} + +APR_DECLARE(apr_status_t) apr_file_unlock(apr_file_t *thefile) +{ + FILELOCK unlockrange = { 0, 0x7fffffff }; + ULONG rc; + + rc = DosSetFileLocks(thefile->filedes, &unlockrange, NULL, 0, 0); + return APR_FROM_OS_ERROR(rc); +} diff --git a/file_io/os2/fullrw.c b/file_io/os2/fullrw.c new file mode 100644 index 00000000000..cf6294882b4 --- /dev/null +++ b/file_io/os2/fullrw.c @@ -0,0 +1 @@ +#include "../unix/fullrw.c" diff --git a/file_io/os2/link.c b/file_io/os2/link.c new file mode 100644 index 00000000000..5487df17c45 --- /dev/null +++ b/file_io/os2/link.c @@ -0,0 +1,23 @@ +/* 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_file_io.h" + +APR_DECLARE(apr_status_t) apr_file_link(const char *from_path, const char *to_path) +{ + /* OS/2 doesn't support links */ + return APR_ENOTIMPL; +} diff --git a/file_io/os2/maperrorcode.c b/file_io/os2/maperrorcode.c index 209eec026bc..282338bba03 100644 --- a/file_io/os2/maperrorcode.c +++ b/file_io/os2/maperrorcode.c @@ -1,65 +1,25 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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 INCL_DOSERRORS -#include "fileio.h" +#include "apr_arch_file_io.h" #include "apr_file_io.h" #include <errno.h> #include <string.h> -#include <os2.h> -#include "../../network_io/os2/os2calls.h" - +#include "apr_errno.h" static int errormap[][2] = { { NO_ERROR, APR_SUCCESS }, @@ -115,7 +75,7 @@ static int errormap[][2] = { #define MAPSIZE (sizeof(errormap)/sizeof(errormap[0])) -int ap_canonical_error(ap_status_t err) +int apr_canonical_error(apr_status_t err) { int rv = -1, index; @@ -129,7 +89,7 @@ int ap_canonical_error(ap_status_t err) if (index<MAPSIZE) rv = errormap[index][1]; else - fprintf(stderr, "ap_canonical_error: Unknown OS/2 error code %d\n", err ); + fprintf(stderr, "apr_canonical_error: Unknown OS/2 error code %d\n", err ); return rv; } diff --git a/file_io/os2/mktemp.c b/file_io/os2/mktemp.c new file mode 100644 index 00000000000..9e8523607f1 --- /dev/null +++ b/file_io/os2/mktemp.c @@ -0,0 +1 @@ +#include "../unix/mktemp.c" diff --git a/file_io/os2/open.c b/file_io/os2/open.c index b65805c546b..996e68bb994 100644 --- a/file_io/os2/open.c +++ b/file_io/os2/open.c @@ -1,132 +1,101 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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 "fileio.h" +#include "apr_arch_file_io.h" #include "apr_file_io.h" #include "apr_lib.h" #include "apr_portable.h" +#include "apr_strings.h" +#include "apr_arch_inherit.h" #include <string.h> -#define INCL_DOS -#include <os2.h> - -ap_status_t apr_file_cleanup(void *thefile) +apr_status_t apr_file_cleanup(void *thefile) { - ap_file_t *file = thefile; - return ap_close(file); + apr_file_t *file = thefile; + return apr_file_close(file); } -ap_status_t ap_open(ap_file_t **new, const char *fname, ap_int32_t flag, ap_fileperms_t perm, ap_pool_t *cntxt) +APR_DECLARE(apr_status_t) apr_file_open(apr_file_t **new, const char *fname, apr_int32_t flag, apr_fileperms_t perm, apr_pool_t *pool) { int oflags = 0; - int mflags = OPEN_FLAGS_FAIL_ON_ERROR|OPEN_SHARE_DENYNONE; + int mflags = OPEN_FLAGS_FAIL_ON_ERROR|OPEN_SHARE_DENYNONE|OPEN_FLAGS_NOINHERIT; int rv; ULONG action; - ap_file_t *dafile = (ap_file_t *)ap_palloc(cntxt, sizeof(ap_file_t)); + apr_file_t *dafile = (apr_file_t *)apr_pcalloc(pool, sizeof(apr_file_t)); - *new = dafile; - dafile->cntxt = cntxt; + if (flag & APR_FOPEN_NONBLOCK) { + return APR_ENOTIMPL; + } + + dafile->pool = pool; dafile->isopen = FALSE; dafile->eof_hit = FALSE; dafile->buffer = NULL; dafile->flags = flag; + dafile->blocking = BLK_ON; + dafile->ungetchar = -1; - if ((flag & APR_READ) && (flag & APR_WRITE)) { + if ((flag & APR_FOPEN_READ) && (flag & APR_FOPEN_WRITE)) { mflags |= OPEN_ACCESS_READWRITE; - } else if (flag & APR_READ) { + } else if (flag & APR_FOPEN_READ) { mflags |= OPEN_ACCESS_READONLY; - } else if (flag & APR_WRITE) { + } else if (flag & APR_FOPEN_WRITE) { mflags |= OPEN_ACCESS_WRITEONLY; } else { dafile->filedes = -1; return APR_EACCES; } - dafile->buffered = (flag & APR_BUFFERED) > 0; + dafile->buffered = (flag & APR_FOPEN_BUFFERED) > 0; if (dafile->buffered) { - dafile->buffer = ap_palloc(cntxt, APR_FILE_BUFSIZE); - rv = ap_create_lock(&dafile->mutex, APR_MUTEX, APR_INTRAPROCESS, NULL, cntxt); + dafile->buffer = apr_palloc(pool, APR_FILE_DEFAULT_BUFSIZE); + dafile->bufsize = APR_FILE_DEFAULT_BUFSIZE; - if (rv) - return APR_OS2_STATUS(rv); + if (flag & APR_FOPEN_XTHREAD) { + rv = apr_thread_mutex_create(&dafile->mutex, 0, pool); + + if (rv) { + return rv; + } + } } - if (flag & APR_CREATE) { - oflags |= OPEN_ACTION_CREATE_IF_NEW; - if (!(flag & APR_EXCL)) { - if (flag & APR_APPEND) - oflags |= OPEN_ACTION_OPEN_IF_EXISTS; - else - oflags |= OPEN_ACTION_REPLACE_IF_EXISTS; + if (flag & APR_FOPEN_CREATE) { + oflags |= OPEN_ACTION_CREATE_IF_NEW; + + if (!(flag & APR_FOPEN_EXCL) && !(flag & APR_FOPEN_TRUNCATE)) { + oflags |= OPEN_ACTION_OPEN_IF_EXISTS; } } - if ((flag & APR_EXCL) && !(flag & APR_CREATE)) + if ((flag & APR_FOPEN_EXCL) && !(flag & APR_FOPEN_CREATE)) return APR_EACCES; - if (flag & APR_TRUNCATE) { + if (flag & APR_FOPEN_TRUNCATE) { oflags |= OPEN_ACTION_REPLACE_IF_EXISTS; - } else if ((oflags & 0xF) == 0) { + } else if ((oflags & 0xFF) == 0) { oflags |= OPEN_ACTION_OPEN_IF_EXISTS; } rv = DosOpen(fname, &(dafile->filedes), &action, 0, 0, oflags, mflags, NULL); - if (rv == 0 && (flag & APR_APPEND)) { + if (rv == 0 && (flag & APR_FOPEN_APPEND)) { ULONG newptr; rv = DosSetFilePtr(dafile->filedes, 0, FILE_END, &newptr ); @@ -135,90 +104,123 @@ ap_status_t ap_open(ap_file_t **new, const char *fname, ap_int32_t flag, ap_fil } if (rv != 0) - return APR_OS2_STATUS(rv); + return APR_FROM_OS_ERROR(rv); dafile->isopen = TRUE; - dafile->fname = ap_pstrdup(cntxt, fname); + dafile->fname = apr_pstrdup(pool, fname); dafile->filePtr = 0; dafile->bufpos = 0; dafile->dataRead = 0; dafile->direction = 0; dafile->pipe = FALSE; - ap_register_cleanup(dafile->cntxt, dafile, apr_file_cleanup, ap_null_cleanup); + if (!(flag & APR_FOPEN_NOCLEANUP)) { + apr_pool_cleanup_register(dafile->pool, dafile, apr_file_cleanup, apr_file_cleanup); + } + + *new = dafile; return APR_SUCCESS; } -ap_status_t ap_close(ap_file_t *file) +APR_DECLARE(apr_status_t) apr_file_close(apr_file_t *file) { ULONG rc; - ap_status_t status; + apr_status_t status; if (file && file->isopen) { - ap_flush(file); + status = apr_file_flush(file); rc = DosClose(file->filedes); if (rc == 0) { file->isopen = FALSE; - status = APR_SUCCESS; - if (file->flags & APR_DELONCLOSE) { - status = APR_OS2_STATUS(DosDelete(file->fname)); + if (file->flags & APR_FOPEN_DELONCLOSE) { + status = APR_FROM_OS_ERROR(DosDelete(file->fname)); } + /* else we return the status of the flush attempt + * when all else succeeds + */ } else { - return APR_OS2_STATUS(rc); + return APR_FROM_OS_ERROR(rc); } } - if (file->buffered) - ap_destroy_lock(file->mutex); + if (file->mutex) { + apr_thread_mutex_destroy(file->mutex); + file->mutex = NULL; + } - return APR_SUCCESS; + return status; } -ap_status_t ap_remove_file(char *path, ap_pool_t *cntxt) +APR_DECLARE(apr_status_t) apr_file_remove(const char *path, apr_pool_t *pool) { ULONG rc = DosDelete(path); - return APR_OS2_STATUS(rc); + return APR_FROM_OS_ERROR(rc); } -ap_status_t ap_get_os_file(ap_os_file_t *thefile, ap_file_t *file) +APR_DECLARE(apr_status_t) apr_file_rename(const char *from_path, const char *to_path, + apr_pool_t *p) { - if (file == NULL) { - return APR_ENOFILE; + ULONG rc = DosMove(from_path, to_path); + + if (rc == ERROR_ACCESS_DENIED || rc == ERROR_ALREADY_EXISTS) { + rc = DosDelete(to_path); + + if (rc == 0 || rc == ERROR_FILE_NOT_FOUND) { + rc = DosMove(from_path, to_path); + } } + return APR_FROM_OS_ERROR(rc); +} + + + +APR_DECLARE(apr_status_t) apr_os_file_get(apr_os_file_t *thefile, apr_file_t *file) +{ *thefile = file->filedes; return APR_SUCCESS; } -ap_status_t ap_put_os_file(ap_file_t **file, ap_os_file_t *thefile, ap_pool_t *cont) +APR_DECLARE(apr_status_t) apr_os_file_put(apr_file_t **file, apr_os_file_t *thefile, apr_int32_t flags, apr_pool_t *pool) { - ap_os_file_t *dafile = thefile; - if ((*file) == NULL) { - (*file) = (ap_file_t *)ap_palloc(cont, sizeof(ap_file_t)); - (*file)->cntxt = cont; - } + apr_os_file_t *dafile = thefile; + + (*file) = apr_palloc(pool, sizeof(apr_file_t)); + (*file)->pool = pool; (*file)->filedes = *dafile; (*file)->isopen = TRUE; - (*file)->buffered = FALSE; (*file)->eof_hit = FALSE; - (*file)->flags = 0; + (*file)->flags = flags; (*file)->pipe = FALSE; + (*file)->buffered = (flags & APR_FOPEN_BUFFERED) > 0; + (*file)->ungetchar = -1; + + if ((*file)->buffered) { + apr_status_t rv; + + (*file)->buffer = apr_palloc(pool, APR_FILE_DEFAULT_BUFSIZE); + (*file)->bufsize = APR_FILE_DEFAULT_BUFSIZE; + rv = apr_thread_mutex_create(&(*file)->mutex, 0, pool); + + if (rv) + return rv; + } + return APR_SUCCESS; } - -ap_status_t ap_eof(ap_file_t *fptr) +APR_DECLARE(apr_status_t) apr_file_eof(apr_file_t *fptr) { if (!fptr->isopen || fptr->eof_hit == 1) { return APR_EOF; @@ -227,21 +229,85 @@ ap_status_t ap_eof(ap_file_t *fptr) } +APR_DECLARE(apr_status_t) apr_file_open_flags_stderr(apr_file_t **thefile, + apr_int32_t flags, + apr_pool_t *pool) +{ + apr_os_file_t fd = 2; + + return apr_os_file_put(thefile, &fd, flags | APR_FOPEN_WRITE, pool); +} + + +APR_DECLARE(apr_status_t) apr_file_open_flags_stdout(apr_file_t **thefile, + apr_int32_t flags, + apr_pool_t *pool) +{ + apr_os_file_t fd = 1; + + return apr_os_file_put(thefile, &fd, flags | APR_FOPEN_WRITE, pool); +} + + +APR_DECLARE(apr_status_t) apr_file_open_flags_stdin(apr_file_t **thefile, + apr_int32_t flags, + apr_pool_t *pool) +{ + apr_os_file_t fd = 0; + + return apr_os_file_put(thefile, &fd, flags | APR_FOPEN_READ, pool); +} + + +APR_DECLARE(apr_status_t) apr_file_open_stderr(apr_file_t **thefile, apr_pool_t *pool) +{ + return apr_file_open_flags_stderr(thefile, 0, pool); +} + + +APR_DECLARE(apr_status_t) apr_file_open_stdout(apr_file_t **thefile, apr_pool_t *pool) +{ + return apr_file_open_flags_stdout(thefile, 0, pool); +} + + +APR_DECLARE(apr_status_t) apr_file_open_stdin(apr_file_t **thefile, apr_pool_t *pool) +{ + return apr_file_open_flags_stdin(thefile, 0, pool); +} + +APR_POOL_IMPLEMENT_ACCESSOR(file); + -ap_status_t ap_open_stderr(ap_file_t **thefile, ap_pool_t *cont) + +APR_DECLARE(apr_status_t) apr_file_inherit_set(apr_file_t *thefile) { - (*thefile) = ap_palloc(cont, sizeof(ap_file_t)); - if ((*thefile) == NULL) { - return APR_ENOMEM; + int rv; + ULONG state; + + rv = DosQueryFHState(thefile->filedes, &state); + + if (rv == 0 && (state & OPEN_FLAGS_NOINHERIT) != 0) { + state &= OPEN_FLAGS_WRITE_THROUGH|OPEN_FLAGS_FAIL_ON_ERROR|OPEN_FLAGS_NO_CACHE; + rv = DosSetFHState(thefile->filedes, state); } - (*thefile)->cntxt = cont; - (*thefile)->filedes = 2; - (*thefile)->fname = NULL; - (*thefile)->isopen = TRUE; - (*thefile)->buffered = FALSE; - (*thefile)->eof_hit = FALSE; - (*thefile)->flags = 0; - (*thefile)->pipe = FALSE; - return APR_SUCCESS; + return APR_FROM_OS_ERROR(rv); +} + + + +APR_DECLARE(apr_status_t) apr_file_inherit_unset(apr_file_t *thefile) +{ + int rv; + ULONG state; + + rv = DosQueryFHState(thefile->filedes, &state); + + if (rv == 0 && (state & OPEN_FLAGS_NOINHERIT) == 0) { + state &= OPEN_FLAGS_WRITE_THROUGH|OPEN_FLAGS_FAIL_ON_ERROR|OPEN_FLAGS_NO_CACHE; + rv = DosSetFHState(thefile->filedes, state | OPEN_FLAGS_NOINHERIT); + } + + return APR_FROM_OS_ERROR(rv); } diff --git a/file_io/os2/pipe.c b/file_io/os2/pipe.c index 4ec94a889d8..4dbe30dbf33 100644 --- a/file_io/os2/pipe.c +++ b/file_io/os2/pipe.c @@ -1,66 +1,31 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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 INCL_DOSERRORS -#include "fileio.h" +#include "apr_arch_file_io.h" #include "apr_file_io.h" #include "apr_general.h" #include "apr_lib.h" +#include "apr_strings.h" +#include "apr_portable.h" #include <string.h> #include <process.h> -ap_status_t ap_create_pipe(ap_file_t **in, ap_file_t **out, ap_pool_t *cont) +static apr_status_t file_pipe_create(apr_file_t **in, apr_file_t **out, + apr_pool_t *pool_in, apr_pool_t *pool_out) { ULONG filedes[2]; ULONG rc, action; @@ -71,13 +36,13 @@ ap_status_t ap_create_pipe(ap_file_t **in, ap_file_t **out, ap_pool_t *cont) rc = DosCreateNPipe(pipename, filedes, NP_ACCESS_INBOUND, NP_NOWAIT|1, 4096, 4096, 0); if (rc) - return APR_OS2_STATUS(rc); + return APR_FROM_OS_ERROR(rc); rc = DosConnectNPipe(filedes[0]); if (rc && rc != ERROR_PIPE_NOT_CONNECTED) { DosClose(filedes[0]); - return APR_OS2_STATUS(rc); + return APR_FROM_OS_ERROR(rc); } rc = DosOpen (pipename, filedes+1, &action, 0, FILE_NORMAL, @@ -87,54 +52,121 @@ ap_status_t ap_create_pipe(ap_file_t **in, ap_file_t **out, ap_pool_t *cont) if (rc) { DosClose(filedes[0]); - return APR_OS2_STATUS(rc); + return APR_FROM_OS_ERROR(rc); } - (*in) = (ap_file_t *)ap_palloc(cont, sizeof(ap_file_t)); + (*in) = (apr_file_t *)apr_palloc(pool_in, sizeof(apr_file_t)); rc = DosCreateEventSem(NULL, &(*in)->pipeSem, DC_SEM_SHARED, FALSE); if (rc) { DosClose(filedes[0]); DosClose(filedes[1]); - return APR_OS2_STATUS(rc); + return APR_FROM_OS_ERROR(rc); } rc = DosSetNPipeSem(filedes[0], (HSEM)(*in)->pipeSem, 1); + if (!rc) { + rc = DosSetNPHState(filedes[0], NP_WAIT); + } + if (rc) { DosClose(filedes[0]); DosClose(filedes[1]); DosCloseEventSem((*in)->pipeSem); - return APR_OS2_STATUS(rc); + return APR_FROM_OS_ERROR(rc); } - (*in)->cntxt = cont; + (*in)->pool = pool_in; (*in)->filedes = filedes[0]; - (*in)->fname = ap_pstrdup(cont, pipename); + (*in)->fname = apr_pstrdup(pool_in, pipename); (*in)->isopen = TRUE; (*in)->buffered = FALSE; - (*in)->flags = 0; + (*in)->flags = APR_FOPEN_READ; (*in)->pipe = 1; (*in)->timeout = -1; - ap_register_cleanup(cont, *in, apr_file_cleanup, ap_null_cleanup); + (*in)->blocking = BLK_ON; + (*in)->ungetchar = -1; + apr_pool_cleanup_register(pool_in, *in, apr_file_cleanup, + apr_pool_cleanup_null); + + (*out) = (apr_file_t *)apr_palloc(pool_out, sizeof(apr_file_t)); + rc = DosCreateEventSem(NULL, &(*out)->pipeSem, DC_SEM_SHARED, FALSE); + + if (rc) { + DosClose(filedes[0]); + DosClose(filedes[1]); + DosCloseEventSem((*in)->pipeSem); + return APR_FROM_OS_ERROR(rc); + } + + rc = DosSetNPipeSem(filedes[1], (HSEM)(*out)->pipeSem, 1); - (*out) = (ap_file_t *)ap_palloc(cont, sizeof(ap_file_t)); - (*out)->cntxt = cont; + if (rc) { + DosClose(filedes[0]); + DosClose(filedes[1]); + DosCloseEventSem((*in)->pipeSem); + DosCloseEventSem((*out)->pipeSem); + return APR_FROM_OS_ERROR(rc); + } + + (*out)->pool = pool_out; (*out)->filedes = filedes[1]; - (*out)->fname = ap_pstrdup(cont, pipename); + (*out)->fname = apr_pstrdup(pool_out, pipename); (*out)->isopen = TRUE; (*out)->buffered = FALSE; - (*out)->flags = 0; + (*out)->flags = APR_FOPEN_WRITE; (*out)->pipe = 1; (*out)->timeout = -1; - ap_register_cleanup(cont, *out, apr_file_cleanup, ap_null_cleanup); - + (*out)->blocking = BLK_ON; + (*out)->ungetchar = -1; + apr_pool_cleanup_register(pool_out, *out, apr_file_cleanup, + apr_pool_cleanup_null); + + switch (blocking) { + case APR_FULL_BLOCK: + break; + case APR_READ_BLOCK: + apr_file_pipe_timeout_set(*out, 0); + break; + case APR_WRITE_BLOCK: + apr_file_pipe_timeout_set(*in, 0); + break; + default: + apr_file_pipe_timeout_set(*out, 0); + apr_file_pipe_timeout_set(*in, 0); + break; + } return APR_SUCCESS; } +APR_DECLARE(apr_status_t) apr_file_pipe_create(apr_file_t **in, + apr_file_t **out, + apr_pool_t *pool) +{ + /* Default is full blocking pipes. */ + return file_pipe_create(in, out, APR_FULL_BLOCK, pool, pool); +} +APR_DECLARE(apr_status_t) apr_file_pipe_create_ex(apr_file_t **in, + apr_file_t **out, + apr_int32_t blocking, + apr_pool_t *pool) +{ + return file_pipe_create(in, out, blocking, pool, pool); +} -ap_status_t ap_create_namedpipe(char *filename, ap_fileperms_t perm, ap_pool_t *cont) +APR_DECLARE(apr_status_t) apr_file_pipe_create_pools(apr_file_t **in, + apr_file_t **out, + apr_int32_t blocking, + apr_pool_t *pool_in, + apr_pool_t *pool_out) +{ + return file_pipe_create(in, out, blocking, pool_in, pool_out); +} + + +APR_DECLARE(apr_status_t) apr_file_namedpipe_create(const char *filename, apr_fileperms_t perm, apr_pool_t *pool) { /* Not yet implemented, interface not suitable */ return APR_ENOTIMPL; @@ -142,17 +174,73 @@ ap_status_t ap_create_namedpipe(char *filename, ap_fileperms_t perm, ap_pool_t * -ap_status_t ap_set_pipe_timeout(ap_file_t *thepipe, ap_interval_time_t timeout) +APR_DECLARE(apr_status_t) apr_file_pipe_timeout_set(apr_file_t *thepipe, apr_interval_time_t timeout) { + apr_status_t rv = APR_SUCCESS; + if (thepipe->pipe == 1) { thepipe->timeout = timeout; + + if (thepipe->timeout >= 0) { + if (thepipe->blocking != BLK_OFF) { + thepipe->blocking = BLK_OFF; + return APR_FROM_OS_ERROR(DosSetNPHState(thepipe->filedes, NP_NOWAIT)); + } + } + else if (thepipe->timeout == -1) { + if (thepipe->blocking != BLK_ON) { + thepipe->blocking = BLK_ON; + return APR_FROM_OS_ERROR(DosSetNPHState(thepipe->filedes, NP_WAIT)); + } + } + } + else { + rv = APR_EINVAL; + } + + return rv; +} + + + +APR_DECLARE(apr_status_t) apr_file_pipe_timeout_get(apr_file_t *thepipe, apr_interval_time_t *timeout) +{ + if (thepipe->pipe == 1) { + *timeout = thepipe->timeout; return APR_SUCCESS; } return APR_EINVAL; } -ap_status_t ap_block_pipe(ap_file_t *thepipe) + +APR_DECLARE(apr_status_t) apr_os_pipe_put_ex(apr_file_t **file, + apr_os_file_t *thefile, + int register_cleanup, + apr_pool_t *pool) +{ + (*file) = apr_pcalloc(pool, sizeof(apr_file_t)); + (*file)->pool = pool; + (*file)->isopen = TRUE; + (*file)->pipe = 1; + (*file)->blocking = BLK_UNKNOWN; /* app needs to make a timeout call */ + (*file)->timeout = -1; + (*file)->ungetchar = -1; + (*file)->filedes = *thefile; + + if (register_cleanup) { + apr_pool_cleanup_register(pool, *file, apr_file_cleanup, + apr_pool_cleanup_null); + } + + return APR_SUCCESS; +} + + + +APR_DECLARE(apr_status_t) apr_os_pipe_put(apr_file_t **file, + apr_os_file_t *thefile, + apr_pool_t *pool) { - return APR_OS2_STATUS(DosSetNPHState (thepipe->filedes, NP_WAIT)); + return apr_os_pipe_put_ex(file, thefile, 0, pool); } diff --git a/file_io/os2/printf.c b/file_io/os2/printf.c new file mode 100644 index 00000000000..a77d258905d --- /dev/null +++ b/file_io/os2/printf.c @@ -0,0 +1 @@ +#include "../unix/printf.c" diff --git a/file_io/os2/readwrite.c b/file_io/os2/readwrite.c index d63ae181353..d567ef3a5c0 100644 --- a/file_io/os2/readwrite.c +++ b/file_io/os2/readwrite.c @@ -1,86 +1,80 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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 INCL_DOS #define INCL_DOSERRORS -#include "fileio.h" +#include "apr_arch_file_io.h" #include "apr_file_io.h" #include "apr_lib.h" +#include "apr_strings.h" -#include <os2.h> #include <malloc.h> -ap_status_t ap_read(ap_file_t *thefile, void *buf, ap_ssize_t *nbytes) +static void file_lock(apr_file_t *thefile) +{ + if (thefile->mutex && thefile->buffered) { + apr_thread_mutex_lock(thefile->mutex); + } +} + + + +static void file_unlock(apr_file_t *thefile) +{ + if (thefile->mutex && thefile->buffered) { + apr_thread_mutex_unlock(thefile->mutex); + } +} + + + +APR_DECLARE(apr_status_t) apr_file_read(apr_file_t *thefile, void *buf, apr_size_t *nbytes) { ULONG rc = 0; ULONG bytesread; + apr_size_t req_nbytes = *nbytes; if (!thefile->isopen) { *nbytes = 0; return APR_EBADF; } + if (thefile->ungetchar != -1 && req_nbytes >= 1) { + *(char *)buf = (char)thefile->ungetchar; + thefile->ungetchar = -1; + (*nbytes) = 1; + return APR_SUCCESS; + } + if (thefile->buffered) { char *pos = (char *)buf; ULONG blocksize; ULONG size = *nbytes; - ap_lock(thefile->mutex); + file_lock(thefile); if (thefile->direction == 1) { - ap_flush(thefile); + int rv = apr_file_flush(thefile); + + if (rv != APR_SUCCESS) { + file_unlock(thefile); + return rv; + } + thefile->bufpos = 0; thefile->direction = 0; thefile->dataRead = 0; @@ -88,12 +82,17 @@ ap_status_t ap_read(ap_file_t *thefile, void *buf, ap_ssize_t *nbytes) while (rc == 0 && size > 0) { if (thefile->bufpos >= thefile->dataRead) { - rc = DosRead(thefile->filedes, thefile->buffer, APR_FILE_BUFSIZE, &thefile->dataRead ); - if (thefile->dataRead == 0) { + ULONG bytesread; + rc = DosRead(thefile->filedes, thefile->buffer, + thefile->bufsize, &bytesread); + + if (bytesread == 0) { if (rc == 0) thefile->eof_hit = TRUE; break; } + + thefile->dataRead = bytesread; thefile->filePtr += thefile->dataRead; thefile->bufpos = 0; } @@ -106,8 +105,13 @@ ap_status_t ap_read(ap_file_t *thefile, void *buf, ap_ssize_t *nbytes) } *nbytes = rc == 0 ? pos - (char *)buf : 0; - ap_unlock(thefile->mutex); - return APR_OS2_STATUS(rc); + file_unlock(thefile); + + if (*nbytes == 0 && rc == 0 && thefile->eof_hit) { + return APR_EOF; + } + + return APR_FROM_OS_ERROR(rc); } else { if (thefile->pipe) DosResetEventSem(thefile->pipeSem, &rc); @@ -117,19 +121,25 @@ ap_status_t ap_read(ap_file_t *thefile, void *buf, ap_ssize_t *nbytes) if (rc == ERROR_NO_DATA && thefile->timeout != 0) { int rcwait = DosWaitEventSem(thefile->pipeSem, thefile->timeout >= 0 ? thefile->timeout / 1000 : SEM_INDEFINITE_WAIT); - if (rcwait == 0) + if (rcwait == 0) { rc = DosRead(thefile->filedes, buf, *nbytes, &bytesread); + } + else if (rcwait == ERROR_TIMEOUT) { + *nbytes = 0; + return APR_TIMEUP; + } } if (rc) { *nbytes = 0; - return APR_OS2_STATUS(rc); + return APR_FROM_OS_ERROR(rc); } *nbytes = bytesread; - if (bytesread == 0) { + if (bytesread == 0 && req_nbytes > 0) { thefile->eof_hit = TRUE; + return APR_EOF; } return APR_SUCCESS; @@ -138,7 +148,7 @@ ap_status_t ap_read(ap_file_t *thefile, void *buf, ap_ssize_t *nbytes) -ap_status_t ap_write(ap_file_t *thefile, void *buf, ap_ssize_t *nbytes) +APR_DECLARE(apr_status_t) apr_file_write(apr_file_t *thefile, const void *buf, apr_size_t *nbytes) { ULONG rc = 0; ULONG byteswritten; @@ -152,11 +162,12 @@ ap_status_t ap_write(ap_file_t *thefile, void *buf, ap_ssize_t *nbytes) char *pos = (char *)buf; int blocksize; int size = *nbytes; + apr_status_t rv = APR_SUCCESS; - DosEnterCritSec(); + file_lock(thefile); if ( thefile->direction == 0 ) { - // Position file pointer for writing at the offset we are logically reading from + /* Position file pointer for writing at the offset we are logically reading from */ ULONG offset = thefile->filePtr - thefile->dataRead + thefile->bufpos; if (offset != thefile->filePtr) DosSetFilePtr(thefile->filedes, offset, FILE_BEGIN, &thefile->filePtr ); @@ -164,25 +175,62 @@ ap_status_t ap_write(ap_file_t *thefile, void *buf, ap_ssize_t *nbytes) thefile->direction = 1; } - while (rc == 0 && size > 0) { - if (thefile->bufpos == APR_FILE_BUFSIZE) // write buffer is full - ap_flush(thefile); + while (rv == APR_SUCCESS && size > 0) { + if (thefile->bufpos == thefile->bufsize) { + /* write buffer is full */ + rv = apr_file_flush(thefile); + } - blocksize = size > APR_FILE_BUFSIZE - thefile->bufpos ? APR_FILE_BUFSIZE - thefile->bufpos : size; + blocksize = size > thefile->bufsize - thefile->bufpos ? thefile->bufsize - thefile->bufpos : size; memcpy(thefile->buffer + thefile->bufpos, pos, blocksize); thefile->bufpos += blocksize; pos += blocksize; size -= blocksize; } - DosExitCritSec(); - return APR_OS2_STATUS(rc); + file_unlock(thefile); + return rv; } else { - rc = DosWrite(thefile->filedes, buf, *nbytes, &byteswritten); + if (thefile->pipe) { + DosResetEventSem(thefile->pipeSem, &rc); + } + + if (thefile->flags & APR_FOPEN_APPEND) { + FILELOCK all = { 0, 0x7fffffff }; + ULONG newpos; + rc = DosSetFileLocks(thefile->filedes, NULL, &all, -1, 0); + + if (rc == 0) { + rc = DosSetFilePtr(thefile->filedes, 0, FILE_END, &newpos); + + if (rc == 0) { + rc = DosWrite(thefile->filedes, buf, *nbytes, &byteswritten); + } + + DosSetFileLocks(thefile->filedes, &all, NULL, -1, 0); + } + } else { + rc = DosWrite(thefile->filedes, buf, *nbytes, &byteswritten); + + if (thefile->pipe && rc == 0 && *nbytes > 0 && byteswritten == 0) { + /* Pipe is full, wait or timeout */ + int rcwait = DosWaitEventSem(thefile->pipeSem, thefile->timeout >= 0 ? thefile->timeout / 1000 : SEM_INDEFINITE_WAIT); + + if (rcwait == 0) { + rc = DosWrite(thefile->filedes, buf, *nbytes, &byteswritten); + } + else if (rcwait == ERROR_TIMEOUT) { + return APR_TIMEUP; + } + else { + rc = rcwait; + } + } + } if (rc) { *nbytes = 0; - return APR_OS2_STATUS(rc); + return APR_FROM_OS_ERROR(rc); } *nbytes = byteswritten; @@ -192,63 +240,51 @@ ap_status_t ap_write(ap_file_t *thefile, void *buf, ap_ssize_t *nbytes) -#ifdef HAVE_WRITEV - -ap_status_t ap_writev(ap_file_t *thefile, const struct iovec *vec, ap_size_t nvec, ap_ssize_t *nbytes) +APR_DECLARE(apr_status_t) apr_file_writev(apr_file_t *thefile, const struct iovec *vec, apr_size_t nvec, apr_size_t *nbytes) { - int bytes; - if ((bytes = writev(thefile->filedes, vec, nvec)) < 0) { - *nbytes = 0; - return errno; - } - else { - *nbytes = bytes; - return APR_SUCCESS; - } + int c; + apr_status_t rv = APR_SUCCESS; + apr_size_t written = 0; + + for (c = 0; c < nvec && rv == APR_SUCCESS; c++) { + apr_size_t nbytes = vec[c].iov_len; + rv = apr_file_write(thefile, vec[c].iov_base, &nbytes); + written += nbytes; + } + + *nbytes = written; + return rv; } -#endif -ap_status_t ap_putc(char ch, ap_file_t *thefile) +APR_DECLARE(apr_status_t) apr_file_putc(char ch, apr_file_t *thefile) { - ULONG rc; - ULONG byteswritten; + apr_size_t nbytes = 1; - if (!thefile->isopen) { - return APR_EBADF; - } - - rc = DosWrite(thefile->filedes, &ch, 1, &byteswritten); - - if (rc) { - return APR_OS2_STATUS(rc); - } - - return APR_SUCCESS; + return apr_file_write(thefile, &ch, &nbytes); } -ap_status_t ap_ungetc(char ch, ap_file_t *thefile) +APR_DECLARE(apr_status_t) apr_file_ungetc(char ch, apr_file_t *thefile) { - ap_off_t offset = -1; - return ap_seek(thefile, APR_CUR, &offset); + thefile->ungetchar = (unsigned char)ch; + return APR_SUCCESS; } - -ap_status_t ap_getc(char *ch, ap_file_t *thefile) +APR_DECLARE(apr_status_t) apr_file_getc(char *ch, apr_file_t *thefile) { ULONG rc; - int bytesread; + apr_size_t bytesread; if (!thefile->isopen) { return APR_EBADF; } bytesread = 1; - rc = ap_read(thefile, ch, &bytesread); + rc = apr_file_read(thefile, ch, &bytesread); if (rc) { return rc; @@ -264,31 +300,34 @@ ap_status_t ap_getc(char *ch, ap_file_t *thefile) -ap_status_t ap_puts(char *str, ap_file_t *thefile) +APR_DECLARE(apr_status_t) apr_file_puts(const char *str, apr_file_t *thefile) { - ap_ssize_t len; + apr_size_t len; len = strlen(str); - return ap_write(thefile, str, &len); + return apr_file_write(thefile, str, &len); } - -ap_status_t ap_flush(ap_file_t *thefile) +APR_DECLARE(apr_status_t) apr_file_flush(apr_file_t *thefile) { if (thefile->buffered) { ULONG written = 0; int rc = 0; if (thefile->direction == 1 && thefile->bufpos) { + file_lock(thefile); + rc = DosWrite(thefile->filedes, thefile->buffer, thefile->bufpos, &written); thefile->filePtr += written; if (rc == 0) thefile->bufpos = 0; + + file_unlock(thefile); } - return APR_OS2_STATUS(rc); + return APR_FROM_OS_ERROR(rc); } else { /* There isn't anything to do if we aren't buffering the output * so just return success. @@ -297,51 +336,112 @@ ap_status_t ap_flush(ap_file_t *thefile) } } +APR_DECLARE(apr_status_t) apr_file_sync(apr_file_t *thefile) +{ + apr_status_t rv; + int rc; + + rv = apr_file_flush(thefile); + if (rv != APR_SUCCESS) { + return rv; + } -ap_status_t ap_fgets(char *str, int len, ap_file_t *thefile) + rc = DosResetBuffer(thefile->filedes); + return APR_FROM_OS_ERROR(rc); +} + +APR_DECLARE(apr_status_t) apr_file_datasync(apr_file_t *thefile) { - ssize_t readlen; - ap_status_t rv = APR_SUCCESS; + return apr_file_sync(thefile); +} + +APR_DECLARE(apr_status_t) apr_file_gets(char *str, int len, apr_file_t *thefile) +{ + apr_size_t readlen; + apr_status_t rv = APR_SUCCESS; int i; for (i = 0; i < len-1; i++) { readlen = 1; - rv = ap_read(thefile, str+i, &readlen); + rv = apr_file_read(thefile, str+i, &readlen); + + if (rv != APR_SUCCESS) { + break; + } if (readlen != 1) { rv = APR_EOF; break; } - if (str[i] == '\r' || str[i] == '\x1A') - i--; - else if (str[i] == '\n') + if (str[i] == '\n') { + i++; break; + } } str[i] = 0; + if (i > 0) { + /* we stored chars; don't report EOF or any other errors; + * the app will find out about that on the next call + */ + return APR_SUCCESS; + } return rv; } -API_EXPORT(int) ap_fprintf(ap_file_t *fptr, const char *format, ...) +apr_status_t apr_file_check_read(apr_file_t *fd) +{ + int rc; + + if (!fd->pipe) + return APR_SUCCESS; /* Not a pipe, assume no waiting */ + + rc = DosWaitEventSem(fd->pipeSem, SEM_IMMEDIATE_RETURN); + + if (rc == ERROR_TIMEOUT) + return APR_TIMEUP; + + return APR_FROM_OS_ERROR(rc); +} + + + +APR_DECLARE(apr_status_t) apr_file_pipe_wait(apr_file_t *pipe, apr_wait_type_t direction) { - int cc; - va_list ap; - char *buf; - int len; - - buf = malloc(HUGE_STRING_LEN); - if (buf == NULL) { - return 0; + int rc; + + if (!pipe->pipe) { + /* No support for waiting on a regular file */ + return APR_ENOTIMPL; } - va_start(ap, format); - len = ap_vsnprintf(buf, HUGE_STRING_LEN, format, ap); - cc = ap_puts(buf, fptr); - va_end(ap); - free(buf); - return (cc == APR_SUCCESS) ? len : -1; + + if (((pipe->flags & APR_FOPEN_READ) > 0) != (direction == APR_WAIT_READ)) { + /* Attempt to wait for read from the write end of the pipe or vica versa */ + return APR_EINVAL; + } + + rc = DosWaitEventSem(pipe->pipeSem, pipe->timeout >= 0 ? pipe->timeout / 1000 : SEM_INDEFINITE_WAIT); + + if (rc == ERROR_TIMEOUT) { + return APR_TIMEUP; + } + + return APR_FROM_OS_ERROR(rc); } + +APR_DECLARE(apr_status_t) apr_file_rotating_check(apr_file_t *thefile) +{ + return APR_ENOTIMPL; +} + + + +APR_DECLARE(apr_status_t) apr_file_rotating_manual_check(apr_file_t *thefile, apr_time_t n) +{ + return APR_ENOTIMPL; +} diff --git a/file_io/os2/seek.c b/file_io/os2/seek.c index e303cf41cdb..7afba30773b 100644 --- a/file_io/os2/seek.c +++ b/file_io/os2/seek.c @@ -1,75 +1,38 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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 "fileio.h" +#include "apr_arch_file_io.h" #include "apr_file_io.h" #include "apr_lib.h" #include <string.h> #include <io.h> -#define INCL_DOS -#include <os2.h> - - -static ap_status_t setptr(ap_file_t *thefile, unsigned long pos ) +static apr_status_t setptr(apr_file_t *thefile, unsigned long pos ) { long newbufpos; ULONG rc; if (thefile->direction == 1) { - ap_flush(thefile); + apr_status_t rv = apr_file_flush(thefile); + + if (rv != APR_SUCCESS) { + return rv; + } + thefile->bufpos = thefile->direction = thefile->dataRead = 0; } @@ -84,20 +47,26 @@ static ap_status_t setptr(ap_file_t *thefile, unsigned long pos ) thefile->bufpos = thefile->dataRead = 0; } - return APR_OS2_STATUS(rc); + return APR_FROM_OS_ERROR(rc); } -ap_status_t ap_seek(ap_file_t *thefile, ap_seek_where_t where, ap_off_t *offset) +APR_DECLARE(apr_status_t) apr_file_seek(apr_file_t *thefile, apr_seek_where_t where, apr_off_t *offset) { if (!thefile->isopen) { return APR_EBADF; } + thefile->eof_hit = 0; + if (thefile->buffered) { int rc = EINVAL; - ap_finfo_t finfo; + apr_finfo_t finfo; + + if (thefile->mutex) { + apr_thread_mutex_lock(thefile->mutex); + } switch (where) { case APR_SET: @@ -109,13 +78,18 @@ ap_status_t ap_seek(ap_file_t *thefile, ap_seek_where_t where, ap_off_t *offset) break; case APR_END: - rc = ap_getfileinfo(&finfo, thefile); + rc = apr_file_info_get(&finfo, APR_FINFO_NORM, thefile); if (rc == APR_SUCCESS) - rc = setptr(thefile, finfo.size - *offset); + rc = setptr(thefile, finfo.size + *offset); break; } - *offset = thefile->filePtr + thefile->bufpos; + *offset = thefile->filePtr - thefile->dataRead + thefile->bufpos; + + if (thefile->mutex) { + apr_thread_mutex_unlock(thefile->mutex); + } + return rc; } else { switch (where) { @@ -132,6 +106,23 @@ ap_status_t ap_seek(ap_file_t *thefile, ap_seek_where_t where, ap_off_t *offset) break; } - return APR_OS2_STATUS(DosSetFilePtr(thefile->filedes, *offset, where, (ULONG *)&offset)); + return APR_FROM_OS_ERROR(DosSetFilePtr(thefile->filedes, *offset, where, (ULONG *)offset)); + } +} + + + +APR_DECLARE(apr_status_t) apr_file_trunc(apr_file_t *fp, apr_off_t offset) +{ + int rc = DosSetFileSize(fp->filedes, offset); + + if (rc != 0) { + return APR_FROM_OS_ERROR(rc); } + + if (fp->buffered) { + return setptr(fp, offset); + } + + return APR_SUCCESS; } diff --git a/file_io/os2/tempdir.c b/file_io/os2/tempdir.c new file mode 100644 index 00000000000..6823569f296 --- /dev/null +++ b/file_io/os2/tempdir.c @@ -0,0 +1 @@ +#include "../unix/tempdir.c" diff --git a/file_io/unix/.cvsignore b/file_io/unix/.cvsignore deleted file mode 100644 index f3c7a7c5da6..00000000000 --- a/file_io/unix/.cvsignore +++ /dev/null @@ -1 +0,0 @@ -Makefile diff --git a/file_io/unix/Makefile.in b/file_io/unix/Makefile.in deleted file mode 100644 index 084572d4069..00000000000 --- a/file_io/unix/Makefile.in +++ /dev/null @@ -1,101 +0,0 @@ -#CFLAGS=$(OPTIM) $(CFLAGS1) $(EXTRA_CFLAGS) -#LIBS=$(EXTRA_LIBS) $(LIBS1) -#INCLUDES=$(INCLUDES1) $(INCLUDES0) $(EXTRA_INCLUDES) -#LDFLAGS=$(LDFLAGS1) $(EXTRA_LDFLAGS) - -RM=@RM@ -CC=@CC@ -RANLIB=@RANLIB@ -CFLAGS=@CFLAGS@ @OPTIM@ -LIBS=@LIBS@ -LDFLAGS=@LDFLAGS@ $(LIBS) -INCDIR=../../include -INCLUDES=-I$(INCDIR) -I. - -#LIB=libfile.a - -OBJS=dir.o \ - fileacc.o \ - filedup.o \ - filestat.o \ - open.o \ - pipe.o \ - readwrite.o \ - seek.o - -.c.o: - $(CC) $(CFLAGS) -c $(INCLUDES) $< - -all: $(OBJS) - -clean: - $(RM) -f *.o *.a *.so - -distclean: clean - -$(RM) -f Makefile - -$(OBJS): Makefile - -#$(LIB): $(OBJS) -# $(RM) -f $@ -# $(AR) cr $@ $(OBJS) -# $(RANLIB) $@ - -# -# We really don't expect end users to use this rule. It works only with -# gcc, and rebuilds Makefile.tmpl. You have to re-run Configure after -# using it. -# -depend: - cp Makefile.in Makefile.in.bak \ - && sed -ne '1,/^# DO NOT REMOVE/p' Makefile.in > Makefile.new \ - && gcc -MM $(INCLUDES) $(CFLAGS) *.c >> Makefile.new \ - && sed -e '1,$$s: $(INCDIR)/: $$(INCDIR)/:g' \ - -e '1,$$s: $(OSDIR)/: $$(OSDIR)/:g' Makefile.new \ - > Makefile.in \ - && rm Makefile.new - -# DO NOT REMOVE -dir.o: dir.c fileio.h $(INCDIR)/apr_private.h \ - $(INCDIR)/apr_general.h $(INCDIR)/apr.h \ - $(INCDIR)/apr_errno.h $(INCDIR)/apr_file_io.h \ - $(INCDIR)/apr_time.h $(INCDIR)/apr_lib.h \ - $(INCDIR)/apr_thread_proc.h $(INCDIR)/apr_portable.h \ - $(INCDIR)/apr_network_io.h $(INCDIR)/apr_lock.h -fileacc.o: fileacc.c fileio.h $(INCDIR)/apr_private.h \ - $(INCDIR)/apr_general.h $(INCDIR)/apr.h \ - $(INCDIR)/apr_errno.h $(INCDIR)/apr_file_io.h \ - $(INCDIR)/apr_time.h $(INCDIR)/apr_lib.h \ - $(INCDIR)/apr_thread_proc.h -filedup.o: filedup.c fileio.h $(INCDIR)/apr_private.h \ - $(INCDIR)/apr_general.h $(INCDIR)/apr.h \ - $(INCDIR)/apr_errno.h $(INCDIR)/apr_file_io.h \ - $(INCDIR)/apr_time.h $(INCDIR)/apr_lib.h \ - $(INCDIR)/apr_thread_proc.h $(INCDIR)/apr_portable.h \ - $(INCDIR)/apr_network_io.h $(INCDIR)/apr_lock.h -filestat.o: filestat.c fileio.h $(INCDIR)/apr_private.h \ - $(INCDIR)/apr_general.h $(INCDIR)/apr.h \ - $(INCDIR)/apr_errno.h $(INCDIR)/apr_file_io.h \ - $(INCDIR)/apr_time.h $(INCDIR)/apr_lib.h \ - $(INCDIR)/apr_thread_proc.h -open.o: open.c fileio.h $(INCDIR)/apr_private.h \ - $(INCDIR)/apr_general.h $(INCDIR)/apr.h \ - $(INCDIR)/apr_errno.h $(INCDIR)/apr_file_io.h \ - $(INCDIR)/apr_time.h $(INCDIR)/apr_lib.h \ - $(INCDIR)/apr_thread_proc.h $(INCDIR)/apr_portable.h \ - $(INCDIR)/apr_network_io.h $(INCDIR)/apr_lock.h -pipe.o: pipe.c fileio.h $(INCDIR)/apr_private.h \ - $(INCDIR)/apr_general.h $(INCDIR)/apr.h \ - $(INCDIR)/apr_errno.h $(INCDIR)/apr_file_io.h \ - $(INCDIR)/apr_time.h $(INCDIR)/apr_lib.h \ - $(INCDIR)/apr_thread_proc.h -readwrite.o: readwrite.c fileio.h $(INCDIR)/apr_private.h \ - $(INCDIR)/apr_general.h $(INCDIR)/apr.h \ - $(INCDIR)/apr_errno.h $(INCDIR)/apr_file_io.h \ - $(INCDIR)/apr_time.h $(INCDIR)/apr_lib.h \ - $(INCDIR)/apr_thread_proc.h $(INCDIR)/apr_lock.h -seek.o: seek.c fileio.h $(INCDIR)/apr_private.h \ - $(INCDIR)/apr_general.h $(INCDIR)/apr.h \ - $(INCDIR)/apr_errno.h $(INCDIR)/apr_file_io.h \ - $(INCDIR)/apr_time.h $(INCDIR)/apr_lib.h \ - $(INCDIR)/apr_thread_proc.h diff --git a/file_io/unix/buffer.c b/file_io/unix/buffer.c new file mode 100644 index 00000000000..ba2a8a7c636 --- /dev/null +++ b/file_io/unix/buffer.c @@ -0,0 +1,60 @@ +/* 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_file_io.h" +#include "apr_pools.h" +#include "apr_thread_mutex.h" + +APR_DECLARE(apr_status_t) apr_file_buffer_set(apr_file_t *file, + char * buffer, + apr_size_t bufsize) +{ + apr_status_t rv; + + file_lock(file); + + if(file->buffered) { + /* Flush the existing buffer */ + rv = apr_file_flush_locked(file); + if (rv != APR_SUCCESS) { + file_unlock(file); + return rv; + } + } + + file->buffer = buffer; + file->bufsize = bufsize; + file->buffered = 1; + file->bufpos = 0; + file->direction = 0; + file->dataRead = 0; + + if (file->bufsize == 0) { + /* Setting the buffer size to zero is equivalent to turning + * buffering off. + */ + file->buffered = 0; + } + + file_unlock(file); + + return APR_SUCCESS; +} + +APR_DECLARE(apr_size_t) apr_file_buffer_size_get(apr_file_t *file) +{ + return file->bufsize; +} diff --git a/file_io/unix/copy.c b/file_io/unix/copy.c new file mode 100644 index 00000000000..bf844aa46e0 --- /dev/null +++ b/file_io/unix/copy.c @@ -0,0 +1,119 @@ +/* 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_file_io.h" +#include "apr_file_io.h" + +static apr_status_t apr_file_transfer_contents(const char *from_path, + const char *to_path, + apr_int32_t flags, + apr_fileperms_t to_perms, + apr_pool_t *pool) +{ + apr_file_t *s, *d; + apr_status_t status; + apr_finfo_t finfo; + apr_fileperms_t perms; + + /* Open source file. */ + status = apr_file_open(&s, from_path, APR_FOPEN_READ, APR_FPROT_OS_DEFAULT, pool); + if (status) + return status; + + /* Maybe get its permissions. */ + if (to_perms == APR_FPROT_FILE_SOURCE_PERMS) { + status = apr_file_info_get(&finfo, APR_FINFO_PROT, s); + if (status != APR_SUCCESS && status != APR_INCOMPLETE) { + apr_file_close(s); /* toss any error */ + return status; + } + perms = finfo.protection; + apr_file_perms_set(to_path, perms); /* ignore any failure */ + } + else + perms = to_perms; + + /* Open dest file. */ + status = apr_file_open(&d, to_path, flags, perms, pool); + if (status) { + apr_file_close(s); /* toss any error */ + return status; + } + +#if BUFSIZ > APR_FILE_DEFAULT_BUFSIZE +#define COPY_BUFSIZ BUFSIZ +#else +#define COPY_BUFSIZ APR_FILE_DEFAULT_BUFSIZE +#endif + + /* Copy bytes till the cows come home. */ + while (1) { + char buf[COPY_BUFSIZ]; + apr_size_t bytes_this_time = sizeof(buf); + apr_status_t read_err; + apr_status_t write_err; + + /* Read 'em. */ + read_err = apr_file_read(s, buf, &bytes_this_time); + if (read_err && !APR_STATUS_IS_EOF(read_err)) { + apr_file_close(s); /* toss any error */ + apr_file_close(d); /* toss any error */ + return read_err; + } + + /* Write 'em. */ + write_err = apr_file_write_full(d, buf, bytes_this_time, NULL); + if (write_err) { + apr_file_close(s); /* toss any error */ + apr_file_close(d); /* toss any error */ + return write_err; + } + + if (read_err && APR_STATUS_IS_EOF(read_err)) { + status = apr_file_close(s); + if (status) { + apr_file_close(d); /* toss any error */ + return status; + } + + /* return the results of this close: an error, or success */ + return apr_file_close(d); + } + } + /* NOTREACHED */ +} + +APR_DECLARE(apr_status_t) apr_file_copy(const char *from_path, + const char *to_path, + apr_fileperms_t perms, + apr_pool_t *pool) +{ + return apr_file_transfer_contents(from_path, to_path, + (APR_FOPEN_WRITE | APR_FOPEN_CREATE | APR_FOPEN_TRUNCATE), + perms, + pool); +} + +APR_DECLARE(apr_status_t) apr_file_append(const char *from_path, + const char *to_path, + apr_fileperms_t perms, + apr_pool_t *pool) +{ + return apr_file_transfer_contents(from_path, to_path, + (APR_FOPEN_WRITE | APR_FOPEN_CREATE | APR_FOPEN_APPEND), + perms, + pool); +} diff --git a/file_io/unix/dir.c b/file_io/unix/dir.c index d8312408516..a94eb8e7fb8 100644 --- a/file_io/unix/dir.c +++ b/file_io/unix/dir.c @@ -1,63 +1,32 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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 "fileio.h" +#include "apr_arch_file_io.h" +#include "apr_strings.h" #include "apr_portable.h" +#if APR_HAVE_SYS_SYSLIMITS_H +#include <sys/syslimits.h> +#endif +#if APR_HAVE_LIMITS_H +#include <limits.h> +#endif -static ap_status_t dir_cleanup(void *thedir) +static apr_status_t dir_cleanup(void *thedir) { - ap_dir_t *dir = thedir; + apr_dir_t *dir = thedir; if (closedir(dir->dirstruct) == 0) { return APR_SUCCESS; } @@ -66,182 +35,316 @@ static ap_status_t dir_cleanup(void *thedir) } } -ap_status_t ap_opendir(ap_dir_t **new, const char *dirname, ap_pool_t *cont) +#define PATH_SEPARATOR '/' + +/* Remove trailing separators that don't affect the meaning of PATH. */ +static const char *path_canonicalize (const char *path, apr_pool_t *pool) +{ + /* At some point this could eliminate redundant components. For + * now, it just makes sure there is no trailing slash. */ + apr_size_t len = strlen (path); + apr_size_t orig_len = len; + + while ((len > 0) && (path[len - 1] == PATH_SEPARATOR)) + len--; + + if (len != orig_len) + return apr_pstrndup (pool, path, len); + else + return path; +} + +/* Remove one component off the end of PATH. */ +static char *path_remove_last_component (const char *path, apr_pool_t *pool) { - (*new) = (ap_dir_t *)ap_palloc(cont, sizeof(ap_dir_t)); + const char *newpath = path_canonicalize (path, pool); + int i; + + for (i = (strlen(newpath) - 1); i >= 0; i--) { + if (path[i] == PATH_SEPARATOR) + break; + } - (*new)->cntxt = cont; - (*new)->dirname = ap_pstrdup(cont, dirname); - (*new)->dirstruct = opendir(dirname); - (*new)->entry = ap_pcalloc(cont, sizeof(struct dirent)); + return apr_pstrndup (pool, path, (i < 0) ? 0 : i); +} + +apr_status_t apr_dir_open(apr_dir_t **new, const char *dirname, + apr_pool_t *pool) +{ + /* On some platforms (e.g., Linux+GNU libc), d_name[] in struct + * dirent is declared with enough storage for the name. On other + * platforms (e.g., Solaris 8 for Intel), d_name is declared as a + * one-byte array. Note: gcc evaluates this at compile time. + */ + apr_size_t dirent_size = + sizeof(*(*new)->entry) + + (sizeof((*new)->entry->d_name) > 1 ? 0 : 255); + DIR *dir = opendir(dirname); - if ((*new)->dirstruct == NULL) { + if (!dir) { return errno; - } - else { - ap_register_cleanup((*new)->cntxt, (void *)(*new), dir_cleanup, - ap_null_cleanup); - return APR_SUCCESS; } + + (*new) = (apr_dir_t *)apr_palloc(pool, sizeof(apr_dir_t)); + + (*new)->pool = pool; + (*new)->dirname = apr_pstrdup(pool, dirname); + (*new)->dirstruct = dir; + (*new)->entry = apr_pcalloc(pool, dirent_size); + + apr_pool_cleanup_register((*new)->pool, *new, dir_cleanup, + apr_pool_cleanup_null); + return APR_SUCCESS; } -ap_status_t ap_closedir(ap_dir_t *thedir) +apr_status_t apr_dir_close(apr_dir_t *thedir) { - ap_status_t rv; + return apr_pool_cleanup_run(thedir->pool, thedir, dir_cleanup); +} - if ((rv = dir_cleanup(thedir)) == APR_SUCCESS) { - ap_kill_cleanup(thedir->cntxt, thedir, dir_cleanup); - return APR_SUCCESS; +#ifdef DIRENT_TYPE +static apr_filetype_e filetype_from_dirent_type(int type) +{ + switch (type) { + case DT_REG: + return APR_REG; + case DT_DIR: + return APR_DIR; + case DT_LNK: + return APR_LNK; + case DT_CHR: + return APR_CHR; + case DT_BLK: + return APR_BLK; +#if defined(DT_FIFO) + case DT_FIFO: + return APR_PIPE; +#endif +#if !defined(BEOS) && defined(DT_SOCK) + case DT_SOCK: + return APR_SOCK; +#endif + default: + return APR_UNKFILE; } - return rv; } +#endif -ap_status_t ap_readdir(ap_dir_t *thedir) +apr_status_t apr_dir_read(apr_finfo_t *finfo, apr_int32_t wanted, + apr_dir_t *thedir) { + apr_status_t ret = 0; +#ifdef DIRENT_TYPE + apr_filetype_e type; +#endif #if APR_HAS_THREADS && defined(_POSIX_THREAD_SAFE_FUNCTIONS) \ - && !defined(READDIR_IS_THREAD_SAFE) - ap_status_t ret; + && !defined(READDIR_IS_THREAD_SAFE) \ + && (defined(APR_USE_READDIR64_R) \ + || defined(APR_USE_READDIR_R)) +#ifdef APR_USE_READDIR64_R + struct dirent64 *retent; + + /* If LFS is enabled and readdir64_r is available, readdir64_r is + * used in preference to readdir_r. This allows directories to be + * read which contain a (64-bit) inode number which doesn't fit + * into the 32-bit apr_ino_t, iff the caller doesn't actually care + * about the inode number (i.e. wanted & APR_FINFO_INODE == 0). + * (such inodes may be seen in some wonky NFS environments) + * + * Similarly, if the d_off field cannot be reprented in a 32-bit + * offset, the libc readdir_r() would barf; using readdir64_r + * bypasses that case entirely since APR does not care about + * d_off. */ + + ret = readdir64_r(thedir->dirstruct, thedir->entry, &retent); +#else + + struct dirent *retent; + + ret = readdir_r(thedir->dirstruct, thedir->entry, &retent); #endif -#if APR_HAS_THREADS && defined(_POSIX_THREAD_SAFE_FUNCTIONS) \ - && !defined(READDIR_IS_THREAD_SAFE) + /* POSIX treats "end of directory" as a non-error case, so ret + * will be zero and retent will be set to NULL in that case. */ + if (!ret && retent == NULL) { + ret = APR_ENOENT; + } - ret = readdir_r(thedir->dirstruct, thedir->entry, &thedir->entry); - /* Avoid the Linux problem where at end-of-directory thedir->entry - * is set to NULL, but ret = APR_SUCCESS. + /* Solaris is a bit strange, if there are no more entries in the + * directory, it returns EINVAL. Since this is against POSIX, we + * hack around the problem here. EINVAL is possible from other + * readdir implementations, but only if the result buffer is too small. + * since we control the size of that buffer, we should never have + * that problem. */ - return (ret == APR_SUCCESS && thedir->entry == NULL) ? APR_ENOENT : ret; + if (ret == EINVAL) { + ret = APR_ENOENT; + } #else - + /* We're about to call readdir() that may possibly set errno, and the + * logic below actually cares about errno after the call. Therefore + * we need to clear errno first. + */ + errno = 0; thedir->entry = readdir(thedir->dirstruct); if (thedir->entry == NULL) { /* If NULL was returned, this can NEVER be a success. Can it?! */ if (errno == APR_SUCCESS) { - return APR_ENOENT; + ret = APR_ENOENT; } - return errno; + else + ret = errno; } - return APR_SUCCESS; #endif -} -ap_status_t ap_rewinddir(ap_dir_t *thedir) -{ - rewinddir(thedir->dirstruct); - return APR_SUCCESS; -} + /* No valid bit flag to test here - do we want one? */ + finfo->fname = NULL; -ap_status_t ap_make_dir(const char *path, ap_fileperms_t perm, ap_pool_t *cont) -{ - mode_t mode = ap_unix_get_fileperms(perm); + if (ret) { + finfo->valid = 0; + return ret; + } - if (mkdir(path, mode) == 0) { - return APR_SUCCESS; +#ifdef DIRENT_TYPE + type = filetype_from_dirent_type(thedir->entry->DIRENT_TYPE); + if (type != APR_UNKFILE) { + wanted &= ~APR_FINFO_TYPE; } - else { - return errno; +#endif +#ifdef DIRENT_INODE + if (thedir->entry->DIRENT_INODE && thedir->entry->DIRENT_INODE != -1) { +#ifdef APR_USE_READDIR64_R + /* If readdir64_r is used, check for the overflow case of trying + * to fit a 64-bit integer into a 32-bit integer. */ + if (sizeof(apr_ino_t) >= sizeof(retent->DIRENT_INODE) + || (apr_ino_t)retent->DIRENT_INODE == retent->DIRENT_INODE) { + wanted &= ~APR_FINFO_INODE; + } else { + /* Prevent the fallback code below from filling in the + * inode if the stat call fails. */ + retent->DIRENT_INODE = 0; + } +#else + wanted &= ~APR_FINFO_INODE; +#endif /* APR_USE_READDIR64_R */ } -} +#endif /* DIRENT_INODE */ -ap_status_t ap_remove_dir(const char *path, ap_pool_t *cont) -{ - if (rmdir(path) == 0) { - return APR_SUCCESS; + wanted &= ~APR_FINFO_NAME; + + if (wanted) + { + char fspec[APR_PATH_MAX]; + char *end; + + end = apr_cpystrn(fspec, thedir->dirname, sizeof fspec); + + if (end > fspec && end[-1] != '/' && (end < fspec + APR_PATH_MAX)) + *end++ = '/'; + + apr_cpystrn(end, thedir->entry->d_name, + sizeof fspec - (end - fspec)); + + ret = apr_stat(finfo, fspec, APR_FINFO_LINK | wanted, thedir->pool); + /* We passed a stack name that will disappear */ + finfo->fname = NULL; + } + + if (wanted && (ret == APR_SUCCESS || ret == APR_INCOMPLETE)) { + wanted &= ~finfo->valid; } else { - return errno; + /* We don't bail because we fail to stat, when we are only -required- + * to readdir... but the result will be APR_INCOMPLETE + */ + finfo->pool = thedir->pool; + finfo->valid = 0; +#ifdef DIRENT_TYPE + if (type != APR_UNKFILE) { + finfo->filetype = type; + finfo->valid |= APR_FINFO_TYPE; + } +#endif +#ifdef DIRENT_INODE + if (thedir->entry->DIRENT_INODE && thedir->entry->DIRENT_INODE != -1) { + finfo->inode = thedir->entry->DIRENT_INODE; + finfo->valid |= APR_FINFO_INODE; + } +#endif } + + finfo->name = apr_pstrdup(thedir->pool, thedir->entry->d_name); + finfo->valid |= APR_FINFO_NAME; + + if (wanted) + return APR_INCOMPLETE; + + return APR_SUCCESS; } -ap_status_t ap_dir_entry_size(ap_ssize_t *size, ap_dir_t *thedir) +apr_status_t apr_dir_rewind(apr_dir_t *thedir) { - struct stat filestat; - char *fname = NULL; - - if (thedir->entry == NULL) { - *size = -1; - return APR_ENOFILE; - } - fname = ap_pstrcat(thedir->cntxt, thedir->dirname, "/", - thedir->entry->d_name, NULL); - if (stat(fname, &filestat) == -1) { - *size = -1; - return errno; - } - - *size = filestat.st_size; + rewinddir(thedir->dirstruct); return APR_SUCCESS; } -ap_status_t ap_dir_entry_mtime(ap_time_t *mtime, ap_dir_t *thedir) +apr_status_t apr_dir_make(const char *path, apr_fileperms_t perm, + apr_pool_t *pool) { - struct stat filestat; - char *fname = NULL; + mode_t mode = apr_unix_perms2mode(perm); - if (thedir->entry == NULL) { - *mtime = -1; - return APR_ENOFILE; + if (mkdir(path, mode) == 0) { + return APR_SUCCESS; } - - fname = ap_pstrcat(thedir->cntxt, thedir->dirname, "/", - thedir->entry->d_name, NULL); - if (stat(fname, &filestat) == -1) { - *mtime = -1; + else { return errno; } - - ap_ansi_time_to_ap_time(mtime, filestat.st_mtime); - return APR_SUCCESS; } - -ap_status_t ap_dir_entry_ftype(ap_filetype_e *type, ap_dir_t *thedir) + +apr_status_t apr_dir_make_recursive(const char *path, apr_fileperms_t perm, + apr_pool_t *pool) { - struct stat filestat; - char *fname = NULL; + apr_status_t apr_err = 0; + + apr_err = apr_dir_make (path, perm, pool); /* Try to make PATH right out */ + + if (apr_err == ENOENT) { /* Missing an intermediate dir */ + char *dir; + + dir = path_remove_last_component(path, pool); + /* If there is no path left, give up. */ + if (dir[0] == '\0') { + return apr_err; + } - if (thedir->entry == NULL) { - *type = APR_REG; - return APR_ENOFILE; + apr_err = apr_dir_make_recursive(dir, perm, pool); + + if (!apr_err) + apr_err = apr_dir_make (path, perm, pool); } - fname = ap_pstrcat(thedir->cntxt, thedir->dirname, "/", - thedir->entry->d_name, NULL); - if (stat(fname, &filestat) == -1) { - *type = APR_REG; - return errno; - } + /* + * It's OK if PATH exists. Timing issues can lead to the second + * apr_dir_make being called on existing dir, therefore this check + * has to come last. + */ + if (APR_STATUS_IS_EEXIST(apr_err)) + return APR_SUCCESS; - if (S_ISREG(filestat.st_mode)) - *type = APR_REG; - if (S_ISDIR(filestat.st_mode)) - *type = APR_DIR; - if (S_ISCHR(filestat.st_mode)) - *type = APR_CHR; - if (S_ISBLK(filestat.st_mode)) - *type = APR_BLK; - if (S_ISFIFO(filestat.st_mode)) - *type = APR_PIPE; - if (S_ISLNK(filestat.st_mode)) - *type = APR_LNK; -#ifndef BEOS - if (S_ISSOCK(filestat.st_mode)) - *type = APR_SOCK; -#endif - return APR_SUCCESS; + return apr_err; } -ap_status_t ap_get_dir_filename(char **new, ap_dir_t *thedir) +apr_status_t apr_dir_remove(const char *path, apr_pool_t *pool) { - /* Detect End-Of-File */ - if (thedir == NULL || thedir->entry == NULL) { - *new = NULL; - return APR_ENOENT; + if (rmdir(path) == 0) { + return APR_SUCCESS; + } + else { + return errno; } - (*new) = ap_pstrdup(thedir->cntxt, thedir->entry->d_name); - return APR_SUCCESS; } -ap_status_t ap_get_os_dir(ap_os_dir_t **thedir, ap_dir_t *dir) +apr_status_t apr_os_dir_get(apr_os_dir_t **thedir, apr_dir_t *dir) { if (dir == NULL) { return APR_ENODIR; @@ -250,12 +353,12 @@ ap_status_t ap_get_os_dir(ap_os_dir_t **thedir, ap_dir_t *dir) return APR_SUCCESS; } -ap_status_t ap_put_os_dir(ap_dir_t **dir, ap_os_dir_t *thedir, - ap_pool_t *cont) +apr_status_t apr_os_dir_put(apr_dir_t **dir, apr_os_dir_t *thedir, + apr_pool_t *pool) { if ((*dir) == NULL) { - (*dir) = (ap_dir_t *)ap_palloc(cont, sizeof(ap_dir_t)); - (*dir)->cntxt = cont; + (*dir) = (apr_dir_t *)apr_pcalloc(pool, sizeof(apr_dir_t)); + (*dir)->pool = pool; } (*dir)->dirstruct = thedir; return APR_SUCCESS; diff --git a/file_io/unix/fileacc.c b/file_io/unix/fileacc.c index 76041a3600a..d44e4e17b3b 100644 --- a/file_io/unix/fileacc.c +++ b/file_io/unix/fileacc.c @@ -1,120 +1,119 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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 "fileio.h" +#include "apr_strings.h" +#include "apr_arch_file_io.h" -/* A file to put ALL of the accessor functions for ap_file_t types. */ +/* A file to put ALL of the accessor functions for apr_file_t types. */ -ap_status_t ap_get_filename(char **new, ap_file_t *thefile) +APR_DECLARE(apr_status_t) apr_file_name_get(const char **fname, + apr_file_t *thefile) { - if (thefile != NULL) { - *new = ap_pstrdup(thefile->cntxt, thefile->fname); - return APR_SUCCESS; - } - else { - *new = NULL; - return APR_ENOFILE; - } + *fname = thefile->fname; + return APR_SUCCESS; } -mode_t ap_unix_get_fileperms(ap_fileperms_t mode) +APR_DECLARE(apr_int32_t) apr_file_flags_get(apr_file_t *f) { - mode_t rv = 0; - - if (mode & APR_UREAD) - rv |= S_IRUSR; - if (mode & APR_UWRITE) - rv |= S_IWUSR; - if (mode & APR_UEXECUTE) - rv |= S_IXUSR; - - if (mode & APR_GREAD) - rv |= S_IRGRP; - if (mode & APR_GWRITE) - rv |= S_IWGRP; - if (mode & APR_GEXECUTE) - rv |= S_IXGRP; - - if (mode & APR_WREAD) - rv |= S_IROTH; - if (mode & APR_WWRITE) - rv |= S_IWOTH; - if (mode & APR_WEXECUTE) - rv |= S_IXOTH; - - return rv; + return f->flags; } -ap_status_t ap_get_filedata(void **data, char *key, ap_file_t *file) -{ - if (file != NULL) { - return ap_get_userdata(data, key, file->cntxt); - } - else { - *data = NULL; - return APR_ENOFILE; - } +#if !defined(OS2) && !defined(WIN32) +mode_t apr_unix_perms2mode(apr_fileperms_t perms) +{ + mode_t mode = 0; + + if (perms & APR_FPROT_USETID) + mode |= S_ISUID; + if (perms & APR_FPROT_UREAD) + mode |= S_IRUSR; + if (perms & APR_FPROT_UWRITE) + mode |= S_IWUSR; + if (perms & APR_FPROT_UEXECUTE) + mode |= S_IXUSR; + + if (perms & APR_FPROT_GSETID) + mode |= S_ISGID; + if (perms & APR_FPROT_GREAD) + mode |= S_IRGRP; + if (perms & APR_FPROT_GWRITE) + mode |= S_IWGRP; + if (perms & APR_FPROT_GEXECUTE) + mode |= S_IXGRP; + +#ifdef S_ISVTX + if (perms & APR_FPROT_WSTICKY) + mode |= S_ISVTX; +#endif + if (perms & APR_FPROT_WREAD) + mode |= S_IROTH; + if (perms & APR_FPROT_WWRITE) + mode |= S_IWOTH; + if (perms & APR_FPROT_WEXECUTE) + mode |= S_IXOTH; + + return mode; } -ap_status_t ap_set_filedata(ap_file_t *file, void *data, char *key, - ap_status_t (*cleanup) (void *)) +apr_fileperms_t apr_unix_mode2perms(mode_t mode) +{ + apr_fileperms_t perms = 0; + + if (mode & S_ISUID) + perms |= APR_FPROT_USETID; + if (mode & S_IRUSR) + perms |= APR_FPROT_UREAD; + if (mode & S_IWUSR) + perms |= APR_FPROT_UWRITE; + if (mode & S_IXUSR) + perms |= APR_FPROT_UEXECUTE; + + if (mode & S_ISGID) + perms |= APR_FPROT_GSETID; + if (mode & S_IRGRP) + perms |= APR_FPROT_GREAD; + if (mode & S_IWGRP) + perms |= APR_FPROT_GWRITE; + if (mode & S_IXGRP) + perms |= APR_FPROT_GEXECUTE; + +#ifdef S_ISVTX + if (mode & S_ISVTX) + perms |= APR_FPROT_WSTICKY; +#endif + if (mode & S_IROTH) + perms |= APR_FPROT_WREAD; + if (mode & S_IWOTH) + perms |= APR_FPROT_WWRITE; + if (mode & S_IXOTH) + perms |= APR_FPROT_WEXECUTE; + + return perms; +} +#endif + +APR_DECLARE(apr_status_t) apr_file_data_get(void **data, const char *key, + apr_file_t *file) { - if (file != NULL) { - return ap_set_userdata(data, key, cleanup, file->cntxt); - } - else { - return APR_ENOFILE; - } + return apr_pool_userdata_get(data, key, file->pool); } +APR_DECLARE(apr_status_t) apr_file_data_set(apr_file_t *file, void *data, + const char *key, + apr_status_t (*cleanup)(void *)) +{ + return apr_pool_userdata_set(data, key, cleanup, file->pool); +} diff --git a/file_io/unix/filedup.c b/file_io/unix/filedup.c index f7c19ac9e38..797f8045f6b 100644 --- a/file_io/unix/filedup.c +++ b/file_io/unix/filedup.c @@ -1,88 +1,192 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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 "fileio.h" +#include "apr_arch_file_io.h" +#include "apr_strings.h" #include "apr_portable.h" +#include "apr_thread_mutex.h" +#include "apr_arch_inherit.h" -ap_status_t ap_dupfile(ap_file_t **new_file, ap_file_t *old_file, ap_pool_t *p) +static apr_status_t file_dup(apr_file_t **new_file, + apr_file_t *old_file, apr_pool_t *p, + int which_dup) { - int have_file = 0; + int rv; +#ifdef HAVE_DUP3 + int flags = 0; +#endif - if ((*new_file) == NULL) { - (*new_file) = (ap_file_t *)ap_pcalloc(p, sizeof(ap_file_t)); + if (which_dup == 2) { if ((*new_file) == NULL) { - return APR_ENOMEM; + /* We can't dup2 unless we have a valid new_file */ + return APR_EINVAL; + } +#ifdef HAVE_DUP3 + if (!((*new_file)->flags & (APR_FOPEN_NOCLEANUP|APR_INHERIT))) + flags |= O_CLOEXEC; + rv = dup3(old_file->filedes, (*new_file)->filedes, flags); +#else + rv = dup2(old_file->filedes, (*new_file)->filedes); + if (!((*new_file)->flags & (APR_FOPEN_NOCLEANUP|APR_INHERIT))) { + int flags; + + if (rv == -1) + return errno; + + if ((flags = fcntl((*new_file)->filedes, F_GETFD)) == -1) + return errno; + + flags |= FD_CLOEXEC; + if (fcntl((*new_file)->filedes, F_SETFD, flags) == -1) + return errno; + } +#endif } else { - have_file = 1; + rv = dup(old_file->filedes); } + + if (rv == -1) + return errno; - (*new_file)->cntxt = p; - if (have_file) { - dup2(old_file->filedes, (*new_file)->filedes); - } - else { - (*new_file)->filedes = dup(old_file->filedes); + if (which_dup == 1) { + (*new_file) = (apr_file_t *)apr_pcalloc(p, sizeof(apr_file_t)); + (*new_file)->pool = p; + (*new_file)->filedes = rv; } + + (*new_file)->fname = apr_pstrdup(p, old_file->fname); + (*new_file)->buffered = old_file->buffered; + + /* If the existing socket in a dup2 is already buffered, we + * have an existing and valid (hopefully) mutex, so we don't + * want to create it again as we could leak! + */ #if APR_HAS_THREADS - ap_create_lock(&((*new_file)->thlock), APR_MUTEX, APR_INTRAPROCESS, NULL, - p); + if ((*new_file)->buffered && !(*new_file)->thlock && old_file->thlock) { + apr_thread_mutex_create(&((*new_file)->thlock), + APR_THREAD_MUTEX_DEFAULT, p); + } +#endif + /* As above, only create the buffer if we haven't already + * got one. + */ + if ((*new_file)->buffered && !(*new_file)->buffer) { + (*new_file)->buffer = apr_palloc(p, old_file->bufsize); + (*new_file)->bufsize = old_file->bufsize; + } + + /* this is the way dup() works */ + (*new_file)->blocking = old_file->blocking; + + /* make sure unget behavior is consistent */ + (*new_file)->ungetchar = old_file->ungetchar; + + if (old_file->rotating != NULL) { + (*new_file)->rotating = (apr_rotating_info_t *)apr_pcalloc(p, sizeof(apr_rotating_info_t)); + + memcpy(&((*new_file)->rotating->finfo), &(old_file->rotating->finfo), sizeof(apr_finfo_t)); + (*new_file)->rotating->timeout = old_file->rotating->timeout; + (*new_file)->rotating->lastcheck = old_file->rotating->lastcheck; + (*new_file)->rotating->oflags = old_file->rotating->oflags; + (*new_file)->rotating->perm = old_file->rotating->perm; + (*new_file)->rotating->manual = old_file->rotating->manual; + } + + /* apr_file_dup2() retains the original cleanup, reflecting + * the existing inherit and nocleanup flags. This means, + * that apr_file_dup2() cannot be called against an apr_file_t + * already closed with apr_file_close, because the expected + * cleanup was already killed. + */ + if (which_dup == 2) { + return APR_SUCCESS; + } + + /* apr_file_dup() retains all old_file flags with the exceptions + * of APR_INHERIT and APR_FOPEN_NOCLEANUP. + * The user must call apr_file_inherit_set() on the dupped + * apr_file_t when desired. + */ + (*new_file)->flags = old_file->flags + & ~(APR_INHERIT | APR_FOPEN_NOCLEANUP); + + apr_pool_cleanup_register((*new_file)->pool, (void *)(*new_file), + apr_unix_file_cleanup, + apr_unix_child_file_cleanup); +#ifndef WAITIO_USES_POLL + /* Start out with no pollset. apr_wait_for_io_or_timeout() will + * initialize the pollset if needed. + */ + (*new_file)->pollset = NULL; #endif - (*new_file)->fname = ap_pstrdup(p, old_file->fname); - (*new_file)->buffered = old_file->buffered; - ap_register_cleanup((*new_file)->cntxt, (void *)(*new_file), ap_unix_file_cleanup, - ap_null_cleanup); return APR_SUCCESS; } +APR_DECLARE(apr_status_t) apr_file_dup(apr_file_t **new_file, + apr_file_t *old_file, apr_pool_t *p) +{ + return file_dup(new_file, old_file, p, 1); +} + +APR_DECLARE(apr_status_t) apr_file_dup2(apr_file_t *new_file, + apr_file_t *old_file, apr_pool_t *p) +{ + return file_dup(&new_file, old_file, p, 2); +} + +APR_DECLARE(apr_status_t) apr_file_setaside(apr_file_t **new_file, + apr_file_t *old_file, + apr_pool_t *p) +{ + *new_file = (apr_file_t *)apr_pmemdup(p, old_file, sizeof(apr_file_t)); + (*new_file)->pool = p; + if (old_file->buffered) { + (*new_file)->buffer = apr_palloc(p, old_file->bufsize); + (*new_file)->bufsize = old_file->bufsize; + if (old_file->direction == 1) { + memcpy((*new_file)->buffer, old_file->buffer, old_file->bufpos); + } + else { + memcpy((*new_file)->buffer, old_file->buffer, old_file->dataRead); + } +#if APR_HAS_THREADS + if (old_file->thlock) { + apr_thread_mutex_create(&((*new_file)->thlock), + APR_THREAD_MUTEX_DEFAULT, p); + apr_thread_mutex_destroy(old_file->thlock); + } +#endif /* APR_HAS_THREADS */ + } + if (old_file->fname) { + (*new_file)->fname = apr_pstrdup(p, old_file->fname); + } + if (!(old_file->flags & APR_FOPEN_NOCLEANUP)) { + apr_pool_cleanup_register(p, (void *)(*new_file), + apr_unix_file_cleanup, + ((*new_file)->flags & APR_INHERIT) + ? apr_pool_cleanup_null + : apr_unix_child_file_cleanup); + } + + old_file->filedes = -1; + apr_pool_cleanup_kill(old_file->pool, (void *)old_file, + apr_unix_file_cleanup); +#ifndef WAITIO_USES_POLL + (*new_file)->pollset = NULL; +#endif + return APR_SUCCESS; +} diff --git a/file_io/unix/fileio.h b/file_io/unix/fileio.h deleted file mode 100644 index 1ef43ba0922..00000000000 --- a/file_io/unix/fileio.h +++ /dev/null @@ -1,138 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#ifndef FILE_IO_H -#define FILE_IO_H - -#include "apr_private.h" -#include "apr_general.h" -#include "apr_file_io.h" -#include "apr_errno.h" -#include "apr_lib.h" - -/* System headers the file I/O library needs */ -#if HAVE_FCNTL_H -#include <fcntl.h> -#endif -#if HAVE_SYS_TYPES_H -#include <sys/types.h> -#endif -#if HAVE_ERRNO_H -#include <errno.h> -#endif -#if HAVE_STRING_H -#include <string.h> -#endif -#if HAVE_DIRENT_H -#include <dirent.h> -#endif -#if HAVE_SYS_STAT_H -#include <sys/stat.h> -#endif -#if HAVE_UNISTD_H -#include <unistd.h> -#endif -#if HAVE_STDIO_H -#include <stdio.h> -#endif -#if HAVE_STDLIB_H -#include <stdlib.h> -#endif -#if HAVE_SYS_UIO_H -#include <sys/uio.h> -#endif -#if HAVE_SYS_TIME_H -#include <sys/time.h> -#endif -#ifdef BEOS -#include <kernel/OS.h> -#endif -/* End System headers */ - -#define APR_FILE_BUFSIZE 4096 - -struct ap_file_t { - ap_pool_t *cntxt; - int filedes; - char * fname; - int oflags; - int eof_hit; - int pipe; - ap_interval_time_t timeout; - int buffered; - int ungetchar; /* Last char provided by an unget op. (-1 = no char)*/ - - /* Stuff for buffered mode */ - char *buffer; - int bufpos; /* Read/Write position in buffer */ - unsigned long dataRead; /* amount of valid data read into buffer */ - int direction; /* buffer being used for 0 = read, 1 = write */ - unsigned long filePtr; /* position in file of handle */ -#if APR_HAS_THREADS - struct ap_lock_t *thlock; -#endif -}; - -struct ap_dir_t { - ap_pool_t *cntxt; - char *dirname; - DIR *dirstruct; - struct dirent *entry; -}; - -ap_status_t ap_unix_file_cleanup(void *); -mode_t ap_unix_get_fileperms(ap_fileperms_t); - -#endif /* ! FILE_IO_H */ - diff --git a/file_io/unix/filepath.c b/file_io/unix/filepath.c new file mode 100644 index 00000000000..b3dd2cac926 --- /dev/null +++ b/file_io/unix/filepath.c @@ -0,0 +1,300 @@ +/* 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_arch_file_io.h" +#include "apr_file_io.h" +#include "apr_strings.h" +#define APR_WANT_STRFUNC +#include "apr_want.h" +#if APR_HAVE_UNISTD_H +#include <unistd.h> +#endif + +/* Win32 malpropism that can go away once everyone believes this + * code is golden, and I'm not testing it anymore :-) + */ +#if APR_HAVE_DIRENT_H +#include <dirent.h> +#endif + +/* Any OS that requires/refuses trailing slashes should be dealt with here. + */ +APR_DECLARE(apr_status_t) apr_filepath_get(char **defpath, apr_int32_t flags, + apr_pool_t *p) +{ + char path[APR_PATH_MAX]; + + if (!getcwd(path, sizeof(path))) { + if (errno == ERANGE) + return APR_ENAMETOOLONG; + else + return errno; + } + *defpath = apr_pstrdup(p, path); + + return APR_SUCCESS; +} + + +/* Any OS that requires/refuses trailing slashes should be dealt with here + */ +APR_DECLARE(apr_status_t) apr_filepath_set(const char *path, apr_pool_t *p) +{ + if (chdir(path) != 0) + return errno; + + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_filepath_root(const char **rootpath, + const char **inpath, + apr_int32_t flags, + apr_pool_t *p) +{ + if (**inpath == '/') { + *rootpath = apr_pstrdup(p, "/"); + do { + ++(*inpath); + } while (**inpath == '/'); + + return APR_SUCCESS; + } + + return APR_ERELATIVE; +} + +APR_DECLARE(apr_status_t) apr_filepath_merge(char **newpath, + const char *rootpath, + const char *addpath, + apr_int32_t flags, + apr_pool_t *p) +{ + char *path; + apr_size_t rootlen; /* is the length of the src rootpath */ + apr_size_t maxlen; /* maximum total path length */ + apr_size_t keptlen; /* is the length of the retained rootpath */ + apr_size_t pathlen; /* is the length of the result path */ + apr_size_t seglen; /* is the end of the current segment */ + apr_status_t rv; + + /* Treat null as an empty path. + */ + if (!addpath) + addpath = ""; + + if (addpath[0] == '/') { + /* If addpath is rooted, then rootpath is unused. + * Ths violates any APR_FILEPATH_SECUREROOTTEST and + * APR_FILEPATH_NOTABSOLUTE flags specified. + */ + if (flags & APR_FILEPATH_SECUREROOTTEST) + return APR_EABOVEROOT; + if (flags & APR_FILEPATH_NOTABSOLUTE) + return APR_EABSOLUTE; + + /* If APR_FILEPATH_NOTABOVEROOT wasn't specified, + * we won't test the root again, it's ignored. + * Waste no CPU retrieving the working path. + */ + if (!rootpath && !(flags & APR_FILEPATH_NOTABOVEROOT)) + rootpath = ""; + } + else { + /* If APR_FILEPATH_NOTABSOLUTE is specified, the caller + * requires a relative result. If the rootpath is + * ommitted, we do not retrieve the working path, + * if rootpath was supplied as absolute then fail. + */ + if (flags & APR_FILEPATH_NOTABSOLUTE) { + if (!rootpath) + rootpath = ""; + else if (rootpath[0] == '/') + return APR_EABSOLUTE; + } + } + + if (!rootpath) { + /* Start with the current working path. This is bass akwards, + * but required since the compiler (at least vc) doesn't like + * passing the address of a char const* for a char** arg. + */ + char *getpath; + rv = apr_filepath_get(&getpath, flags, p); + rootpath = getpath; + if (rv != APR_SUCCESS) + return errno; + + /* XXX: Any kernel subject to goofy, uncanonical results + * must run the rootpath against the user's given flags. + * Simplest would be a recursive call to apr_filepath_merge + * with an empty (not null) rootpath and addpath of the cwd. + */ + } + + rootlen = strlen(rootpath); + maxlen = rootlen + strlen(addpath) + 4; /* 4 for slashes at start, after + * root, and at end, plus trailing + * null */ + if (maxlen > APR_PATH_MAX) { + return APR_ENAMETOOLONG; + } + path = (char *)apr_palloc(p, maxlen); + + if (addpath[0] == '/') { + /* Ignore the given root path, strip off leading + * '/'s to a single leading '/' from the addpath, + * and leave addpath at the first non-'/' character. + */ + keptlen = 0; + while (addpath[0] == '/') + ++addpath; + path[0] = '/'; + pathlen = 1; + } + else { + /* If both paths are relative, fail early + */ + if (rootpath[0] != '/' && (flags & APR_FILEPATH_NOTRELATIVE)) + return APR_ERELATIVE; + + /* Base the result path on the rootpath + */ + keptlen = rootlen; + memcpy(path, rootpath, rootlen); + + /* Always '/' terminate the given root path + */ + if (keptlen && path[keptlen - 1] != '/') { + path[keptlen++] = '/'; + } + pathlen = keptlen; + } + + while (*addpath) { + /* Parse each segment, find the closing '/' + */ + const char *next = addpath; + while (*next && (*next != '/')) { + ++next; + } + seglen = next - addpath; + + if (seglen == 0 || (seglen == 1 && addpath[0] == '.')) { + /* noop segment (/ or ./) so skip it + */ + } + else if (seglen == 2 && addpath[0] == '.' && addpath[1] == '.') { + /* backpath (../) */ + if (pathlen == 1 && path[0] == '/') { + /* Attempt to move above root. Always die if the + * APR_FILEPATH_SECUREROOTTEST flag is specified. + */ + if (flags & APR_FILEPATH_SECUREROOTTEST) { + return APR_EABOVEROOT; + } + + /* Otherwise this is simply a noop, above root is root. + * Flag that rootpath was entirely replaced. + */ + keptlen = 0; + } + else if (pathlen == 0 + || (pathlen == 3 + && !memcmp(path + pathlen - 3, "../", 3)) + || (pathlen > 3 + && !memcmp(path + pathlen - 4, "/../", 4))) { + /* Path is already backpathed or empty, if the + * APR_FILEPATH_SECUREROOTTEST.was given die now. + */ + if (flags & APR_FILEPATH_SECUREROOTTEST) { + return APR_EABOVEROOT; + } + + /* Otherwise append another backpath, including + * trailing slash if present. + */ + memcpy(path + pathlen, "../", *next ? 3 : 2); + pathlen += *next ? 3 : 2; + } + else { + /* otherwise crop the prior segment + */ + do { + --pathlen; + } while (pathlen && path[pathlen - 1] != '/'); + } + + /* Now test if we are above where we started and back up + * the keptlen offset to reflect the added/altered path. + */ + if (pathlen < keptlen) { + if (flags & APR_FILEPATH_SECUREROOTTEST) { + return APR_EABOVEROOT; + } + keptlen = pathlen; + } + } + else { + /* An actual segment, append it to the destination path + */ + if (*next) { + seglen++; + } + memcpy(path + pathlen, addpath, seglen); + pathlen += seglen; + } + + /* Skip over trailing slash to the next segment + */ + if (*next) { + ++next; + } + + addpath = next; + } + path[pathlen] = '\0'; + + /* keptlen will be the rootlen unless the addpath contained + * backpath elements. If so, and APR_FILEPATH_NOTABOVEROOT + * is specified (APR_FILEPATH_SECUREROOTTEST was caught above), + * compare the original root to assure the result path is + * still within given root path. + */ + if ((flags & APR_FILEPATH_NOTABOVEROOT) && keptlen < rootlen) { + if (strncmp(rootpath, path, rootlen)) { + return APR_EABOVEROOT; + } + if (rootpath[rootlen - 1] != '/' + && path[rootlen] && path[rootlen] != '/') { + return APR_EABOVEROOT; + } + } + + *newpath = path; + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_filepath_encoding(int *style, apr_pool_t *p) +{ +#if defined(DARWIN) + *style = APR_FILEPATH_ENCODING_UTF8; +#else + *style = APR_FILEPATH_ENCODING_LOCALE; +#endif + return APR_SUCCESS; +} diff --git a/file_io/unix/filepath_util.c b/file_io/unix/filepath_util.c new file mode 100644 index 00000000000..82d97e48144 --- /dev/null +++ b/file_io/unix/filepath_util.c @@ -0,0 +1,115 @@ +/* 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 +#define APR_WANT_MEMFUNC +#include "apr_want.h" +#include "apr_file_info.h" +#include "apr_errno.h" +#include "apr_pools.h" +#include "apr_strings.h" +#include "apr_tables.h" + +#include "apr_private.h" + +#if defined(WIN32) || defined(OS2) || defined(NETWARE) +#define PATH_SEPARATOR ';' +#define PATH_SEPARATOR_STRING ";" +#else +#define PATH_SEPARATOR ':' +#define PATH_SEPARATOR_STRING ":" +#endif + +APR_DECLARE(apr_status_t) apr_filepath_list_split(apr_array_header_t **pathelts, + const char *liststr, + apr_pool_t *p) +{ + char *path, *part, *ptr; + apr_array_header_t *elts; + int nelts; + + /* Count the number of path elements. We know there'll be at least + one even if path is an empty string. */ + path = apr_pstrdup(p, liststr); + for (nelts = 0, ptr = path; ptr != NULL; ++nelts) + { + ptr = strchr(ptr, PATH_SEPARATOR); + if (ptr) + ++ptr; + } + + /* Split the path into the array. */ + elts = apr_array_make(p, nelts, sizeof(char*)); + while ((part = apr_strtok(path, PATH_SEPARATOR_STRING, &ptr)) != NULL) + { + if (*part == '\0') /* Ignore empty path components. */ + continue; + + *(char**)apr_array_push(elts) = part; + path = NULL; /* For the next call to apr_strtok */ + } + + *pathelts = elts; + return APR_SUCCESS; +} + + +APR_DECLARE(apr_status_t) apr_filepath_list_merge(char **liststr, + apr_array_header_t *pathelts, + apr_pool_t *p) +{ + apr_size_t path_size = 0; + char *path; + int i; + + /* This test isn't 100% certain, but it'll catch at least some + invalid uses... */ + if (pathelts->elt_size != sizeof(char*)) + return APR_EINVAL; + + /* Calculate the size of the merged path */ + for (i = 0; i < pathelts->nelts; ++i) + path_size += strlen(((char**)pathelts->elts)[i]); + + if (path_size == 0) + { + *liststr = NULL; + return APR_SUCCESS; + } + + if (i > 0) /* Add space for the separators */ + path_size += (i - 1); + + /* Merge the path components */ + path = *liststr = apr_palloc(p, path_size + 1); + for (i = 0; i < pathelts->nelts; ++i) + { + /* ### Hmmmm. Calling strlen twice on the same string. Yuck. + But is is better than reallocation in apr_pstrcat? */ + const char *part = ((char**)pathelts->elts)[i]; + apr_size_t part_size = strlen(part); + if (part_size == 0) /* Ignore empty path components. */ + continue; + + if (i > 0) + *path++ = PATH_SEPARATOR; + memcpy(path, part, part_size); + path += part_size; + } + *path = '\0'; + return APR_SUCCESS; +} diff --git a/file_io/unix/filestat.c b/file_io/unix/filestat.c index e6baf7191ca..65918c2127e 100644 --- a/file_io/unix/filestat.c +++ b/file_io/unix/filestat.c @@ -1,123 +1,339 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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 "fileio.h" +#include "apr_arch_file_io.h" #include "apr_file_io.h" #include "apr_general.h" +#include "apr_strings.h" #include "apr_errno.h" -static ap_filetype_e filetype_from_mode(int mode) +#ifdef HAVE_UTIME +#include <utime.h> +#endif + +static apr_filetype_e filetype_from_mode(mode_t mode) { - ap_filetype_e type = APR_NOFILE; - - if (S_ISREG(mode)) - type = APR_REG; - if (S_ISDIR(mode)) - type = APR_DIR; - if (S_ISCHR(mode)) - type = APR_CHR; - if (S_ISBLK(mode)) - type = APR_BLK; - if (S_ISFIFO(mode)) - type = APR_PIPE; - if (S_ISLNK(mode)) - type = APR_LNK; -#ifndef BEOS - if (S_ISSOCK(mode)) - type = APR_SOCK; + apr_filetype_e type; + + switch (mode & S_IFMT) { + case S_IFREG: + type = APR_REG; break; + case S_IFDIR: + type = APR_DIR; break; + case S_IFLNK: + type = APR_LNK; break; + case S_IFCHR: + type = APR_CHR; break; + case S_IFBLK: + type = APR_BLK; break; +#if defined(S_IFFIFO) + case S_IFFIFO: + type = APR_PIPE; break; #endif +#if !defined(BEOS) && defined(S_IFSOCK) + case S_IFSOCK: + type = APR_SOCK; break; +#endif + + default: + /* Work around missing S_IFxxx values above + * for Linux et al. + */ +#if !defined(S_IFFIFO) && defined(S_ISFIFO) + if (S_ISFIFO(mode)) { + type = APR_PIPE; + } else +#endif +#if !defined(BEOS) && !defined(S_IFSOCK) && defined(S_ISSOCK) + if (S_ISSOCK(mode)) { + type = APR_SOCK; + } else +#endif + type = APR_UNKFILE; + } return type; } -ap_status_t ap_getfileinfo(ap_finfo_t *finfo, ap_file_t *thefile) +static void fill_out_finfo(apr_finfo_t *finfo, struct_stat *info, + apr_int32_t wanted) +{ + finfo->valid = APR_FINFO_MIN | APR_FINFO_IDENT | APR_FINFO_NLINK + | APR_FINFO_OWNER | APR_FINFO_PROT; + finfo->protection = apr_unix_mode2perms(info->st_mode); + finfo->filetype = filetype_from_mode(info->st_mode); + finfo->user = info->st_uid; + finfo->group = info->st_gid; + finfo->size = info->st_size; + finfo->device = info->st_dev; + finfo->nlink = info->st_nlink; + + /* Check for overflow if storing a 64-bit st_ino in a 32-bit + * apr_ino_t for LFS builds: */ + if (sizeof(apr_ino_t) >= sizeof(info->st_ino) + || (apr_ino_t)info->st_ino == info->st_ino) { + finfo->inode = info->st_ino; + } else { + finfo->valid &= ~APR_FINFO_INODE; + } + + apr_time_ansi_put(&finfo->atime, info->st_atime); +#ifdef HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC + finfo->atime += info->st_atim.tv_nsec / APR_TIME_C(1000); +#elif defined(HAVE_STRUCT_STAT_ST_ATIMENSEC) + finfo->atime += info->st_atimensec / APR_TIME_C(1000); +#elif defined(HAVE_STRUCT_STAT_ST_ATIME_N) + finfo->atime += info->st_atime_n / APR_TIME_C(1000); +#endif + + apr_time_ansi_put(&finfo->mtime, info->st_mtime); +#ifdef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC + finfo->mtime += info->st_mtim.tv_nsec / APR_TIME_C(1000); +#elif defined(HAVE_STRUCT_STAT_ST_MTIMENSEC) + finfo->mtime += info->st_mtimensec / APR_TIME_C(1000); +#elif defined(HAVE_STRUCT_STAT_ST_MTIME_N) + finfo->mtime += info->st_mtime_n / APR_TIME_C(1000); +#endif + + apr_time_ansi_put(&finfo->ctime, info->st_ctime); +#ifdef HAVE_STRUCT_STAT_ST_CTIM_TV_NSEC + finfo->ctime += info->st_ctim.tv_nsec / APR_TIME_C(1000); +#elif defined(HAVE_STRUCT_STAT_ST_CTIMENSEC) + finfo->ctime += info->st_ctimensec / APR_TIME_C(1000); +#elif defined(HAVE_STRUCT_STAT_ST_CTIME_N) + finfo->ctime += info->st_ctime_n / APR_TIME_C(1000); +#endif + +#ifdef HAVE_STRUCT_STAT_ST_BLOCKS +#ifdef DEV_BSIZE + finfo->csize = (apr_off_t)info->st_blocks * (apr_off_t)DEV_BSIZE; +#else + finfo->csize = (apr_off_t)info->st_blocks * (apr_off_t)512; +#endif + finfo->valid |= APR_FINFO_CSIZE; +#endif +} + +apr_status_t apr_file_info_get_locked(apr_finfo_t *finfo, apr_int32_t wanted, + apr_file_t *thefile) { - struct stat info; + struct_stat info; + + if (thefile->buffered) { + apr_status_t rv = apr_file_flush_locked(thefile); + if (rv != APR_SUCCESS) + return rv; + } if (fstat(thefile->filedes, &info) == 0) { - finfo->protection = info.st_mode; - finfo->filetype = filetype_from_mode(info.st_mode); - finfo->user = info.st_uid; - finfo->group = info.st_gid; - finfo->size = info.st_size; - finfo->inode = info.st_ino; - ap_ansi_time_to_ap_time(&finfo->atime, info.st_atime); - ap_ansi_time_to_ap_time(&finfo->mtime, info.st_mtime); - ap_ansi_time_to_ap_time(&finfo->ctime, info.st_ctime); - return APR_SUCCESS; + finfo->pool = thefile->pool; + finfo->fname = thefile->fname; + fill_out_finfo(finfo, &info, wanted); + return (wanted & ~finfo->valid) ? APR_INCOMPLETE : APR_SUCCESS; } else { return errno; } } -ap_status_t ap_stat(ap_finfo_t *finfo, const char *fname, ap_pool_t *cont) +APR_DECLARE(apr_status_t) apr_file_info_get(apr_finfo_t *finfo, + apr_int32_t wanted, + apr_file_t *thefile) { - struct stat info; - - if (stat(fname, &info) == 0) { - finfo->protection = info.st_mode; - finfo->filetype = filetype_from_mode(info.st_mode); - finfo->user = info.st_uid; - finfo->group = info.st_gid; - finfo->size = info.st_size; - finfo->inode = info.st_ino; - ap_ansi_time_to_ap_time(&finfo->atime, info.st_atime); - ap_ansi_time_to_ap_time(&finfo->mtime, info.st_mtime); - ap_ansi_time_to_ap_time(&finfo->ctime, info.st_ctime); + struct_stat info; + + if (thefile->buffered) { + apr_status_t rv = apr_file_flush(thefile); + if (rv != APR_SUCCESS) + return rv; + } + + if (fstat(thefile->filedes, &info) == 0) { + finfo->pool = thefile->pool; + finfo->fname = thefile->fname; + fill_out_finfo(finfo, &info, wanted); + return (wanted & ~finfo->valid) ? APR_INCOMPLETE : APR_SUCCESS; + } + else { + return errno; + } +} + +APR_DECLARE(apr_status_t) apr_file_perms_set(const char *fname, + apr_fileperms_t perms) +{ + mode_t mode = apr_unix_perms2mode(perms); + + if (chmod(fname, mode) == -1) + return errno; + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_file_attrs_set(const char *fname, + apr_fileattrs_t attributes, + apr_fileattrs_t attr_mask, + apr_pool_t *pool) +{ + apr_status_t status; + apr_finfo_t finfo; + + /* Don't do anything if we can't handle the requested attributes */ + if (!(attr_mask & (APR_FILE_ATTR_READONLY + | APR_FILE_ATTR_EXECUTABLE))) return APR_SUCCESS; + + status = apr_stat(&finfo, fname, APR_FINFO_PROT, pool); + if (status) + return status; + + /* ### TODO: should added bits be umask'd? */ + if (attr_mask & APR_FILE_ATTR_READONLY) + { + if (attributes & APR_FILE_ATTR_READONLY) + { + finfo.protection &= ~APR_FPROT_UWRITE; + finfo.protection &= ~APR_FPROT_GWRITE; + finfo.protection &= ~APR_FPROT_WWRITE; + } + else + { + /* ### umask this! */ + finfo.protection |= APR_FPROT_UWRITE; + finfo.protection |= APR_FPROT_GWRITE; + finfo.protection |= APR_FPROT_WWRITE; + } + } + + if (attr_mask & APR_FILE_ATTR_EXECUTABLE) + { + if (attributes & APR_FILE_ATTR_EXECUTABLE) + { + /* ### umask this! */ + finfo.protection |= APR_FPROT_UEXECUTE; + finfo.protection |= APR_FPROT_GEXECUTE; + finfo.protection |= APR_FPROT_WEXECUTE; + } + else + { + finfo.protection &= ~APR_FPROT_UEXECUTE; + finfo.protection &= ~APR_FPROT_GEXECUTE; + finfo.protection &= ~APR_FPROT_WEXECUTE; + } + } + + return apr_file_perms_set(fname, finfo.protection); +} + + +APR_DECLARE(apr_status_t) apr_file_mtime_set(const char *fname, + apr_time_t mtime, + apr_pool_t *pool) +{ + apr_status_t status; + apr_finfo_t finfo; + + status = apr_stat(&finfo, fname, APR_FINFO_ATIME, pool); + if (status) { + return status; + } + +#ifdef HAVE_UTIMES + { + struct timeval tvp[2]; + + tvp[0].tv_sec = apr_time_sec(finfo.atime); + tvp[0].tv_usec = apr_time_usec(finfo.atime); + tvp[1].tv_sec = apr_time_sec(mtime); + tvp[1].tv_usec = apr_time_usec(mtime); + + if (utimes(fname, tvp) == -1) { + return errno; + } + } +#elif defined(HAVE_UTIME) + { + struct utimbuf buf; + + buf.actime = (time_t) (finfo.atime / APR_USEC_PER_SEC); + buf.modtime = (time_t) (mtime / APR_USEC_PER_SEC); + + if (utime(fname, &buf) == -1) { + return errno; + } + } +#else + return APR_ENOTIMPL; +#endif + + return APR_SUCCESS; +} + + +APR_DECLARE(apr_status_t) apr_stat(apr_finfo_t *finfo, + const char *fname, + apr_int32_t wanted, apr_pool_t *pool) +{ + struct_stat info; + int srv; + + if (wanted & APR_FINFO_LINK) + srv = lstat(fname, &info); + else + srv = stat(fname, &info); + + if (srv == 0) { + finfo->pool = pool; + finfo->fname = fname; + fill_out_finfo(finfo, &info, wanted); + if (wanted & APR_FINFO_LINK) + wanted &= ~APR_FINFO_LINK; + return (wanted & ~finfo->valid) ? APR_INCOMPLETE : APR_SUCCESS; } else { +#if !defined(ENOENT) || !defined(ENOTDIR) +#error ENOENT || ENOTDIR not defined; please see the +#error comments at this line in the source for a workaround. + /* + * If ENOENT || ENOTDIR is not defined in one of the your OS's + * include files, APR cannot report a good reason why the stat() + * of the file failed; there are cases where it can fail even though + * the file exists. This opens holes in Apache, for example, because + * it becomes possible for someone to get a directory listing of a + * directory even though there is an index (eg. index.html) file in + * it. If you do not have a problem with this, delete the above + * #error lines and start the compile again. If you need to do this, + * please submit a bug report to http://www.apache.org/bug_report.html + * letting us know that you needed to do this. Please be sure to + * include the operating system you are using. + */ + /* WARNING: All errors will be handled as not found + */ +#if !defined(ENOENT) + return APR_ENOENT; +#else + /* WARNING: All errors but not found will be handled as not directory + */ + if (errno != ENOENT) + return APR_ENOENT; + else + return errno; +#endif +#else /* All was defined well, report the usual: */ return errno; +#endif } } + + diff --git a/file_io/unix/flock.c b/file_io/unix/flock.c new file mode 100644 index 00000000000..01e8a639ba9 --- /dev/null +++ b/file_io/unix/flock.c @@ -0,0 +1,120 @@ +/* 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_file_io.h" + +#if APR_HAVE_FCNTL_H +#include <fcntl.h> +#endif +#ifdef HAVE_SYS_FILE_H +#include <sys/file.h> +#endif + +APR_DECLARE(apr_status_t) apr_file_lock(apr_file_t *thefile, int type) +{ + int rc; + +#if defined(HAVE_FCNTL_H) + { + struct flock l = { 0 }; + int fc; + + l.l_whence = SEEK_SET; /* count l_start from start of file */ + l.l_start = 0; /* lock from start of file */ + l.l_len = 0; /* lock to end of file */ + if ((type & APR_FLOCK_TYPEMASK) == APR_FLOCK_SHARED) + l.l_type = F_RDLCK; + else + l.l_type = F_WRLCK; + + fc = (type & APR_FLOCK_NONBLOCK) ? F_SETLK : F_SETLKW; + + /* keep trying if fcntl() gets interrupted (by a signal) */ + while ((rc = fcntl(thefile->filedes, fc, &l)) < 0 && errno == EINTR) + continue; + + if (rc == -1) { + /* on some Unix boxes (e.g., Tru64), we get EACCES instead + * of EAGAIN; we don't want APR_STATUS_IS_EAGAIN() matching EACCES + * since that breaks other things, so fix up the retcode here + */ + if (errno == EACCES) { + return EAGAIN; + } + return errno; + } + } +#elif defined(HAVE_SYS_FILE_H) + { + int ltype; + + if ((type & APR_FLOCK_TYPEMASK) == APR_FLOCK_SHARED) + ltype = LOCK_SH; + else + ltype = LOCK_EX; + if ((type & APR_FLOCK_NONBLOCK) != 0) + ltype |= LOCK_NB; + + /* keep trying if flock() gets interrupted (by a signal) */ + while ((rc = flock(thefile->filedes, ltype)) < 0 && errno == EINTR) + continue; + + if (rc == -1) + return errno; + } +#else +#error No file locking mechanism is available. +#endif + + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_file_unlock(apr_file_t *thefile) +{ + int rc; + +#if defined(HAVE_FCNTL_H) + { + struct flock l = { 0 }; + + l.l_whence = SEEK_SET; /* count l_start from start of file */ + l.l_start = 0; /* lock from start of file */ + l.l_len = 0; /* lock to end of file */ + l.l_type = F_UNLCK; + + /* keep trying if fcntl() gets interrupted (by a signal) */ + while ((rc = fcntl(thefile->filedes, F_SETLKW, &l)) < 0 + && errno == EINTR) + continue; + + if (rc == -1) + return errno; + } +#elif defined(HAVE_SYS_FILE_H) + { + /* keep trying if flock() gets interrupted (by a signal) */ + while ((rc = flock(thefile->filedes, LOCK_UN)) < 0 && errno == EINTR) + continue; + + if (rc == -1) + return errno; + } +#else +#error No file locking mechanism is available. +#endif + + return APR_SUCCESS; +} diff --git a/file_io/unix/fullrw.c b/file_io/unix/fullrw.c new file mode 100644 index 00000000000..3c67f65904d --- /dev/null +++ b/file_io/unix/fullrw.c @@ -0,0 +1,111 @@ +/* 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_file_io.h" + + +APR_DECLARE(apr_status_t) apr_file_read_full(apr_file_t *thefile, void *buf, + apr_size_t nbytes, + apr_size_t *bytes_read) +{ + apr_status_t status; + apr_size_t total_read = 0; + + do { + apr_size_t amt = nbytes; + + status = apr_file_read(thefile, buf, &amt); + buf = (char *)buf + amt; + nbytes -= amt; + total_read += amt; + } while (status == APR_SUCCESS && nbytes > 0); + + if (bytes_read != NULL) + *bytes_read = total_read; + + return status; +} + +APR_DECLARE(apr_status_t) apr_file_write_full(apr_file_t *thefile, + const void *buf, + apr_size_t nbytes, + apr_size_t *bytes_written) +{ + apr_status_t status; + apr_size_t total_written = 0; + + do { + apr_size_t amt = nbytes; + + status = apr_file_write(thefile, buf, &amt); + buf = (char *)buf + amt; + nbytes -= amt; + total_written += amt; + } while (status == APR_SUCCESS && nbytes > 0); + + if (bytes_written != NULL) + *bytes_written = total_written; + + return status; +} + +APR_DECLARE(apr_status_t) apr_file_writev_full(apr_file_t *thefile, + const struct iovec *vec, + apr_size_t nvec, + apr_size_t *bytes_written) +{ + apr_status_t rv = APR_SUCCESS; + apr_size_t i; + apr_size_t amt = 0; + apr_size_t total = 0; + + for (i = 0; i < nvec; i++) { + total += vec[i].iov_len; + } + + rv = apr_file_writev(thefile, vec, nvec, &amt); + + if (bytes_written != NULL) + *bytes_written = amt; + + if (rv != APR_SUCCESS || (amt == total)) { + return rv; + } + + for (i = 0; i < nvec && amt; i++) { + if (amt >= vec[i].iov_len) { + amt -= vec[i].iov_len; + } + else { + break; + } + } + + if (amt) { + rv = apr_file_write_full(thefile, (const char *)vec[i].iov_base + amt, + vec[i].iov_len - amt, NULL); + } + + for (; i < nvec && rv == APR_SUCCESS; i++) { + rv = apr_file_write_full(thefile, vec[i].iov_base, + vec[i].iov_len, &amt); + } + + if (bytes_written != NULL) + *bytes_written = total; + + return rv; +} diff --git a/file_io/unix/mktemp.c b/file_io/unix/mktemp.c new file mode 100644 index 00000000000..4ba28a7b44c --- /dev/null +++ b/file_io/unix/mktemp.c @@ -0,0 +1,231 @@ +/* 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. + */ +/* + * Copyright (c) 1987, 1993 + * 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_private.h" +#include "apr_file_io.h" /* prototype of apr_mkstemp() */ +#include "apr_strings.h" /* prototype of apr_mkstemp() */ +#include "apr_arch_file_io.h" /* prototype of apr_mkstemp() */ +#include "apr_portable.h" /* for apr_os_file_put() */ +#include "apr_arch_inherit.h" + +#ifndef HAVE_MKSTEMP + +#if defined(SVR4) || defined(WIN32) || defined(NETWARE) +#ifdef SVR4 +#if HAVE_INTTYPES_H +#include <inttypes.h> +#endif +#endif +#define arc4random() rand() +#define seedrandom(a) srand(a) +#else +#if APR_HAVE_STDINT_H +#include <stdint.h> +#endif +#define arc4random() random() +#define seedrandom(a) srandom(a) +#endif + +#if APR_HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif +#if APR_HAVE_FCNTL_H +#include <fcntl.h> +#endif +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#ifdef HAVE_TIME_H +#include <time.h> +#endif + +static const unsigned char padchar[] = +"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; +static apr_uint32_t randseed=0; + +static int gettemp(char *path, apr_file_t **doopen, apr_int32_t flags, apr_pool_t *p) +{ + register char *start, *trv, *suffp; + char *pad; + apr_finfo_t sbuf; + apr_status_t rv; + apr_uint32_t randnum; + + if (randseed==0) { + randseed = (int)apr_time_now(); + seedrandom(randseed); + } + + for (trv = path; *trv; ++trv) + ; + suffp = trv; + --trv; + if (trv < path) { + return APR_EINVAL; + } + + /* Fill space with random characters */ + while (*trv == 'X') { + randnum = arc4random() % (sizeof(padchar) - 1); + *trv-- = padchar[randnum]; + } + start = trv + 1; + + /* + * check the target directory. + */ + for (;; --trv) { + if (trv <= path) + break; + if (*trv == '/') { + *trv = '\0'; + rv = apr_stat(&sbuf, path, APR_FINFO_TYPE, p); + *trv = '/'; + if (rv != APR_SUCCESS) + return rv; + if (sbuf.filetype != APR_DIR) { + return APR_ENOTDIR; + } + break; + } + } + + for (;;) { + if ((rv = apr_file_open(doopen, path, flags, + APR_FPROT_UREAD | APR_FPROT_UWRITE, p)) == APR_SUCCESS) + return APR_SUCCESS; + if (!APR_STATUS_IS_EEXIST(rv)) + return rv; + + /* If we have a collision, cycle through the space of filenames */ + for (trv = start;;) { + if (*trv == '\0' || trv == suffp) + return APR_EINVAL; /* XXX: is this the correct return code? */ + pad = strchr((char *)padchar, *trv); + if (pad == NULL || !*++pad) { + *trv++ = padchar[0]; + } + else { + *trv++ = *pad; + break; + } + } + } + /*NOTREACHED*/ +} + +#else + +#if APR_HAVE_STDLIB_H +#include <stdlib.h> /* for mkstemp() - Single Unix */ +#endif +#if APR_HAVE_UNISTD_H +#include <unistd.h> /* for mkstemp() - FreeBSD */ +#endif +#endif /* !defined(HAVE_MKSTEMP) */ + +#if defined(HAVE_MKOSTEMP64) +#define wrap_mkostemp(t, f) mkostemp64(t, (f)) +#elif defined(HAVE_MKOSTEMP) +#define wrap_mkostemp(t, f) mkostemp(t, (f)) +#elif defined(HAVE_MKSTEMP64) +#define wrap_mkostemp(t, f) mkstemp64(t) +#else +#define wrap_mkostemp(t, f) mkstemp(t) +#endif + +APR_DECLARE(apr_status_t) apr_file_mktemp(apr_file_t **fp, char *template, apr_int32_t flags, apr_pool_t *p) +{ +#ifdef HAVE_MKSTEMP + int fd; +#endif + flags = (!flags) ? APR_FOPEN_CREATE | APR_FOPEN_READ | APR_FOPEN_WRITE | APR_FOPEN_EXCL | + APR_FOPEN_DELONCLOSE : flags; +#ifndef HAVE_MKSTEMP + return gettemp(template, fp, flags, p); +#else + + fd = wrap_mkostemp(template, + (flags & APR_FOPEN_NOCLEANUP) ? 0 : O_CLOEXEC); + if (fd == -1) { + return errno; + } + /* XXX: We must reset several flags values as passed-in, since + * mkstemp didn't subscribe to our preference flags. + * + * We either have to unset the flags, or fix up the fd and other + * xthread and inherit bits appropriately. Since gettemp() above + * calls apr_file_open, our flags are respected in that code path. + */ + apr_os_file_put(fp, &fd, flags, p); + (*fp)->fname = apr_pstrdup(p, template); + + if (!(flags & APR_FOPEN_NOCLEANUP)) { +#if !defined(HAVE_MKOSTEMP64) && !defined(HAVE_MKOSTEMP) + int flags; + + if ((flags = fcntl(fd, F_GETFD)) == -1) + return errno; + + flags |= FD_CLOEXEC; + if (fcntl(fd, F_SETFD, flags) == -1) + return errno; +#endif + + apr_pool_cleanup_register((*fp)->pool, (void *)(*fp), + apr_unix_file_cleanup, + apr_unix_child_file_cleanup); + } +#endif + return APR_SUCCESS; +} + diff --git a/file_io/unix/open.c b/file_io/unix/open.c index 6e0039ac73c..770d438ae34 100644 --- a/file_io/unix/open.c +++ b/file_io/unix/open.c @@ -1,151 +1,234 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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 "fileio.h" +#include "apr_arch_file_io.h" +#include "apr_strings.h" #include "apr_portable.h" +#include "apr_thread_mutex.h" +#include "apr_arch_inherit.h" +#include "apr_time.h" -ap_status_t ap_unix_file_cleanup(void *thefile) +#ifdef NETWARE +#include "nks/dirio.h" +#include "apr_hash.h" +#include "fsio.h" +#endif + +static apr_status_t file_cleanup(apr_file_t *file, int is_child) { - ap_file_t *file = thefile; - int rv; + apr_status_t rv = APR_SUCCESS; + int fd = file->filedes; - rv = close(file->filedes); + /* Set file descriptor to -1 before close(), so that there is no + * chance of returning an already closed FD from apr_os_file_get(). + */ + file->filedes = -1; - if (rv == 0) { - file->filedes = -1; + if (close(fd) == 0) { + /* Only the parent process should delete the file! */ + if (!is_child && (file->flags & APR_FOPEN_DELONCLOSE)) { + unlink(file->fname); + } #if APR_HAS_THREADS if (file->thlock) { - return ap_destroy_lock(file->thlock); + rv = apr_thread_mutex_destroy(file->thlock); } - return APR_SUCCESS; -#else - return APR_SUCCESS; #endif } else { - return errno; - /* Are there any error conditions other than EINTR or EBADF? */ + /* Restore, close() was not successful. */ + file->filedes = fd; + + /* Are there any error conditions other than EINTR or EBADF? */ + rv = errno; } +#ifndef WAITIO_USES_POLL + if (file->pollset != NULL) { + apr_status_t pollset_rv = apr_pollset_destroy(file->pollset); + /* If the file close failed, return its error value, + * not apr_pollset_destroy()'s. + */ + if (rv == APR_SUCCESS) { + rv = pollset_rv; + } + } +#endif /* !WAITIO_USES_POLL */ + return rv; } -ap_status_t ap_open(ap_file_t **new, const char *fname, ap_int32_t flag, ap_fileperms_t perm, ap_pool_t *cont) +apr_status_t apr_unix_file_cleanup(void *thefile) { - int oflags = 0; + apr_file_t *file = thefile; + apr_status_t flush_rv = APR_SUCCESS, rv = APR_SUCCESS; - if ((*new) == NULL) { - (*new) = (ap_file_t *)ap_pcalloc(cont, sizeof(ap_file_t)); + if (file->buffered) { + flush_rv = apr_file_flush(file); } - (*new)->cntxt = cont; - (*new)->oflags = oflags; - (*new)->filedes = -1; - (*new)->buffer = NULL; + rv = file_cleanup(file, 0); + + return rv != APR_SUCCESS ? rv : flush_rv; +} + +apr_status_t apr_unix_child_file_cleanup(void *thefile) +{ + return file_cleanup(thefile, 1); +} + +APR_DECLARE(apr_status_t) apr_file_open(apr_file_t **new, + const char *fname, + apr_int32_t flag, + apr_fileperms_t perm, + apr_pool_t *pool) +{ + apr_os_file_t fd; + int oflags = 0; #if APR_HAS_THREADS - ap_create_lock(&((*new)->thlock), APR_MUTEX, APR_INTRAPROCESS, NULL, cont); + apr_thread_mutex_t *thlock = NULL; #endif + apr_status_t rv; - if ((flag & APR_READ) && (flag & APR_WRITE)) { + if ((flag & APR_FOPEN_READ) && (flag & APR_FOPEN_WRITE)) { oflags = O_RDWR; } - else if (flag & APR_READ) { + else if (flag & APR_FOPEN_READ) { oflags = O_RDONLY; } - else if (flag & APR_WRITE) { + else if (flag & APR_FOPEN_WRITE) { oflags = O_WRONLY; } else { return APR_EACCES; } - (*new)->fname = ap_pstrdup(cont, fname); - - (*new)->buffered = (flag & APR_BUFFERED) > 0; - - if (flag & APR_CREATE) { - oflags |= O_CREAT; - if (flag & APR_EXCL) { - oflags |= O_EXCL; - } + if (flag & APR_FOPEN_CREATE) { + oflags |= O_CREAT; + if (flag & APR_FOPEN_EXCL) { + oflags |= O_EXCL; + } } - if ((flag & APR_EXCL) && !(flag & APR_CREATE)) { + if ((flag & APR_FOPEN_EXCL) && !(flag & APR_FOPEN_CREATE)) { return APR_EACCES; } - if (flag & APR_APPEND) { + if (flag & APR_FOPEN_APPEND) { oflags |= O_APPEND; } - if (flag & APR_TRUNCATE) { + if (flag & APR_FOPEN_TRUNCATE) { oflags |= O_TRUNC; } - - if (perm == APR_OS_DEFAULT) { - (*new)->filedes = open(fname, oflags, 0666); +#ifdef O_BINARY + if (flag & APR_FOPEN_BINARY) { + oflags |= O_BINARY; } - else { - (*new)->filedes = open(fname, oflags, ap_unix_get_fileperms(perm)); - } +#endif + + if (flag & APR_FOPEN_NONBLOCK) { +#ifdef O_NONBLOCK + oflags |= O_NONBLOCK; +#else + return APR_ENOTIMPL; +#endif + } + +#ifdef O_CLOEXEC + /* Introduced in Linux 2.6.23. Silently ignored on earlier Linux kernels. + */ + if (!(flag & APR_FOPEN_NOCLEANUP)) { + oflags |= O_CLOEXEC; +} +#endif + +#if APR_HAS_LARGE_FILES && defined(_LARGEFILE64_SOURCE) + oflags |= O_LARGEFILE; +#elif defined(O_LARGEFILE) + if (flag & APR_FOPEN_LARGEFILE) { + oflags |= O_LARGEFILE; + } +#endif + +#if APR_HAS_THREADS + if ((flag & APR_FOPEN_BUFFERED) && (flag & APR_FOPEN_XTHREAD)) { + rv = apr_thread_mutex_create(&thlock, + APR_THREAD_MUTEX_DEFAULT, pool); + if (rv) { + return rv; + } + } +#endif - if ((*new)->filedes < 0) { - (*new)->filedes = -1; - (*new)->eof_hit = 1; + if (perm == APR_FPROT_OS_DEFAULT) { + fd = open(fname, oflags, 0666); + } + else { + fd = open(fname, oflags, apr_unix_perms2mode(perm)); + } + if (fd < 0) { return errno; } + if (!(flag & APR_FOPEN_NOCLEANUP)) { +#ifdef O_CLOEXEC + static int has_o_cloexec = 0; + if (!has_o_cloexec) +#endif + { + int flags; - if (flag & APR_DELONCLOSE) { - unlink(fname); + if ((flags = fcntl(fd, F_GETFD)) == -1) { + close(fd); + return errno; + } + if ((flags & FD_CLOEXEC) == 0) { + flags |= FD_CLOEXEC; + if (fcntl(fd, F_SETFD, flags) == -1) { + close(fd); + return errno; + } + } +#ifdef O_CLOEXEC + else { + has_o_cloexec = 1; + } +#endif + } } - (*new)->pipe = 0; + + (*new) = (apr_file_t *)apr_pcalloc(pool, sizeof(apr_file_t)); + (*new)->pool = pool; + (*new)->flags = flag; + (*new)->filedes = fd; + + (*new)->fname = apr_pstrdup(pool, fname); + + (*new)->blocking = BLK_ON; + (*new)->buffered = (flag & APR_FOPEN_BUFFERED) > 0; + + if ((*new)->buffered) { + (*new)->buffer = apr_palloc(pool, APR_FILE_DEFAULT_BUFSIZE); + (*new)->bufsize = APR_FILE_DEFAULT_BUFSIZE; + } + else { + (*new)->buffer = NULL; + } + +#if APR_HAS_THREADS + (*new)->thlock = thlock; +#endif + + (*new)->is_pipe = 0; (*new)->timeout = -1; (*new)->ungetchar = -1; (*new)->eof_hit = 0; @@ -153,23 +236,52 @@ ap_status_t ap_open(ap_file_t **new, const char *fname, ap_int32_t flag, ap_fil (*new)->bufpos = 0; (*new)->dataRead = 0; (*new)->direction = 0; - ap_register_cleanup((*new)->cntxt, (void *)(*new), ap_unix_file_cleanup, - ap_null_cleanup); +#ifndef WAITIO_USES_POLL + /* Start out with no pollset. apr_wait_for_io_or_timeout() will + * initialize the pollset if needed. + */ + (*new)->pollset = NULL; +#endif + if (!(flag & APR_FOPEN_NOCLEANUP)) { + apr_pool_cleanup_register((*new)->pool, (void *)(*new), + apr_unix_file_cleanup, + apr_unix_child_file_cleanup); + } + + if ((flag & APR_FOPEN_ROTATING) || (flag & APR_FOPEN_MANUAL_ROTATE)) { + (*new)->rotating = (apr_rotating_info_t *)apr_pcalloc(pool, + sizeof(apr_rotating_info_t)); + + rv = apr_file_info_get(&(*new)->rotating->finfo, + APR_FINFO_DEV|APR_FINFO_INODE, *new); + if (rv != APR_SUCCESS) { + return rv; + } + + if (flag & APR_FOPEN_MANUAL_ROTATE) { + (*new)->rotating->manual = 1; + } + else { + (*new)->rotating->manual = 0; + } + (*new)->rotating->timeout = 60; + (*new)->rotating->lastcheck = apr_time_sec(apr_time_now()); + (*new)->rotating->oflags = oflags; + (*new)->rotating->perm = perm; + } + else { + (*new)->rotating = NULL; + } + return APR_SUCCESS; } -ap_status_t ap_close(ap_file_t *file) +APR_DECLARE(apr_status_t) apr_file_close(apr_file_t *file) { - ap_status_t rv; - - if ((rv = ap_unix_file_cleanup(file)) == APR_SUCCESS) { - ap_kill_cleanup(file->cntxt, file, ap_unix_file_cleanup); - return APR_SUCCESS; - } - return rv; + return apr_pool_cleanup_run(file->pool, file, apr_unix_file_cleanup); } -ap_status_t ap_remove_file(char *path, ap_pool_t *cont) +APR_DECLARE(apr_status_t) apr_file_remove(const char *path, apr_pool_t *pool) { if (unlink(path) == 0) { return APR_SUCCESS; @@ -179,37 +291,64 @@ ap_status_t ap_remove_file(char *path, ap_pool_t *cont) } } -ap_status_t ap_get_os_file(ap_os_file_t *thefile, ap_file_t *file) +APR_DECLARE(apr_status_t) apr_file_rename(const char *from_path, + const char *to_path, + apr_pool_t *p) { - if (file == NULL) { - return APR_ENOFILE; + if (rename(from_path, to_path) != 0) { + return errno; } + return APR_SUCCESS; +} +APR_DECLARE(apr_status_t) apr_os_file_get(apr_os_file_t *thefile, + apr_file_t *file) +{ *thefile = file->filedes; return APR_SUCCESS; } -ap_status_t ap_put_os_file(ap_file_t **file, ap_os_file_t *thefile, - ap_pool_t *cont) +APR_DECLARE(apr_status_t) apr_os_file_put(apr_file_t **file, + apr_os_file_t *thefile, + apr_int32_t flags, apr_pool_t *pool) { int *dafile = thefile; - if ((*file) == NULL) { - (*file) = ap_pcalloc(cont, sizeof(ap_file_t)); - (*file)->cntxt = cont; - } + (*file) = apr_pcalloc(pool, sizeof(apr_file_t)); + (*file)->pool = pool; (*file)->eof_hit = 0; - (*file)->buffered = 0; + (*file)->blocking = BLK_UNKNOWN; /* in case it is a pipe */ (*file)->timeout = -1; + (*file)->ungetchar = -1; /* no char avail */ (*file)->filedes = *dafile; - /* buffer already NULL */ + (*file)->flags = flags | APR_FOPEN_NOCLEANUP; + (*file)->buffered = (flags & APR_FOPEN_BUFFERED) > 0; + +#ifndef WAITIO_USES_POLL + /* Start out with no pollset. apr_wait_for_io_or_timeout() will + * initialize the pollset if needed. + */ + (*file)->pollset = NULL; +#endif + + if ((*file)->buffered) { + (*file)->buffer = apr_palloc(pool, APR_FILE_DEFAULT_BUFSIZE); + (*file)->bufsize = APR_FILE_DEFAULT_BUFSIZE; #if APR_HAS_THREADS - ap_create_lock(&((*file)->thlock), APR_MUTEX, APR_INTRAPROCESS, NULL, cont); + if ((*file)->flags & APR_FOPEN_XTHREAD) { + apr_status_t rv; + rv = apr_thread_mutex_create(&((*file)->thlock), + APR_THREAD_MUTEX_DEFAULT, pool); + if (rv) { + return rv; + } + } #endif + } return APR_SUCCESS; } -ap_status_t ap_eof(ap_file_t *fptr) +APR_DECLARE(apr_status_t) apr_file_eof(apr_file_t *fptr) { if (fptr->eof_hit == 1) { return APR_EOF; @@ -217,25 +356,88 @@ ap_status_t ap_eof(ap_file_t *fptr) return APR_SUCCESS; } -ap_status_t ap_ferror(ap_file_t *fptr) +APR_DECLARE(apr_status_t) apr_file_open_flags_stderr(apr_file_t **thefile, + apr_int32_t flags, + apr_pool_t *pool) { -/* This function should be removed ASAP. It is next on my list once - * I am sure nobody is using it. - */ + int fd = STDERR_FILENO; + + return apr_os_file_put(thefile, &fd, flags | APR_FOPEN_WRITE, pool); +} + +APR_DECLARE(apr_status_t) apr_file_open_flags_stdout(apr_file_t **thefile, + apr_int32_t flags, + apr_pool_t *pool) +{ + int fd = STDOUT_FILENO; + + return apr_os_file_put(thefile, &fd, flags | APR_FOPEN_WRITE, pool); +} + +APR_DECLARE(apr_status_t) apr_file_open_flags_stdin(apr_file_t **thefile, + apr_int32_t flags, + apr_pool_t *pool) +{ + int fd = STDIN_FILENO; + + return apr_os_file_put(thefile, &fd, flags | APR_FOPEN_READ, pool); +} + +APR_DECLARE(apr_status_t) apr_file_open_stderr(apr_file_t **thefile, + apr_pool_t *pool) +{ + return apr_file_open_flags_stderr(thefile, 0, pool); +} + +APR_DECLARE(apr_status_t) apr_file_open_stdout(apr_file_t **thefile, + apr_pool_t *pool) +{ + return apr_file_open_flags_stdout(thefile, 0, pool); +} + +APR_DECLARE(apr_status_t) apr_file_open_stdin(apr_file_t **thefile, + apr_pool_t *pool) +{ + return apr_file_open_flags_stdin(thefile, 0, pool); +} + +APR_IMPLEMENT_INHERIT_SET(file, flags, pool, apr_unix_file_cleanup) + +/* We need to do this by hand instead of using APR_IMPLEMENT_INHERIT_UNSET + * because the macro sets both cleanups to the same function, which is not + * suitable on Unix (see PR 41119). */ +APR_DECLARE(apr_status_t) apr_file_inherit_unset(apr_file_t *thefile) +{ + if (thefile->flags & APR_FOPEN_NOCLEANUP) { + return APR_EINVAL; + } + if (thefile->flags & APR_INHERIT) { + int flags; + + if ((flags = fcntl(thefile->filedes, F_GETFD)) == -1) + return errno; + + flags |= FD_CLOEXEC; + if (fcntl(thefile->filedes, F_SETFD, flags) == -1) + return errno; + + thefile->flags &= ~APR_INHERIT; + apr_pool_child_cleanup_set(thefile->pool, + (void *)thefile, + apr_unix_file_cleanup, + apr_unix_child_file_cleanup); + } return APR_SUCCESS; -} +} + +APR_POOL_IMPLEMENT_ACCESSOR(file) -ap_status_t ap_open_stderr(ap_file_t **thefile, ap_pool_t *cont) +APR_DECLARE(apr_status_t) apr_file_link(const char *from_path, + const char *to_path) { - (*thefile) = ap_pcalloc(cont, sizeof(ap_file_t)); - if ((*thefile) == NULL) { - return APR_ENOMEM; + if (link(from_path, to_path) == -1) { + return errno; } - (*thefile)->filedes = STDERR_FILENO; - (*thefile)->cntxt = cont; - (*thefile)->buffered = 0; - (*thefile)->fname = NULL; - (*thefile)->eof_hit = 0; return APR_SUCCESS; } diff --git a/file_io/unix/pipe.c b/file_io/unix/pipe.c index 2f2091bd821..b68ac65423e 100644 --- a/file_io/unix/pipe.c +++ b/file_io/unix/pipe.c @@ -1,91 +1,186 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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 "fileio.h" +#include "apr_arch_file_io.h" +#include "apr_strings.h" +#include "apr_portable.h" -static ap_status_t pipenonblock(ap_file_t *thefile) -{ -#ifndef BEOS /* this code won't work on BeOS */ - int fd_flags = fcntl(thefile->filedes, F_GETFL, 0); - -#if defined(O_NONBLOCK) - fd_flags |= O_NONBLOCK; -#elif defined(O_NDELAY) - fd_flags |= O_NDELAY; -#elif defined(FNDELAY) - fd_flags |= O_FNDELAY; +#include "apr_arch_inherit.h" + +/* Figure out how to get pipe block/nonblock on BeOS... + * Basically, BONE7 changed things again so that ioctl didn't work, + * but now fcntl does, hence we need to do this extra checking. + * The joys of beta programs. :-) + */ +#if defined(BEOS) +#if !defined(BONE7) +# define BEOS_BLOCKING 1 #else - /* XXXX: this breaks things, but an alternative isn't obvious...*/ - return -1; +# define BEOS_BLOCKING 0 #endif - if (fcntl(thefile->filedes, F_SETFL, fd_flags) == -1) { - return errno; - } -#endif /* !BeOS */ +#endif + +static apr_status_t pipeblock(apr_file_t *thepipe) +{ +#if !defined(BEOS) || !BEOS_BLOCKING + int fd_flags; + + fd_flags = fcntl(thepipe->filedes, F_GETFL, 0); +# if defined(O_NONBLOCK) + fd_flags &= ~O_NONBLOCK; +# elif defined(O_NDELAY) + fd_flags &= ~O_NDELAY; +# elif defined(O_FNDELAY) + fd_flags &= ~O_FNDELAY; +# else + /* XXXX: this breaks things, but an alternative isn't obvious...*/ + return APR_ENOTIMPL; +# endif + if (fcntl(thepipe->filedes, F_SETFL, fd_flags) == -1) { + return errno; + } +#else /* BEOS_BLOCKING */ + +# if BEOS_BONE /* This only works on BONE 0-6 */ + int on = 0; + if (ioctl(thepipe->filedes, FIONBIO, &on, sizeof(on)) < 0) { + return errno; + } +# else /* "classic" BeOS doesn't support this at all */ + return APR_ENOTIMPL; +# endif + +#endif /* !BEOS_BLOCKING */ + + thepipe->blocking = BLK_ON; return APR_SUCCESS; } -ap_status_t ap_set_pipe_timeout(ap_file_t *thepipe, ap_interval_time_t timeout) +static apr_status_t pipenonblock(apr_file_t *thepipe) { - if (thepipe->pipe == 1) { +#if !defined(BEOS) || !BEOS_BLOCKING + int fd_flags = fcntl(thepipe->filedes, F_GETFL, 0); + +# if defined(O_NONBLOCK) + fd_flags |= O_NONBLOCK; +# elif defined(O_NDELAY) + fd_flags |= O_NDELAY; +# elif defined(O_FNDELAY) + fd_flags |= O_FNDELAY; +# else + /* XXXX: this breaks things, but an alternative isn't obvious...*/ + return APR_ENOTIMPL; +# endif + if (fcntl(thepipe->filedes, F_SETFL, fd_flags) == -1) { + return errno; + } + +#else /* BEOS_BLOCKING */ + +# if BEOS_BONE /* This only works on BONE 0-6 */ + int on = 1; + if (ioctl(thepipe->filedes, FIONBIO, &on, sizeof(on)) < 0) { + return errno; + } +# else /* "classic" BeOS doesn't support this at all */ + return APR_ENOTIMPL; +# endif + +#endif /* !BEOS_BLOCKING */ + + thepipe->blocking = BLK_OFF; + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_file_pipe_timeout_set(apr_file_t *thepipe, apr_interval_time_t timeout) +{ + if (thepipe->is_pipe == 1) { thepipe->timeout = timeout; + if (timeout >= 0) { + if (thepipe->blocking != BLK_OFF) { /* blocking or unknown state */ + return pipenonblock(thepipe); + } + } + else { + if (thepipe->blocking != BLK_ON) { /* non-blocking or unknown state */ + return pipeblock(thepipe); + } + } + return APR_SUCCESS; + } + return APR_EINVAL; +} + +APR_DECLARE(apr_status_t) apr_file_pipe_timeout_get(apr_file_t *thepipe, apr_interval_time_t *timeout) +{ + if (thepipe->is_pipe == 1) { + *timeout = thepipe->timeout; return APR_SUCCESS; } return APR_EINVAL; } -ap_status_t ap_create_pipe(ap_file_t **in, ap_file_t **out, ap_pool_t *cont) +APR_DECLARE(apr_status_t) apr_os_pipe_put_ex(apr_file_t **file, + apr_os_file_t *thefile, + int register_cleanup, + apr_pool_t *pool) +{ + int *dafile = thefile; + + (*file) = apr_pcalloc(pool, sizeof(apr_file_t)); + (*file)->pool = pool; + (*file)->eof_hit = 0; + (*file)->is_pipe = 1; + (*file)->blocking = BLK_UNKNOWN; /* app needs to make a timeout call */ + (*file)->timeout = -1; + (*file)->ungetchar = -1; /* no char avail */ + (*file)->filedes = *dafile; + if (!register_cleanup) { + (*file)->flags = APR_FOPEN_NOCLEANUP; + } + (*file)->buffered = 0; +#if APR_HAS_THREADS + (*file)->thlock = NULL; +#endif + if (register_cleanup) { + apr_pool_cleanup_register((*file)->pool, (void *)(*file), + apr_unix_file_cleanup, + apr_pool_cleanup_null); + } +#ifndef WAITIO_USES_POLL + /* Start out with no pollset. apr_wait_for_io_or_timeout() will + * initialize the pollset if needed. + */ + (*file)->pollset = NULL; +#endif + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_os_pipe_put(apr_file_t **file, + apr_os_file_t *thefile, + apr_pool_t *pool) +{ + return apr_os_pipe_put_ex(file, thefile, 0, pool); +} + +static apr_status_t file_pipe_create(apr_file_t **in, + apr_file_t **out, + apr_int32_t blocking, + apr_pool_t *pool_in, + apr_pool_t *pool_out) { int filedes[2]; @@ -93,39 +188,88 @@ ap_status_t ap_create_pipe(ap_file_t **in, ap_file_t **out, ap_pool_t *cont) return errno; } - (*in) = (ap_file_t *)ap_palloc(cont, sizeof(ap_file_t)); - (*in)->cntxt = cont; + (*in) = (apr_file_t *)apr_pcalloc(pool_in, sizeof(apr_file_t)); + (*in)->pool = pool_in; (*in)->filedes = filedes[0]; - (*in)->pipe = 1; - (*in)->fname = ap_pstrdup(cont, "PIPE"); + (*in)->is_pipe = 1; + (*in)->fname = NULL; (*in)->buffered = 0; + (*in)->blocking = BLK_ON; (*in)->timeout = -1; (*in)->ungetchar = -1; + (*in)->flags = APR_INHERIT; #if APR_HAS_THREADS (*in)->thlock = NULL; #endif - - (*out) = (ap_file_t *)ap_palloc(cont, sizeof(ap_file_t)); - (*out)->cntxt = cont; +#ifndef WAITIO_USES_POLL + (*in)->pollset = NULL; +#endif + (*out) = (apr_file_t *)apr_pcalloc(pool_out, sizeof(apr_file_t)); + (*out)->pool = pool_out; (*out)->filedes = filedes[1]; - (*out)->pipe = 1; - (*out)->fname = ap_pstrdup(cont, "PIPE"); + (*out)->is_pipe = 1; + (*out)->fname = NULL; (*out)->buffered = 0; + (*out)->blocking = BLK_ON; + (*out)->flags = APR_INHERIT; (*out)->timeout = -1; #if APR_HAS_THREADS - (*in)->thlock = NULL; + (*out)->thlock = NULL; #endif +#ifndef WAITIO_USES_POLL + (*out)->pollset = NULL; +#endif + apr_pool_cleanup_register((*in)->pool, (void *)(*in), apr_unix_file_cleanup, + apr_pool_cleanup_null); + apr_pool_cleanup_register((*out)->pool, (void *)(*out), apr_unix_file_cleanup, + apr_pool_cleanup_null); - pipenonblock(*in); - pipenonblock(*out); - + switch (blocking) { + case APR_FULL_BLOCK: + break; + case APR_READ_BLOCK: + apr_file_pipe_timeout_set(*out, 0); + break; + case APR_WRITE_BLOCK: + apr_file_pipe_timeout_set(*in, 0); + break; + default: + apr_file_pipe_timeout_set(*out, 0); + apr_file_pipe_timeout_set(*in, 0); + break; + } return APR_SUCCESS; } -ap_status_t ap_create_namedpipe(char *filename, - ap_fileperms_t perm, ap_pool_t *cont) +APR_DECLARE(apr_status_t) apr_file_pipe_create(apr_file_t **in, + apr_file_t **out, + apr_pool_t *pool) +{ + /* Default is full blocking pipes. */ + return file_pipe_create(in, out, APR_FULL_BLOCK, pool, pool); +} + +APR_DECLARE(apr_status_t) apr_file_pipe_create_ex(apr_file_t **in, + apr_file_t **out, + apr_int32_t blocking, + apr_pool_t *pool) +{ + return file_pipe_create(in, out, blocking, pool, pool); +} + +APR_DECLARE(apr_status_t) apr_file_pipe_create_pools(apr_file_t **in, + apr_file_t **out, + apr_int32_t blocking, + apr_pool_t *pool_in, + apr_pool_t *pool_out) +{ + return file_pipe_create(in, out, blocking, pool_in, pool_out); +} + +APR_DECLARE(apr_status_t) apr_file_namedpipe_create(const char *filename, + apr_fileperms_t perm, apr_pool_t *pool) { - mode_t mode = ap_unix_get_fileperms(perm); + mode_t mode = apr_unix_perms2mode(perm); if (mkfifo(filename, mode) == -1) { return errno; @@ -133,27 +277,5 @@ ap_status_t ap_create_namedpipe(char *filename, return APR_SUCCESS; } -ap_status_t ap_block_pipe(ap_file_t *thepipe) -{ -#ifndef BEOS /* this code won't work on BeOS */ - int fd_flags; - - fd_flags = fcntl(thepipe->filedes, F_GETFL, 0); -#if defined(O_NONBLOCK) - fd_flags &= ~O_NONBLOCK; -#elif defined(~O_NDELAY) - fd_flags &= ~O_NDELAY; -#elif defined(FNDELAY) - fd_flags &= ~O_FNDELAY; -#else - /* XXXX: this breaks things, but an alternative isn't obvious...*/ - return -1; -#endif - if (fcntl(thepipe->filedes, F_SETFL, fd_flags) == -1) { - return errno; - } -#endif /* !BeOS */ - return APR_SUCCESS; -} diff --git a/file_io/unix/printf.c b/file_io/unix/printf.c new file mode 100644 index 00000000000..03c23b22256 --- /dev/null +++ b/file_io/unix/printf.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. + */ + +#include "apr_file_io.h" +#include "apr_strings.h" +#include "apr_lib.h" + +#if APR_HAVE_STDLIB_H +#include <stdlib.h> +#endif + +struct apr_file_printf_data { + apr_vformatter_buff_t vbuff; + apr_file_t *fptr; + char *buf; +}; + +static int file_printf_flush(apr_vformatter_buff_t *buff) +{ + struct apr_file_printf_data *data = (struct apr_file_printf_data *)buff; + + if (apr_file_write_full(data->fptr, data->buf, + data->vbuff.curpos - data->buf, NULL)) { + return -1; + } + + data->vbuff.curpos = data->buf; + return 0; +} + +APR_DECLARE_NONSTD(int) apr_file_printf(apr_file_t *fptr, + const char *format, ...) +{ + struct apr_file_printf_data data; + va_list ap; + int count; + + /* don't really need a HUGE_STRING_LEN anymore */ + data.buf = malloc(HUGE_STRING_LEN); + if (data.buf == NULL) { + return -1; + } + data.vbuff.curpos = data.buf; + data.vbuff.endpos = data.buf + HUGE_STRING_LEN; + data.fptr = fptr; + va_start(ap, format); + count = apr_vformatter(file_printf_flush, + (apr_vformatter_buff_t *)&data, format, ap); + /* apr_vformatter does not call flush for the last bits */ + if (count >= 0) file_printf_flush((apr_vformatter_buff_t *)&data); + + va_end(ap); + + free(data.buf); + + return count; +} diff --git a/file_io/unix/readwrite.c b/file_io/unix/readwrite.c index 5b0d1d6a6cd..f9c7b06bdb4 100644 --- a/file_io/unix/readwrite.c +++ b/file_io/unix/readwrite.c @@ -1,143 +1,103 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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 "fileio.h" -#include "apr_lock.h" +#include "apr_arch_file_io.h" +#include "apr_strings.h" +#include "apr_thread_mutex.h" +#include "apr_support.h" +#include "apr_time.h" +#include "apr_file_info.h" + +/* The only case where we don't use wait_for_io_or_timeout is on + * pre-BONE BeOS, so this check should be sufficient and simpler */ +#if !defined(BEOS_R5) +#define USE_WAIT_FOR_IO +#endif -static ap_status_t wait_for_io_or_timeout(ap_file_t *file, int for_read) +static apr_status_t file_read_buffered(apr_file_t *thefile, void *buf, + apr_size_t *nbytes) { - struct timeval tv, *tvptr; - fd_set fdset; - int srv; - - /* TODO - timeout should be less each time through this loop */ - - do { - FD_ZERO(&fdset); - FD_SET(file->filedes, &fdset); - if (file->timeout >= 0) { - tv.tv_sec = file->timeout / AP_USEC_PER_SEC; - tv.tv_usec = file->timeout % AP_USEC_PER_SEC; - tvptr = &tv; + apr_ssize_t rv; + char *pos = (char *)buf; + apr_uint64_t blocksize; + apr_uint64_t size = *nbytes; + + if (thefile->direction == 1) { + rv = apr_file_flush_locked(thefile); + if (rv) { + return rv; } - else { - tvptr = NULL; + thefile->bufpos = 0; + thefile->direction = 0; + thefile->dataRead = 0; + } + + rv = 0; + if (thefile->ungetchar != -1) { + *pos = (char)thefile->ungetchar; + ++pos; + --size; + thefile->ungetchar = -1; + } + while (rv == 0 && size > 0) { + if (thefile->bufpos >= thefile->dataRead) { + int bytesread = read(thefile->filedes, thefile->buffer, + thefile->bufsize); + if (bytesread == 0) { + thefile->eof_hit = TRUE; + rv = APR_EOF; + break; + } + else if (bytesread == -1) { + rv = errno; + break; + } + thefile->dataRead = bytesread; + thefile->filePtr += thefile->dataRead; + thefile->bufpos = 0; } - srv = select(FD_SETSIZE, - for_read ? &fdset : NULL, - for_read ? NULL : &fdset, - NULL, - tvptr); - } while (srv == -1 && errno == EINTR); - - if (srv == 0) { - return APR_TIMEUP; + + blocksize = size > thefile->dataRead - thefile->bufpos ? thefile->dataRead - thefile->bufpos : size; + memcpy(pos, thefile->buffer + thefile->bufpos, blocksize); + thefile->bufpos += blocksize; + pos += blocksize; + size -= blocksize; } - else if (srv < 0) { - return errno; + + *nbytes = pos - (char *)buf; + if (*nbytes) { + rv = 0; } - return APR_SUCCESS; + return rv; } -ap_status_t ap_read(ap_file_t *thefile, void *buf, ap_ssize_t *nbytes) +APR_DECLARE(apr_status_t) apr_file_read(apr_file_t *thefile, void *buf, apr_size_t *nbytes) { - ap_ssize_t rv; - ap_ssize_t bytes_read; + apr_ssize_t rv; + apr_size_t bytes_read; - if(*nbytes <= 0) { + if (*nbytes <= 0) { *nbytes = 0; - return APR_SUCCESS; + return APR_SUCCESS; } if (thefile->buffered) { - char *pos = (char *)buf; - ap_uint64_t blocksize; - ap_uint64_t size = *nbytes; - -#if APR_HAS_THREADS - ap_lock(thefile->thlock); -#endif - - if (thefile->direction == 1) { - ap_flush(thefile); - thefile->bufpos = 0; - thefile->direction = 0; - thefile->dataRead = 0; - } - - rv = 0; - while (rv == 0 && size > 0) { - if (thefile->bufpos >= thefile->dataRead) { - thefile->dataRead = read(thefile->filedes, thefile->buffer, APR_FILE_BUFSIZE); - if (thefile->dataRead == 0) { - thefile->eof_hit = TRUE; - break; - } - thefile->filePtr += thefile->dataRead; - thefile->bufpos = 0; - } - - blocksize = size > thefile->dataRead - thefile->bufpos ? thefile->dataRead - thefile->bufpos : size; memcpy(pos, thefile->buffer + thefile->bufpos, blocksize); - thefile->bufpos += blocksize; - pos += blocksize; - size -= blocksize; - } - - *nbytes = rv == 0 ? pos - (char *)buf : 0; -#if APR_HAS_THREADS - ap_unlock(thefile->thlock); -#endif + file_lock(thefile); + rv = file_read_buffered(thefile, buf, nbytes); + file_unlock(thefile); return rv; } else { @@ -148,20 +108,20 @@ ap_status_t ap_read(ap_file_t *thefile, void *buf, ap_ssize_t *nbytes) buf = (char *)buf + 1; (*nbytes)--; thefile->ungetchar = -1; - if (*nbytes == 0) { - *nbytes = bytes_read; - return APR_SUCCESS; - } + if (*nbytes == 0) { + *nbytes = bytes_read; + return APR_SUCCESS; + } } do { rv = read(thefile->filedes, buf, *nbytes); } while (rv == -1 && errno == EINTR); - +#ifdef USE_WAIT_FOR_IO if (rv == -1 && (errno == EAGAIN || errno == EWOULDBLOCK) && thefile->timeout != 0) { - ap_status_t arv = wait_for_io_or_timeout(thefile, 1); + apr_status_t arv = apr_wait_for_io_or_timeout(thefile, NULL, 1); if (arv != APR_SUCCESS) { *nbytes = bytes_read; return arv; @@ -172,81 +132,173 @@ ap_status_t ap_read(ap_file_t *thefile, void *buf, ap_ssize_t *nbytes) } while (rv == -1 && errno == EINTR); } } - +#endif *nbytes = bytes_read; if (rv == 0) { - return APR_EOF; + thefile->eof_hit = TRUE; + return APR_EOF; } if (rv > 0) { - *nbytes += rv; - return APR_SUCCESS; + *nbytes += rv; + return APR_SUCCESS; } return errno; } } -ap_status_t ap_write(ap_file_t *thefile, void *buf, ap_ssize_t *nbytes) +static apr_status_t do_rotating_check(apr_file_t *thefile, apr_time_t now) +{ + apr_size_t rv = APR_SUCCESS; + + if ((now - thefile->rotating->lastcheck) >= thefile->rotating->timeout) { + apr_finfo_t new_finfo; + apr_pool_t *tmp_pool; + + apr_pool_create(&tmp_pool, thefile->pool); + + rv = apr_stat(&new_finfo, thefile->fname, + APR_FINFO_DEV|APR_FINFO_INODE, tmp_pool); + + if (rv != APR_SUCCESS || + new_finfo.inode != thefile->rotating->finfo.inode || + new_finfo.device != thefile->rotating->finfo.device) { + + if (thefile->buffered) { + apr_file_flush(thefile); + } + + close(thefile->filedes); + thefile->filedes = -1; + + if (thefile->rotating->perm == APR_FPROT_OS_DEFAULT) { + thefile->filedes = open(thefile->fname, + thefile->rotating->oflags, + 0666); + } + else { + thefile->filedes = open(thefile->fname, + thefile->rotating->oflags, + apr_unix_perms2mode(thefile->rotating->perm)); + } + + if (thefile->filedes < 0) { + rv = errno; + } + else { + rv = apr_file_info_get(&thefile->rotating->finfo, + APR_FINFO_DEV|APR_FINFO_INODE, + thefile); + } + } + + apr_pool_destroy(tmp_pool); + thefile->rotating->lastcheck = now; + } + return rv; +} + +static apr_status_t file_rotating_check(apr_file_t *thefile) { - ap_size_t rv; + if (thefile->rotating && thefile->rotating->manual == 0) { + apr_time_t now = apr_time_sec(apr_time_now()); + return do_rotating_check(thefile, now); + } + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_file_rotating_check(apr_file_t *thefile) +{ + if (thefile->rotating) { + apr_time_t now = apr_time_sec(apr_time_now()); + return do_rotating_check(thefile, now); + } + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_file_rotating_manual_check(apr_file_t *thefile, apr_time_t n) +{ + if (thefile->rotating) { + return do_rotating_check(thefile, n); + } + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_file_write(apr_file_t *thefile, const void *buf, apr_size_t *nbytes) +{ + apr_size_t rv; + + rv = file_rotating_check(thefile); + if (rv != APR_SUCCESS) { + return rv; + } if (thefile->buffered) { char *pos = (char *)buf; int blocksize; int size = *nbytes; -#if APR_HAS_THREADS - ap_lock(thefile->thlock); -#endif + file_lock(thefile); if ( thefile->direction == 0 ) { /* Position file pointer for writing at the offset we are * logically reading from */ - ap_int64_t offset = thefile->filePtr - thefile->dataRead + thefile->bufpos; + apr_int64_t offset = thefile->filePtr - thefile->dataRead + thefile->bufpos; if (offset != thefile->filePtr) lseek(thefile->filedes, offset, SEEK_SET); thefile->bufpos = thefile->dataRead = 0; thefile->direction = 1; } - rv = 0; + rv = 0; while (rv == 0 && size > 0) { - if (thefile->bufpos == APR_FILE_BUFSIZE) /* write buffer is full*/ - ap_flush(thefile); + if (thefile->bufpos == thefile->bufsize) /* write buffer is full*/ + rv = apr_file_flush_locked(thefile); - blocksize = size > APR_FILE_BUFSIZE - thefile->bufpos ? - APR_FILE_BUFSIZE - thefile->bufpos : size; - memcpy(thefile->buffer + thefile->bufpos, pos, blocksize); thefile->bufpos += blocksize; + blocksize = size > thefile->bufsize - thefile->bufpos ? + thefile->bufsize - thefile->bufpos : size; + memcpy(thefile->buffer + thefile->bufpos, pos, blocksize); + thefile->bufpos += blocksize; pos += blocksize; size -= blocksize; } -#if APR_HAS_THREADS - ap_unlock(thefile->thlock); -#endif + file_unlock(thefile); + return rv; } else { do { rv = write(thefile->filedes, buf, *nbytes); - } while (rv == (ap_size_t)-1 && errno == EINTR); - - if (rv == (ap_size_t)-1 && + } while (rv == (apr_size_t)-1 && errno == EINTR); +#ifdef USE_WAIT_FOR_IO + if (rv == (apr_size_t)-1 && (errno == EAGAIN || errno == EWOULDBLOCK) && thefile->timeout != 0) { - ap_status_t arv = wait_for_io_or_timeout(thefile, 0); + apr_status_t arv = apr_wait_for_io_or_timeout(thefile, NULL, 0); if (arv != APR_SUCCESS) { *nbytes = 0; return arv; } else { do { - rv = write(thefile->filedes, buf, *nbytes); - } while (rv == (ap_size_t)-1 && errno == EINTR); + do { + rv = write(thefile->filedes, buf, *nbytes); + } while (rv == (apr_size_t)-1 && errno == EINTR); + if (rv == (apr_size_t)-1 && + (errno == EAGAIN || errno == EWOULDBLOCK)) { + *nbytes /= 2; /* yes, we'll loop if kernel lied + * and we can't even write 1 byte + */ + } + else { + break; + } + } while (1); } } - - if (rv == (ap_size_t)-1) { +#endif + if (rv == (apr_size_t)-1) { (*nbytes) = 0; return errno; } @@ -255,160 +307,271 @@ ap_status_t ap_write(ap_file_t *thefile, void *buf, ap_ssize_t *nbytes) } } -ap_status_t ap_writev(ap_file_t *thefile, const struct iovec *vec, - ap_size_t nvec, ap_ssize_t *nbytes) +APR_DECLARE(apr_status_t) apr_file_writev(apr_file_t *thefile, const struct iovec *vec, + apr_size_t nvec, apr_size_t *nbytes) { #ifdef HAVE_WRITEV - int bytes; + apr_status_t rv; + apr_ssize_t bytes; + + if (thefile->buffered) { + file_lock(thefile); + + rv = apr_file_flush_locked(thefile); + if (rv != APR_SUCCESS) { + file_unlock(thefile); + return rv; + } + if (thefile->direction == 0) { + /* Position file pointer for writing at the offset we are + * logically reading from + */ + apr_int64_t offset = thefile->filePtr - thefile->dataRead + + thefile->bufpos; + if (offset != thefile->filePtr) + lseek(thefile->filedes, offset, SEEK_SET); + thefile->bufpos = thefile->dataRead = 0; + } + + file_unlock(thefile); + } + + rv = file_rotating_check(thefile); + if (rv != APR_SUCCESS) { + return rv; + } if ((bytes = writev(thefile->filedes, vec, nvec)) < 0) { *nbytes = 0; - return errno; + rv = errno; } else { *nbytes = bytes; - return APR_SUCCESS; + rv = APR_SUCCESS; } + return rv; #else + /** + * The problem with trying to output the entire iovec is that we cannot + * maintain the behaviour that a real writev would have. If we iterate + * over the iovec one at a time, we lose the atomic properties of + * writev(). The other option is to combine the entire iovec into one + * buffer that we could then send in one call to write(). This is not + * reasonable since we do not know how much data an iovec could contain. + * + * The only reasonable option, that maintains the semantics of a real + * writev(), is to only write the first iovec. Callers of file_writev() + * must deal with partial writes as they normally would. If you want to + * ensure an entire iovec is written, use apr_file_writev_full(). + */ + *nbytes = vec[0].iov_len; - return ap_write(thefile, vec[0].iov_base, nbytes); + return apr_file_write(thefile, vec[0].iov_base, nbytes); #endif } -ap_status_t ap_putc(char ch, ap_file_t *thefile) +APR_DECLARE(apr_status_t) apr_file_putc(char ch, apr_file_t *thefile) { - if (write(thefile->filedes, &ch, 1) != 1) { - return errno; - } - return APR_SUCCESS; + apr_size_t nbytes = 1; + + return apr_file_write(thefile, &ch, &nbytes); } -ap_status_t ap_ungetc(char ch, ap_file_t *thefile) +APR_DECLARE(apr_status_t) apr_file_ungetc(char ch, apr_file_t *thefile) { thefile->ungetchar = (unsigned char)ch; return APR_SUCCESS; } -ap_status_t ap_getc(char *ch, ap_file_t *thefile) +APR_DECLARE(apr_status_t) apr_file_getc(char *ch, apr_file_t *thefile) { - ssize_t rv; - - if (thefile->ungetchar != -1) { - *ch = (char) thefile->ungetchar; - thefile->ungetchar = -1; - return APR_SUCCESS; - } - rv = read(thefile->filedes, ch, 1); - if (rv == 0) { - thefile->eof_hit = TRUE; - return APR_EOF; - } - else if (rv != 1) { - return errno; - } - return APR_SUCCESS; + apr_size_t nbytes = 1; + + return apr_file_read(thefile, ch, &nbytes); } -ap_status_t ap_puts(char *str, ap_file_t *thefile) +APR_DECLARE(apr_status_t) apr_file_puts(const char *str, apr_file_t *thefile) { - ssize_t rv; - int len; - - len = strlen(str); - rv = write(thefile->filedes, str, len); - if (rv != len) { - return errno; - } - return APR_SUCCESS; + return apr_file_write_full(thefile, str, strlen(str), NULL); } -ap_status_t ap_flush(ap_file_t *thefile) +apr_status_t apr_file_flush_locked(apr_file_t *thefile) { - if (thefile->buffered) { - ap_int64_t written = 0; - int rc = 0; + apr_status_t rv = APR_SUCCESS; - if (thefile->direction == 1 && thefile->bufpos) { - written= write(thefile->filedes, thefile->buffer, thefile->bufpos); - thefile->filePtr += written; + if (thefile->direction == 1 && thefile->bufpos) { + apr_ssize_t written = 0, ret; - if (rc == 0) - thefile->bufpos = 0; + do { + ret = write(thefile->filedes, thefile->buffer + written, + thefile->bufpos - written); + if (ret > 0) + written += ret; + } while (written < thefile->bufpos && + (ret > 0 || (ret == -1 && errno == EINTR))); + if (ret == -1) { + rv = errno; + } else { + thefile->filePtr += written; + thefile->bufpos = 0; } + } + + return rv; +} + +APR_DECLARE(apr_status_t) apr_file_flush(apr_file_t *thefile) +{ + apr_status_t rv = APR_SUCCESS; - return rc; + if (thefile->buffered) { + file_lock(thefile); + rv = apr_file_flush_locked(thefile); + file_unlock(thefile); } /* There isn't anything to do if we aren't buffering the output * so just return success. */ - return APR_SUCCESS; + return rv; } -ap_status_t ap_fgets(char *str, int len, ap_file_t *thefile) +APR_DECLARE(apr_status_t) apr_file_sync(apr_file_t *thefile) { - ssize_t rv; - int i, used_unget = FALSE, beg_idx; + apr_status_t rv = APR_SUCCESS; - if(len <= 1) /* as per fgets() */ - return APR_SUCCESS; + file_lock(thefile); - if(thefile->ungetchar != -1){ - str[0] = thefile->ungetchar; - used_unget = TRUE; - beg_idx = 1; - if(str[0] == '\n' || str[0] == '\r'){ - thefile->ungetchar = -1; - str[1] = '\0'; - return APR_SUCCESS; - } - } else - beg_idx = 0; - - for (i = beg_idx; i < len; i++) { - rv = read(thefile->filedes, &str[i], 1); - if (rv == 0) { - thefile->eof_hit = TRUE; - if(used_unget) thefile->filedes = -1; - str[i] = '\0'; - return APR_EOF; - } - else if (rv != 1) { - return errno; + if (thefile->buffered) { + rv = apr_file_flush_locked(thefile); + + if (rv != APR_SUCCESS) { + file_unlock(thefile); + return rv; } - if (str[i] == '\n' || str[i] == '\r') - break; } - if (i < len-1) - str[i+1] = '\0'; - return APR_SUCCESS; + + if (fsync(thefile->filedes)) { + rv = apr_get_os_error(); + } + + file_unlock(thefile); + + return rv; } -#if 0 /* not currently used */ -static int printf_flush(ap_vformatter_buff_t *vbuff) +APR_DECLARE(apr_status_t) apr_file_datasync(apr_file_t *thefile) { - /* I would love to print this stuff out to the file, but I will - * get that working later. :) For now, just return. - */ - return -1; -} + apr_status_t rv = APR_SUCCESS; + + file_lock(thefile); + + if (thefile->buffered) { + rv = apr_file_flush_locked(thefile); + + if (rv != APR_SUCCESS) { + file_unlock(thefile); + return rv; + } + } + +#ifdef HAVE_FDATASYNC + if (fdatasync(thefile->filedes)) { +#elif defined(F_FULLFSYNC) + if (fcntl(thefile->filedes, F_FULLFSYNC)) { +#else + if (fsync(thefile->filedes)) { #endif + rv = apr_get_os_error(); + } + + file_unlock(thefile); + + return rv; +} -API_EXPORT(int) ap_fprintf(ap_file_t *fptr, const char *format, ...) +APR_DECLARE(apr_status_t) apr_file_gets(char *str, int len, apr_file_t *thefile) { - int cc; - va_list ap; - char *buf; - int len; - - buf = malloc(HUGE_STRING_LEN); - if (buf == NULL) { - return 0; + apr_status_t rv = APR_SUCCESS; /* get rid of gcc warning */ + apr_size_t nbytes; + const char *str_start = str; + char *final = str + len - 1; + + if (len <= 1) { + /* sort of like fgets(), which returns NULL and stores no bytes + */ + return APR_SUCCESS; } - va_start(ap, format); - len = ap_vsnprintf(buf, HUGE_STRING_LEN, format, ap); - cc = ap_puts(buf, fptr); - va_end(ap); - free(buf); - return (cc == APR_SUCCESS) ? len : -1; + + /* If we have an underlying buffer, we can be *much* more efficient + * and skip over the apr_file_read calls. + */ + if (thefile->buffered) { + file_lock(thefile); + + if (thefile->direction == 1) { + rv = apr_file_flush_locked(thefile); + if (rv) { + file_unlock(thefile); + return rv; + } + + thefile->direction = 0; + thefile->bufpos = 0; + thefile->dataRead = 0; + } + + while (str < final) { /* leave room for trailing '\0' */ + /* Force ungetc leftover to call apr_file_read. */ + if (thefile->bufpos < thefile->dataRead && + thefile->ungetchar == -1) { + *str = thefile->buffer[thefile->bufpos++]; + } + else { + nbytes = 1; + rv = file_read_buffered(thefile, str, &nbytes); + if (rv != APR_SUCCESS) { + break; + } + } + if (*str == '\n') { + ++str; + break; + } + ++str; + } + file_unlock(thefile); + } + else { + while (str < final) { /* leave room for trailing '\0' */ + nbytes = 1; + rv = apr_file_read(thefile, str, &nbytes); + if (rv != APR_SUCCESS) { + break; + } + if (*str == '\n') { + ++str; + break; + } + ++str; + } + } + + /* We must store a terminating '\0' if we've stored any chars. We can + * get away with storing it if we hit an error first. + */ + *str = '\0'; + if (str > str_start) { + /* we stored chars; don't report EOF or any other errors; + * the app will find out about that on the next call + */ + return APR_SUCCESS; + } + return rv; } + + +APR_DECLARE(apr_status_t) apr_file_pipe_wait(apr_file_t *thepipe, apr_wait_type_t direction) +{ + return apr_wait_for_io_or_timeout(thepipe, NULL, direction == APR_WAIT_READ); +} diff --git a/file_io/unix/seek.c b/file_io/unix/seek.c index 1fcb0cbab90..2e973377bf8 100644 --- a/file_io/unix/seek.c +++ b/file_io/unix/seek.c @@ -1,98 +1,65 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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 "fileio.h" +#include "apr_arch_file_io.h" -static ap_status_t setptr(ap_file_t *thefile, unsigned long pos ) +static apr_status_t setptr(apr_file_t *thefile, apr_off_t pos ) { - long newbufpos; - int rc; + apr_off_t newbufpos; + apr_status_t rv; if (thefile->direction == 1) { - ap_flush(thefile); + rv = apr_file_flush_locked(thefile); + if (rv) { + return rv; + } thefile->bufpos = thefile->direction = thefile->dataRead = 0; } newbufpos = pos - (thefile->filePtr - thefile->dataRead); if (newbufpos >= 0 && newbufpos <= thefile->dataRead) { thefile->bufpos = newbufpos; - rc = 0; - } + rv = APR_SUCCESS; + } else { - rc = lseek(thefile->filedes, pos, SEEK_SET); - - if (rc != -1 ) { + if (lseek(thefile->filedes, pos, SEEK_SET) != -1) { thefile->bufpos = thefile->dataRead = 0; - rc = 0; + thefile->filePtr = pos; + rv = APR_SUCCESS; } else { - rc = errno; + rv = errno; } } - return rc; + return rv; } -ap_status_t ap_seek(ap_file_t *thefile, ap_seek_where_t where, ap_off_t *offset) +APR_DECLARE(apr_status_t) apr_file_seek(apr_file_t *thefile, apr_seek_where_t where, apr_off_t *offset) { - ap_off_t rv; + apr_off_t rv; + thefile->eof_hit = 0; if (thefile->buffered) { int rc = EINVAL; - ap_finfo_t finfo; + apr_finfo_t finfo; + + file_lock(thefile); switch (where) { case APR_SET: @@ -104,16 +71,19 @@ ap_status_t ap_seek(ap_file_t *thefile, ap_seek_where_t where, ap_off_t *offset) break; case APR_END: - rc = ap_getfileinfo(&finfo, thefile); + rc = apr_file_info_get_locked(&finfo, APR_FINFO_SIZE, thefile); if (rc == APR_SUCCESS) - rc = setptr(thefile, finfo.size - *offset); + rc = setptr(thefile, finfo.size + *offset); break; } - *offset = thefile->filePtr + thefile->bufpos; - return rc; - } else { + *offset = thefile->filePtr - thefile->dataRead + thefile->bufpos; + file_unlock(thefile); + + return rc; + } + else { rv = lseek(thefile->filedes, *offset, where); if (rv == -1) { *offset = -1; @@ -125,3 +95,42 @@ ap_status_t ap_seek(ap_file_t *thefile, ap_seek_where_t where, ap_off_t *offset) } } } + +apr_status_t apr_file_trunc(apr_file_t *fp, apr_off_t offset) +{ + if (fp->buffered) { + int rc = 0; + file_lock(fp); + if (fp->direction == 1 && fp->bufpos != 0) { + apr_off_t len = fp->filePtr + fp->bufpos; + if (offset < len) { + /* New file end fall below our write buffer limit. + * Figure out if and what needs to be flushed. + */ + apr_off_t off = len - offset; + if (off >= 0 && off <= fp->bufpos) + fp->bufpos = fp->bufpos - (size_t)off; + else + fp->bufpos = 0; + } + rc = apr_file_flush_locked(fp); + /* Reset buffer positions for write mode */ + fp->bufpos = fp->direction = fp->dataRead = 0; + } + else if (fp->direction == 0) { + /* Discard the read buffer, as we are about to reposition + * ourselves to the end of file. + */ + fp->bufpos = 0; + fp->dataRead = 0; + } + file_unlock(fp); + if (rc) { + return rc; + } + } + if (ftruncate(fp->filedes, offset) == -1) { + return errno; + } + return apr_file_seek(fp, APR_SET, &offset); +} diff --git a/file_io/unix/tempdir.c b/file_io/unix/tempdir.c new file mode 100644 index 00000000000..22325eff1c1 --- /dev/null +++ b/file_io/unix/tempdir.c @@ -0,0 +1,129 @@ +/* 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_file_io.h" +#include "apr_strings.h" +#include "apr_env.h" + + +/* Try to open a temporary file in the temporary dir, write to it, + and then close it. */ +static int test_tempdir(const char *temp_dir, apr_pool_t *p) +{ + apr_file_t *dummy_file; + char *path = apr_pstrcat(p, temp_dir, "/apr-tmp.XXXXXX", NULL); + + if (apr_file_mktemp(&dummy_file, path, 0, p) == APR_SUCCESS) { + if (apr_file_putc('!', dummy_file) == APR_SUCCESS) { + if (apr_file_close(dummy_file) == APR_SUCCESS) { + return 1; + } + } + } + return 0; +} + + +APR_DECLARE(apr_status_t) apr_temp_dir_get(const char **temp_dir, + apr_pool_t *p) +{ + apr_status_t apr_err; + const char *try_dirs[] = { "/tmp", "/usr/tmp", "/var/tmp" }; + const char *try_envs[] = { "TMPDIR", "TMP", "TEMP"}; + const char *dir; + char *cwd; + int i; + + /* Our goal is to find a temporary directory suitable for writing + into. + Here's the order in which we'll try various paths: + + $TMPDIR + $TMP + $TEMP + "C:\TEMP" (windows only) + "SYS:\TMP" (netware only) + "/tmp" + "/var/tmp" + "/usr/tmp" + P_tmpdir (POSIX define) + `pwd` + + NOTE: This algorithm is basically the same one used by Python + 2.2's tempfile.py module. */ + + /* Try the environment first. */ + for (i = 0; i < (sizeof(try_envs) / sizeof(const char *)); i++) { + char *value; + apr_err = apr_env_get(&value, try_envs[i], p); + if ((apr_err == APR_SUCCESS) && value) { + apr_size_t len = strlen(value); + if (len && (len < APR_PATH_MAX) && test_tempdir(value, p)) { + dir = value; + goto end; + } + } + } + +#ifdef WIN32 + /* Next, on Win32, try the C:\TEMP directory. */ + if (test_tempdir("C:\\TEMP", p)) { + dir = "C:\\TEMP"; + goto end; + } +#endif +#ifdef NETWARE + /* Next, on NetWare, try the SYS:/TMP directory. */ + if (test_tempdir("SYS:/TMP", p)) { + dir = "SYS:/TMP"; + goto end; + } +#endif + + /* Next, try a set of hard-coded paths. */ + for (i = 0; i < (sizeof(try_dirs) / sizeof(const char *)); i++) { + if (test_tempdir(try_dirs[i], p)) { + dir = try_dirs[i]; + goto end; + } + } + +#ifdef P_tmpdir + /* + * If we have it, use the POSIX definition of where + * the tmpdir should be + */ + if (test_tempdir(P_tmpdir, p)) { + dir = P_tmpdir; + goto end; + } +#endif + + /* Finally, try the current working directory. */ + if (APR_SUCCESS == apr_filepath_get(&cwd, APR_FILEPATH_NATIVE, p)) { + if (test_tempdir(cwd, p)) { + dir = cwd; + goto end; + } + } + + /* We didn't find a suitable temp dir anywhere */ + return APR_EGENERAL; + +end: + *temp_dir = apr_pstrdup(p, dir); + return APR_SUCCESS; +} diff --git a/file_io/win32/buffer.c b/file_io/win32/buffer.c new file mode 100644 index 00000000000..1b7d857ca39 --- /dev/null +++ b/file_io/win32/buffer.c @@ -0,0 +1,63 @@ +/* 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_file_io.h" +#include "apr_thread_mutex.h" + +APR_DECLARE(apr_status_t) apr_file_buffer_set(apr_file_t *file, + char * buffer, + apr_size_t bufsize) +{ + apr_status_t rv; + + if (file->flags & APR_FOPEN_XTHREAD) { + apr_thread_mutex_lock(file->mutex); + } + + if(file->buffered) { + /* Flush the existing buffer */ + rv = apr_file_flush(file); + if (rv != APR_SUCCESS) { + apr_thread_mutex_unlock(file->mutex); + return rv; + } + } + + file->buffer = buffer; + file->bufsize = bufsize; + file->buffered = 1; + file->bufpos = 0; + file->direction = 0; + file->dataRead = 0; + + if (file->bufsize == 0) { + /* Setting the buffer size to zero is equivalent to turning + * buffering off. + */ + file->buffered = 0; + } + + if (file->flags & APR_FOPEN_XTHREAD) { + apr_thread_mutex_unlock(file->mutex); + } + + return APR_SUCCESS; +} + +APR_DECLARE(apr_size_t) apr_file_buffer_size_get(apr_file_t *file) +{ + return file->bufsize; +} diff --git a/file_io/win32/dir.c b/file_io/win32/dir.c index a74a5aa90fb..5c30af8fdc3 100644 --- a/file_io/win32/dir.c +++ b/file_io/win32/dir.c @@ -1,207 +1,397 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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. */ -#ifdef HAVE_ERRNO_H +#include "apr.h" +#include "apr_arch_file_io.h" +#include "apr_file_io.h" +#include "apr_strings.h" +#include "apr_portable.h" +#include "apr_arch_atime.h" + +#if APR_HAVE_ERRNO_H #include <errno.h> #endif -#ifdef HAVE_STRING_H +#if APR_HAVE_STRING_H #include <string.h> #endif -#ifdef HAVE_DIRENT_H +#if APR_HAVE_DIRENT_H #include <dirent.h> #endif #ifdef HAVE_SYS_STAT_H #include <sys/stat.h> #endif -#include "fileio.h" -#include "apr_file_io.h" -#include "apr_lib.h" -#include "apr_portable.h" -#include "atime.h" -ap_status_t dir_cleanup(void *thedir) + +static apr_status_t dir_cleanup(void *thedir) { - ap_dir_t *dir = thedir; - if (!CloseHandle(dir->dirhand)) { - return GetLastError(); + apr_dir_t *dir = thedir; + if (dir->dirhand != INVALID_HANDLE_VALUE && !FindClose(dir->dirhand)) { + return apr_get_os_error(); } + dir->dirhand = INVALID_HANDLE_VALUE; return APR_SUCCESS; } -ap_status_t ap_opendir(ap_dir_t **new, const char *dirname, ap_pool_t *cont) +APR_DECLARE(apr_status_t) apr_dir_open(apr_dir_t **new, const char *dirname, + apr_pool_t *pool) { - char * temp; - (*new) = ap_pcalloc(cont, sizeof(ap_dir_t)); - (*new)->cntxt = cont; - (*new)->entry = NULL; - temp = canonical_filename((*new)->cntxt, dirname); - if (temp[strlen(temp)] == '/') { - (*new)->dirname = ap_pstrcat(cont, dirname, "*", NULL); + apr_status_t rv; + + apr_size_t len = strlen(dirname); + (*new) = apr_pcalloc(pool, sizeof(apr_dir_t)); + /* Leave room here to add and pop the '*' wildcard for FindFirstFile + * and double-null terminate so we have one character to change. + */ + (*new)->dirname = apr_palloc(pool, len + 3); + memcpy((*new)->dirname, dirname, len); + if (len && (*new)->dirname[len - 1] != '/') { + (*new)->dirname[len++] = '/'; + } + (*new)->dirname[len++] = '\0'; + (*new)->dirname[len] = '\0'; + +#if APR_HAS_UNICODE_FS + IF_WIN_OS_IS_UNICODE + { + /* Create a buffer for the longest file name we will ever see + */ + (*new)->w.entry = apr_pcalloc(pool, sizeof(WIN32_FIND_DATAW)); + (*new)->name = apr_pcalloc(pool, APR_FILE_MAX * 3 + 1); } - else { - (*new)->dirname = ap_pstrcat(cont, dirname, "/*", NULL); +#endif +#if APR_HAS_ANSI_FS + ELSE_WIN_OS_IS_ANSI + { + /* Note that we won't open a directory that is greater than MAX_PATH, + * counting the additional '/' '*' wildcard suffix. If a * won't fit + * then neither will any other file name within the directory. + * The length not including the trailing '*' is stored as rootlen, to + * skip over all paths which are too long. + */ + if (len >= APR_PATH_MAX) { + (*new) = NULL; + return APR_ENAMETOOLONG; + } + (*new)->n.entry = apr_pcalloc(pool, sizeof(WIN32_FIND_DATAW)); } +#endif + (*new)->rootlen = len - 1; + (*new)->pool = pool; (*new)->dirhand = INVALID_HANDLE_VALUE; - ap_register_cleanup((*new)->cntxt, (void *)(*new), dir_cleanup, - ap_null_cleanup); - return APR_SUCCESS; -} + apr_pool_cleanup_register((*new)->pool, (void *)(*new), dir_cleanup, + apr_pool_cleanup_null); -ap_status_t ap_closedir(ap_dir_t *thedir) -{ - if (!FindClose(thedir->dirhand)) { - return GetLastError(); + rv = apr_dir_read(NULL, 0, *new); + if (rv != APR_SUCCESS) { + dir_cleanup(*new); + *new = NULL; } - ap_kill_cleanup(thedir->cntxt, thedir, dir_cleanup); - return APR_SUCCESS; + + return rv; } -ap_status_t ap_readdir(ap_dir_t *thedir) +APR_DECLARE(apr_status_t) apr_dir_close(apr_dir_t *dir) { - if (thedir->dirhand == INVALID_HANDLE_VALUE) { - thedir->entry = ap_pcalloc(thedir->cntxt, sizeof(WIN32_FIND_DATA)); - thedir->dirhand = FindFirstFile(thedir->dirname, thedir->entry); - if (thedir->dirhand == INVALID_HANDLE_VALUE) { - return GetLastError(); - } - return APR_SUCCESS; - } - if (!FindNextFile(thedir->dirhand, thedir->entry)) { - return GetLastError(); - } - return APR_SUCCESS; + apr_pool_cleanup_kill(dir->pool, dir, dir_cleanup); + return dir_cleanup(dir); } -ap_status_t ap_rewinddir(ap_dir_t *thedir) +APR_DECLARE(apr_status_t) apr_dir_read(apr_finfo_t *finfo, apr_int32_t wanted, + apr_dir_t *thedir) { - ap_status_t stat; - ap_pool_t *cont = thedir->cntxt; - char *temp = ap_pstrdup(cont, thedir->dirname); - temp[strlen(temp) - 2] = '\0'; /*remove the \* at the end */ - if (thedir->dirhand == INVALID_HANDLE_VALUE) { - return APR_SUCCESS; + apr_status_t rv; + char *fname; + /* The while loops below allow us to skip all invalid file names, so that + * we aren't reporting any files where their absolute paths are too long. + */ +#if APR_HAS_UNICODE_FS + apr_wchar_t wdirname[APR_PATH_MAX]; + apr_wchar_t *eos = NULL; + IF_WIN_OS_IS_UNICODE + { + /* This code path is always be invoked by apr_dir_open or + * apr_dir_rewind, so return without filling out the finfo. + */ + if (thedir->dirhand == INVALID_HANDLE_VALUE) + { + apr_status_t rv; + if ((rv = utf8_to_unicode_path(wdirname, sizeof(wdirname) + / sizeof(apr_wchar_t), + thedir->dirname))) { + return rv; + } + eos = wcschr(wdirname, '\0'); + eos[0] = '*'; + eos[1] = '\0'; + thedir->dirhand = FindFirstFileW(wdirname, thedir->w.entry); + eos[0] = '\0'; + if (thedir->dirhand == INVALID_HANDLE_VALUE) { + return apr_get_os_error(); + } + thedir->bof = 1; + return APR_SUCCESS; + } + else if (thedir->bof) { + /* Noop - we already called FindFirstFileW from + * either apr_dir_open or apr_dir_rewind ... use + * that first record. + */ + thedir->bof = 0; + } + else if (!FindNextFileW(thedir->dirhand, thedir->w.entry)) { + return apr_get_os_error(); + } + + while (thedir->rootlen && + thedir->rootlen + wcslen(thedir->w.entry->cFileName) >= APR_PATH_MAX) + { + if (!FindNextFileW(thedir->dirhand, thedir->w.entry)) { + return apr_get_os_error(); + } + } + if ((rv = unicode_to_utf8_path(thedir->name, APR_FILE_MAX * 3 + 1, + thedir->w.entry->cFileName))) + return rv; + fname = thedir->name; } - if ((stat = ap_closedir(thedir)) == APR_SUCCESS) { - if ((stat = ap_opendir(&thedir, temp, cont)) == APR_SUCCESS) { - ap_readdir(thedir); +#endif +#if APR_HAS_ANSI_FS + ELSE_WIN_OS_IS_ANSI + { + /* This code path is always be invoked by apr_dir_open or + * apr_dir_rewind, so return without filling out the finfo. + */ + if (thedir->dirhand == INVALID_HANDLE_VALUE) { + /* '/' terminated, so add the '*' and pop it when we finish */ + char *eop = strchr(thedir->dirname, '\0'); + eop[0] = '*'; + eop[1] = '\0'; + thedir->dirhand = FindFirstFileA(thedir->dirname, + thedir->n.entry); + eop[0] = '\0'; + if (thedir->dirhand == INVALID_HANDLE_VALUE) { + return apr_get_os_error(); + } + thedir->bof = 1; return APR_SUCCESS; } + else if (thedir->bof) { + /* Noop - we already called FindFirstFileW from + * either apr_dir_open or apr_dir_rewind ... use + * that first record. + */ + thedir->bof = 0; + } + else if (!FindNextFileA(thedir->dirhand, thedir->n.entry)) { + return apr_get_os_error(); + } + while (thedir->rootlen && + thedir->rootlen + strlen(thedir->n.entry->cFileName) >= MAX_PATH) + { + if (!FindNextFileA(thedir->dirhand, thedir->n.entry)) { + return apr_get_os_error(); + } + } + fname = thedir->n.entry->cFileName; } - return stat; -} +#endif -ap_status_t ap_make_dir(const char *path, ap_fileperms_t perm, ap_pool_t *cont) -{ - if (!CreateDirectory(path, NULL)) { - return GetLastError(); + fillin_fileinfo(finfo, (WIN32_FILE_ATTRIBUTE_DATA *) thedir->w.entry, + 0, wanted); + finfo->pool = thedir->pool; + + finfo->valid |= APR_FINFO_NAME; + finfo->name = fname; + + if (wanted &= ~finfo->valid) { + /* Go back and get more_info if we can't answer the whole inquiry + */ +#if APR_HAS_UNICODE_FS + IF_WIN_OS_IS_UNICODE + { + /* Almost all our work is done. Tack on the wide file name + * to the end of the wdirname (already / delimited) + */ + if (!eos) + eos = wcschr(wdirname, '\0'); + wcscpy(eos, thedir->w.entry->cFileName); + rv = more_finfo(finfo, wdirname, wanted, MORE_OF_WFSPEC); + eos[0] = '\0'; + return rv; + } +#endif +#if APR_HAS_ANSI_FS + ELSE_WIN_OS_IS_ANSI + { +#if APR_HAS_UNICODE_FS + /* Don't waste stack space on a second buffer, the one we set + * aside for the wide directory name is twice what we need. + */ + char *fspec = (char*)wdirname; +#else + char fspec[APR_PATH_MAX]; +#endif + apr_size_t dirlen = strlen(thedir->dirname); + if (dirlen >= sizeof(fspec)) + dirlen = sizeof(fspec) - 1; + apr_cpystrn(fspec, thedir->dirname, sizeof(fspec)); + apr_cpystrn(fspec + dirlen, fname, sizeof(fspec) - dirlen); + return more_finfo(finfo, fspec, wanted, MORE_OF_FSPEC); + } +#endif } + return APR_SUCCESS; } -ap_status_t ap_remove_dir(const char *path, ap_pool_t *cont) +APR_DECLARE(apr_status_t) apr_dir_rewind(apr_dir_t *dir) { - char *temp = canonical_filename(cont, path); - if (!RemoveDirectory(temp)) { - return GetLastError(); - } - return APR_SUCCESS; + apr_status_t rv; + + /* this will mark the handle as invalid and we'll open it + * again if apr_dir_read() is subsequently called + */ + rv = dir_cleanup(dir); + + if (rv == APR_SUCCESS) + rv = apr_dir_read(NULL, 0, dir); + + return rv; } -ap_status_t ap_dir_entry_size(ap_ssize_t *size, ap_dir_t *thedir) +APR_DECLARE(apr_status_t) apr_dir_make(const char *path, apr_fileperms_t perm, + apr_pool_t *pool) { - if (thedir == NULL || thedir->entry == NULL) { - return APR_ENODIR; +#if APR_HAS_UNICODE_FS + IF_WIN_OS_IS_UNICODE + { + apr_wchar_t wpath[APR_PATH_MAX]; + apr_status_t rv; + if ((rv = utf8_to_unicode_path(wpath, + sizeof(wpath) / sizeof(apr_wchar_t), + path))) { + return rv; + } + if (!CreateDirectoryW(wpath, NULL)) { + return apr_get_os_error(); + } } - (*size) = (thedir->entry->nFileSizeHigh * MAXDWORD) + - thedir->entry->nFileSizeLow; +#endif +#if APR_HAS_ANSI_FS + ELSE_WIN_OS_IS_ANSI + if (!CreateDirectory(path, NULL)) { + return apr_get_os_error(); + } +#endif return APR_SUCCESS; } -ap_status_t ap_dir_entry_mtime(ap_time_t *time, ap_dir_t *thedir) + +static apr_status_t dir_make_parent(char *path, + apr_fileperms_t perm, + apr_pool_t *pool) { - if (thedir == NULL || thedir->entry == NULL) { - return APR_ENODIR; + apr_status_t rv; + char *ch = strrchr(path, '\\'); + if (!ch) { + return APR_ENOENT; } - FileTimeToAprTime(time, &thedir->entry->ftLastWriteTime); - return APR_SUCCESS; + + *ch = '\0'; + rv = apr_dir_make (path, perm, pool); /* Try to make straight off */ + + if (APR_STATUS_IS_ENOENT(rv)) { /* Missing an intermediate dir */ + rv = dir_make_parent(path, perm, pool); + + if (rv == APR_SUCCESS || APR_STATUS_IS_EEXIST(rv)) { + rv = apr_dir_make(path, perm, pool); /* And complete the path */ + } + } + + *ch = '\\'; /* Always replace the slash before returning */ + return rv; } - -ap_status_t ap_dir_entry_ftype(ap_filetype_e *type, ap_dir_t *thedir) + +APR_DECLARE(apr_status_t) apr_dir_make_recursive(const char *path, + apr_fileperms_t perm, + apr_pool_t *pool) { - switch(thedir->entry->dwFileAttributes) { - case FILE_ATTRIBUTE_DIRECTORY: { - (*type) = APR_DIR; - return APR_SUCCESS; - } - case FILE_ATTRIBUTE_NORMAL: { - (*type) = APR_REG; - return APR_SUCCESS; - } - default: { - (*type) = APR_REG; /* As valid as anything else.*/ - return APR_SUCCESS; + apr_status_t rv = 0; + + rv = apr_dir_make (path, perm, pool); /* Try to make PATH right out */ + + if (APR_STATUS_IS_ENOENT(rv)) { /* Missing an intermediate dir */ + char *dir; + + rv = apr_filepath_merge(&dir, "", path, APR_FILEPATH_NATIVE, pool); + + if (rv != APR_SUCCESS) + return rv; + + rv = dir_make_parent(dir, perm, pool); /* Make intermediate dirs */ + + if (rv == APR_SUCCESS || APR_STATUS_IS_EEXIST(rv)) { + rv = apr_dir_make (dir, perm, pool); /* And complete the path */ + + if (APR_STATUS_IS_EEXIST(rv)) { + rv = APR_SUCCESS; /* Timing issue; see comment below */ + } + } } + else if (APR_STATUS_IS_EEXIST(rv)) { + /* + * It's OK if PATH exists. Timing issues can lead to the + * second apr_dir_make being called on existing dir, therefore + * this check has to come last. + */ + rv = APR_SUCCESS; } + + return rv; } -ap_status_t ap_get_dir_filename(char **new, ap_dir_t *thedir) + +APR_DECLARE(apr_status_t) apr_dir_remove(const char *path, apr_pool_t *pool) { - (*new) = ap_pstrdup(thedir->cntxt, thedir->entry->cFileName); +#if APR_HAS_UNICODE_FS + IF_WIN_OS_IS_UNICODE + { + apr_wchar_t wpath[APR_PATH_MAX]; + apr_status_t rv; + if ((rv = utf8_to_unicode_path(wpath, + sizeof(wpath) / sizeof(apr_wchar_t), + path))) { + return rv; + } + if (!RemoveDirectoryW(wpath)) { + return apr_get_os_error(); + } + } +#endif +#if APR_HAS_ANSI_FS + ELSE_WIN_OS_IS_ANSI + if (!RemoveDirectory(path)) { + return apr_get_os_error(); + } +#endif return APR_SUCCESS; } -ap_status_t ap_get_os_dir(ap_os_dir_t **thedir, ap_dir_t *dir) +APR_DECLARE(apr_status_t) apr_os_dir_get(apr_os_dir_t **thedir, + apr_dir_t *dir) { if (dir == NULL) { return APR_ENODIR; @@ -210,15 +400,9 @@ ap_status_t ap_get_os_dir(ap_os_dir_t **thedir, ap_dir_t *dir) return APR_SUCCESS; } -ap_status_t ap_put_os_dir(ap_dir_t **dir, ap_os_dir_t *thedir, ap_pool_t *cont) +APR_DECLARE(apr_status_t) apr_os_dir_put(apr_dir_t **dir, + apr_os_dir_t *thedir, + apr_pool_t *pool) { - if (cont == NULL) { - return APR_ENOPOOL; - } - if ((*dir) == NULL) { - (*dir) = (ap_dir_t *)ap_pcalloc(cont, sizeof(ap_dir_t)); - (*dir)->cntxt = cont; - } - (*dir)->dirhand = thedir; - return APR_SUCCESS; + return APR_ENOTIMPL; } diff --git a/file_io/win32/fileacc.c b/file_io/win32/fileacc.c deleted file mode 100644 index 7edb8e3edf5..00000000000 --- a/file_io/win32/fileacc.c +++ /dev/null @@ -1,141 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#include "fileio.h" -#include "apr_file_io.h" -#include "apr_general.h" -#include "apr_lib.h" -#include <errno.h> -#include <string.h> -#include <sys/types.h> - -/* A file to put ALL of the accessor functions for ap_file_t types. */ - -ap_status_t ap_get_filename(char **new, ap_file_t *thefile) -{ - if (thefile != NULL) { - *new = ap_pstrdup(thefile->cntxt, thefile->fname); - return APR_SUCCESS; - } - else { - *new = NULL; - return APR_ENOFILE; - } -} - -/*mode_t get_fileperms(ap_fileperms_t mode) -{ - mode_t rv = 0; - - if (mode & APR_UREAD) - rv |= S_IRUSR; - if (mode & APR_UWRITE) - rv |= S_IWUSR; - if (mode & APR_UEXECUTE) - rv |= S_IXUSR; - - if (mode & APR_GREAD) - rv |= S_IRGRP; - if (mode & APR_GWRITE) - rv |= S_IWGRP; - if (mode & APR_GEXECUTE) - rv |= S_IXGRP; - - if (mode & APR_WREAD) - rv |= S_IROTH; - if (mode & APR_WWRITE) - rv |= S_IWOTH; - if (mode & APR_WEXECUTE) - rv |= S_IXOTH; - - return rv; -}*/ - - -/* -ap_status_t ap_get_fileperms(ap_fileperms_t *perm, ap_file_t *file) -{ - if (file != NULL) { - *perm = file->protection; - return APR_SUCCESS; - } - else { - *perm = -1; - return APR_ENOFILE; - } -} -*/ - -ap_status_t ap_get_filedata(void **data, char *key, ap_file_t *file) -{ - if (file != NULL) { - return ap_get_userdata(data, key, file->cntxt); - } - else { - data = NULL; - return APR_ENOFILE; - } -} - -ap_status_t ap_set_filedata(ap_file_t *file, void *data, char *key, - ap_status_t (*cleanup) (void *)) -{ - if (file != NULL) { - return ap_set_userdata(data, key, cleanup, file->cntxt); - } - else { - data = NULL; - return APR_ENOFILE; - } -} diff --git a/file_io/win32/filedup.c b/file_io/win32/filedup.c index 012a523dc77..eaafaff4290 100644 --- a/file_io/win32/filedup.c +++ b/file_io/win32/filedup.c @@ -1,120 +1,229 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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 "fileio.h" +#include "apr_arch_file_io.h" #include "apr_file_io.h" #include "apr_general.h" -#include "apr_lib.h" +#include "apr_strings.h" #include <string.h> +#include "apr_arch_inherit.h" +#include <io.h> /* for [_open/_get]_osfhandle */ + -ap_status_t ap_dupfile(ap_file_t **new_file, ap_file_t *old_file, ap_pool_t *p) +APR_DECLARE(apr_status_t) apr_file_dup(apr_file_t **new_file, + apr_file_t *old_file, apr_pool_t *p) { - HANDLE hCurrentProcess = GetCurrentProcess(); +#ifdef _WIN32_WCE + return APR_ENOTIMPL; +#else + HANDLE hproc = GetCurrentProcess(); + HANDLE newhand = NULL; - if ((*new_file) == NULL) { - if (p == NULL) { - p = old_file->cntxt; - } - - (*new_file) = (ap_file_t *) ap_pcalloc(p, - sizeof(ap_file_t)); - if ((*new_file) == NULL) { - return APR_ENOMEM; + if (!DuplicateHandle(hproc, old_file->filehand, + hproc, &newhand, 0, FALSE, + DUPLICATE_SAME_ACCESS)) { + return apr_get_os_error(); + } + + (*new_file) = (apr_file_t *) apr_pcalloc(p, sizeof(apr_file_t)); + (*new_file)->filehand = newhand; + (*new_file)->flags = old_file->flags & ~(APR_STD_FLAGS | APR_INHERIT); + (*new_file)->pool = p; + (*new_file)->fname = apr_pstrdup(p, old_file->fname); + (*new_file)->append = old_file->append; + (*new_file)->buffered = FALSE; + (*new_file)->ungetchar = old_file->ungetchar; + +#if APR_HAS_THREADS + if (old_file->mutex) { + apr_thread_mutex_create(&((*new_file)->mutex), + APR_THREAD_MUTEX_DEFAULT, p); + } +#endif + + apr_pool_cleanup_register((*new_file)->pool, (void *)(*new_file), file_cleanup, + apr_pool_cleanup_null); + +#if APR_FILES_AS_SOCKETS + /* Create a pollset with room for one descriptor. */ + /* ### check return codes */ + (void) apr_pollset_create(&(*new_file)->pollset, 1, p, 0); +#endif + return APR_SUCCESS; +#endif /* !defined(_WIN32_WCE) */ +} + +APR_DECLARE(apr_status_t) apr_file_dup2(apr_file_t *new_file, + apr_file_t *old_file, apr_pool_t *p) +{ +#ifdef _WIN32_WCE + return APR_ENOTIMPL; +#else + HANDLE hproc = GetCurrentProcess(); + HANDLE newhand = NULL; + apr_int32_t newflags; + int fd; + + if (new_file->flags & APR_STD_FLAGS) + { + if ((new_file->flags & APR_STD_FLAGS) == APR_STDERR_FLAG) + { + /* Flush stderr and unset its buffer, then commit the fd-based buffer. + * This is typically a noop for Win2K/XP since services with NULL std + * handles [but valid FILE *'s, oddly enough], but is required + * for NT 4.0 and to use this code outside of services. + */ + fflush(stderr); + setvbuf(stderr, NULL, _IONBF, 0); + if (!_isatty(2)) { + _commit(2 /* stderr */); + } + + /* Clone a handle can _close() without harming the source handle, + * open an MSVCRT-based pseudo-fd for the file handle, then dup2 + * and close our temporary pseudo-fd once it's been duplicated. + * This will incidently keep the FILE-based stderr in sync. + * Note the apparently redundant _O_BINARY coersions are required. + * Note the _dup2 will close the previous std Win32 handle. + */ + if (!DuplicateHandle(hproc, old_file->filehand, hproc, &newhand, + 0, FALSE, DUPLICATE_SAME_ACCESS)) { + return apr_get_os_error(); + } + fd = _open_osfhandle((INT_PTR)newhand, _O_WRONLY | _O_BINARY); + _dup2(fd, 2); + _close(fd); + _setmode(2, _O_BINARY); + + /* hPipeWrite was _close()'ed above, and _dup2()'ed + * to fd 2 creating a new, inherited Win32 handle. + * Recover that real handle from fd 2. Note that + * SetStdHandle(STD_ERROR_HANDLE, _get_osfhandle(2)) + * is implicit in the dup2() call above + */ + newhand = (HANDLE)_get_osfhandle(2); } - if (!DuplicateHandle(hCurrentProcess, old_file->filehand, - hCurrentProcess, - &(*new_file)->filehand, 0, FALSE, - DUPLICATE_SAME_ACCESS)) { - return GetLastError(); + else if ((new_file->flags & APR_STD_FLAGS) == APR_STDOUT_FLAG) { + /* For the process flow see the stderr case above */ + fflush(stdout); + setvbuf(stdout, NULL, _IONBF, 0); + if (!_isatty(1)) { + _commit(1 /* stdout */); + } + + if (!DuplicateHandle(hproc, old_file->filehand, hproc, &newhand, + 0, FALSE, DUPLICATE_SAME_ACCESS)) { + return apr_get_os_error(); + } + fd = _open_osfhandle((INT_PTR)newhand, _O_WRONLY | _O_BINARY); + _dup2(fd, 1); + _close(fd); + _setmode(1, _O_BINARY); + newhand = (HANDLE)_get_osfhandle(1); } - } else { - HANDLE hFile = (*new_file)->filehand; - /* dup2 is not supported with native Windows handles. We - * can, however, emulate dup2 for the standard i/o handles. - */ - if (hFile == GetStdHandle(STD_ERROR_HANDLE)) { - if (!SetStdHandle(STD_ERROR_HANDLE, old_file->filehand)) - return GetLastError(); + else if ((new_file->flags & APR_STD_FLAGS) == APR_STDIN_FLAG) { + /* For the process flow see the stderr case above */ + fflush(stdin); + setvbuf(stdin, NULL, _IONBF, 0); + + if (!DuplicateHandle(hproc, old_file->filehand, hproc, &newhand, + 0, FALSE, DUPLICATE_SAME_ACCESS)) { + return apr_get_os_error(); + } + fd = _open_osfhandle((INT_PTR)newhand, _O_RDONLY | _O_BINARY); + _dup2(fd, 0); + _close(fd); + _setmode(0, _O_BINARY); + newhand = (HANDLE)_get_osfhandle(0); } - else if (hFile == GetStdHandle(STD_OUTPUT_HANDLE)) { - if (!SetStdHandle(STD_OUTPUT_HANDLE, old_file->filehand)) - return GetLastError(); + newflags = (new_file->flags & APR_STD_FLAGS) + | (old_file->flags & ~APR_STD_FLAGS) | APR_INHERIT; + + /* No need to close the old file, _dup2() above did that for us */ + } + else { + if (!DuplicateHandle(hproc, old_file->filehand, + hproc, &newhand, 0, + FALSE, DUPLICATE_SAME_ACCESS)) { + return apr_get_os_error(); } - else if (hFile == GetStdHandle(STD_INPUT_HANDLE)) { - if (!SetStdHandle(STD_INPUT_HANDLE, old_file->filehand)) - return GetLastError(); + newflags = old_file->flags & ~(APR_STD_FLAGS | APR_INHERIT); + + if (new_file->filehand + && (new_file->filehand != INVALID_HANDLE_VALUE)) { + CloseHandle(new_file->filehand); } - else - return APR_ENOTIMPL; } - (*new_file)->cntxt = old_file->cntxt; - (*new_file)->fname = ap_pstrdup(old_file->cntxt, old_file->fname); - (*new_file)->demonfname = ap_pstrdup(old_file->cntxt, old_file->demonfname); - (*new_file)->lowerdemonfname = ap_pstrdup(old_file->cntxt, old_file->lowerdemonfname); - (*new_file)->append = old_file->append; -/* (*new_file)->protection = old_file->protection; - (*new_file)->user = old_file->user; - (*new_file)->group = old_file->group;*/ - (*new_file)->size = old_file->size; - (*new_file)->atime = old_file->atime; - (*new_file)->mtime = old_file->mtime; - (*new_file)->ctime = old_file->ctime; - ap_register_cleanup((*new_file)->cntxt, (void *)(*new_file), file_cleanup, - ap_null_cleanup); + new_file->flags = newflags; + new_file->filehand = newhand; + new_file->fname = apr_pstrdup(new_file->pool, old_file->fname); + new_file->append = old_file->append; + new_file->buffered = FALSE; + new_file->ungetchar = old_file->ungetchar; + +#if APR_HAS_THREADS + if (old_file->mutex) { + apr_thread_mutex_create(&(new_file->mutex), + APR_THREAD_MUTEX_DEFAULT, p); + } +#endif return APR_SUCCESS; +#endif /* !defined(_WIN32_WCE) */ } +APR_DECLARE(apr_status_t) apr_file_setaside(apr_file_t **new_file, + apr_file_t *old_file, + apr_pool_t *p) +{ + *new_file = (apr_file_t *)apr_pmemdup(p, old_file, sizeof(apr_file_t)); + (*new_file)->pool = p; + if (old_file->buffered) { + (*new_file)->buffer = apr_palloc(p, old_file->bufsize); + (*new_file)->bufsize = old_file->bufsize; + if (old_file->direction == 1) { + memcpy((*new_file)->buffer, old_file->buffer, old_file->bufpos); + } + else { + memcpy((*new_file)->buffer, old_file->buffer, old_file->dataRead); + } + } + if (old_file->mutex) { + apr_thread_mutex_create(&((*new_file)->mutex), + APR_THREAD_MUTEX_DEFAULT, p); + apr_thread_mutex_destroy(old_file->mutex); + } + if (old_file->fname) { + (*new_file)->fname = apr_pstrdup(p, old_file->fname); + } + if (!(old_file->flags & APR_FOPEN_NOCLEANUP)) { + apr_pool_cleanup_register(p, (void *)(*new_file), + file_cleanup, + file_cleanup); + } + + old_file->filehand = INVALID_HANDLE_VALUE; + apr_pool_cleanup_kill(old_file->pool, (void *)old_file, + file_cleanup); +#if APR_FILES_AS_SOCKETS + /* Create a pollset with room for one descriptor. */ + /* ### check return codes */ + (void) apr_pollset_create(&(*new_file)->pollset, 1, p, 0); +#endif + return APR_SUCCESS; +} diff --git a/file_io/win32/fileio.h b/file_io/win32/fileio.h deleted file mode 100644 index 974889dd03a..00000000000 --- a/file_io/win32/fileio.h +++ /dev/null @@ -1,134 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#ifndef FILE_IO_H -#define FILE_IO_H - -#ifdef HAVE_SYS_STAT_H -#include <sys/stat.h> -#endif -#ifdef HAVE_SYS_TYPES_H -#include <sys/types.h> -#endif -#ifdef HAVE_SYS_FCNTL_H -#include <fcntl.h> -#endif -#ifdef HAVE_TIME_H -#include <time.h> -#endif -#ifdef HAVE_DIRENT_H -#include <dirent.h> -#endif -#ifdef HAVE_MALLOC_H -#include <malloc.h> -#endif -#ifdef HAVE_UIO_H -#include <sys/uio.h> -#endif -#include "apr_private.h" -#include "apr_pools.h" -#include "apr_general.h" -#include "apr_file_io.h" -#include "apr_errno.h" - -/* quick run-down of fields in windows' ap_file_t structure that may have - * obvious uses. - * fname -- the filename as passed to the open call. - * dwFileAttricutes -- Attributes used to open the file. - * demonfname -- the canonicalized filename. Used to store the result from - * ap_os_canonicalize_filename. - * lowerdemonfname -- inserted at Ken Parzygnat's request, because of the - * ugly way windows deals with case in the filesystem. - * append -- Windows doesn't support the append concept when opening files. - * APR needs to keep track of this, and always make sure we append - * correctly when writing to a file with this flag set TRUE. - */ - -struct ap_file_t { - ap_pool_t *cntxt; - HANDLE filehand; - char *fname; - DWORD dwFileAttributes; - int eof_hit; - int pipe; - ap_interval_time_t timeout; - int buffered; /* Not currently used on Windows */ - int ungetchar; /* Not used. Last char provided by an unget op. (-1 = no char)*/ - - char *demonfname; - char *lowerdemonfname; - int append; - - off_t size; - ap_time_t atime; - ap_time_t mtime; - ap_time_t ctime; -}; - -struct ap_dir_t { - ap_pool_t *cntxt; - char *dirname; - HANDLE dirhand; - WIN32_FIND_DATA *entry; -}; - -ap_status_t file_cleanup(void *); -/*mode_t get_fileperms(ap_fileperms_t); -*/ -API_EXPORT(char *) ap_os_systemcase_filename(struct ap_pool_t *pCont, - const char *szFile); -char * canonical_filename(struct ap_pool_t *pCont, const char *szFile); - -#endif /* ! FILE_IO_H */ - diff --git a/file_io/win32/filepath.c b/file_io/win32/filepath.c new file mode 100644 index 00000000000..23870bc5461 --- /dev/null +++ b/file_io/win32/filepath.c @@ -0,0 +1,990 @@ +/* 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_arch_file_io.h" +#include "apr_strings.h" +#include "apr_lib.h" +#include <string.h> +#include <ctype.h> + +#ifdef NETWARE +#include <unistd.h> +#include <fsio.h> +#endif + + /* WinNT accepts several odd forms of a 'root' path. Under Unicode + * calls (ApiFunctionW) the //?/C:/foo or //?/UNC/mach/share/foo forms + * are accepted. Ansi and Unicode functions both accept the //./C:/foo + * form under WinNT/2K. Since these forms are handled in the utf-8 to + * unicode translation phase, we don't want the user confused by them, so + * we will accept them but always return the canonical C:/ or //mach/share/ + * + * OS2 appears immune from the nonsense :) + */ + +APR_DECLARE(apr_status_t) apr_filepath_root(const char **rootpath, + const char **inpath, + apr_int32_t flags, + apr_pool_t *p) +{ + const char *testpath = *inpath; + char *newpath; +#ifdef NETWARE + char seperator[2] = { 0, 0}; + char server[APR_PATH_MAX+1]; + char volume[APR_PATH_MAX+1]; + char file[APR_PATH_MAX+1]; + char *volsep = NULL; + int elements; + + if (inpath && *inpath) + volsep = strchr (*inpath, ':'); + else + return APR_EBADPATH; + + if (strlen(*inpath) > APR_PATH_MAX) { + return APR_EBADPATH; + } + + seperator[0] = (flags & APR_FILEPATH_NATIVE) ? '\\' : '/'; + + /* Allocate and initialize each of the segment buffers + */ + server[0] = volume[0] = file[0] = '\0'; + + /* If we don't have a volume separator then don't bother deconstructing + the path since we won't use the deconstructed information anyway. + */ + if (volsep) { + /* Split the inpath into its separate parts. */ + deconstruct(testpath, server, volume, NULL, file, NULL, &elements, PATH_UNDEF); + + /* If we got a volume part then continue splitting out the root. + Otherwise we either have an incomplete or relative path + */ + if (volume && strlen(volume) > 0) { + newpath = apr_pcalloc(p, strlen(server)+strlen(volume)+5); + construct(newpath, server, volume, NULL, NULL, NULL, PATH_NETWARE); + + /* NetWare doesn't add the root slash so we need to add it manually. + */ + strcat(newpath, seperator); + *rootpath = newpath; + + /* Skip the inpath pointer down to the first non-root character + */ + newpath = volsep; + do { + ++newpath; + } while (*newpath && ((*newpath == '/') || (*newpath == '\\'))); + *inpath = newpath; + + /* Need to handle APR_FILEPATH_TRUENAME checking here. */ + + return APR_SUCCESS; + } + else + return APR_EBADPATH; + } + else if ((**inpath == '/') || (**inpath == '\\')) { + /* if we have a root path without a volume then just split + in same manner as unix although this path will be + incomplete. + */ + *rootpath = apr_pstrdup(p, seperator); + do { + ++(*inpath); + } while ((**inpath == '/') || (**inpath == '\\')); + } + else + return APR_ERELATIVE; + + return APR_EINCOMPLETE; + +#else /* ndef(NETWARE) */ + + char seperator[2]; + const char *delim1; + const char *delim2; + + seperator[0] = (flags & APR_FILEPATH_NATIVE) ? '\\' : '/'; + seperator[1] = 0; + + if (testpath[0] == '/' || testpath[0] == '\\') { + if (testpath[1] == '/' || testpath[1] == '\\') { + +#ifdef WIN32 /* //server/share isn't the only // delimited syntax */ + if ((testpath[2] == '?' || testpath[2] == '.') + && (testpath[3] == '/' || testpath[3] == '\\')) { + if (IS_FNCHAR(testpath[4]) && testpath[5] == ':') + { + apr_status_t rv; + testpath += 4; + /* given '//?/C: or //./C: let us try this + * all over again from the drive designator + */ + rv = apr_filepath_root(rootpath, &testpath, flags, p); + if (!rv || rv == APR_EINCOMPLETE) + *inpath = testpath; + return rv; + } + else if (strncasecmp(testpath + 4, "UNC", 3) == 0 + && (testpath[7] == '/' || testpath[7] == '\\') + && (testpath[2] == '?')) { + /* given '//?/UNC/machine/share, a little magic + * at the end makes this all work out by using + * 'C/machine' as the starting point and replacing + * the UNC delimiters with \'s, including the 'C' + */ + testpath += 6; + } + else + /* This must not be a path to a file, but rather + * a volume or device. Die for now. + */ + return APR_EBADPATH; + } +#endif /* WIN32 (non - //server/share syntax) */ + + /* Evaluate path of '//[machine/[share[/]]]' */ + delim1 = testpath + 2; + do { + /* Protect against //X/ where X is illegal */ + if (*delim1 && !IS_FNCHAR(*(delim1++))) + return APR_EBADPATH; + } while (*delim1 && *delim1 != '/' && *delim1 != '\\'); + + if (*delim1) { + apr_status_t rv; + delim2 = delim1 + 1; + while (*delim2 && *delim2 != '/' && *delim2 != '\\') { + /* Protect against //machine/X/ where X is illegal */ + if (!IS_FNCHAR(*(delim2++))) + return APR_EBADPATH; + } + + /* Copy the '//machine/[share[/]]' path, always providing + * an extra byte for the trailing slash. + */ + newpath = apr_pstrmemdup(p, testpath, delim2 - testpath + 1); + + if (delim2 == delim1 + 1) { + /* We found simply \\machine\, so give up already + */ + *rootpath = newpath; + *inpath = delim2; + return APR_EINCOMPLETE; + } + + if (flags & APR_FILEPATH_TRUENAME) { + /* Validate the \\Machine\Share\ designation, + * Win32 will argue about slashed in UNC paths, + * so use backslashes till we finish testing, + * and add the trailing backslash [required]. + * apr_pstrmemdup above guarentees us the new + * trailing null character. + */ + newpath[0] = '\\'; + newpath[1] = '\\'; + newpath[delim1 - testpath] = '\\'; + newpath[delim2 - testpath] = '\\'; + + rv = filepath_root_test(newpath, p); + if (rv) + return rv; + rv = filepath_root_case(&newpath, newpath, p); + if (rv) + return rv; + newpath[0] = seperator[0]; + newpath[1] = seperator[0]; + newpath[delim1 - testpath] = seperator[0]; + newpath[delim2 - testpath] = (*delim2 ? seperator[0] : '\0'); + } + else { + /* Give back the caller's own choice of delimiters + */ + newpath[0] = testpath[0]; + newpath[1] = testpath[1]; + newpath[delim1 - testpath] = *delim1; + newpath[delim2 - testpath] = *delim2; + } + + /* If this root included the trailing / or \ designation + * then lop off multiple trailing slashes and give back + * appropriate delimiters. + */ + if (*delim2) { + *inpath = delim2 + 1; + while (**inpath == '/' || **inpath == '\\') + ++*inpath; + } + else { + *inpath = delim2; + } + + *rootpath = newpath; + return APR_SUCCESS; + } + + /* Have path of '\\[machine]', if the machine is given, + * append same trailing slash as the leading slash + */ + delim1 = strchr(testpath, '\0'); + if (delim1 > testpath + 2) { + newpath = apr_pstrndup(p, testpath, delim1 - testpath + 1); + if (flags & APR_FILEPATH_TRUENAME) + newpath[delim1 - testpath] = seperator[0]; + else + newpath[delim1 - testpath] = newpath[0]; + newpath[delim1 - testpath + 1] = '\0'; + } + else { + newpath = apr_pstrndup(p, testpath, delim1 - testpath); + } + if (flags & APR_FILEPATH_TRUENAME) { + newpath[0] = seperator[0]; + newpath[1] = seperator[0]; + } + *rootpath = newpath; + *inpath = delim1; + return APR_EINCOMPLETE; + } + + /* Left with a path of '/', what drive are we asking about? + */ + *inpath = testpath + 1; + newpath = apr_palloc(p, 2); + if (flags & APR_FILEPATH_TRUENAME) + newpath[0] = seperator[0]; + else + newpath[0] = testpath[0]; + newpath[1] = '\0'; + *rootpath = newpath; + return APR_EINCOMPLETE; + } + + /* Evaluate path of 'd:[/]' */ + if (IS_FNCHAR(*testpath) && testpath[1] == ':') + { + apr_status_t rv; + /* Validate that D:\ drive exists, test must be rooted + * Note that posix/win32 insists a drive letter is upper case, + * so who are we to argue with a 'feature'. + * It is a safe fold, since only A-Z is legal, and has no + * side effects of legal mis-mapped non-us-ascii codes. + */ + newpath = apr_palloc(p, 4); + newpath[0] = testpath[0]; + newpath[1] = testpath[1]; + newpath[2] = seperator[0]; + newpath[3] = '\0'; + if (flags & APR_FILEPATH_TRUENAME) { + newpath[0] = apr_toupper(newpath[0]); + rv = filepath_root_test(newpath, p); + if (rv) + return rv; + } + /* Just give back the root the user handed to us. + */ + if (testpath[2] != '/' && testpath[2] != '\\') { + newpath[2] = '\0'; + *rootpath = newpath; + *inpath = testpath + 2; + return APR_EINCOMPLETE; + } + + /* strip off remaining slashes that designate the root, + * give the caller back their original choice of slash + * unless this is TRUENAME'ed + */ + *inpath = testpath + 3; + while (**inpath == '/' || **inpath == '\\') + ++*inpath; + if (!(flags & APR_FILEPATH_TRUENAME)) + newpath[2] = testpath[2]; + *rootpath = newpath; + return APR_SUCCESS; + } + + /* Nothing interesting */ + return APR_ERELATIVE; + +#endif /* ndef(NETWARE) */ +} + +#if !defined(NETWARE) +static int same_drive(const char *path1, const char *path2) +{ + char drive1 = path1[0]; + char drive2 = path2[0]; + + if (!drive1 || !drive2 || path1[1] != ':' || path2[1] != ':') + return FALSE; + + if (drive1 == drive2) + return TRUE; + + if (drive1 >= 'a' && drive1 <= 'z') + drive1 += 'A' - 'a'; + + if (drive2 >= 'a' && drive2 <= 'z') + drive2 += 'A' - 'a'; + + return (drive1 == drive2); +} +#endif + +APR_DECLARE(apr_status_t) apr_filepath_merge(char **newpath, + const char *basepath, + const char *addpath, + apr_int32_t flags, + apr_pool_t *p) +{ + char path[APR_PATH_MAX]; /* isn't null term */ + const char *baseroot = NULL; + const char *addroot; + apr_size_t rootlen; /* the length of the root portion of path, d:/ is 3 */ + apr_size_t baselen; /* the length of basepath (excluding baseroot) */ + apr_size_t keptlen; /* the length of the retained basepath (incl root) */ + apr_size_t pathlen; /* the length of the result path */ + apr_size_t segend; /* the end of the current segment */ + apr_size_t seglen; /* the length of the segment (excl trailing chars) */ + apr_status_t basetype = 0; /* from parsing the basepath's baseroot */ + apr_status_t addtype; /* from parsing the addpath's addroot */ + apr_status_t rv; +#ifndef NETWARE + int fixunc = 0; /* flag to complete an incomplete UNC basepath */ +#endif + + /* Treat null as an empty path, otherwise split addroot from the addpath + */ + if (!addpath) { + addpath = addroot = ""; + addtype = APR_ERELATIVE; + } + else { + /* This call _should_ test the path + */ + addtype = apr_filepath_root(&addroot, &addpath, + APR_FILEPATH_TRUENAME + | (flags & APR_FILEPATH_NATIVE), + p); + if (addtype == APR_SUCCESS) { + addtype = APR_EABSOLUTE; + } + else if (addtype == APR_ERELATIVE) { + addroot = ""; + } + else if (addtype != APR_EINCOMPLETE) { + /* apr_filepath_root was incomprehensible so fail already + */ + return addtype; + } + } + + /* If addpath is (even partially) rooted, then basepath is + * unused. Ths violates any APR_FILEPATH_SECUREROOTTEST + * and APR_FILEPATH_NOTABSOLUTE flags specified. + */ + if (addtype == APR_EABSOLUTE || addtype == APR_EINCOMPLETE) + { + if (flags & APR_FILEPATH_SECUREROOTTEST) + return APR_EABOVEROOT; + if (flags & APR_FILEPATH_NOTABSOLUTE) + return addtype; + } + + /* Optimized tests before we query the current working path + */ + if (!basepath) { + + /* If APR_FILEPATH_NOTABOVEROOT wasn't specified, + * we won't test the root again, it's ignored. + * Waste no CPU retrieving the working path. + */ + if (addtype == APR_EABSOLUTE && !(flags & APR_FILEPATH_NOTABOVEROOT)) { + basepath = baseroot = ""; + basetype = APR_ERELATIVE; + } + + /* If APR_FILEPATH_NOTABSOLUTE is specified, the caller + * requires an absolutely relative result, So do not retrieve + * the working path. + */ + if (addtype == APR_ERELATIVE && (flags & APR_FILEPATH_NOTABSOLUTE)) { + basepath = baseroot = ""; + basetype = APR_ERELATIVE; + } + } + + if (!basepath) + { + /* Start with the current working path. This is bass akwards, + * but required since the compiler (at least vc) doesn't like + * passing the address of a char const* for a char** arg. + * We must grab the current path of the designated drive + * if addroot is given in drive-relative form (e.g. d:foo) + */ + char *getpath; +#ifndef NETWARE + if (addtype == APR_EINCOMPLETE && addroot[1] == ':') + rv = filepath_drive_get(&getpath, addroot[0], flags, p); + else +#endif + rv = apr_filepath_get(&getpath, flags, p); + if (rv != APR_SUCCESS) + return rv; + basepath = getpath; + } + + if (!baseroot) { + /* This call should _not_ test the path + */ + basetype = apr_filepath_root(&baseroot, &basepath, + (flags & APR_FILEPATH_NATIVE), p); + if (basetype == APR_SUCCESS) { + basetype = APR_EABSOLUTE; + } + else if (basetype == APR_ERELATIVE) { + baseroot = ""; + } + else if (basetype != APR_EINCOMPLETE) { + /* apr_filepath_root was incomprehensible so fail already + */ + return basetype; + } + } + baselen = strlen(basepath); + + /* If APR_FILEPATH_NOTABSOLUTE is specified, the caller + * requires an absolutely relative result. If the given + * basepath is not relative then fail. + */ + if ((flags & APR_FILEPATH_NOTABSOLUTE) && basetype != APR_ERELATIVE) + return basetype; + + /* The Win32 nightmare on unc street... start combining for + * many possible root combinations. + */ + if (addtype == APR_EABSOLUTE) + { + /* Ignore the given root path, and start with the addroot + */ + if ((flags & APR_FILEPATH_NOTABOVEROOT) + && strncmp(baseroot, addroot, strlen(baseroot))) + return APR_EABOVEROOT; + keptlen = 0; + rootlen = pathlen = strlen(addroot); + memcpy(path, addroot, pathlen); + } + else if (addtype == APR_EINCOMPLETE) + { + /* There are several types of incomplete paths, + * incomplete UNC paths (//foo/ or //), + * drives without rooted paths (d: as in d:foo), + * and simple roots (/ as in /foo). + * Deal with these in significantly different manners... + */ +#ifndef NETWARE + if ((addroot[0] == '/' || addroot[0] == '\\') && + (addroot[1] == '/' || addroot[1] == '\\')) + { + /* Ignore the given root path if the incomplete addpath is UNC, + * (note that the final result will be incomplete). + */ + if (flags & APR_FILEPATH_NOTRELATIVE) + return addtype; + if ((flags & APR_FILEPATH_NOTABOVEROOT) + && strncmp(baseroot, addroot, strlen(baseroot))) + return APR_EABOVEROOT; + fixunc = 1; + keptlen = 0; + rootlen = pathlen = strlen(addroot); + memcpy(path, addroot, pathlen); + } + else +#endif + if ((addroot[0] == '/' || addroot[0] == '\\') && !addroot[1]) + { + /* Bring together the drive or UNC root from the baseroot + * if the addpath is a simple root and basepath is rooted, + * otherwise disregard the basepath entirely. + */ + if (basetype != APR_EABSOLUTE && (flags & APR_FILEPATH_NOTRELATIVE)) + return basetype; + if (basetype != APR_ERELATIVE) { +#ifndef NETWARE + if (basetype == APR_INCOMPLETE + && (baseroot[0] == '/' || baseroot[0] == '\\') + && (baseroot[1] == '/' || baseroot[1] == '\\')) + fixunc = 1; +#endif + keptlen = rootlen = pathlen = strlen(baseroot); + memcpy(path, baseroot, pathlen); + } + else { + if (flags & APR_FILEPATH_NOTABOVEROOT) + return APR_EABOVEROOT; + keptlen = 0; + rootlen = pathlen = strlen(addroot); + memcpy(path, addroot, pathlen); + } + } +#ifdef NETWARE + else if (filepath_has_drive(addroot, DRIVE_ONLY, p)) + { + /* If the addroot is a drive (without a volume root) + * use the basepath _if_ it matches this drive letter! + * Otherwise we must discard the basepath. + */ + if (!filepath_compare_drive(addroot, baseroot, p) && + filepath_has_drive(baseroot, 0, p)) { +#else + else if (addroot[0] && addroot[1] == ':' && !addroot[2]) + { + /* If the addroot is a drive (without a volume root) + * use the basepath _if_ it matches this drive letter! + * Otherwise we must discard the basepath. + */ + if (same_drive(addroot, baseroot)) { +#endif + /* Base the result path on the basepath + */ + if (basetype != APR_EABSOLUTE && (flags & APR_FILEPATH_NOTRELATIVE)) + return basetype; + rootlen = strlen(baseroot); + keptlen = pathlen = rootlen + baselen; + if (keptlen >= sizeof(path)) + return APR_ENAMETOOLONG; + memcpy(path, baseroot, rootlen); + memcpy(path + rootlen, basepath, baselen); + } + else { + if (flags & APR_FILEPATH_NOTRELATIVE) + return addtype; + if (flags & APR_FILEPATH_NOTABOVEROOT) + return APR_EABOVEROOT; + keptlen = 0; + rootlen = pathlen = strlen(addroot); + memcpy(path, addroot, pathlen); + } + } + else { + /* Now this is unexpected, we aren't aware of any other + * incomplete path forms! Fail now. + */ + return APR_EBADPATH; + } + } + else { /* addtype == APR_ERELATIVE */ + /* If both paths are relative, fail early + */ + if (basetype != APR_EABSOLUTE && (flags & APR_FILEPATH_NOTRELATIVE)) + return basetype; + +#ifndef NETWARE + /* An incomplete UNC path must be completed + */ + if (basetype == APR_INCOMPLETE + && (baseroot[0] == '/' || baseroot[0] == '\\') + && (baseroot[1] == '/' || baseroot[1] == '\\')) + fixunc = 1; +#endif + + /* Base the result path on the basepath + */ + rootlen = strlen(baseroot); + keptlen = pathlen = rootlen + baselen; + if (keptlen >= sizeof(path)) + return APR_ENAMETOOLONG; + memcpy(path, baseroot, rootlen); + memcpy(path + rootlen, basepath, baselen); + } + + /* '/' terminate the given root path unless it's already terminated + * or is an incomplete drive root. Correct the trailing slash unless + * we have an incomplete UNC path still to fix. + */ + if (pathlen && path[pathlen - 1] != ':') { + if (path[pathlen - 1] != '/' && path[pathlen - 1] != '\\') { + if (pathlen + 1 >= sizeof(path)) + return APR_ENAMETOOLONG; + + path[pathlen++] = ((flags & APR_FILEPATH_NATIVE) ? '\\' : '/'); + } + /* XXX: wrong, but gotta figure out what I intended; + * else if (!fixunc) + * path[pathlen++] = ((flags & APR_FILEPATH_NATIVE) ? '\\' : '/'); + */ + } + + while (*addpath) + { + /* Parse each segment, find the closing '/' + */ + seglen = 0; + while (addpath[seglen] && addpath[seglen] != '/' + && addpath[seglen] != '\\') + ++seglen; + + /* Truncate all trailing spaces and all but the first two dots */ + segend = seglen; + while (seglen && (addpath[seglen - 1] == ' ' + || addpath[seglen - 1] == '.')) { + if (seglen > 2 || addpath[seglen - 1] != '.' || addpath[0] != '.') + --seglen; + else + break; + } + + if (seglen == 0 || (seglen == 1 && addpath[0] == '.')) + { + /* NOTE: win32 _hates_ '/ /' and '/. /' (yes, with spaces in there) + * so eliminate all preconceptions that it is valid. + */ + if (seglen < segend) + return APR_EBADPATH; + +#ifndef NETWARE + /* This isn't legal unless the unc path is completed + */ + if (fixunc) + return APR_EBADPATH; +#endif + + /* Otherwise, this is a noop segment (/ or ./) so ignore it + */ + } + else if (seglen == 2 && addpath[0] == '.' && addpath[1] == '.') + { + /* NOTE: win32 _hates_ '/.. /' (yes, with a space in there) + * and '/..../', some functions treat it as ".", and some + * fail! Eliminate all preconceptions that they are valid. + */ + if (seglen < segend && (seglen != 3 || addpath[2] != '.')) + return APR_EBADPATH; + +#ifndef NETWARE + /* This isn't legal unless the unc path is completed + */ + if (fixunc) + return APR_EBADPATH; +#endif + + /* backpath (../) when an absolute path is given */ + if (rootlen && (pathlen <= rootlen)) + { + /* Attempt to move above root. Always die if the + * APR_FILEPATH_SECUREROOTTEST flag is specified. + */ + if (flags & APR_FILEPATH_SECUREROOTTEST) + return APR_EABOVEROOT; + + /* Otherwise this is simply a noop, above root is root. + */ + } + else if (pathlen == 0 + || (pathlen >= 3 + && (pathlen == 3 + || path[pathlen - 4] == ':' + || path[pathlen - 4] == '/' + || path[pathlen - 4] == '\\') + && path[pathlen - 3] == '.' + && path[pathlen - 2] == '.' + && (path[pathlen - 1] == '/' + || path[pathlen - 1] == '\\'))) + { + /* Verified path is empty, exactly "..[/\]", or ends + * in "[:/\]..[/\]" - these patterns we will not back + * over since they aren't 'prior segements'. + * + * If APR_FILEPATH_SECUREROOTTEST.was given, die now. + */ + if (flags & APR_FILEPATH_SECUREROOTTEST) + return APR_EABOVEROOT; + + /* Otherwise append another backpath. + */ + if (pathlen + 3 >= sizeof(path)) + return APR_ENAMETOOLONG; + path[pathlen++] = '.'; + path[pathlen++] = '.'; + if (addpath[segend]) { + path[pathlen++] = ((flags & APR_FILEPATH_NATIVE) + ? '\\' : ((flags & APR_FILEPATH_TRUENAME) + ? '/' : addpath[segend])); + } + /* The 'root' part of this path now includes the ../ path, + * because that backpath will not be parsed by the truename + * code below. + */ + keptlen = pathlen; + } + else + { + /* otherwise crop the prior segment + */ + do { + --pathlen; + } while (pathlen && path[pathlen - 1] != '/' + && path[pathlen - 1] != '\\'); + + /* Now test if we are above where we started and back up + * the keptlen offset to reflect the added/altered path. + */ + if (pathlen < keptlen) + { + if (flags & APR_FILEPATH_SECUREROOTTEST) + return APR_EABOVEROOT; + keptlen = pathlen; + } + } + } + else /* not empty or dots */ + { +#ifndef NETWARE + if (fixunc) { + const char *testpath = path; + const char *testroot; + apr_status_t testtype; + apr_size_t i = (addpath[segend] != '\0'); + + /* This isn't legal unless the unc path is complete! + */ + if (seglen < segend) + return APR_EBADPATH; + if (pathlen + seglen + 1 >= sizeof(path)) + return APR_ENAMETOOLONG; + memcpy(path + pathlen, addpath, seglen + i); + + /* Always add the trailing slash to a UNC segment + */ + path[pathlen + seglen] = ((flags & APR_FILEPATH_NATIVE) + ? '\\' : '/'); + pathlen += seglen + 1; + + /* Recanonicalize the UNC root with the new UNC segment, + * and if we succeed, reset this test and the rootlen, + * and replace our path with the canonical UNC root path + */ + path[pathlen] = '\0'; + /* This call _should_ test the path + */ + testtype = apr_filepath_root(&testroot, &testpath, + APR_FILEPATH_TRUENAME + | (flags & APR_FILEPATH_NATIVE), + p); + if (testtype == APR_SUCCESS) { + rootlen = pathlen = (testpath - path); + memcpy(path, testroot, pathlen); + fixunc = 0; + } + else if (testtype != APR_EINCOMPLETE) { + /* apr_filepath_root was very unexpected so fail already + */ + return testtype; + } + } + else +#endif + { + /* An actual segment, append it to the destination path + */ + apr_size_t i = (addpath[segend] != '\0'); + if (pathlen + seglen + i >= sizeof(path)) + return APR_ENAMETOOLONG; + memcpy(path + pathlen, addpath, seglen + i); + if (i) + path[pathlen + seglen] = ((flags & APR_FILEPATH_NATIVE) + ? '\\' : '/'); + pathlen += seglen + i; + } + } + + /* Skip over trailing slash to the next segment + */ + if (addpath[segend]) + ++segend; + + addpath += segend; + } + + /* keptlen will be the baselen unless the addpath contained + * backpath elements. If so, and APR_FILEPATH_NOTABOVEROOT + * is specified (APR_FILEPATH_SECUREROOTTEST was caught above), + * compare the string beyond the root to assure the result path + * is still within given basepath. Note that the root path + * segment is thoroughly tested prior to path parsing. + */ + if ((flags & APR_FILEPATH_NOTABOVEROOT) && baselen) { + if (memcmp(basepath, path + rootlen, baselen) != 0) + return APR_EABOVEROOT; + + /* Ahem... if we have a basepath without a trailing slash, + * we better be sure that /foo wasn't replaced with /foobar! + */ + if (basepath[baselen - 1] != '/' && basepath[baselen - 1] != '\\' + && path[rootlen + baselen] && path[rootlen + baselen] != '/' + && path[rootlen + baselen] != '\\') + return APR_EABOVEROOT; + } + + if (addpath && (flags & APR_FILEPATH_TRUENAME)) { + /* We can always skip the root, it's already true-named. */ + if (rootlen > keptlen) + keptlen = rootlen; + if ((path[keptlen] == '/') || (path[keptlen] == '\\')) { + /* By rights, keptlen may grown longer than pathlen. + * we wont' use it again (in that case) so we don't care. + */ + ++keptlen; + } + /* Go through all the new segments */ + while (keptlen < pathlen) { + apr_finfo_t finfo; + char saveslash = 0; + seglen = 0; + /* find any slash and set it aside for a minute. */ + for (seglen = 0; keptlen + seglen < pathlen; ++seglen) { + if ((path[keptlen + seglen] == '/') || + (path[keptlen + seglen] == '\\')) { + saveslash = path[keptlen + seglen]; + break; + } + } + /* Null term for stat! */ + path[keptlen + seglen] = '\0'; + if ((rv = apr_stat(&finfo, path, + APR_FINFO_LINK | APR_FINFO_TYPE | APR_FINFO_NAME, p)) + == APR_SUCCESS) { + apr_size_t namelen = strlen(finfo.name); + +#if defined(OS2) /* only has case folding, never aliases that change the length */ + + if (memcmp(finfo.name, path + keptlen, seglen) != 0) { + memcpy(path + keptlen, finfo.name, namelen); + } +#else /* WIN32 || NETWARE; here there be aliases that gire and gimble and change length */ + + if ((namelen != seglen) || + (memcmp(finfo.name, path + keptlen, seglen) != 0)) + { + if (namelen <= seglen) { + memcpy(path + keptlen, finfo.name, namelen); + if ((namelen < seglen) && saveslash) { + memmove(path + keptlen + namelen + 1, + path + keptlen + seglen + 1, + pathlen - keptlen - seglen); + } + pathlen += namelen - seglen; + seglen = namelen; + } + else { /* namelen > seglen */ + if (pathlen + namelen - seglen >= sizeof(path)) + return APR_ENAMETOOLONG; + if (saveslash) { + memmove(path + keptlen + namelen + 1, + path + keptlen + seglen + 1, + pathlen - keptlen - seglen); + } + memcpy(path + keptlen, finfo.name, namelen); + pathlen += namelen - seglen; + seglen = namelen; + } + } +#endif /* !OS2 (Whatever that alias was we're over it) */ + + /* That's it, the rest is path info. + * I don't know how we aught to handle this. Should + * we define a new error to indicate 'more info'? + * Should we split out the rest of the path? + */ + if ((finfo.filetype != APR_DIR) && + (finfo.filetype != APR_LNK) && saveslash) + rv = APR_ENOTDIR; +#ifdef XXX_FIGURE_THIS_OUT + { + /* the example inserts a null between the end of + * the filename and the next segment, and increments + * the path length so we would return both segments. + */ + if (saveslash) { + keptlen += seglen; + path[keptlen] = saveslash; + if (pathlen + 1 >= sizeof(path)) + return APR_ENAMETOOLONG; + memmove(path + keptlen + 1, + path + keptlen, + pathlen - keptlen); + path[keptlen] = '\0'; + ++pathlen; + break; + } + } +#endif + } + + /* put back the '/' */ + if (saveslash) { + path[keptlen + seglen] = saveslash; + ++seglen; + } + keptlen += seglen; + + if (rv != APR_SUCCESS) { + if (APR_STATUS_IS_ENOENT(rv)) + break; + if (APR_STATUS_IS_EPATHWILD(rv)) + /* This path included wildcards. The path elements + * that did not contain wildcards are canonicalized, + * so we will return the path, although later elements + * don't necessarily exist, and aren't canonical. + */ + break; + else if (APR_STATUS_IS_ENOTDIR(rv)) + /* This is a little more serious, we just added a name + * onto a filename (think http's PATH_INFO) + * If the caller is foolish enough to do this, we expect + * the've already canonicalized the root) that they knew + * what they are doing :( + */ + break; + else + return rv; + } + } + } + + *newpath = apr_pstrmemdup(p, path, pathlen); + return APR_SUCCESS; +} + + +APR_DECLARE(apr_status_t) apr_filepath_encoding(int *style, apr_pool_t *p) +{ +#if APR_HAS_UNICODE_FS + IF_WIN_OS_IS_UNICODE + { + *style = APR_FILEPATH_ENCODING_UTF8; + return APR_SUCCESS; + } +#endif + + *style = APR_FILEPATH_ENCODING_LOCALE; + return APR_SUCCESS; +} diff --git a/file_io/win32/filestat.c b/file_io/win32/filestat.c index 861f12b32e3..ba4160785d6 100644 --- a/file_io/win32/filestat.c +++ b/file_io/win32/filestat.c @@ -1,201 +1,825 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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 <aclapi.h> #include "apr_private.h" -#include "fileio.h" +#include "apr_arch_file_io.h" #include "apr_file_io.h" #include "apr_general.h" +#include "apr_strings.h" #include "apr_errno.h" #include "apr_time.h" #include <sys/stat.h> -#include "atime.h" -#include "misc.h" +#include "apr_arch_atime.h" +#include "apr_arch_misc.h" + +/* We have to assure that the file name contains no '*'s, or other + * wildcards when using FindFirstFile to recover the true file name. + */ +static apr_status_t test_safe_name(const char *name) +{ + /* Only accept ':' in the second position of the filename, + * as the drive letter delimiter: + */ + if (apr_isalpha(*name) && (name[1] == ':')) { + name += 2; + } + while (*name) { + if (!IS_FNCHAR(*name) && (*name != '\\') && (*name != '/')) { + if (*name == '?' || *name == '*') + return APR_EPATHWILD; + else + return APR_EBADPATH; + } + ++name; + } + return APR_SUCCESS; +} -#define S_ISLNK(m) (0) -#define S_ISREG(m) (((m) & (S_IFMT)) == S_IFREG) -#define S_ISDIR(m) (((m) & (S_IFDIR)) == S_IFDIR) +static apr_status_t free_localheap(void *heap) { + LocalFree(heap); + return APR_SUCCESS; +} -static ap_filetype_e filetype_from_mode(int mode) +static apr_gid_t worldid = NULL; + +static void free_world(void) { - ap_filetype_e type = APR_NOFILE; + if (worldid) { + FreeSid(worldid); + worldid = NULL; + } +} - if (S_ISREG(mode)) - type = APR_REG; - if (S_ISDIR(mode)) - type = APR_DIR; - if (S_ISLNK(mode)) - type = APR_LNK; +/* Left bit shifts from World scope to given scope */ +typedef enum prot_scope_e { + prot_scope_world = 0, + prot_scope_group = 4, + prot_scope_user = 8 +} prot_scope_e; - return type; +static apr_fileperms_t convert_prot(ACCESS_MASK acc, prot_scope_e scope) +{ + /* These choices are based on the single filesystem bit that controls + * the given behavior. They are -not- recommended for any set protection + * function, such a function should -set- use GENERIC_READ/WRITE/EXECUTE + */ + apr_fileperms_t prot = 0; + if (acc & FILE_EXECUTE) + prot |= APR_FPROT_WEXECUTE; + if (acc & FILE_WRITE_DATA) + prot |= APR_FPROT_WWRITE; + if (acc & FILE_READ_DATA) + prot |= APR_FPROT_WREAD; + return (prot << scope); } -BOOLEAN is_exe(const char* fname, ap_pool_t *cont) { - const char* exename; - const char* ext; - exename = strrchr(fname, '/'); - if (!exename) { - exename = strrchr(fname, '\\'); + +static void resolve_prot(apr_finfo_t *finfo, apr_int32_t wanted, PACL dacl) +{ + TRUSTEE_W ident = {NULL, NO_MULTIPLE_TRUSTEE, TRUSTEE_IS_SID}; + ACCESS_MASK acc; + /* + * This function is only invoked for WinNT, + * there is no reason for os_level testing here. + */ + if ((wanted & APR_FINFO_WPROT) && !worldid) { + SID_IDENTIFIER_AUTHORITY SIDAuth = {SECURITY_WORLD_SID_AUTHORITY}; + if (AllocateAndInitializeSid(&SIDAuth, 1, SECURITY_WORLD_RID, + 0, 0, 0, 0, 0, 0, 0, &worldid)) + atexit(free_world); + else + worldid = NULL; } - if (!exename) { - exename = fname; + if ((wanted & APR_FINFO_UPROT) && (finfo->valid & APR_FINFO_USER)) { + ident.TrusteeType = TRUSTEE_IS_USER; + ident.ptstrName = finfo->user; + /* GetEffectiveRightsFromAcl isn't supported under Win9x, + * which shouldn't come as a surprize. Since we are passing + * TRUSTEE_IS_SID, always skip the A->W layer. + */ + if (GetEffectiveRightsFromAclW(dacl, &ident, &acc) == ERROR_SUCCESS) { + finfo->protection |= convert_prot(acc, prot_scope_user); + finfo->valid |= APR_FINFO_UPROT; + } } - else { - exename++; + /* Windows NT: did not return group rights. + * Windows 2000 returns group rights information. + * Since WinNT kernels don't follow the unix model of + * group associations, this all all pretty mute. + */ + if ((wanted & APR_FINFO_GPROT) && (finfo->valid & APR_FINFO_GROUP)) { + ident.TrusteeType = TRUSTEE_IS_GROUP; + ident.ptstrName = finfo->group; + if (GetEffectiveRightsFromAclW(dacl, &ident, &acc) == ERROR_SUCCESS) { + finfo->protection |= convert_prot(acc, prot_scope_group); + finfo->valid |= APR_FINFO_GPROT; + } + } + if ((wanted & APR_FINFO_WPROT) && (worldid)) { + ident.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP; + ident.ptstrName = worldid; + if (GetEffectiveRightsFromAclW(dacl, &ident, &acc) == ERROR_SUCCESS) { + finfo->protection |= convert_prot(acc, prot_scope_world); + finfo->valid |= APR_FINFO_WPROT; + } } - ext = strrchr(exename, '.'); +} - if (ext && (!strcasecmp(ext,".exe") || !strcasecmp(ext,".com") || - !strcasecmp(ext,".bat") || !strcasecmp(ext,".cmd"))) { - return TRUE; +static apr_status_t resolve_ident(apr_finfo_t *finfo, const char *fname, + apr_int32_t wanted, apr_pool_t *pool) +{ + apr_file_t *thefile = NULL; + apr_status_t rv; + /* + * NT5 (W2K) only supports symlinks in the same manner as mount points. + * This code should eventually take that into account, for now treat + * every reparse point as a symlink... + * + * We must open the file with READ_CONTROL if we plan to retrieve the + * user, group or permissions. + */ + + if ((rv = apr_file_open(&thefile, fname, APR_OPENINFO + | ((wanted & APR_FINFO_LINK) ? APR_OPENLINK : 0) + | ((wanted & (APR_FINFO_PROT | APR_FINFO_OWNER)) + ? APR_READCONTROL : 0), + APR_FPROT_OS_DEFAULT, pool)) == APR_SUCCESS) { + rv = apr_file_info_get(finfo, wanted, thefile); + finfo->filehand = NULL; + apr_file_close(thefile); + } + else if (APR_STATUS_IS_EACCES(rv) && (wanted & (APR_FINFO_PROT + | APR_FINFO_OWNER))) { + /* We have a backup plan. Perhaps we couldn't grab READ_CONTROL? + * proceed without asking for that permission... + */ + if ((rv = apr_file_open(&thefile, fname, APR_OPENINFO + | ((wanted & APR_FINFO_LINK) ? APR_OPENLINK : 0), + APR_FPROT_OS_DEFAULT, pool)) == APR_SUCCESS) { + rv = apr_file_info_get(finfo, wanted & ~(APR_FINFO_PROT + | APR_FINFO_OWNER), + thefile); + finfo->filehand = NULL; + apr_file_close(thefile); + } } - return FALSE; + + if (rv != APR_SUCCESS && rv != APR_INCOMPLETE) + return (rv); + + /* We picked up this case above and had opened the link's properties */ + if (wanted & APR_FINFO_LINK) + finfo->valid |= APR_FINFO_LINK; + + return rv; } -ap_status_t ap_getfileinfo(ap_finfo_t *finfo, ap_file_t *thefile) +static apr_status_t guess_protection_bits(apr_finfo_t *finfo, + apr_int32_t wanted) { - /* TODO: - * Windows should call GetFileInformationByHandle(), which is similar - * to fstat(), for the best performance. Then we would need to map the - * BY_HANDLE_FILE_INFORMATION to ap_finfo_t. + /* Read, write execute for owner. In the Win9x environment, any + * readable file is executable (well, not entirely 100% true, but + * still looking for some cheap logic that would help us here.) + * The same holds on NT if a file doesn't have a DACL (e.g., on FAT) */ - struct stat info; - int rv = stat(thefile->fname, &info); - - if (rv == 0) { - finfo->protection = info.st_mode; - finfo->filetype = filetype_from_mode(info.st_mode); - finfo->user = info.st_uid; - finfo->group = info.st_gid; - finfo->size = info.st_size; - finfo->inode = info.st_ino; - ap_ansi_time_to_ap_time(&finfo->atime, info.st_atime); - ap_ansi_time_to_ap_time(&finfo->mtime, info.st_mtime); - ap_ansi_time_to_ap_time(&finfo->ctime, info.st_ctime); - return APR_SUCCESS; + if (finfo->protection & APR_FREADONLY) { + finfo->protection |= APR_FPROT_WREAD | APR_FPROT_WEXECUTE; } else { - return errno; + finfo->protection |= APR_FPROT_WREAD | APR_FPROT_WEXECUTE | APR_FPROT_WWRITE; } + finfo->protection |= (finfo->protection << prot_scope_group) + | (finfo->protection << prot_scope_user); + + finfo->valid |= APR_FINFO_UPROT | APR_FINFO_GPROT | APR_FINFO_WPROT; + + return ((wanted & ~finfo->valid) ? APR_INCOMPLETE : APR_SUCCESS); } -ap_status_t ap_stat(ap_finfo_t *finfo, const char *fname, ap_pool_t *cont) + +apr_status_t more_finfo(apr_finfo_t *finfo, const void *ufile, + apr_int32_t wanted, int whatfile) { - /* WIN32_FILE_ATTRIBUTE_DATA is an exact subset of the first - * entries of WIN32_FIND_DATA - */ - WIN32_FIND_DATA FileInformation; - HANDLE hFind; - ap_oslevel_e os_level; - ap_status_t rv = APR_SUCCESS; + PSID user = NULL, grp = NULL; + PACL dacl = NULL; + apr_status_t rv; + + if (apr_os_level < APR_WIN_NT) + return guess_protection_bits(finfo, wanted); + + if (wanted & (APR_FINFO_PROT | APR_FINFO_OWNER)) + { + /* On NT this request is incredibly expensive, but accurate. + * Since the WinNT-only functions below are protected by the + * (apr_os_level < APR_WIN_NT) case above, we need no extra + * tests, but remember GetNamedSecurityInfo & GetSecurityInfo + * are not supported on 9x. + */ + SECURITY_INFORMATION sinf = 0; + PSECURITY_DESCRIPTOR pdesc = NULL; + if (wanted & (APR_FINFO_USER | APR_FINFO_UPROT)) + sinf |= OWNER_SECURITY_INFORMATION; + if (wanted & (APR_FINFO_GROUP | APR_FINFO_GPROT)) + sinf |= GROUP_SECURITY_INFORMATION; + if (wanted & APR_FINFO_PROT) + sinf |= DACL_SECURITY_INFORMATION; + if (whatfile == MORE_OF_WFSPEC) { + apr_wchar_t *wfile = (apr_wchar_t*) ufile; + int fix = 0; + if (wcsncmp(wfile, L"\\\\?\\", 4) == 0) { + fix = 4; + if (wcsncmp(wfile + fix, L"UNC\\", 4) == 0) + wfile[6] = L'\\', fix = 6; + } + rv = GetNamedSecurityInfoW(wfile + fix, + SE_FILE_OBJECT, sinf, + ((wanted & (APR_FINFO_USER | APR_FINFO_UPROT)) ? &user : NULL), + ((wanted & (APR_FINFO_GROUP | APR_FINFO_GPROT)) ? &grp : NULL), + ((wanted & APR_FINFO_PROT) ? &dacl : NULL), + NULL, &pdesc); + if (fix == 6) + wfile[6] = L'C'; + } + else if (whatfile == MORE_OF_FSPEC) + rv = GetNamedSecurityInfoA((char*)ufile, + SE_FILE_OBJECT, sinf, + ((wanted & (APR_FINFO_USER | APR_FINFO_UPROT)) ? &user : NULL), + ((wanted & (APR_FINFO_GROUP | APR_FINFO_GPROT)) ? &grp : NULL), + ((wanted & APR_FINFO_PROT) ? &dacl : NULL), + NULL, &pdesc); + else if (whatfile == MORE_OF_HANDLE) + rv = GetSecurityInfo((HANDLE)ufile, + SE_FILE_OBJECT, sinf, + ((wanted & (APR_FINFO_USER | APR_FINFO_UPROT)) ? &user : NULL), + ((wanted & (APR_FINFO_GROUP | APR_FINFO_GPROT)) ? &grp : NULL), + ((wanted & APR_FINFO_PROT) ? &dacl : NULL), + NULL, &pdesc); + else + return APR_INCOMPLETE; /* should not occur */ + if (rv == ERROR_SUCCESS) + apr_pool_cleanup_register(finfo->pool, pdesc, free_localheap, + apr_pool_cleanup_null); + else + user = grp = dacl = NULL; + + if (user) { + finfo->user = user; + finfo->valid |= APR_FINFO_USER; + } + + if (grp) { + finfo->group = grp; + finfo->valid |= APR_FINFO_GROUP; + } - memset(finfo,'\0', sizeof(*finfo)); + if (dacl) { + /* Retrieved the discresionary access list */ + resolve_prot(finfo, wanted, dacl); + } + else if (wanted & APR_FINFO_PROT) + guess_protection_bits(finfo, wanted); + } - if (!ap_get_oslevel(cont, &os_level) && os_level >= APR_WIN_98) { - if (!GetFileAttributesEx(fname, GetFileExInfoStandard, - (WIN32_FILE_ATTRIBUTE_DATA*) &FileInformation)) { - rv = GetLastError(); + if ((apr_os_level >= APR_WIN_2000) && (wanted & APR_FINFO_CSIZE) + && (finfo->filetype == APR_REG)) + { + DWORD sizelo, sizehi; + if (whatfile == MORE_OF_HANDLE) { + /* Not available for development and implementation under + * a reasonable license; if you review the licensing + * terms and conditions of; + * http://go.microsoft.com/fwlink/?linkid=84083 + * you probably understand why APR chooses not to implement. + */ + IOSB sb; + FSI fi; + if ((ZwQueryInformationFile((HANDLE)ufile, &sb, + &fi, sizeof(fi), 5) == 0) + && (sb.Status == 0)) { + finfo->csize = fi.AllocationSize; + finfo->valid |= APR_FINFO_CSIZE; + } + } + else { + SetLastError(NO_ERROR); + if (whatfile == MORE_OF_WFSPEC) + sizelo = GetCompressedFileSizeW((apr_wchar_t*)ufile, &sizehi); + else if (whatfile == MORE_OF_FSPEC) + sizelo = GetCompressedFileSizeA((char*)ufile, &sizehi); + else + return APR_EGENERAL; /* should not occur */ + + if (sizelo != INVALID_FILE_SIZE || GetLastError() == NO_ERROR) { +#if APR_HAS_LARGE_FILES + finfo->csize = (apr_off_t)sizelo + | ((apr_off_t)sizehi << 32); +#else + finfo->csize = (apr_off_t)sizelo; + if (finfo->csize < 0 || sizehi) + finfo->csize = 0x7fffffff; +#endif + finfo->valid |= APR_FINFO_CSIZE; + } } } + return ((wanted & ~finfo->valid) ? APR_INCOMPLETE : APR_SUCCESS); +} + + +/* This generic fillin depends upon byhandle to be passed as 0 when + * a WIN32_FILE_ATTRIBUTE_DATA or either WIN32_FIND_DATA [A or W] is + * passed for wininfo. When the BY_HANDLE_FILE_INFORMATION structure + * is passed for wininfo, byhandle is passed as 1 to offset the one + * dword discrepancy in offset of the High/Low size structure members. + * + * The generic fillin returns 1 if the caller should further inquire + * if this is a CHR filetype. If it's reasonably certain it can't be, + * then the function returns 0. + */ +int fillin_fileinfo(apr_finfo_t *finfo, + WIN32_FILE_ATTRIBUTE_DATA *wininfo, + int byhandle, apr_int32_t wanted) +{ + DWORD *sizes = &wininfo->nFileSizeHigh + byhandle; + int warn = 0; + + memset(finfo, '\0', sizeof(*finfo)); + + FileTimeToAprTime(&finfo->atime, &wininfo->ftLastAccessTime); + FileTimeToAprTime(&finfo->ctime, &wininfo->ftCreationTime); + FileTimeToAprTime(&finfo->mtime, &wininfo->ftLastWriteTime); + +#if APR_HAS_LARGE_FILES + finfo->size = (apr_off_t)sizes[1] + | ((apr_off_t)sizes[0] << 32); +#else + finfo->size = (apr_off_t)sizes[1]; + if (finfo->size < 0 || sizes[0]) + finfo->size = 0x7fffffff; +#endif + + if (wanted & APR_FINFO_LINK && + wininfo->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { + finfo->filetype = APR_LNK; + } + else if (wininfo->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + finfo->filetype = APR_DIR; + } + else if (wininfo->dwFileAttributes & FILE_ATTRIBUTE_DEVICE) { + /* Warning: This test only succeeds on Win9x, on NT these files + * (con, aux, nul, lpt#, com# etc) escape early detection! + */ + finfo->filetype = APR_CHR; + } else { - /* The question remains, can we assume fname is not a wildcard? - * Must we test it? + /* Warning: Short of opening the handle to the file, the 'FileType' + * appears to be unknowable (in any trustworthy or consistent sense) + * on WinNT/2K as far as PIPE, CHR, etc are concerned. + */ + if (!wininfo->ftLastWriteTime.dwLowDateTime + && !wininfo->ftLastWriteTime.dwHighDateTime + && !finfo->size) + warn = 1; + finfo->filetype = APR_REG; + } + + /* The following flags are [for this moment] private to Win32. + * That's the only excuse for not toggling valid bits to reflect them. + */ + if (wininfo->dwFileAttributes & FILE_ATTRIBUTE_READONLY) + finfo->protection = APR_FREADONLY; + + finfo->valid = APR_FINFO_ATIME | APR_FINFO_CTIME | APR_FINFO_MTIME + | APR_FINFO_SIZE | APR_FINFO_TYPE; /* == APR_FINFO_MIN */ + + /* Only byhandle optionally tests link targets, so tell that caller + * what it wants to hear, otherwise the byattributes is never + * reporting anything but the link. + */ + if (!byhandle || (wanted & APR_FINFO_LINK)) + finfo->valid |= APR_FINFO_LINK; + return warn; +} + + +APR_DECLARE(apr_status_t) apr_file_info_get(apr_finfo_t *finfo, apr_int32_t wanted, + apr_file_t *thefile) +{ + BY_HANDLE_FILE_INFORMATION FileInfo; + + if (thefile->buffered) { + /* XXX: flush here is not mutex protected */ + apr_status_t rv = apr_file_flush(thefile); + if (rv != APR_SUCCESS) + return rv; + } + + /* GetFileInformationByHandle() is implemented via two syscalls: + * QueryInformationVolume and QueryAllInformationFile. Use cheaper + * GetFileSizeEx() API if we only need to get the file size. */ + if (wanted == APR_FINFO_SIZE) { + LARGE_INTEGER size; + + if (!GetFileSizeEx(thefile->filehand, &size)) { + return apr_get_os_error(); + } + + finfo->pool = thefile->pool; + finfo->fname = thefile->fname; + finfo->size = size.QuadPart; + finfo->valid = APR_FINFO_SIZE; + + return APR_SUCCESS; + } + + if (!GetFileInformationByHandle(thefile->filehand, &FileInfo)) { + return apr_get_os_error(); + } + + fillin_fileinfo(finfo, (WIN32_FILE_ATTRIBUTE_DATA *) &FileInfo, 1, wanted); + + if (finfo->filetype == APR_REG) + { + /* Go the extra mile to be -certain- that we have a real, regular + * file, since the attribute bits aren't a certain thing. Even + * though fillin should have hinted if we *must* do this, we + * don't need to take chances while the handle is already open. */ - hFind = FindFirstFile(fname, &FileInformation); - if (hFind == INVALID_HANDLE_VALUE) { - rv = GetLastError(); - } else { + DWORD FileType; + if ((FileType = GetFileType(thefile->filehand))) { + if (FileType == FILE_TYPE_CHAR) { + finfo->filetype = APR_CHR; + } + else if (FileType == FILE_TYPE_PIPE) { + finfo->filetype = APR_PIPE; + } + /* Otherwise leave the original conclusion alone + */ + } + } + + finfo->pool = thefile->pool; + + /* ### The finfo lifetime may exceed the lifetime of thefile->pool + * but finfo's aren't managed in pools, so where on earth would + * we pstrdup the fname into??? + */ + finfo->fname = thefile->fname; + + /* Extra goodies known only by GetFileInformationByHandle() */ + finfo->inode = (apr_ino_t)FileInfo.nFileIndexLow + | ((apr_ino_t)FileInfo.nFileIndexHigh << 32); + finfo->device = FileInfo.dwVolumeSerialNumber; + finfo->nlink = FileInfo.nNumberOfLinks; + + finfo->valid |= APR_FINFO_IDENT | APR_FINFO_NLINK; + + /* If we still want something more (besides the name) go get it! + */ + if ((wanted &= ~finfo->valid) & ~APR_FINFO_NAME) { + return more_finfo(finfo, thefile->filehand, wanted, MORE_OF_HANDLE); + } + + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_file_perms_set(const char *fname, + apr_fileperms_t perms) +{ + return APR_ENOTIMPL; +} + +APR_DECLARE(apr_status_t) apr_stat(apr_finfo_t *finfo, const char *fname, + apr_int32_t wanted, apr_pool_t *pool) +{ + /* XXX: is constant - needs testing - which requires a lighter-weight root test fn */ + int isroot = 0; + apr_status_t ident_rv = 0; + apr_status_t rv; +#if APR_HAS_UNICODE_FS + apr_wchar_t wfname[APR_PATH_MAX]; + +#endif + char *filename = NULL; + /* These all share a common subset of this structure */ + union { + WIN32_FIND_DATAW w; + WIN32_FIND_DATAA n; + WIN32_FILE_ATTRIBUTE_DATA i; + } FileInfo; + + /* Catch fname length == MAX_PATH since GetFileAttributesEx fails + * with PATH_NOT_FOUND. We would rather indicate length error than + * 'not found' + */ + if (strlen(fname) >= APR_PATH_MAX) { + return APR_ENAMETOOLONG; + } + +#if APR_HAS_UNICODE_FS + IF_WIN_OS_IS_UNICODE + { + if ((wanted & (APR_FINFO_IDENT | APR_FINFO_NLINK)) + || (~wanted & APR_FINFO_LINK)) { + /* FindFirstFile and GetFileAttributesEx can't figure the inode, + * device or number of links, so we need to resolve with an open + * file handle. If the user has asked for these fields, fall over + * to the get file info by handle method. If we fail, or the user + * also asks for the file name, continue by our usual means. + * + * We also must use this method for a 'true' stat, that resolves + * a symlink (NTFS Junction) target. This is because all fileinfo + * on a Junction always returns the junction, opening the target + * is the only way to resolve the target's attributes. + */ + if ((ident_rv = resolve_ident(finfo, fname, wanted, pool)) + == APR_SUCCESS) + return ident_rv; + else if (ident_rv == APR_INCOMPLETE) + wanted &= ~finfo->valid; + } + + if ((rv = utf8_to_unicode_path(wfname, sizeof(wfname) + / sizeof(apr_wchar_t), fname))) + return rv; + if (!(wanted & APR_FINFO_NAME)) { + if (!GetFileAttributesExW(wfname, GetFileExInfoStandard, + &FileInfo.i)) + return apr_get_os_error(); + } + else { + /* Guard against bogus wildcards and retrieve by name + * since we want the true name, and set aside a long + * enough string to handle the longest file name. + */ + char tmpname[APR_FILE_MAX * 3 + 1]; + HANDLE hFind; + if ((rv = test_safe_name(fname)) != APR_SUCCESS) { + return rv; + } + hFind = FindFirstFileW(wfname, &FileInfo.w); + if (hFind == INVALID_HANDLE_VALUE) + return apr_get_os_error(); FindClose(hFind); + if (unicode_to_utf8_path(tmpname, sizeof(tmpname), + FileInfo.w.cFileName)) { + return APR_ENAMETOOLONG; + } + filename = apr_pstrdup(pool, tmpname); } } +#endif +#if APR_HAS_ANSI_FS + ELSE_WIN_OS_IS_ANSI + { + const char *root = NULL; + const char *test = fname; + rv = apr_filepath_root(&root, &test, APR_FILEPATH_NATIVE, pool); + isroot = (root && *root && !(*test)); - if (rv != APR_SUCCESS) { - /* a little ad-hoc canonicalization to the most common - * error conditions - */ - if (rv == ERROR_FILE_NOT_FOUND || rv == ERROR_PATH_NOT_FOUND) - return APR_ENOENT; - return rv; + if ((apr_os_level >= APR_WIN_98) && (!(wanted & APR_FINFO_NAME) || isroot)) + { + /* cannot use FindFile on a Win98 root, it returns \* + * GetFileAttributesExA is not available on Win95 + */ + if (!GetFileAttributesExA(fname, GetFileExInfoStandard, + &FileInfo.i)) { + return apr_get_os_error(); + } + } + else if (isroot) { + /* This is Win95 and we are trying to stat a root. Lie. + */ + if (GetDriveType(fname) != DRIVE_UNKNOWN) + { + finfo->pool = pool; + finfo->filetype = 0; + finfo->mtime = apr_time_now(); + finfo->protection |= APR_FPROT_WREAD | APR_FPROT_WEXECUTE | APR_FPROT_WWRITE; + finfo->protection |= (finfo->protection << prot_scope_group) + | (finfo->protection << prot_scope_user); + finfo->valid |= APR_FINFO_TYPE | APR_FINFO_PROT + | APR_FINFO_MTIME + | (wanted & APR_FINFO_LINK); + return (wanted &= ~finfo->valid) ? APR_INCOMPLETE + : APR_SUCCESS; + } + else + return APR_FROM_OS_ERROR(ERROR_PATH_NOT_FOUND); + } + else { + /* Guard against bogus wildcards and retrieve by name + * since we want the true name, or are stuck in Win95, + * or are looking for the root of a Win98 drive. + */ + HANDLE hFind; + if ((rv = test_safe_name(fname)) != APR_SUCCESS) { + return rv; + } + hFind = FindFirstFileA(fname, &FileInfo.n); + if (hFind == INVALID_HANDLE_VALUE) { + return apr_get_os_error(); + } + FindClose(hFind); + filename = apr_pstrdup(pool, FileInfo.n.cFileName); + } } +#endif - /* Filetype - Directory or file? */ - if (FileInformation.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { - finfo->protection |= S_IFDIR; - finfo->filetype = APR_DIR; + if (ident_rv != APR_INCOMPLETE) { + if (fillin_fileinfo(finfo, (WIN32_FILE_ATTRIBUTE_DATA *) &FileInfo, + 0, wanted)) + { + /* Go the extra mile to assure we have a file. WinNT/2000 seems + * to reliably translate char devices to the path '\\.\device' + * so go ask for the full path. + */ + if (apr_os_level >= APR_WIN_NT) + { +#if APR_HAS_UNICODE_FS + apr_wchar_t tmpname[APR_FILE_MAX]; + apr_wchar_t *tmpoff = NULL; + if (GetFullPathNameW(wfname, sizeof(tmpname) / sizeof(apr_wchar_t), + tmpname, &tmpoff)) + { + if (!wcsncmp(tmpname, L"\\\\.\\", 4)) { +#else + /* Same initial logic as above, but + * only for WinNT/non-UTF-8 builds of APR: + */ + char tmpname[APR_FILE_MAX]; + char *tmpoff; + if (GetFullPathName(fname, sizeof(tmpname), tmpname, &tmpoff)) + { + if (!strncmp(tmpname, "\\\\.\\", 4)) { +#endif + if (tmpoff == tmpname + 4) { + finfo->filetype = APR_CHR; + } + /* For WHATEVER reason, CHR devices such as \\.\con + * or \\.\lpt1 *may*not* update tmpoff; in fact the + * resulting tmpoff is set to NULL. Guard against + * either case. + * + * This code is identical for wide and narrow chars... + */ + else if (!tmpoff) { + tmpoff = tmpname + 4; + while (*tmpoff) { + if (*tmpoff == '\\' || *tmpoff == '/') { + break; + } + ++tmpoff; + } + if (!*tmpoff) { + finfo->filetype = APR_CHR; + } + } + } + } + else { + finfo->valid &= ~APR_FINFO_TYPE; + } + + } + else { + finfo->valid &= ~APR_FINFO_TYPE; + } + } + finfo->pool = pool; } - else { - finfo->protection |= S_IFREG; - finfo->filetype = APR_REG; + + if (filename && !isroot) { + finfo->name = filename; + finfo->valid |= APR_FINFO_NAME; } - /* Read, write execute for owner */ - if (FileInformation.dwFileAttributes & FILE_ATTRIBUTE_READONLY) { - finfo->protection |= S_IREAD; + + if (wanted &= ~finfo->valid) { + /* Caller wants more than APR_FINFO_MIN | APR_FINFO_NAME */ +#if APR_HAS_UNICODE_FS + if (apr_os_level >= APR_WIN_NT) + return more_finfo(finfo, wfname, wanted, MORE_OF_WFSPEC); +#endif + return more_finfo(finfo, fname, wanted, MORE_OF_FSPEC); } - else { - finfo->protection |= S_IREAD; - finfo->protection |= S_IWRITE; + + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_file_attrs_set(const char *fname, + apr_fileattrs_t attributes, + apr_fileattrs_t attr_mask, + apr_pool_t *pool) +{ + DWORD flags; + apr_status_t rv; +#if APR_HAS_UNICODE_FS + apr_wchar_t wfname[APR_PATH_MAX]; +#endif + + /* Don't do anything if we can't handle the requested attributes */ + if (!(attr_mask & (APR_FILE_ATTR_READONLY + | APR_FILE_ATTR_HIDDEN))) + return APR_SUCCESS; + +#if APR_HAS_UNICODE_FS + IF_WIN_OS_IS_UNICODE + { + if ((rv = utf8_to_unicode_path(wfname, + sizeof(wfname) / sizeof(wfname[0]), + fname))) + return rv; + flags = GetFileAttributesW(wfname); + } +#endif +#if APR_HAS_ANSI_FS + ELSE_WIN_OS_IS_ANSI + { + flags = GetFileAttributesA(fname); + } +#endif + + if (flags == 0xFFFFFFFF) + return apr_get_os_error(); + + if (attr_mask & APR_FILE_ATTR_READONLY) + { + if (attributes & APR_FILE_ATTR_READONLY) + flags |= FILE_ATTRIBUTE_READONLY; + else + flags &= ~FILE_ATTRIBUTE_READONLY; + } + + if (attr_mask & APR_FILE_ATTR_HIDDEN) + { + if (attributes & APR_FILE_ATTR_HIDDEN) + flags |= FILE_ATTRIBUTE_HIDDEN; + else + flags &= ~FILE_ATTRIBUTE_HIDDEN; + } + +#if APR_HAS_UNICODE_FS + IF_WIN_OS_IS_UNICODE + { + rv = SetFileAttributesW(wfname, flags); } - /* Is this an executable? Guess based on the file extension. */ - if (is_exe(fname, cont)) { - finfo->protection |= S_IEXEC; +#endif +#if APR_HAS_ANSI_FS + ELSE_WIN_OS_IS_ANSI + { + rv = SetFileAttributesA(fname, flags); } - /* File times */ - FileTimeToAprTime(&finfo->atime, &FileInformation.ftLastAccessTime); - FileTimeToAprTime(&finfo->ctime, &FileInformation.ftCreationTime); - FileTimeToAprTime(&finfo->mtime, &FileInformation.ftLastWriteTime); +#endif - /* File size - * Note: This cannot handle files greater than can be held by an int */ - finfo->size = FileInformation.nFileSizeLow; + if (rv == 0) + return apr_get_os_error(); return APR_SUCCESS; } + +APR_DECLARE(apr_status_t) apr_file_mtime_set(const char *fname, + apr_time_t mtime, + apr_pool_t *pool) +{ + apr_file_t *thefile; + apr_status_t rv; + + rv = apr_file_open(&thefile, fname, + APR_FOPEN_READ | APR_WRITEATTRS, + APR_FPROT_OS_DEFAULT, pool); + if (!rv) + { + FILETIME file_ctime; + FILETIME file_atime; + FILETIME file_mtime; + + if (!GetFileTime(thefile->filehand, + &file_ctime, &file_atime, &file_mtime)) + rv = apr_get_os_error(); + else + { + AprTimeToFileTime(&file_mtime, mtime); + if (!SetFileTime(thefile->filehand, + &file_ctime, &file_atime, &file_mtime)) + rv = apr_get_os_error(); + } + + apr_file_close(thefile); + } + + return rv; +} diff --git a/file_io/win32/filesys.c b/file_io/win32/filesys.c new file mode 100644 index 00000000000..e812139551a --- /dev/null +++ b/file_io/win32/filesys.c @@ -0,0 +1,229 @@ +/* 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_file_io.h" +#include "apr_strings.h" + +/* Win32 Exceptions: + * + * Note that trailing spaces and trailing periods are never recorded + * in the file system, except by a very obscure bug where any file + * that is created with a trailing space or period, followed by the + * ':' stream designator on an NTFS volume can never be accessed again. + * In other words, don't ever accept them when designating a stream! + * + * An interesting side effect is that two or three periods are both + * treated as the parent directory, although the fourth and on are + * not [strongly suggest all trailing periods are trimmed off, or + * down to two if there are no other characters.] + * + * Leading spaces and periods are accepted, however. + * The * ? < > codes all have wildcard side effects + * The " / \ : are exclusively component separator tokens + * The system doesn't accept | for any (known) purpose + * Oddly, \x7f _is_ acceptable ;) + */ + +/* apr_c_is_fnchar[] maps Win32's file name and shell escape symbols + * + * element & 1 == valid file name character [excluding delimiters] + * element & 2 == character should be shell (caret) escaped from cmd.exe + * + * this must be in-sync with Apache httpd's gen_test_char.c for cgi escaping. + */ + +const char apr_c_is_fnchar[256] = +{/* Reject all ctrl codes... Escape \n and \r (ascii 10 and 13) */ + 0,0,0,0,0,0,0,0,0,0,2,0,0,2,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + /* ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ + 1,1,2,1,3,3,3,3,3,3,2,1,1,1,1,0, 1,1,1,1,1,1,1,1,1,1,0,3,2,1,2,2, + /* @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ */ + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,3,2,3,3,1, + /* ` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~ */ + 3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,3,2,3,3,1, + /* High bit codes are accepted (subject to utf-8->Unicode xlation) */ + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 +}; + + +apr_status_t filepath_root_test(char *path, apr_pool_t *p) +{ + apr_status_t rv; +#if APR_HAS_UNICODE_FS + if (apr_os_level >= APR_WIN_NT) + { + apr_wchar_t wpath[APR_PATH_MAX]; + if ((rv = utf8_to_unicode_path(wpath, sizeof(wpath) + / sizeof(apr_wchar_t), path))) + return rv; + rv = GetDriveTypeW(wpath); + } + else +#endif + rv = GetDriveType(path); + + if (rv == DRIVE_UNKNOWN || rv == DRIVE_NO_ROOT_DIR) + return APR_EBADPATH; + return APR_SUCCESS; +} + + +apr_status_t filepath_drive_get(char **rootpath, char drive, + apr_int32_t flags, apr_pool_t *p) +{ + char path[APR_PATH_MAX]; +#if APR_HAS_UNICODE_FS + IF_WIN_OS_IS_UNICODE + { + apr_wchar_t *ignored; + apr_wchar_t wdrive[8]; + apr_wchar_t wpath[APR_PATH_MAX]; + apr_status_t rv; + /* ???: This needs review, apparently "\\?\d:." returns "\\?\d:" + * as if that is useful for anything. + */ + wcscpy(wdrive, L"D:."); + wdrive[0] = (apr_wchar_t)(unsigned char)drive; + if (!GetFullPathNameW(wdrive, sizeof(wpath) / sizeof(apr_wchar_t), wpath, &ignored)) + return apr_get_os_error(); + if ((rv = unicode_to_utf8_path(path, sizeof(path), wpath))) + return rv; + } +#endif +#if APR_HAS_ANSI_FS + ELSE_WIN_OS_IS_ANSI + { + char *ignored; + char drivestr[4]; + drivestr[0] = drive; + drivestr[1] = ':'; + drivestr[2] = '.';; + drivestr[3] = '\0'; + if (!GetFullPathName(drivestr, sizeof(path), path, &ignored)) + return apr_get_os_error(); + } +#endif + if (!(flags & APR_FILEPATH_NATIVE)) { + for (*rootpath = path; **rootpath; ++*rootpath) { + if (**rootpath == '\\') + **rootpath = '/'; + } + } + *rootpath = apr_pstrdup(p, path); + return APR_SUCCESS; +} + + +apr_status_t filepath_root_case(char **rootpath, char *root, apr_pool_t *p) +{ +#if APR_HAS_UNICODE_FS + IF_WIN_OS_IS_UNICODE + { + apr_wchar_t *ignored; + apr_wchar_t wpath[APR_PATH_MAX]; + apr_status_t rv; + apr_wchar_t wroot[APR_PATH_MAX]; + /* ???: This needs review, apparently "\\?\d:." returns "\\?\d:" + * as if that is useful for anything. + */ + if ((rv = utf8_to_unicode_path(wroot, sizeof(wroot) + / sizeof(apr_wchar_t), root))) + return rv; + if (!GetFullPathNameW(wroot, sizeof(wpath) / sizeof(apr_wchar_t), wpath, &ignored)) + return apr_get_os_error(); + + /* Borrow wroot as a char buffer (twice as big as necessary) + */ + if ((rv = unicode_to_utf8_path((char*)wroot, sizeof(wroot), wpath))) + return rv; + *rootpath = apr_pstrdup(p, (char*)wroot); + } +#endif +#if APR_HAS_ANSI_FS + ELSE_WIN_OS_IS_ANSI + { + char path[APR_PATH_MAX]; + char *ignored; + if (!GetFullPathName(root, sizeof(path), path, &ignored)) + return apr_get_os_error(); + *rootpath = apr_pstrdup(p, path); + } +#endif + return APR_SUCCESS; +} + + +APR_DECLARE(apr_status_t) apr_filepath_get(char **rootpath, apr_int32_t flags, + apr_pool_t *p) +{ + char path[APR_PATH_MAX]; +#if APR_HAS_UNICODE_FS + IF_WIN_OS_IS_UNICODE + { + apr_wchar_t wpath[APR_PATH_MAX]; + apr_status_t rv; + if (!GetCurrentDirectoryW(sizeof(wpath) / sizeof(apr_wchar_t), wpath)) + return apr_get_os_error(); + if ((rv = unicode_to_utf8_path(path, sizeof(path), wpath))) + return rv; + } +#endif +#if APR_HAS_ANSI_FS + ELSE_WIN_OS_IS_ANSI + { + if (!GetCurrentDirectory(sizeof(path), path)) + return apr_get_os_error(); + } +#endif + if (!(flags & APR_FILEPATH_NATIVE)) { + for (*rootpath = path; **rootpath; ++*rootpath) { + if (**rootpath == '\\') + **rootpath = '/'; + } + } + *rootpath = apr_pstrdup(p, path); + return APR_SUCCESS; +} + + +APR_DECLARE(apr_status_t) apr_filepath_set(const char *rootpath, + apr_pool_t *p) +{ +#if APR_HAS_UNICODE_FS + IF_WIN_OS_IS_UNICODE + { + apr_wchar_t wpath[APR_PATH_MAX]; + apr_status_t rv; + if ((rv = utf8_to_unicode_path(wpath, sizeof(wpath) + / sizeof(apr_wchar_t), rootpath))) + return rv; + if (!SetCurrentDirectoryW(wpath)) + return apr_get_os_error(); + } +#endif +#if APR_HAS_ANSI_FS + ELSE_WIN_OS_IS_ANSI + { + if (!SetCurrentDirectory(rootpath)) + return apr_get_os_error(); + } +#endif + return APR_SUCCESS; +} diff --git a/file_io/win32/flock.c b/file_io/win32/flock.c new file mode 100644 index 00000000000..e08e08a7a40 --- /dev/null +++ b/file_io/win32/flock.c @@ -0,0 +1,86 @@ +/* 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_file_io.h" + +APR_DECLARE(apr_status_t) apr_file_lock(apr_file_t *thefile, int type) +{ +#ifdef _WIN32_WCE + /* The File locking is unsuported on WCE */ + return APR_ENOTIMPL; +#else + const DWORD len = 0xffffffff; + DWORD flags; + + flags = ((type & APR_FLOCK_NONBLOCK) ? LOCKFILE_FAIL_IMMEDIATELY : 0) + + (((type & APR_FLOCK_TYPEMASK) == APR_FLOCK_SHARED) + ? 0 : LOCKFILE_EXCLUSIVE_LOCK); + if (apr_os_level >= APR_WIN_NT) { + /* Syntax is correct, len is passed for LengthLow and LengthHigh*/ + OVERLAPPED offset; + memset (&offset, 0, sizeof(offset)); + if (!LockFileEx(thefile->filehand, flags, 0, len, len, &offset)) + return apr_get_os_error(); + } + else { + /* On Win9x, LockFile() never blocks. Hack in a crufty poll. + * + * Note that this hack exposes threads to being unserviced forever, + * in the situation that the given lock has low availability. + * When implemented in the kernel, LockFile will typically use + * FIFO or round robin distribution to ensure all threads get + * one crack at the lock; but in this case we can't emulate that. + * + * However Win9x are barely maintainable anyways, if the user does + * choose to build to them, this is the best we can do. + */ + while (!LockFile(thefile->filehand, 0, 0, len, 0)) { + DWORD err = GetLastError(); + if ((err == ERROR_LOCK_VIOLATION) && !(type & APR_FLOCK_NONBLOCK)) + { + Sleep(500); /* pause for a half second */ + continue; /* ... and then poll again */ + } + return APR_FROM_OS_ERROR(err); + } + } + + return APR_SUCCESS; +#endif /* !defined(_WIN32_WCE) */ +} + +APR_DECLARE(apr_status_t) apr_file_unlock(apr_file_t *thefile) +{ +#ifdef _WIN32_WCE + return APR_ENOTIMPL; +#else + DWORD len = 0xffffffff; + + if (apr_os_level >= APR_WIN_NT) { + /* Syntax is correct, len is passed for LengthLow and LengthHigh*/ + OVERLAPPED offset; + memset (&offset, 0, sizeof(offset)); + if (!UnlockFileEx(thefile->filehand, 0, len, len, &offset)) + return apr_get_os_error(); + } + else { + if (!UnlockFile(thefile->filehand, 0, 0, len, 0)) + return apr_get_os_error(); + } + + return APR_SUCCESS; +#endif /* !defined(_WIN32_WCE) */ +} diff --git a/file_io/win32/open.c b/file_io/win32/open.c index df08302f861..b6c01432e81 100644 --- a/file_io/win32/open.c +++ b/file_io/win32/open.c @@ -1,124 +1,362 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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 "fileio.h" +#include "apr_arch_file_io.h" #include "apr_file_io.h" #include "apr_general.h" -#include "apr_lib.h" +#include "apr_strings.h" #include "apr_portable.h" +#include "apr_thread_mutex.h" +#if APR_HAVE_ERRNO_H #include <errno.h> +#endif #include <winbase.h> #include <string.h> +#ifdef HAVE_SYS_STAT_H #include <sys/stat.h> -#include "misc.h" +#endif +#include "apr_arch_misc.h" +#include "apr_arch_inherit.h" +#include <io.h> +#include <winioctl.h> + +#if APR_HAS_UNICODE_FS +apr_status_t utf8_to_unicode_path(apr_wchar_t* retstr, apr_size_t retlen, + const char* srcstr) +{ + /* TODO: The computations could preconvert the string to determine + * the true size of the retstr, but that's a memory over speed + * tradeoff that isn't appropriate this early in development. + * + * Allocate the maximum string length based on leading 4 + * characters of \\?\ (allowing nearly unlimited path lengths) + * plus the trailing null, then transform /'s into \\'s since + * the \\?\ form doesn't allow '/' path seperators. + * + * Note that the \\?\ form only works for local drive paths, and + * \\?\UNC\ is needed UNC paths. + */ + apr_size_t srcremains = strlen(srcstr) + 1; + apr_wchar_t *t = retstr; + apr_status_t rv; + + /* This is correct, we don't twist the filename if it is will + * definitely be shorter than 248 characters. It merits some + * performance testing to see if this has any effect, but there + * seem to be applications that get confused by the resulting + * Unicode \\?\ style file names, especially if they use argv[0] + * or call the Win32 API functions such as GetModuleName, etc. + * Not every application is prepared to handle such names. + * + * Note also this is shorter than MAX_PATH, as directory paths + * are actually limited to 248 characters. + * + * Note that a utf-8 name can never result in more wide chars + * than the original number of utf-8 narrow chars. + */ + if (srcremains > 248) { + if (srcstr[1] == ':' && (srcstr[2] == '/' || srcstr[2] == '\\')) { + wcscpy (retstr, L"\\\\?\\"); + retlen -= 4; + t += 4; + } + else if ((srcstr[0] == '/' || srcstr[0] == '\\') + && (srcstr[1] == '/' || srcstr[1] == '\\') + && (srcstr[2] != '?')) { + /* Skip the slashes */ + srcstr += 2; + srcremains -= 2; + wcscpy (retstr, L"\\\\?\\UNC\\"); + retlen -= 8; + t += 8; + } + } + + if ((rv = apr_conv_utf8_to_ucs2(srcstr, &srcremains, t, &retlen))) { + return (rv == APR_INCOMPLETE) ? APR_EINVAL : rv; + } + if (srcremains) { + return APR_ENAMETOOLONG; + } + for (; *t; ++t) + if (*t == L'/') + *t = L'\\'; + return APR_SUCCESS; +} -ap_status_t file_cleanup(void *thefile) +apr_status_t unicode_to_utf8_path(char* retstr, apr_size_t retlen, + const apr_wchar_t* srcstr) { - ap_file_t *file = thefile; - if (!CloseHandle(file->filehand)) { - return GetLastError(); + /* Skip the leading 4 characters if the path begins \\?\, or substitute + * // for the \\?\UNC\ path prefix, allocating the maximum string + * length based on the remaining string, plus the trailing null. + * then transform \\'s back into /'s since the \\?\ form never + * allows '/' path seperators, and APR always uses '/'s. + */ + apr_size_t srcremains = wcslen(srcstr) + 1; + apr_status_t rv; + char *t = retstr; + if (srcstr[0] == L'\\' && srcstr[1] == L'\\' && + srcstr[2] == L'?' && srcstr[3] == L'\\') { + if (srcstr[4] == L'U' && srcstr[5] == L'N' && + srcstr[6] == L'C' && srcstr[7] == L'\\') { + srcremains -= 8; + srcstr += 8; + retstr[0] = '\\'; + retstr[1] = '\\'; + retlen -= 2; + t += 2; + } + else { + srcremains -= 4; + srcstr += 4; + } + } + + if ((rv = apr_conv_ucs2_to_utf8(srcstr, &srcremains, t, &retlen))) { + return rv; + } + if (srcremains) { + return APR_ENAMETOOLONG; } - file->filehand = INVALID_HANDLE_VALUE; return APR_SUCCESS; } +#endif -ap_status_t ap_open(ap_file_t **dafile, const char *fname, - ap_int32_t flag, ap_fileperms_t perm, ap_pool_t *cont) +void *res_name_from_filename(const char *file, int global, apr_pool_t *pool) { +#if APR_HAS_UNICODE_FS + IF_WIN_OS_IS_UNICODE + { + apr_wchar_t *wpre, *wfile, *ch; + apr_size_t n = strlen(file) + 1; + apr_size_t r, d; + + if (apr_os_level >= APR_WIN_2000) { + if (global) + wpre = L"Global\\"; + else + wpre = L"Local\\"; + } + else + wpre = L""; + r = wcslen(wpre); + + if (n > 256 - r) { + file += n - 256 - r; + n = 256; + /* skip utf8 continuation bytes */ + while ((*file & 0xC0) == 0x80) { + ++file; + --n; + } + } + wfile = apr_palloc(pool, (r + n) * sizeof(apr_wchar_t)); + wcscpy(wfile, wpre); + d = n; + if (apr_conv_utf8_to_ucs2(file, &n, wfile + r, &d)) { + return NULL; + } + for (ch = wfile + r; *ch; ++ch) { + if (*ch == ':' || *ch == '/' || *ch == '\\') + *ch = '_'; + } + return wfile; + } +#endif +#if APR_HAS_ANSI_FS + ELSE_WIN_OS_IS_ANSI + { + char *nfile, *ch; + apr_size_t n = strlen(file) + 1; + +#if !APR_HAS_UNICODE_FS + apr_size_t r, d; + char *pre; + + if (apr_os_level >= APR_WIN_2000) { + if (global) + pre = "Global\\"; + else + pre = "Local\\"; + } + else + pre = ""; + r = strlen(pre); + + if (n > 256 - r) { + file += n - 256 - r; + n = 256; + } + nfile = apr_palloc(pool, (r + n) * sizeof(apr_wchar_t)); + memcpy(nfile, pre, r); + memcpy(nfile + r, file, n); +#else + const apr_size_t r = 0; + if (n > 256) { + file += n - 256; + n = 256; + } + nfile = apr_pmemdup(pool, file, n); +#endif + for (ch = nfile + r; *ch; ++ch) { + if (*ch == ':' || *ch == '/' || *ch == '\\') + *ch = '_'; + } + return nfile; + } +#endif +} + +#if APR_HAS_UNICODE_FS +static apr_status_t make_sparse_file(apr_file_t *file) +{ + BY_HANDLE_FILE_INFORMATION info; + apr_status_t rv; + DWORD bytesread = 0; + DWORD res; + + /* test */ + + if (GetFileInformationByHandle(file->filehand, &info) + && (info.dwFileAttributes & FILE_ATTRIBUTE_SPARSE_FILE)) + return APR_SUCCESS; + + if (file->pOverlapped) { + file->pOverlapped->Offset = 0; + file->pOverlapped->OffsetHigh = 0; + } + + if (DeviceIoControl(file->filehand, FSCTL_SET_SPARSE, NULL, 0, NULL, 0, + &bytesread, file->pOverlapped)) { + rv = APR_SUCCESS; + } + else + { + rv = apr_get_os_error(); + + if (rv == APR_FROM_OS_ERROR(ERROR_IO_PENDING)) + { + do { + res = WaitForSingleObject(file->pOverlapped->hEvent, + (file->timeout > 0) + ? (DWORD)(file->timeout/1000) + : ((file->timeout == -1) + ? INFINITE : 0)); + } while (res == WAIT_ABANDONED); + + if (res != WAIT_OBJECT_0) { + CancelIo(file->filehand); + } + + if (GetOverlappedResult(file->filehand, file->pOverlapped, + &bytesread, TRUE)) + rv = APR_SUCCESS; + else + rv = apr_get_os_error(); + } + } + return rv; +} +#endif + +apr_status_t file_cleanup(void *thefile) +{ + apr_file_t *file = thefile; + apr_status_t flush_rv = APR_SUCCESS; + + if (file->filehand != INVALID_HANDLE_VALUE) { + + if (file->buffered) { + /* XXX: flush here is not mutex protected */ + flush_rv = apr_file_flush((apr_file_t *)thefile); + } + + /* In order to avoid later segfaults with handle 'reuse', + * we must protect against the case that a dup2'ed handle + * is being closed, and invalidate the corresponding StdHandle + * We also tell msvcrt when stdhandles are closed. + */ + if (file->flags & APR_STD_FLAGS) + { + if ((file->flags & APR_STD_FLAGS) == APR_STDERR_FLAG) { + _close(2); + SetStdHandle(STD_ERROR_HANDLE, INVALID_HANDLE_VALUE); + } + else if ((file->flags & APR_STD_FLAGS) == APR_STDOUT_FLAG) { + _close(1); + SetStdHandle(STD_OUTPUT_HANDLE, INVALID_HANDLE_VALUE); + } + else if ((file->flags & APR_STD_FLAGS) == APR_STDIN_FLAG) { + _close(0); + SetStdHandle(STD_INPUT_HANDLE, INVALID_HANDLE_VALUE); + } + } + else + CloseHandle(file->filehand); + + file->filehand = INVALID_HANDLE_VALUE; + } + if (file->pOverlapped && file->pOverlapped->hEvent) { + CloseHandle(file->pOverlapped->hEvent); + file->pOverlapped = NULL; + } + return flush_rv; +} + +APR_DECLARE(apr_status_t) apr_file_open(apr_file_t **new, const char *fname, + apr_int32_t flag, apr_fileperms_t perm, + apr_pool_t *pool) +{ + HANDLE handle = INVALID_HANDLE_VALUE; DWORD oflags = 0; DWORD createflags = 0; DWORD attributes = 0; DWORD sharemode = FILE_SHARE_READ | FILE_SHARE_WRITE; - ap_oslevel_e level; - - (*dafile) = (ap_file_t *)ap_pcalloc(cont, sizeof(ap_file_t)); + apr_status_t rv; - (*dafile)->cntxt = cont; - - if (flag & APR_READ) { + if (flag & APR_FOPEN_NONBLOCK) { + return APR_ENOTIMPL; + } + if (flag & APR_FOPEN_READ) { oflags |= GENERIC_READ; } - if (flag & APR_WRITE) { + if (flag & APR_FOPEN_WRITE) { oflags |= GENERIC_WRITE; } - if (!(flag & APR_READ) && !(flag & APR_WRITE)) { - (*dafile)->filehand = INVALID_HANDLE_VALUE; - return APR_EACCES; + if (flag & APR_WRITEATTRS) { + oflags |= FILE_WRITE_ATTRIBUTES; } - (*dafile)->fname = ap_pstrdup(cont, fname); - - (*dafile)->demonfname = canonical_filename((*dafile)->cntxt, fname); - (*dafile)->lowerdemonfname = strlwr((*dafile)->demonfname); - - if (ap_get_oslevel(cont, &level) == APR_SUCCESS && level >= APR_WIN_NT) { + if (apr_os_level >= APR_WIN_NT) sharemode |= FILE_SHARE_DELETE; - } - if (flag & APR_CREATE) { - if (flag & APR_EXCL) { + if (flag & APR_FOPEN_CREATE) { + if (flag & APR_FOPEN_EXCL) { /* only create new if file does not already exist */ createflags = CREATE_NEW; - } else if (flag & APR_TRUNCATE) { + } else if (flag & APR_FOPEN_TRUNCATE) { /* truncate existing file or create new */ createflags = CREATE_ALWAYS; } else { /* open existing but create if necessary */ createflags = OPEN_ALWAYS; } - } else if (flag & APR_TRUNCATE) { + } else if (flag & APR_FOPEN_TRUNCATE) { /* only truncate if file already exists */ createflags = TRUNCATE_EXISTING; } else { @@ -126,85 +364,309 @@ ap_status_t ap_open(ap_file_t **dafile, const char *fname, createflags = OPEN_EXISTING; } - if ((flag & APR_EXCL) && !(flag & APR_CREATE)) { - (*dafile)->filehand = INVALID_HANDLE_VALUE; + if ((flag & APR_FOPEN_EXCL) && !(flag & APR_FOPEN_CREATE)) { return APR_EACCES; } + + if (flag & APR_FOPEN_DELONCLOSE) { + attributes |= FILE_FLAG_DELETE_ON_CLOSE; + } - if (flag & APR_APPEND) { - (*dafile)->append = 1; + if (flag & APR_OPENLINK) { + attributes |= FILE_FLAG_OPEN_REPARSE_POINT; } - else { - (*dafile)->append = 0; + + /* Without READ or WRITE, we fail unless apr called apr_file_open + * internally with the private APR_OPENINFO flag. + * + * With the APR_OPENINFO flag on NT, use the option flag + * FILE_FLAG_BACKUP_SEMANTICS to allow us to open directories. + * See the static resolve_ident() fn in file_io/win32/filestat.c + */ + if (!(flag & (APR_FOPEN_READ | APR_FOPEN_WRITE))) { + if (flag & APR_OPENINFO) { + if (apr_os_level >= APR_WIN_NT) { + attributes |= FILE_FLAG_BACKUP_SEMANTICS; + } + } + else { + return APR_EACCES; + } + if (flag & APR_READCONTROL) + oflags |= READ_CONTROL; } - attributes = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN; - if (flag & APR_DELONCLOSE) { - attributes |= FILE_FLAG_DELETE_ON_CLOSE; + if (flag & APR_FOPEN_XTHREAD) { + /* This win32 specific feature is required + * to allow multiple threads to work with the file. + */ + attributes |= FILE_FLAG_OVERLAPPED; + } + +#if APR_HAS_UNICODE_FS + IF_WIN_OS_IS_UNICODE + { + apr_wchar_t wfname[APR_PATH_MAX]; + + if (flag & APR_FOPEN_SENDFILE_ENABLED) { + /* This feature is required to enable sendfile operations + * against the file on Win32. Also implies APR_FOPEN_XTHREAD. + */ + flag |= APR_FOPEN_XTHREAD; + attributes |= FILE_FLAG_SEQUENTIAL_SCAN | FILE_FLAG_OVERLAPPED; + } + + if ((rv = utf8_to_unicode_path(wfname, sizeof(wfname) + / sizeof(apr_wchar_t), fname))) + return rv; + handle = CreateFileW(wfname, oflags, sharemode, + NULL, createflags, attributes, 0); + } +#endif +#if APR_HAS_ANSI_FS + ELSE_WIN_OS_IS_ANSI { + handle = CreateFileA(fname, oflags, sharemode, + NULL, createflags, attributes, 0); + /* This feature is not supported on this platform. */ + flag &= ~APR_FOPEN_SENDFILE_ENABLED; + } +#endif + if (handle == INVALID_HANDLE_VALUE) { + return apr_get_os_error(); } - (*dafile)->filehand = CreateFile(fname, oflags, sharemode, - NULL, createflags, attributes, 0); + (*new) = (apr_file_t *)apr_pcalloc(pool, sizeof(apr_file_t)); + (*new)->pool = pool; + (*new)->filehand = handle; + (*new)->fname = apr_pstrdup(pool, fname); + (*new)->flags = flag; + (*new)->timeout = -1; + (*new)->ungetchar = -1; - if ((*dafile)->filehand == INVALID_HANDLE_VALUE) { - return GetLastError(); + if (flag & APR_FOPEN_APPEND) { + (*new)->append = 1; + } + if (flag & APR_FOPEN_BUFFERED) { + (*new)->buffered = 1; + (*new)->buffer = apr_palloc(pool, APR_FILE_DEFAULT_BUFSIZE); + (*new)->bufsize = APR_FILE_DEFAULT_BUFSIZE; } - if (flag & APR_APPEND) { - SetFilePointer((*dafile)->filehand, 0, NULL, FILE_END); + /* Need the mutex to share an apr_file_t across multiple threads */ + if (flag & APR_FOPEN_XTHREAD) { + rv = apr_thread_mutex_create(&(*new)->mutex, + APR_THREAD_MUTEX_DEFAULT, pool); + if (rv) { + if (file_cleanup(*new) == APR_SUCCESS) { + apr_pool_cleanup_kill(pool, *new, file_cleanup); + } + return rv; + } } - (*dafile)->eof_hit = 0; - ap_register_cleanup((*dafile)->cntxt, (void *)(*dafile), file_cleanup, - ap_null_cleanup); +#if APR_HAS_UNICODE_FS + if ((apr_os_level >= APR_WIN_2000) && ((*new)->flags & APR_FOPEN_SPARSE)) { + if ((rv = make_sparse_file(*new)) != APR_SUCCESS) + /* The great mystery; do we close the file and return an error? + * Do we add a new APR_INCOMPLETE style error saying opened, but + * NOTSPARSE? For now let's simply mark the file as not-sparse. + */ + (*new)->flags &= ~APR_FOPEN_SPARSE; + } + else +#endif + /* This feature is not supported on this platform. */ + (*new)->flags &= ~APR_FOPEN_SPARSE; + +#if APR_FILES_AS_SOCKETS + /* Create a pollset with room for one descriptor. */ + /* ### check return codes */ + (void) apr_pollset_create(&(*new)->pollset, 1, pool, 0); +#endif + if (!(flag & APR_FOPEN_NOCLEANUP)) { + apr_pool_cleanup_register((*new)->pool, (void *)(*new), file_cleanup, + apr_pool_cleanup_null); + } return APR_SUCCESS; } -ap_status_t ap_close(ap_file_t *file) +APR_DECLARE(apr_status_t) apr_file_close(apr_file_t *file) { - ap_status_t stat; + apr_status_t stat; if ((stat = file_cleanup(file)) == APR_SUCCESS) { - ap_kill_cleanup(file->cntxt, file, file_cleanup); + apr_pool_cleanup_kill(file->pool, file, file_cleanup); + + if (file->mutex) { + apr_thread_mutex_destroy(file->mutex); + } + return APR_SUCCESS; } return stat; } -ap_status_t ap_remove_file(char *path, ap_pool_t *cont) +APR_DECLARE(apr_status_t) apr_file_remove(const char *path, apr_pool_t *pool) { - char *temp = canonical_filename(cont, path); - - if (DeleteFile(temp)) { - return APR_SUCCESS; +#if APR_HAS_UNICODE_FS + IF_WIN_OS_IS_UNICODE + { + apr_wchar_t wpath[APR_PATH_MAX]; + apr_status_t rv; + if ((rv = utf8_to_unicode_path(wpath, sizeof(wpath) + / sizeof(apr_wchar_t), path))) { + return rv; + } + if (DeleteFileW(wpath)) + return APR_SUCCESS; } - else { - return APR_EEXIST; +#endif +#if APR_HAS_ANSI_FS + ELSE_WIN_OS_IS_ANSI + if (DeleteFile(path)) + return APR_SUCCESS; +#endif + return apr_get_os_error(); +} + +APR_DECLARE(apr_status_t) apr_file_rename(const char *frompath, + const char *topath, + apr_pool_t *pool) +{ + IF_WIN_OS_IS_UNICODE + { +#if APR_HAS_UNICODE_FS + apr_wchar_t wfrompath[APR_PATH_MAX], wtopath[APR_PATH_MAX]; + apr_status_t rv; + if ((rv = utf8_to_unicode_path(wfrompath, + sizeof(wfrompath) / sizeof(apr_wchar_t), + frompath))) { + return rv; + } + if ((rv = utf8_to_unicode_path(wtopath, + sizeof(wtopath) / sizeof(apr_wchar_t), + topath))) { + return rv; + } +#ifndef _WIN32_WCE + if (MoveFileExW(wfrompath, wtopath, MOVEFILE_REPLACE_EXISTING | + MOVEFILE_COPY_ALLOWED)) +#else + if (MoveFileW(wfrompath, wtopath)) +#endif + return APR_SUCCESS; +#else + if (MoveFileEx(frompath, topath, MOVEFILE_REPLACE_EXISTING | + MOVEFILE_COPY_ALLOWED)) + return APR_SUCCESS; +#endif } +#if APR_HAS_ANSI_FS + ELSE_WIN_OS_IS_ANSI + { + /* Windows 95 and 98 do not support MoveFileEx, so we'll use + * the old MoveFile function. However, MoveFile requires that + * the new file not already exist...so we have to delete that + * file if it does. Perhaps we should back up the to-be-deleted + * file in case something happens? + */ + HANDLE handle = INVALID_HANDLE_VALUE; + + if ((handle = CreateFile(topath, GENERIC_WRITE, 0, 0, + OPEN_EXISTING, 0, 0 )) != INVALID_HANDLE_VALUE ) + { + CloseHandle(handle); + if (!DeleteFile(topath)) + return apr_get_os_error(); + } + if (MoveFile(frompath, topath)) + return APR_SUCCESS; + } +#endif + return apr_get_os_error(); } -ap_status_t ap_get_os_file(ap_os_file_t *thefile, ap_file_t *file) +APR_DECLARE(apr_status_t) apr_file_link(const char *from_path, + const char *to_path) { - if (file == NULL) { - return APR_ENOFILE; + apr_status_t rv = APR_SUCCESS; + +#if APR_HAS_UNICODE_FS + IF_WIN_OS_IS_UNICODE + { + apr_wchar_t wfrom_path[APR_PATH_MAX]; + apr_wchar_t wto_path[APR_PATH_MAX]; + + if ((rv = utf8_to_unicode_path(wfrom_path, + sizeof(wfrom_path) / sizeof(apr_wchar_t), + from_path))) + return rv; + if ((rv = utf8_to_unicode_path(wto_path, + sizeof(wto_path) / sizeof(apr_wchar_t), + to_path))) + return rv; + + if (!CreateHardLinkW(wto_path, wfrom_path, NULL)) + return apr_get_os_error(); + } +#endif +#if APR_HAS_ANSI_FS + ELSE_WIN_OS_IS_ANSI { + if (!CreateHardLinkA(to_path, from_path, NULL)) + return apr_get_os_error(); } +#endif + return rv; +} + +APR_DECLARE(apr_status_t) apr_os_file_get(apr_os_file_t *thefile, + apr_file_t *file) +{ *thefile = file->filehand; return APR_SUCCESS; } -ap_status_t ap_put_os_file(ap_file_t **file, ap_os_file_t *thefile, - ap_pool_t *cont) +APR_DECLARE(apr_status_t) apr_os_file_put(apr_file_t **file, + apr_os_file_t *thefile, + apr_int32_t flags, + apr_pool_t *pool) { - if ((*file) == NULL) { - if (cont == NULL) { - return APR_ENOPOOL; + (*file) = apr_pcalloc(pool, sizeof(apr_file_t)); + (*file)->pool = pool; + (*file)->filehand = *thefile; + (*file)->ungetchar = -1; /* no char avail */ + (*file)->timeout = -1; + (*file)->flags = flags; + + if (flags & APR_FOPEN_APPEND) { + (*file)->append = 1; + } + if (flags & APR_FOPEN_BUFFERED) { + (*file)->buffered = 1; + (*file)->buffer = apr_palloc(pool, APR_FILE_DEFAULT_BUFSIZE); + (*file)->bufsize = APR_FILE_DEFAULT_BUFSIZE; + } + if (flags & APR_FOPEN_XTHREAD) { + apr_status_t rv; + rv = apr_thread_mutex_create(&(*file)->mutex, + APR_THREAD_MUTEX_DEFAULT, pool); + if (rv) { + return rv; } - (*file) = (ap_file_t *)ap_pcalloc(cont, sizeof(ap_file_t)); - (*file)->cntxt = cont; } - (*file)->filehand = *thefile; + +#if APR_FILES_AS_SOCKETS + /* Create a pollset with room for one descriptor. */ + /* ### check return codes */ + (void) apr_pollset_create(&(*file)->pollset, 1, pool, 0); +#endif + /* Should we be testing if thefile is a handle to + * a PIPE and set up the mechanics appropriately? + * + * (*file)->pipe; + */ return APR_SUCCESS; } -ap_status_t ap_eof(ap_file_t *fptr) +APR_DECLARE(apr_status_t) apr_file_eof(apr_file_t *fptr) { if (fptr->eof_hit == 1) { return APR_EOF; @@ -212,19 +674,80 @@ ap_status_t ap_eof(ap_file_t *fptr) return APR_SUCCESS; } -ap_status_t ap_open_stderr(ap_file_t **thefile, ap_pool_t *cont) +APR_DECLARE(apr_status_t) apr_file_open_flags_stderr(apr_file_t **thefile, + apr_int32_t flags, + apr_pool_t *pool) { - (*thefile) = ap_pcalloc(cont, sizeof(ap_file_t)); - if ((*thefile) == NULL) { - return APR_ENOMEM; - } - (*thefile)->filehand = GetStdHandle(STD_ERROR_HANDLE); - if ((*thefile)->filehand == INVALID_HANDLE_VALUE) - return GetLastError(); - (*thefile)->cntxt = cont; - (*thefile)->fname = "STD_ERROR_HANDLE"; - (*thefile)->eof_hit = 0; +#ifdef _WIN32_WCE + return APR_ENOTIMPL; +#else + apr_os_file_t file_handle; - return APR_SUCCESS; + apr_set_os_error(APR_SUCCESS); + file_handle = GetStdHandle(STD_ERROR_HANDLE); + if (!file_handle) + file_handle = INVALID_HANDLE_VALUE; + + return apr_os_file_put(thefile, &file_handle, + flags | APR_FOPEN_WRITE | APR_STDERR_FLAG, pool); +#endif } +APR_DECLARE(apr_status_t) apr_file_open_flags_stdout(apr_file_t **thefile, + apr_int32_t flags, + apr_pool_t *pool) +{ +#ifdef _WIN32_WCE + return APR_ENOTIMPL; +#else + apr_os_file_t file_handle; + + apr_set_os_error(APR_SUCCESS); + file_handle = GetStdHandle(STD_OUTPUT_HANDLE); + if (!file_handle) + file_handle = INVALID_HANDLE_VALUE; + + return apr_os_file_put(thefile, &file_handle, + flags | APR_FOPEN_WRITE | APR_STDOUT_FLAG, pool); +#endif +} + +APR_DECLARE(apr_status_t) apr_file_open_flags_stdin(apr_file_t **thefile, + apr_int32_t flags, + apr_pool_t *pool) +{ +#ifdef _WIN32_WCE + return APR_ENOTIMPL; +#else + apr_os_file_t file_handle; + + apr_set_os_error(APR_SUCCESS); + file_handle = GetStdHandle(STD_INPUT_HANDLE); + if (!file_handle) + file_handle = INVALID_HANDLE_VALUE; + + return apr_os_file_put(thefile, &file_handle, + flags | APR_FOPEN_READ | APR_STDIN_FLAG, pool); +#endif +} + +APR_DECLARE(apr_status_t) apr_file_open_stderr(apr_file_t **thefile, apr_pool_t *pool) +{ + return apr_file_open_flags_stderr(thefile, 0, pool); +} + +APR_DECLARE(apr_status_t) apr_file_open_stdout(apr_file_t **thefile, apr_pool_t *pool) +{ + return apr_file_open_flags_stdout(thefile, 0, pool); +} + +APR_DECLARE(apr_status_t) apr_file_open_stdin(apr_file_t **thefile, apr_pool_t *pool) +{ + return apr_file_open_flags_stdin(thefile, 0, pool); +} + +APR_POOL_IMPLEMENT_ACCESSOR(file); + +APR_IMPLEMENT_INHERIT_SET(file, flags, pool, file_cleanup) + +APR_IMPLEMENT_INHERIT_UNSET(file, flags, pool, file_cleanup) diff --git a/file_io/win32/pipe.c b/file_io/win32/pipe.c index 1ab30ae0a18..6014582583d 100644 --- a/file_io/win32/pipe.c +++ b/file_io/win32/pipe.c @@ -1,117 +1,493 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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 "fileio.h" +#include "apr_arch_file_io.h" #include "apr_file_io.h" #include "apr_general.h" -#include "apr_lib.h" +#include "apr_strings.h" +#include "apr_escape.h" +#if APR_HAVE_ERRNO_H #include <errno.h> +#endif #include <string.h> #include <stdio.h> +#if APR_HAVE_SYS_TYPES_H #include <sys/types.h> +#endif +#ifdef HAVE_SYS_STAT_H #include <sys/stat.h> -#include "misc.h" +#endif +#if APR_HAVE_PROCESS_H +#include <process.h> /* for getpid() on Win32 */ +#endif +#include "apr_arch_misc.h" -ap_status_t ap_set_pipe_timeout(ap_file_t *thepipe, ap_int32_t timeout) +APR_DECLARE(apr_status_t) apr_file_pipe_timeout_set(apr_file_t *thepipe, + apr_interval_time_t timeout) { - DWORD dwMode; - ap_oslevel_e oslevel; - - /* This code relies on the fact that anonymous pipes (which - * do not support nonblocking I/O) are really named pipes - * (which support nonblocking I/O) on Windows NT. - */ - if (thepipe->pipe == 1) { + /* Always OK to unset timeouts */ + if (timeout == -1) { thepipe->timeout = timeout; - if (ap_get_oslevel(thepipe->cntxt, &oslevel) == APR_SUCCESS && - oslevel >= APR_WIN_NT) { - if (timeout == 0) { - dwMode = PIPE_NOWAIT; - } else { - dwMode = PIPE_WAIT; - } - SetNamedPipeHandleState(thepipe->filehand, &dwMode, NULL, NULL); - } return APR_SUCCESS; } - return APR_EINVAL; + if (!thepipe->pipe) { + return APR_ENOTIMPL; + } + if (timeout && !(thepipe->pOverlapped)) { + /* Cannot be nonzero if a pipe was opened blocking + */ + return APR_EINVAL; + } + thepipe->timeout = timeout; + return APR_SUCCESS; } -ap_status_t ap_create_pipe(ap_file_t **in, ap_file_t **out, ap_pool_t *cont) +APR_DECLARE(apr_status_t) apr_file_pipe_timeout_get(apr_file_t *thepipe, + apr_interval_time_t *timeout) { + /* Always OK to get the timeout (even if it's unset ... -1) */ + *timeout = thepipe->timeout; + return APR_SUCCESS; +} + +static apr_status_t file_pipe_create(apr_file_t **in, + apr_file_t **out, + apr_int32_t blocking, + apr_pool_t *pool_in, + apr_pool_t *pool_out) +{ +#ifdef _WIN32_WCE + return APR_ENOTIMPL; +#else SECURITY_ATTRIBUTES sa; + static unsigned long id = 0; + DWORD dwPipeMode; + DWORD dwOpenMode; sa.nLength = sizeof(sa); - sa.bInheritHandle = TRUE; + +#if APR_HAS_UNICODE_FS + IF_WIN_OS_IS_UNICODE + sa.bInheritHandle = FALSE; +#endif +#if APR_HAS_ANSI_FS + ELSE_WIN_OS_IS_ANSI + sa.bInheritHandle = TRUE; +#endif sa.lpSecurityDescriptor = NULL; - (*in) = (ap_file_t *)ap_pcalloc(cont, sizeof(ap_file_t)); - (*in)->cntxt = cont; + (*in) = (apr_file_t *)apr_pcalloc(pool_in, sizeof(apr_file_t)); + (*in)->pool = pool_in; + (*in)->fname = NULL; (*in)->pipe = 1; - (*in)->fname = ap_pstrdup(cont, "PIPE"); (*in)->timeout = -1; (*in)->ungetchar = -1; - - (*out) = (ap_file_t *)ap_pcalloc(cont, sizeof(ap_file_t)); - (*out)->cntxt = cont; + (*in)->eof_hit = 0; + (*in)->filePtr = 0; + (*in)->bufpos = 0; + (*in)->dataRead = 0; + (*in)->direction = 0; + (*in)->pOverlapped = NULL; +#if APR_FILES_AS_SOCKETS + (void) apr_pollset_create(&(*in)->pollset, 1, p, 0); +#endif + (*out) = (apr_file_t *)apr_pcalloc(pool_out, sizeof(apr_file_t)); + (*out)->pool = pool_out; + (*out)->fname = NULL; (*out)->pipe = 1; - (*out)->fname = ap_pstrdup(cont, "PIPE"); (*out)->timeout = -1; + (*out)->ungetchar = -1; + (*out)->eof_hit = 0; + (*out)->filePtr = 0; + (*out)->bufpos = 0; + (*out)->dataRead = 0; + (*out)->direction = 0; + (*out)->pOverlapped = NULL; +#if APR_FILES_AS_SOCKETS + (void) apr_pollset_create(&(*out)->pollset, 1, p, 0); +#endif + if (apr_os_level >= APR_WIN_NT) { + char rand[8]; + int pid = getpid(); +#define FMT_PIPE_NAME "\\\\.\\pipe\\apr-pipe-%x.%lx." + /* ^ ^ ^ + * pid | | + * | | + * id | + * | + * hex-escaped rand[8] (16 bytes) + */ + char name[sizeof FMT_PIPE_NAME + 2 * sizeof(pid) + + 2 * sizeof(id) + + 2 * sizeof(rand)]; + apr_size_t pos; + + /* Create the read end of the pipe */ + dwOpenMode = PIPE_ACCESS_INBOUND; +#ifdef FILE_FLAG_FIRST_PIPE_INSTANCE + dwOpenMode |= FILE_FLAG_FIRST_PIPE_INSTANCE; +#endif + if (blocking == APR_WRITE_BLOCK /* READ_NONBLOCK */ + || blocking == APR_FULL_NONBLOCK) { + dwOpenMode |= FILE_FLAG_OVERLAPPED; + (*in)->pOverlapped = + (OVERLAPPED*) apr_pcalloc((*in)->pool, sizeof(OVERLAPPED)); + (*in)->pOverlapped->hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + (*in)->timeout = 0; + } + dwPipeMode = 0; + + apr_generate_random_bytes(rand, sizeof rand); + pos = apr_snprintf(name, sizeof name, FMT_PIPE_NAME, pid, id++); + apr_escape_hex(name + pos, rand, sizeof rand, 0, NULL); + + (*in)->filehand = CreateNamedPipe(name, + dwOpenMode, + dwPipeMode, + 1, /* nMaxInstances, */ + 0, /* nOutBufferSize, */ + 65536, /* nInBufferSize, */ + 1, /* nDefaultTimeOut, */ + &sa); + if ((*in)->filehand == INVALID_HANDLE_VALUE) { + apr_status_t rv = apr_get_os_error(); + file_cleanup(*in); + return rv; + } - if (!CreatePipe(&(*in)->filehand, &(*out)->filehand, &sa, 0)) { - return GetLastError(); + /* Create the write end of the pipe */ + dwOpenMode = FILE_ATTRIBUTE_NORMAL; + if (blocking == APR_READ_BLOCK /* WRITE_NONBLOCK */ + || blocking == APR_FULL_NONBLOCK) { + dwOpenMode |= FILE_FLAG_OVERLAPPED; + (*out)->pOverlapped = + (OVERLAPPED*) apr_pcalloc((*out)->pool, sizeof(OVERLAPPED)); + (*out)->pOverlapped->hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + (*out)->timeout = 0; + } + + (*out)->filehand = CreateFile(name, + GENERIC_WRITE, /* access mode */ + 0, /* share mode */ + &sa, /* Security attributes */ + OPEN_EXISTING, /* dwCreationDisposition */ + dwOpenMode, /* Pipe attributes */ + NULL); /* handle to template file */ + if ((*out)->filehand == INVALID_HANDLE_VALUE) { + apr_status_t rv = apr_get_os_error(); + file_cleanup(*out); + file_cleanup(*in); + return rv; + } + } + else { + /* Pipes on Win9* are blocking. Live with it. */ + if (!CreatePipe(&(*in)->filehand, &(*out)->filehand, &sa, 65536)) { + return apr_get_os_error(); + } } + apr_pool_cleanup_register((*in)->pool, (void *)(*in), file_cleanup, + apr_pool_cleanup_null); + apr_pool_cleanup_register((*out)->pool, (void *)(*out), file_cleanup, + apr_pool_cleanup_null); return APR_SUCCESS; +#endif /* _WIN32_WCE */ +} + +APR_DECLARE(apr_status_t) apr_file_pipe_create(apr_file_t **in, + apr_file_t **out, + apr_pool_t *pool) +{ + /* Default is full blocking pipes. */ + return file_pipe_create(in, out, APR_FULL_BLOCK, pool, pool); +} + +APR_DECLARE(apr_status_t) apr_file_pipe_create_ex(apr_file_t **in, + apr_file_t **out, + apr_int32_t blocking, + apr_pool_t *pool) +{ + return file_pipe_create(in, out, blocking, pool, pool); +} + +APR_DECLARE(apr_status_t) apr_file_pipe_create_pools(apr_file_t **in, + apr_file_t **out, + apr_int32_t blocking, + apr_pool_t *pool_in, + apr_pool_t *pool_out) +{ + return file_pipe_create(in, out, blocking, pool_in, pool_out); +} + +APR_DECLARE(apr_status_t) apr_file_namedpipe_create(const char *filename, + apr_fileperms_t perm, + apr_pool_t *pool) +{ + /* Not yet implemented, interface not suitable. + * Win32 requires the named pipe to be *opened* at the time it's + * created, and to do so, blocking or non blocking must be elected. + */ + return APR_ENOTIMPL; +} + + +/* XXX: Problem; we need to choose between blocking and nonblocking based + * on how *thefile was opened, and we don't have that information :-/ + * Hack; assume a blocking socket, since the most common use for the fn + * would be to handle stdio-style or blocking pipes. Win32 doesn't have + * select() blocking for pipes anyways :( + */ +APR_DECLARE(apr_status_t) apr_os_pipe_put_ex(apr_file_t **file, + apr_os_file_t *thefile, + int register_cleanup, + apr_pool_t *pool) +{ + (*file) = apr_pcalloc(pool, sizeof(apr_file_t)); + (*file)->pool = pool; + (*file)->pipe = 1; + (*file)->timeout = -1; + (*file)->ungetchar = -1; + (*file)->filehand = *thefile; +#if APR_FILES_AS_SOCKETS + (void) apr_pollset_create(&(*file)->pollset, 1, pool, 0); +#endif + if (register_cleanup) { + apr_pool_cleanup_register(pool, *file, file_cleanup, + apr_pool_cleanup_null); + } + + return APR_SUCCESS; +} + + +APR_DECLARE(apr_status_t) apr_os_pipe_put(apr_file_t **file, + apr_os_file_t *thefile, + apr_pool_t *pool) +{ + return apr_os_pipe_put_ex(file, thefile, 0, pool); +} + +static apr_status_t create_socket_pipe(SOCKET *rd, SOCKET *wr) +{ + static int id = 0; + FD_SET rs; + SOCKET ls; + struct timeval socktm; + struct sockaddr_in pa; + struct sockaddr_in la; + struct sockaddr_in ca; + int nrd; + apr_status_t rv = APR_SUCCESS; + int ll = sizeof(la); + int lc = sizeof(ca); + unsigned long bm = 1; + int uid[2]; + int iid[2]; + + *rd = INVALID_SOCKET; + *wr = INVALID_SOCKET; + + /* Create the unique socket identifier + * so that we know the connection originated + * from us. + */ + uid[0] = getpid(); + uid[1] = id++; + if ((ls = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) { + return apr_get_netos_error(); + } + + pa.sin_family = AF_INET; + pa.sin_port = 0; + pa.sin_addr.s_addr = inet_addr("127.0.0.1"); + + if (bind(ls, (SOCKADDR *)&pa, sizeof(pa)) == SOCKET_ERROR) { + rv = apr_get_netos_error(); + goto cleanup; + } + if (getsockname(ls, (SOCKADDR *)&la, &ll) == SOCKET_ERROR) { + rv = apr_get_netos_error(); + goto cleanup; + } + if (listen(ls, 1) == SOCKET_ERROR) { + rv = apr_get_netos_error(); + goto cleanup; + } + if ((*wr = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) { + rv = apr_get_netos_error(); + goto cleanup; + } + if (connect(*wr, (SOCKADDR *)&la, sizeof(la)) == SOCKET_ERROR) { + rv = apr_get_netos_error(); + goto cleanup; + } + if (send(*wr, (char *)uid, sizeof(uid), 0) != sizeof(uid)) { + if ((rv = apr_get_netos_error()) == 0) { + rv = APR_EINVAL; + } + goto cleanup; + } + if (ioctlsocket(ls, FIONBIO, &bm) == SOCKET_ERROR) { + rv = apr_get_netos_error(); + goto cleanup; + } + for (;;) { + int ns; + int nc = 0; + /* Listening socket is nonblocking by now. + * The accept should create the socket + * immediatelly because we are connected already. + * However on buys systems this can take a while + * until winsock gets a chance to handle the events. + */ + FD_ZERO(&rs); + FD_SET(ls, &rs); + + socktm.tv_sec = 1; + socktm.tv_usec = 0; + if ((ns = select(0, &rs, NULL, NULL, &socktm)) == SOCKET_ERROR) { + /* Accept still not signaled */ + Sleep(100); + continue; + } + if (ns == 0) { + /* No connections in the last second */ + continue; + } + if ((*rd = accept(ls, (SOCKADDR *)&ca, &lc)) == INVALID_SOCKET) { + rv = apr_get_netos_error(); + goto cleanup; + } + /* Verify the connection by reading the send identification. + */ + do { + if (nc++) + Sleep(1); + nrd = recv(*rd, (char *)iid, sizeof(iid), 0); + rv = nrd == SOCKET_ERROR ? apr_get_netos_error() : APR_SUCCESS; + } while (APR_STATUS_IS_EAGAIN(rv)); + + if (nrd == sizeof(iid)) { + if (memcmp(uid, iid, sizeof(uid)) == 0) { + /* Wow, we recived what we send. + * Put read side of the pipe to the blocking + * mode and return. + */ + bm = 0; + if (ioctlsocket(*rd, FIONBIO, &bm) == SOCKET_ERROR) { + rv = apr_get_netos_error(); + goto cleanup; + } + break; + } + } + else if (nrd == SOCKET_ERROR) { + goto cleanup; + } + closesocket(*rd); + } + /* We don't need the listening socket any more */ + closesocket(ls); + return 0; + +cleanup: + /* Don't leak resources */ + if (*rd != INVALID_SOCKET) + closesocket(*rd); + if (*wr != INVALID_SOCKET) + closesocket(*wr); + + *rd = INVALID_SOCKET; + *wr = INVALID_SOCKET; + closesocket(ls); + return rv; +} + +static apr_status_t socket_pipe_cleanup(void *thefile) +{ + apr_file_t *file = thefile; + if (file->filehand != INVALID_HANDLE_VALUE) { + shutdown((SOCKET)file->filehand, SD_BOTH); + closesocket((SOCKET)file->filehand); + file->filehand = INVALID_HANDLE_VALUE; + } + return APR_SUCCESS; +} + +apr_status_t file_socket_pipe_create(apr_file_t **in, + apr_file_t **out, + apr_pool_t *p) +{ + apr_status_t rv; + SOCKET rd; + SOCKET wr; + + if ((rv = create_socket_pipe(&rd, &wr)) != APR_SUCCESS) { + return rv; + } + (*in) = (apr_file_t *)apr_pcalloc(p, sizeof(apr_file_t)); + (*in)->pool = p; + (*in)->fname = NULL; + (*in)->pipe = 1; + (*in)->timeout = -1; + (*in)->ungetchar = -1; + (*in)->eof_hit = 0; + (*in)->filePtr = 0; + (*in)->bufpos = 0; + (*in)->dataRead = 0; + (*in)->direction = 0; + (*in)->pOverlapped = (OVERLAPPED*)apr_pcalloc(p, sizeof(OVERLAPPED)); + (*in)->filehand = (HANDLE)rd; + + (*out) = (apr_file_t *)apr_pcalloc(p, sizeof(apr_file_t)); + (*out)->pool = p; + (*out)->fname = NULL; + (*out)->pipe = 1; + (*out)->timeout = -1; + (*out)->ungetchar = -1; + (*out)->eof_hit = 0; + (*out)->filePtr = 0; + (*out)->bufpos = 0; + (*out)->dataRead = 0; + (*out)->direction = 0; + (*out)->pOverlapped = (OVERLAPPED*)apr_pcalloc(p, sizeof(OVERLAPPED)); + (*out)->filehand = (HANDLE)wr; + + apr_pool_cleanup_register(p, (void *)(*in), socket_pipe_cleanup, + apr_pool_cleanup_null); + apr_pool_cleanup_register(p, (void *)(*out), socket_pipe_cleanup, + apr_pool_cleanup_null); + + return rv; +} + +apr_status_t file_socket_pipe_close(apr_file_t *file) +{ + apr_status_t stat; + if (!file->pipe) + return apr_file_close(file); + if ((stat = socket_pipe_cleanup(file)) == APR_SUCCESS) { + apr_pool_cleanup_kill(file->pool, file, socket_pipe_cleanup); + + if (file->mutex) { + apr_thread_mutex_destroy(file->mutex); + } + + return APR_SUCCESS; + } + return stat; } diff --git a/file_io/win32/readwrite.c b/file_io/win32/readwrite.c index fb16769d834..5ad2c3b83ce 100644 --- a/file_io/win32/readwrite.c +++ b/file_io/win32/readwrite.c @@ -1,126 +1,523 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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 "fileio.h" +#include "apr_arch_file_io.h" #include "apr_file_io.h" #include "apr_general.h" +#include "apr_strings.h" #include "apr_lib.h" #include "apr_errno.h" #include <malloc.h> -#include <windows.h> -#include "atime.h" +#include "apr_arch_atime.h" +#include "apr_arch_misc.h" + +/* + * read_with_timeout() + * Uses async i/o to emulate unix non-blocking i/o with timeouts. + */ +static apr_status_t read_with_timeout(apr_file_t *file, void *buf, apr_size_t len_in, apr_size_t *nbytes) +{ + apr_status_t rv; + DWORD res; + DWORD len = (DWORD)len_in; + DWORD bytesread = 0; -#define GetFilePointer(hfile) SetFilePointer(hfile,0,NULL, FILE_CURRENT) + /* Handle the zero timeout non-blocking case */ + if (file->timeout == 0) { + /* Peek at the pipe. If there is no data available, return APR_EAGAIN. + * If data is available, go ahead and read it. + */ + if (file->pipe) { + DWORD bytes; + if (!PeekNamedPipe(file->filehand, NULL, 0, NULL, &bytes, NULL)) { + rv = apr_get_os_error(); + if (rv == APR_FROM_OS_ERROR(ERROR_BROKEN_PIPE)) { + rv = APR_EOF; + } + *nbytes = 0; + return rv; + } + else { + if (bytes == 0) { + *nbytes = 0; + return APR_EAGAIN; + } + if (len > bytes) { + len = bytes; + } + } + } + else { + /* ToDo: Handle zero timeout non-blocking file i/o + * This is not needed until an APR application needs to + * timeout file i/o (which means setting file i/o non-blocking) + */ + } + } -ap_status_t ap_read(ap_file_t *thefile, void *buf, ap_ssize_t *nbytes) + if (file->pOverlapped && !file->pipe) { + file->pOverlapped->Offset = (DWORD)file->filePtr; + file->pOverlapped->OffsetHigh = (DWORD)(file->filePtr >> 32); + } + + if (ReadFile(file->filehand, buf, len, + &bytesread, file->pOverlapped)) { + rv = APR_SUCCESS; + } + else { + rv = apr_get_os_error(); + if (rv == APR_FROM_OS_ERROR(ERROR_IO_PENDING)) { + /* Wait for the pending i/o, timeout converted from us to ms + * Note that we loop if someone gives up the event, since + * folks suggest that WAIT_ABANDONED isn't actually a result + * but an alert that ownership of the event has passed from + * one owner to a new proc/thread. + */ + do { + res = WaitForSingleObject(file->pOverlapped->hEvent, + (file->timeout > 0) + ? (DWORD)(file->timeout/1000) + : ((file->timeout == -1) + ? INFINITE : 0)); + } while (res == WAIT_ABANDONED); + + /* There is one case that represents entirely + * successful operations, otherwise we will cancel + * the operation in progress. + */ + if (res != WAIT_OBJECT_0) { + CancelIo(file->filehand); + } + + /* Ignore any failures above. Attempt to complete + * the overlapped operation and use only _its_ result. + * For example, CancelIo or WaitForSingleObject can + * fail if the handle is closed, yet the read may have + * completed before we attempted to CancelIo... + */ + if (GetOverlappedResult(file->filehand, file->pOverlapped, + &bytesread, TRUE)) { + rv = APR_SUCCESS; + } + else { + rv = apr_get_os_error(); + if (((rv == APR_FROM_OS_ERROR(ERROR_IO_INCOMPLETE)) + || (rv == APR_FROM_OS_ERROR(ERROR_OPERATION_ABORTED))) + && (res == WAIT_TIMEOUT)) + rv = APR_TIMEUP; + } + } + if (rv == APR_FROM_OS_ERROR(ERROR_BROKEN_PIPE)) { + /* Assume ERROR_BROKEN_PIPE signals an EOF reading from a pipe */ + rv = APR_EOF; + } else if (rv == APR_FROM_OS_ERROR(ERROR_HANDLE_EOF)) { + /* Did we hit EOF reading from the handle? */ + rv = APR_EOF; + } + } + + /* OK and 0 bytes read ==> end of file */ + if (rv == APR_SUCCESS && bytesread == 0) + rv = APR_EOF; + + if (rv == APR_SUCCESS && file->pOverlapped && !file->pipe) { + file->filePtr += bytesread; + } + *nbytes = bytesread; + return rv; +} + +static apr_status_t read_buffered(apr_file_t *thefile, void *buf, apr_size_t *len) { - DWORD bread; - int lasterror; + apr_status_t rv; + char *pos = (char *)buf; + apr_size_t blocksize; + apr_size_t size = *len; - if (ReadFile(thefile->filehand, buf, *nbytes, &bread, NULL)) { - *nbytes = bread; - return APR_SUCCESS; + if (thefile->direction == 1) { + rv = apr_file_flush(thefile); + if (rv != APR_SUCCESS) { + return rv; + } + thefile->bufpos = 0; + thefile->direction = 0; + thefile->dataRead = 0; } - *nbytes = 0; - lasterror = GetLastError(); - if (lasterror == ERROR_BROKEN_PIPE) { - /* Assume ERROR_BROKEN_PIPE signals an EOF reading from a pipe */ + rv = 0; + while (rv == 0 && size > 0) { + if (thefile->bufpos >= thefile->dataRead) { + apr_size_t read; + rv = read_with_timeout(thefile, thefile->buffer, + thefile->bufsize, &read); + if (read == 0) { + if (rv == APR_EOF) + thefile->eof_hit = TRUE; + break; + } + else { + thefile->dataRead = read; + thefile->filePtr += thefile->dataRead; + thefile->bufpos = 0; + } + } + + blocksize = size > thefile->dataRead - thefile->bufpos ? thefile->dataRead - thefile->bufpos : size; + memcpy(pos, thefile->buffer + thefile->bufpos, blocksize); + thefile->bufpos += blocksize; + pos += blocksize; + size -= blocksize; + } + + *len = pos - (char *)buf; + if (*len) { + rv = APR_SUCCESS; + } + + return rv; +} + +APR_DECLARE(apr_status_t) apr_file_read(apr_file_t *thefile, void *buf, apr_size_t *len) +{ + apr_status_t rv; + DWORD bytes_read = 0; + + if (*len <= 0) { + *len = 0; return APR_SUCCESS; - } else if (lasterror == ERROR_NO_DATA) { - /* Receive this error on a read to a pipe in nonblocking mode */ - return APR_EAGAIN; } - return lasterror; + /* If the file is open for xthread support, allocate and + * initialize the overlapped and io completion event (hEvent). + * Threads should NOT share an apr_file_t or its hEvent. + */ + if ((thefile->flags & APR_FOPEN_XTHREAD) && !thefile->pOverlapped ) { + thefile->pOverlapped = (OVERLAPPED*) apr_pcalloc(thefile->pool, + sizeof(OVERLAPPED)); + thefile->pOverlapped->hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + if (!thefile->pOverlapped->hEvent) { + rv = apr_get_os_error(); + return rv; + } + } + + /* Handle the ungetchar if there is one */ + if (thefile->ungetchar != -1) { + bytes_read = 1; + *(char *)buf = (char)thefile->ungetchar; + buf = (char *)buf + 1; + (*len)--; + thefile->ungetchar = -1; + if (*len == 0) { + *len = bytes_read; + return APR_SUCCESS; + } + } + if (thefile->buffered) { + if (thefile->flags & APR_FOPEN_XTHREAD) { + apr_thread_mutex_lock(thefile->mutex); + } + rv = read_buffered(thefile, buf, len); + if (thefile->flags & APR_FOPEN_XTHREAD) { + apr_thread_mutex_unlock(thefile->mutex); + } + } else { + /* Unbuffered i/o */ + apr_size_t nbytes; + rv = read_with_timeout(thefile, buf, *len, &nbytes); + if (rv == APR_EOF) + thefile->eof_hit = TRUE; + *len = nbytes; + } + + return rv; } -ap_status_t ap_write(ap_file_t *thefile, void *buf, ap_ssize_t *nbytes) +APR_DECLARE(apr_status_t) apr_file_rotating_check(apr_file_t *thefile) { - ap_status_t rv; - DWORD bwrote; + return APR_ENOTIMPL; +} - if (!thefile->pipe && thefile->append) { - SetFilePointer(thefile->filehand, 0, NULL, FILE_END); +APR_DECLARE(apr_status_t) apr_file_rotating_manual_check(apr_file_t *thefile, + apr_time_t n) +{ + return APR_ENOTIMPL; +} + +/* Helper function that adapts WriteFile() to apr_size_t instead + * of DWORD. */ +static apr_status_t write_helper(HANDLE filehand, const char *buf, + apr_size_t len, apr_size_t *pwritten) +{ + apr_size_t remaining = len; + + *pwritten = 0; + do { + DWORD to_write; + DWORD written; + + if (remaining > APR_DWORD_MAX) { + to_write = APR_DWORD_MAX; + } + else { + to_write = (DWORD)remaining; + } + + if (!WriteFile(filehand, buf, to_write, &written, NULL)) { + *pwritten += written; + return apr_get_os_error(); + } + + *pwritten += written; + remaining -= written; + buf += written; + } while (remaining); + + return APR_SUCCESS; +} + +static apr_status_t write_buffered(apr_file_t *thefile, const char *buf, + apr_size_t len, apr_size_t *pwritten) +{ + apr_status_t rv; + + if (thefile->direction == 0) { + /* Position file pointer for writing at the offset we are logically reading from */ + apr_off_t offset = thefile->filePtr - thefile->dataRead + thefile->bufpos; + DWORD offlo = (DWORD)offset; + LONG offhi = (LONG)(offset >> 32); + if (offset != thefile->filePtr) + SetFilePointer(thefile->filehand, offlo, &offhi, FILE_BEGIN); + thefile->bufpos = thefile->dataRead = 0; + thefile->direction = 1; } - if (WriteFile(thefile->filehand, buf, *nbytes, &bwrote, NULL)) { - *nbytes = bwrote; - rv = APR_SUCCESS; - } - else { - (*nbytes) = 0; - rv = GetLastError(); + + *pwritten = 0; + + while (len > 0) { + if (thefile->bufpos == thefile->bufsize) { /* write buffer is full */ + rv = apr_file_flush(thefile); + if (rv) { + return rv; + } + } + /* If our buffer is empty, and we cannot fit the remaining chunk + * into it, write the chunk with a single syscall and return. + */ + if (thefile->bufpos == 0 && len > thefile->bufsize) { + apr_size_t written; + + rv = write_helper(thefile->filehand, buf, len, &written); + thefile->filePtr += written; + *pwritten += written; + return rv; + } + else { + apr_size_t blocksize = len; + + if (blocksize > thefile->bufsize - thefile->bufpos) { + blocksize = thefile->bufsize - thefile->bufpos; + } + memcpy(thefile->buffer + thefile->bufpos, buf, blocksize); + thefile->bufpos += blocksize; + buf += blocksize; + len -= blocksize; + *pwritten += blocksize; + } } + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_file_write(apr_file_t *thefile, const void *buf, apr_size_t *nbytes) +{ + apr_status_t rv; + DWORD bwrote; + + /* If the file is open for xthread support, allocate and + * initialize the overlapped and io completion event (hEvent). + * Threads should NOT share an apr_file_t or its hEvent. + */ + if ((thefile->flags & APR_FOPEN_XTHREAD) && !thefile->pOverlapped ) { + thefile->pOverlapped = (OVERLAPPED*) apr_pcalloc(thefile->pool, + sizeof(OVERLAPPED)); + thefile->pOverlapped->hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + if (!thefile->pOverlapped->hEvent) { + rv = apr_get_os_error(); + return rv; + } + } + + if (thefile->buffered) { + if (thefile->flags & APR_FOPEN_XTHREAD) { + apr_thread_mutex_lock(thefile->mutex); + } + rv = write_buffered(thefile, buf, *nbytes, nbytes); + if (thefile->flags & APR_FOPEN_XTHREAD) { + apr_thread_mutex_unlock(thefile->mutex); + } + return rv; + } else { + if (thefile->pipe) { + rv = WriteFile(thefile->filehand, buf, (DWORD)*nbytes, &bwrote, + thefile->pOverlapped); + } + else if (thefile->append && !thefile->pOverlapped) { + OVERLAPPED ov = {0}; + + /* If the file is opened for synchronous I/O, take advantage of the + * documented way to atomically append data by calling WriteFile() + * with both the OVERLAPPED.Offset and OffsetHigh members set to + * 0xFFFFFFFF. This avoids calling LockFile() that is otherwise + * required to avoid a race condition between seeking to the end + * and writing data. Not locking the file improves robustness of + * such appends and avoids a deadlock when appending to an already + * locked file, as described in PR50058. + * + * We use this approach only for files opened for synchronous I/O + * because in this case the I/O Manager maintains the current file + * position. Otherwise, the file offset returned or changed by + * the SetFilePointer() API is not guaranteed to be valid and that + * could, for instance, break apr_file_seek() calls after appending + * data. Sadly, if a file is opened for asynchronous I/O, this + * call doesn't update the OVERLAPPED.Offset member to reflect the + * actual offset used when appending the data (which we could then + * use to make seeking and other operations involving filePtr work). + * Therefore, when appending to files opened for asynchronous I/O, + * we still use the LockFile + SetFilePointer + WriteFile approach. + * + * References: + * https://bz.apache.org/bugzilla/show_bug.cgi?id=50058 + * https://msdn.microsoft.com/en-us/library/windows/desktop/aa365747 + * https://msdn.microsoft.com/en-us/library/windows/hardware/ff567121 + */ + ov.Offset = MAXDWORD; + ov.OffsetHigh = MAXDWORD; + rv = WriteFile(thefile->filehand, buf, (DWORD)*nbytes, &bwrote, &ov); + } + else { + apr_off_t offset = 0; + apr_status_t rc; + if (thefile->append) { + if (thefile->flags & APR_FOPEN_XTHREAD) { + /* apr_file_lock will mutex the file across processes. + * The call to apr_thread_mutex_lock is added to avoid + * a race condition between LockFile and WriteFile + * that occasionally leads to deadlocked threads. + */ + apr_thread_mutex_lock(thefile->mutex); + } + rc = apr_file_lock(thefile, APR_FLOCK_EXCLUSIVE); + if (rc != APR_SUCCESS) { + if (thefile->flags & APR_FOPEN_XTHREAD) { + apr_thread_mutex_unlock(thefile->mutex); + } + return rc; + } + rc = apr_file_seek(thefile, APR_END, &offset); + if (rc != APR_SUCCESS) { + if (thefile->flags & APR_FOPEN_XTHREAD) { + apr_thread_mutex_unlock(thefile->mutex); + } + return rc; + } + } + if (thefile->pOverlapped) { + thefile->pOverlapped->Offset = (DWORD)thefile->filePtr; + thefile->pOverlapped->OffsetHigh = (DWORD)(thefile->filePtr >> 32); + } + rv = WriteFile(thefile->filehand, buf, (DWORD)*nbytes, &bwrote, + thefile->pOverlapped); + if (thefile->append) { + apr_file_unlock(thefile); + if (thefile->flags & APR_FOPEN_XTHREAD) { + apr_thread_mutex_unlock(thefile->mutex); + } + } + } + if (rv) { + *nbytes = bwrote; + rv = APR_SUCCESS; + } + else { + (*nbytes) = 0; + rv = apr_get_os_error(); + + /* XXX: This must be corrected, per the apr_file_read logic!!! */ + if (rv == APR_FROM_OS_ERROR(ERROR_IO_PENDING)) { + + DWORD timeout_ms; + + if (thefile->timeout == 0) { + timeout_ms = 0; + } + else if (thefile->timeout < 0) { + timeout_ms = INFINITE; + } + else { + timeout_ms = (DWORD)(thefile->timeout / 1000); + } + + rv = WaitForSingleObject(thefile->pOverlapped->hEvent, timeout_ms); + switch (rv) { + case WAIT_OBJECT_0: + GetOverlappedResult(thefile->filehand, thefile->pOverlapped, + &bwrote, TRUE); + *nbytes = bwrote; + rv = APR_SUCCESS; + break; + case WAIT_TIMEOUT: + rv = (timeout_ms == 0) ? APR_EAGAIN : APR_TIMEUP; + break; + case WAIT_FAILED: + rv = apr_get_os_error(); + break; + default: + break; + } + if (rv != APR_SUCCESS) { + if (apr_os_level >= APR_WIN_98) + CancelIo(thefile->filehand); + } + } + } + if (rv == APR_SUCCESS && thefile->pOverlapped && !thefile->pipe) { + thefile->filePtr += *nbytes; + } + } return rv; } -/* - * Too bad WriteFileGather() is not supported on 95&98 (or NT prior to SP2) +/* ToDo: Write for it anyway and test the oslevel! + * Too bad WriteFileGather() is not supported on 95&98 (or NT prior to SP2) */ -ap_status_t ap_writev(ap_file_t *thefile, const struct iovec *vec, ap_size_t nvec, - ap_ssize_t *nbytes) +APR_DECLARE(apr_status_t) apr_file_writev(apr_file_t *thefile, + const struct iovec *vec, + apr_size_t nvec, + apr_size_t *nbytes) { - ap_status_t rv = APR_SUCCESS; - int i; - DWORD bwrote = 0; + apr_status_t rv = APR_SUCCESS; + apr_size_t i; + apr_size_t bwrote = 0; char *buf; *nbytes = 0; for (i = 0; i < nvec; i++) { buf = vec[i].iov_base; bwrote = vec[i].iov_len; - rv = ap_write(thefile, buf, &bwrote); + rv = apr_file_write(thefile, buf, &bwrote); *nbytes += bwrote; if (rv != APR_SUCCESS) { break; @@ -129,50 +526,31 @@ ap_status_t ap_writev(ap_file_t *thefile, const struct iovec *vec, ap_size_t nve return rv; } -ap_status_t ap_putc(char ch, ap_file_t *thefile) +APR_DECLARE(apr_status_t) apr_file_putc(char ch, apr_file_t *thefile) { - DWORD len = 1; + apr_size_t len = 1; - return ap_write(thefile, &ch, &len); + return apr_file_write(thefile, &ch, &len); } -ap_status_t ap_ungetc(char ch, ap_file_t *thefile) +APR_DECLARE(apr_status_t) apr_file_ungetc(char ch, apr_file_t *thefile) { - /* - * Your application must provide its own serialization (locking) if - * it allows multiple threads to access the same file handle - * concurrently. - * - * ToDo: This function does not use the char ch argument. Could add - * gorpy code to read the file after the SetFilePointer() call to - * make sure the character pushed back on the stream is the same as - * arg ch. Then, need to SetFilePointer() once more to reset the - * file pointer to the point before the read. Yech... Just assume - * the caller knows what he is doing. There may be a nifty Win32 - * call for this I've not discovered.... - */ - - /* SetFilePointer is only valid for a file device ...*/ - if (GetFileType(thefile->filehand) != FILE_TYPE_DISK) { - return GetLastError(); - } - /* and the file pointer is not pointing to the start of the file. */ - if (GetFilePointer(thefile->filehand)) { - if (SetFilePointer(thefile->filehand, -1, NULL, FILE_CURRENT) - == 0xFFFFFFFF) { - return GetLastError(); - } - } - - return APR_SUCCESS; + thefile->ungetchar = (unsigned char) ch; + return APR_SUCCESS; } -ap_status_t ap_getc(char *ch, ap_file_t *thefile) +APR_DECLARE(apr_status_t) apr_file_getc(char *ch, apr_file_t *thefile) { - DWORD bread; - if (!ReadFile(thefile->filehand, ch, 1, &bread, NULL)) { - return GetLastError(); + apr_status_t rc; + apr_size_t bread; + + bread = 1; + rc = apr_file_read(thefile, ch, &bread); + + if (rc) { + return rc; } + if (bread == 0) { thefile->eof_hit = TRUE; return APR_EOF; @@ -180,74 +558,211 @@ ap_status_t ap_getc(char *ch, ap_file_t *thefile) return APR_SUCCESS; } -ap_status_t ap_puts(char *str, ap_file_t *thefile) +APR_DECLARE(apr_status_t) apr_file_puts(const char *str, apr_file_t *thefile) { - DWORD len = strlen(str); + apr_size_t len = strlen(str); - return ap_write(thefile, str, &len); + return apr_file_write(thefile, str, &len); } -ap_status_t ap_fgets(char *str, int len, ap_file_t *thefile) +APR_DECLARE(apr_status_t) apr_file_gets(char *str, int len, apr_file_t *thefile) { - DWORD bread; - int i; - if (!ReadFile(thefile->filehand, str, len, &bread, NULL)) { - switch(GetLastError()) { - case ERROR_HANDLE_EOF: - return APR_EOF; - default: - return GetLastError(); + apr_status_t rv = APR_SUCCESS; + apr_size_t nbytes; + const char *str_start = str; + char *final = str + len - 1; + + /* If the file is open for xthread support, allocate and + * initialize the overlapped and io completion event (hEvent). + * Threads should NOT share an apr_file_t or its hEvent. + */ + if ((thefile->flags & APR_FOPEN_XTHREAD) && !thefile->pOverlapped) { + thefile->pOverlapped = (OVERLAPPED*) apr_pcalloc(thefile->pool, + sizeof(OVERLAPPED)); + thefile->pOverlapped->hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + if (!thefile->pOverlapped->hEvent) { + rv = apr_get_os_error(); + return rv; } } - if (bread == 0) { - thefile->eof_hit = TRUE; - return APR_EOF; - } - for (i=0; i<len; i++) { - if (str[i] == '\n') { - ++i; - if (i < len) - str[i] = '\0'; - else - str [--i] = '\0'; - SetFilePointer(thefile->filehand, (i - bread), NULL, FILE_CURRENT); + + /* Handle the ungetchar if there is one. */ + if (thefile->ungetchar != -1 && str < final) { + *str = thefile->ungetchar; + thefile->ungetchar = -1; + if (*str == '\n') { + *(++str) = '\0'; return APR_SUCCESS; } + ++str; } - str[i] = '\0'; - return APR_SUCCESS; + + /* If we have an underlying buffer, we can be *much* more efficient + * and skip over the read_with_timeout() calls. + */ + if (thefile->buffered) { + if (thefile->flags & APR_FOPEN_XTHREAD) { + apr_thread_mutex_lock(thefile->mutex); + } + + if (thefile->direction == 1) { + rv = apr_file_flush(thefile); + if (rv) { + if (thefile->flags & APR_FOPEN_XTHREAD) { + apr_thread_mutex_unlock(thefile->mutex); + } + return rv; + } + + thefile->direction = 0; + thefile->bufpos = 0; + thefile->dataRead = 0; + } + + while (str < final) { /* leave room for trailing '\0' */ + if (thefile->bufpos < thefile->dataRead) { + *str = thefile->buffer[thefile->bufpos++]; + } + else { + nbytes = 1; + rv = read_buffered(thefile, str, &nbytes); + if (rv != APR_SUCCESS) { + break; + } + } + if (*str == '\n') { + ++str; + break; + } + ++str; + } + if (thefile->flags & APR_FOPEN_XTHREAD) { + apr_thread_mutex_unlock(thefile->mutex); + } + } + else { + while (str < final) { /* leave room for trailing '\0' */ + nbytes = 1; + rv = read_with_timeout(thefile, str, nbytes, &nbytes); + if (rv == APR_EOF) + thefile->eof_hit = TRUE; + + if (rv != APR_SUCCESS) { + break; + } + if (*str == '\n') { + ++str; + break; + } + ++str; + } + } + + /* We must store a terminating '\0' if we've stored any chars. We can + * get away with storing it if we hit an error first. + */ + *str = '\0'; + if (str > str_start) { + /* We stored chars; don't report EOF or any other errors; + * the app will find out about that on the next call. + */ + return APR_SUCCESS; + } + return rv; } -ap_status_t ap_flush(ap_file_t *thefile) + +APR_DECLARE(apr_status_t) apr_file_flush(apr_file_t *thefile) { - FlushFileBuffers(thefile->filehand); + if (thefile->buffered) { + apr_status_t rc = 0; + + if (thefile->direction == 1 && thefile->bufpos) { + apr_size_t written; + + rc = write_helper(thefile->filehand, thefile->buffer, + thefile->bufpos, &written); + thefile->filePtr += written; + + if (rc == 0) + thefile->bufpos = 0; + } + + return rc; + } + + /* There isn't anything to do if we aren't buffering the output + * so just return success. + */ return APR_SUCCESS; } -static int printf_flush(ap_vformatter_buff_t *vbuff) +APR_DECLARE(apr_status_t) apr_file_sync(apr_file_t *thefile){ + apr_status_t rv; + + rv = apr_file_flush(thefile); + if (rv != APR_SUCCESS) { + return rv; + } + + if (!FlushFileBuffers(thefile->filehand)) { + rv = apr_get_os_error(); + } + + return rv; +} + +APR_DECLARE(apr_status_t) apr_file_datasync(apr_file_t *thefile){ + return apr_file_sync(thefile); +} + +struct apr_file_printf_data { + apr_vformatter_buff_t vbuff; + apr_file_t *fptr; + char *buf; +}; + +static int file_printf_flush(apr_vformatter_buff_t *buff) { - /* I would love to print this stuff out to the file, but I will - * get that working later. :) For now, just return. - */ - return -1; + struct apr_file_printf_data *data = (struct apr_file_printf_data *)buff; + + if (apr_file_write_full(data->fptr, data->buf, + data->vbuff.curpos - data->buf, NULL)) { + return -1; + } + + data->vbuff.curpos = data->buf; + return 0; } -API_EXPORT(int) ap_fprintf(ap_file_t *fptr, const char *format, ...) +APR_DECLARE_NONSTD(int) apr_file_printf(apr_file_t *fptr, + const char *format, ...) { - int cc; + struct apr_file_printf_data data; va_list ap; - char *buf; - int len; + int count; - buf = malloc(HUGE_STRING_LEN); - if (buf == NULL) { + data.buf = malloc(HUGE_STRING_LEN); + if (data.buf == NULL) { return 0; } + data.vbuff.curpos = data.buf; + data.vbuff.endpos = data.buf + HUGE_STRING_LEN; + data.fptr = fptr; va_start(ap, format); - len = ap_vsnprintf(buf, HUGE_STRING_LEN, format, ap); - cc = ap_puts(buf, fptr); + count = apr_vformatter(file_printf_flush, + (apr_vformatter_buff_t *)&data, format, ap); + /* apr_vformatter does not call flush for the last bits */ + if (count >= 0) file_printf_flush((apr_vformatter_buff_t *)&data); + va_end(ap); - free(buf); - return (cc == APR_SUCCESS) ? len : -1; + + free(data.buf); + return count; } +APR_DECLARE(apr_status_t) apr_file_pipe_wait(apr_file_t *thepipe, + apr_wait_type_t direction) +{ + return APR_ENOTIMPL; +} diff --git a/file_io/win32/seek.c b/file_io/win32/seek.c index 34b1fa22679..afe6edb0050 100644 --- a/file_io/win32/seek.c +++ b/file_io/win32/seek.c @@ -1,89 +1,203 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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 "fileio.h" +#include "apr_arch_file_io.h" #include "apr_file_io.h" #include <errno.h> #include <string.h> -ap_status_t ap_seek(ap_file_t *thefile, ap_seek_where_t where, ap_off_t *offset) +static apr_status_t setptr(apr_file_t *thefile, apr_off_t pos ) { - DWORD howmove; - DWORD rv; + apr_off_t newbufpos; + apr_status_t rv; + DWORD rc; - switch(where) { - case APR_SET: { - howmove = FILE_BEGIN; - break; + if (thefile->direction == 1) { + /* XXX: flush here is not mutex protected */ + rv = apr_file_flush(thefile); + if (rv != APR_SUCCESS) + return rv; + thefile->bufpos = thefile->dataRead = 0; + thefile->direction = 0; } - case APR_CUR: { - howmove = FILE_CURRENT; - break; - } - case APR_END: { - howmove = FILE_END; - break; + + /* We may be truncating to size here. + * XXX: testing an 'unsigned' as >= 0 below indicates a bug + */ + newbufpos = pos - (thefile->filePtr - thefile->dataRead); + + if (newbufpos >= 0 && newbufpos <= (apr_off_t)thefile->dataRead) { + thefile->bufpos = (apr_size_t)newbufpos; + rv = APR_SUCCESS; + } else { + DWORD offlo = (DWORD)pos; + LONG offhi = (LONG)(pos >> 32); + rc = SetFilePointer(thefile->filehand, offlo, &offhi, FILE_BEGIN); + + if (rc == (DWORD)-1) + /* A legal value, perhaps? MSDN implies prior SetLastError isn't + * needed, googling for SetLastError SetFilePointer seems + * to confirm this. INVALID_SET_FILE_POINTER is too recently + * added for us to rely on it as a constant. + */ + rv = apr_get_os_error(); + else + rv = APR_SUCCESS; + + if (rv == APR_SUCCESS) { + rv = APR_SUCCESS; + thefile->eof_hit = 0; + thefile->bufpos = thefile->dataRead = 0; + thefile->filePtr = pos; + } } + + return rv; +} + + +APR_DECLARE(apr_status_t) apr_file_seek(apr_file_t *thefile, apr_seek_where_t where, apr_off_t *offset) +{ + apr_finfo_t finfo; + apr_status_t rc = APR_SUCCESS; + + thefile->eof_hit = 0; + + if (thefile->buffered) { + switch (where) { + case APR_SET: + rc = setptr(thefile, *offset); + break; + + case APR_CUR: + rc = setptr(thefile, thefile->filePtr - thefile->dataRead + + thefile->bufpos + *offset); + break; + + case APR_END: + rc = apr_file_info_get(&finfo, APR_FINFO_SIZE, thefile); + if (rc == APR_SUCCESS) + rc = setptr(thefile, finfo.size + *offset); + break; + + default: + return APR_EINVAL; + } + + *offset = thefile->filePtr - thefile->dataRead + thefile->bufpos; + return rc; } + /* A file opened with APR_FOPEN_XTHREAD has been opened for overlapped i/o. + * APR must explicitly track the file pointer in this case. + */ + else if (thefile->pOverlapped || thefile->flags & APR_FOPEN_XTHREAD) { + switch(where) { + case APR_SET: + thefile->filePtr = *offset; + break; + + case APR_CUR: + thefile->filePtr += *offset; + break; + + case APR_END: + rc = apr_file_info_get(&finfo, APR_FINFO_SIZE, thefile); + if (rc == APR_SUCCESS && finfo.size + *offset >= 0) + thefile->filePtr = finfo.size + *offset; + break; - rv = SetFilePointer(thefile->filehand, *offset, NULL, howmove); - if (rv == -1) { - *offset = -1; - return APR_EEXIST; + default: + return APR_EINVAL; + } + *offset = thefile->filePtr; + return rc; } else { - *offset = rv; - return APR_SUCCESS; + DWORD howmove; + DWORD offlo = (DWORD)*offset; + DWORD offhi = (DWORD)(*offset >> 32); + + switch(where) { + case APR_SET: + howmove = FILE_BEGIN; break; + case APR_CUR: + howmove = FILE_CURRENT; break; + case APR_END: + howmove = FILE_END; break; + default: + return APR_EINVAL; + } + offlo = SetFilePointer(thefile->filehand, (LONG)offlo, + (LONG*)&offhi, howmove); + if (offlo == 0xFFFFFFFF) + rc = apr_get_os_error(); + else + rc = APR_SUCCESS; + /* Since we can land at 0xffffffff we will measure our APR_SUCCESS */ + if (rc == APR_SUCCESS) + *offset = ((apr_off_t)offhi << 32) | offlo; + return rc; } } + + +APR_DECLARE(apr_status_t) apr_file_trunc(apr_file_t *thefile, apr_off_t offset) +{ + apr_status_t rv; + DWORD offlo = (DWORD)offset; + LONG offhi = (LONG)(offset >> 32); + DWORD rc; + + if (thefile->buffered) { + if (thefile->direction == 1) { + /* Figure out what needs to be flushed. Don't flush the part + * of the write buffer that will get truncated anyway. + */ + if (offset < thefile->filePtr) { + thefile->bufpos = 0; + } + else if (offset < thefile->filePtr + (apr_off_t)thefile->bufpos) { + thefile->bufpos = offset - thefile->filePtr; + } + + if (thefile->bufpos != 0) { + rv = apr_file_flush(thefile); + if (rv != APR_SUCCESS) + return rv; + } + } + else if (thefile->direction == 0) { + /* Discard the read buffer, as we are about to reposition + * ourselves to the end of file. + */ + thefile->bufpos = 0; + thefile->dataRead = 0; + } + } + + rc = SetFilePointer(thefile->filehand, offlo, &offhi, FILE_BEGIN); + if (rc == 0xFFFFFFFF) + if ((rv = apr_get_os_error()) != APR_SUCCESS) + return rv; + thefile->filePtr = offset; + /* Don't report EOF until the next read. */ + thefile->eof_hit = 0; + + if (!SetEndOfFile(thefile->filehand)) + return apr_get_os_error(); + + return APR_SUCCESS; +} diff --git a/helpers/apr_rename.pl b/helpers/apr_rename.pl new file mode 100755 index 00000000000..25b9d52d4c0 --- /dev/null +++ b/helpers/apr_rename.pl @@ -0,0 +1,106 @@ +#!/usr/bin/perl -w +use strict; +use ExtUtils::MakeMaker qw(prompt); +use File::Find; + +my $just_check = @ARGV ? $ARGV[0] eq '-c' : 0; +shift if $just_check; +my $dir = shift || '.'; +my %names; + +my $prefix = 'apr_'; + +while (<DATA>) { + chomp; + my($old, $new) = grep { s/^$prefix//o } split; + next unless $old and $new; + $names{$old} = $new; +} + +my $pattern = join '|', keys %names; +#print "replacement pattern=$pattern\n"; + +find sub { + chomp; + return unless /\.[ch]$/; + my $file = "$File::Find::dir/$_"; + print "looking in $file\n"; + + replace($_, !$just_check); + +}, $dir; + +sub replace { + my($file, $replace) = @_; + local *IN, *OUT; + my @lines; + my $found = 0; + + open IN, $file or die "open $file: $!"; + + while (<IN>) { + for (m/[^_\"]*$prefix($pattern)\b/og) { + $found++; + print " $file:$. apr_$_ -> apr_$names{$_}\n"; + } + push @lines, $_ if $replace; + } + + close IN; + + return unless $found and $replace; + +# my $ans = prompt("replace?", 'y'); +# return unless $ans =~ /^y/i; + + open OUT, ">$file" or die "open $file: $!"; + + for (@lines) { + unless (/^\#include/) { + s/([^_\"]*$prefix)($pattern)\b/$1$names{$2}/og; + } + print OUT $_; + } + + close OUT; +} + +__DATA__ +apr_time_t: +apr_implode_gmt apr_time_exp_gmt_get + +apr_socket_t: +apr_close_socket apr_socket_close +apr_create_socket apr_socket_create +apr_get_sockaddr apr_socket_addr_get +apr_get_socketdata apr_socket_data_get +apr_set_socketdata apr_socket_data_set +apr_shutdown apr_socket_shutdown +apr_bind apr_socket_bind +apr_listen apr_socket_listen +apr_accept apr_socket_accept +apr_connect apr_socket_connect +apr_send apr_socket_send +apr_sendv apr_socket_sendv +apr_sendto apr_socket_sendto +apr_recvfrom apr_socket_recvfrom +apr_sendfile apr_socket_sendfile +apr_recv apr_socket_recv + +apr_filepath_*: +apr_filename_of_pathname apr_filepath_name_get + +apr_gid_t: +apr_get_groupid apr_gid_get +apr_get_groupname apr_gid_name_get +apr_group_name_get apr_gid_name_get +apr_compare_groups apr_gid_compare + +apr_uid_t: +apr_get_home_directory apr_uid_homepath_get +apr_get_userid apr_uid_get +apr_current_userid apr_uid_current +apr_compare_users apr_uid_compare +apr_get_username apr_uid_name_get +apr_compare_users apr_uid_compare + diff --git a/helpers/build-modules-c.awk b/helpers/build-modules-c.awk deleted file mode 100644 index 15ff82ccfb4..00000000000 --- a/helpers/build-modules-c.awk +++ /dev/null @@ -1,56 +0,0 @@ -BEGIN { - RS = " " - modules[n++] = "core" - pmodules[pn++] = "core" -} -{ - modules[n] = $1; - pmodules[pn] = $1; - gsub("\n","",modules[n]); - gsub("\n","",pmodules[pn]); - ++n; - ++pn; -} -END { - print "/*" - print " * modules.c --- automatically generated by Apache" - print " * configuration script. DO NOT HAND EDIT!!!!!" - print " */" - print "" - print "#include \"ap_config.h\"" - print "#include \"httpd.h\"" - print "#include \"http_config.h\"" - print "" - for (i = 0; i < pn; ++i) { - printf ("extern module %s_module;\n", pmodules[i]) - } - print "" - print "/*" - print " * Modules which implicitly form the" - print " * list of activated modules on startup," - print " * i.e. these are the modules which are" - print " * initially linked into the Apache processing" - print " * [extendable under run-time via AddModule]" - print " */" - print "module *ap_prelinked_modules[] = {" - for (i = 0; i < n; ++i) { - printf " &%s_module,\n", modules[i] - } - print " NULL" - print "};" - print "" - print "/*" - print " * Modules which initially form the" - print " * list of available modules on startup," - print " * i.e. these are the modules which are" - print " * initially loaded into the Apache process" - print " * [extendable under run-time via LoadModule]" - print " */" - print "module *ap_preloaded_modules[] = {" - for (i = 0; i < pn; ++i) { - printf " &%s_module,\n", pmodules[i] - } - print " NULL" - print "};" - print "" -} diff --git a/helpers/config-stubs b/helpers/config-stubs deleted file mode 100755 index aff00a57d48..00000000000 --- a/helpers/config-stubs +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh - -dir=$1 -for stubdir in `find $dir -type d`; do - if [ -r $stubdir/config.m4 ]; then - echo "sinclude($stubdir/config.m4)" - fi -done diff --git a/helpers/cvsclean b/helpers/cvsclean deleted file mode 100755 index e98ec49b768..00000000000 --- a/helpers/cvsclean +++ /dev/null @@ -1,3 +0,0 @@ -#! /bin/sh - -${MAKE:-make} -f build/build.mk cvsclean diff --git a/helpers/snapshot b/helpers/snapshot deleted file mode 100755 index 9553a753f9d..00000000000 --- a/helpers/snapshot +++ /dev/null @@ -1,5 +0,0 @@ -#! /bin/sh - -test -n "$1" && ARG="DISTNAME='$1'" - -${MAKE:-make} $ARG -f build/build.mk snapshot diff --git a/hooks/apr_hooks.c b/hooks/apr_hooks.c new file mode 100644 index 00000000000..22045620433 --- /dev/null +++ b/hooks/apr_hooks.c @@ -0,0 +1,414 @@ +/* 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 <assert.h> +#include <stdio.h> +#include <stdlib.h> + +#include "apr_pools.h" +#include "apr_tables.h" +#include "apr.h" +#include "apr_hooks.h" +#include "apr_hash.h" +#include "apr_optional_hooks.h" +#include "apr_optional.h" +#define APR_WANT_MEMFUNC +#define APR_WANT_STRFUNC +#include "apr_want.h" + +#if 0 +#define apr_palloc(pool,size) malloc(size) +#endif + +APR_DECLARE_DATA apr_pool_t *apr_hook_global_pool = NULL; +APR_DECLARE_DATA int apr_hook_debug_enabled = 0; +APR_DECLARE_DATA const char *apr_hook_debug_current = NULL; + +/** @deprecated @see apr_hook_global_pool */ +APR_DECLARE_DATA apr_pool_t *apr_global_hook_pool = NULL; + +/** @deprecated @see apr_hook_debug_enabled */ +APR_DECLARE_DATA int apr_debug_module_hooks = 0; + +/** @deprecated @see apr_hook_debug_current */ +APR_DECLARE_DATA const char *apr_current_hooking_module = NULL; + +/* NB: This must echo the LINK_##name structure */ +typedef struct +{ + void (*dummy)(void *); + const char *szName; + const char * const *aszPredecessors; + const char * const *aszSuccessors; + int nOrder; +} TSortData; + +typedef struct tsort_ +{ + void *pData; + int nPredecessors; + struct tsort_ **ppPredecessors; + struct tsort_ *pNext; +} TSort; + +#ifdef NETWARE +#include "apr_private.h" +#define get_apd APP_DATA* apd = (APP_DATA*)get_app_data(gLibId); +#define s_aHooksToSort ((apr_array_header_t *)(apd->gs_aHooksToSort)) +#define s_phOptionalHooks ((apr_hash_t *)(apd->gs_phOptionalHooks)) +#define s_phOptionalFunctions ((apr_hash_t *)(apd->gs_phOptionalFunctions)) +#endif + +static int crude_order(const void *a_,const void *b_) +{ + const TSortData *a=a_; + const TSortData *b=b_; + + return a->nOrder-b->nOrder; +} + +static TSort *prepare(apr_pool_t *p,TSortData *pItems,int nItems) +{ + TSort *pData=apr_palloc(p,nItems*sizeof *pData); + int n; + + qsort(pItems,nItems,sizeof *pItems,crude_order); + for(n=0 ; n < nItems ; ++n) { + pData[n].nPredecessors=0; + pData[n].ppPredecessors=apr_pcalloc(p,nItems*sizeof *pData[n].ppPredecessors); + pData[n].pNext=NULL; + pData[n].pData=&pItems[n]; + } + + for(n=0 ; n < nItems ; ++n) { + int i,k; + + for(i=0 ; pItems[n].aszPredecessors && pItems[n].aszPredecessors[i] ; ++i) + for(k=0 ; k < nItems ; ++k) + if(!strcmp(pItems[k].szName,pItems[n].aszPredecessors[i])) { + int l; + + for(l=0 ; l < pData[n].nPredecessors ; ++l) + if(pData[n].ppPredecessors[l] == &pData[k]) + goto got_it; + pData[n].ppPredecessors[pData[n].nPredecessors]=&pData[k]; + ++pData[n].nPredecessors; + got_it: + break; + } + for(i=0 ; pItems[n].aszSuccessors && pItems[n].aszSuccessors[i] ; ++i) + for(k=0 ; k < nItems ; ++k) + if(!strcmp(pItems[k].szName,pItems[n].aszSuccessors[i])) { + int l; + + for(l=0 ; l < pData[k].nPredecessors ; ++l) + if(pData[k].ppPredecessors[l] == &pData[n]) + goto got_it2; + pData[k].ppPredecessors[pData[k].nPredecessors]=&pData[n]; + ++pData[k].nPredecessors; + got_it2: + break; + } + } + + return pData; +} + +/* Topologically sort, dragging out-of-order items to the front. Note that + this tends to preserve things that want to be near the front better, and + changing that behaviour might compromise some of Apache's behaviour (in + particular, mod_log_forensic might otherwise get pushed to the end, and + core.c's log open function used to end up at the end when pushing items + to the back was the methedology). Also note that the algorithm could + go back to its original simplicity by sorting from the back instead of + the front. +*/ +static TSort *tsort(TSort *pData,int nItems) +{ + int nTotal; + TSort *pHead=NULL; + TSort *pTail=NULL; + + for(nTotal=0 ; nTotal < nItems ; ++nTotal) { + int n,i,k; + + for(n=0 ; ; ++n) { + if(n == nItems) + assert(0); /* we have a loop... */ + if(!pData[n].pNext) { + if(pData[n].nPredecessors) { + for(k=0 ; ; ++k) { + assert(k < nItems); + if(pData[n].ppPredecessors[k]) + break; + } + for(i=0 ; ; ++i) { + assert(i < nItems); + if(&pData[i] == pData[n].ppPredecessors[k]) { + n=i-1; + break; + } + } + } else + break; + } + } + if(pTail) + pTail->pNext=&pData[n]; + else + pHead=&pData[n]; + pTail=&pData[n]; + pTail->pNext=pTail; /* fudge it so it looks linked */ + for(i=0 ; i < nItems ; ++i) + for(k=0 ; k < nItems ; ++k) + if(pData[i].ppPredecessors[k] == &pData[n]) { + --pData[i].nPredecessors; + pData[i].ppPredecessors[k]=NULL; + break; + } + } + pTail->pNext=NULL; /* unfudge the tail */ + return pHead; +} + +static apr_array_header_t *sort_hook(apr_array_header_t *pHooks, + const char *szName) +{ + apr_pool_t *p; + TSort *pSort; + apr_array_header_t *pNew; + int n; + + apr_pool_create(&p, apr_hook_global_pool); + pSort=prepare(p,(TSortData *)pHooks->elts,pHooks->nelts); + pSort=tsort(pSort,pHooks->nelts); + pNew=apr_array_make(apr_hook_global_pool,pHooks->nelts,sizeof(TSortData)); + if(apr_hook_debug_enabled) + printf("Sorting %s:",szName); + for(n=0 ; pSort ; pSort=pSort->pNext,++n) { + TSortData *pHook; + assert(n < pHooks->nelts); + pHook=apr_array_push(pNew); + memcpy(pHook,pSort->pData,sizeof *pHook); + if(apr_hook_debug_enabled) + printf(" %s",pHook->szName); + } + if(apr_hook_debug_enabled) + fputc('\n',stdout); + + /* destroy the pool - the sorted hooks were already copied */ + apr_pool_destroy(p); + + return pNew; +} + +#ifndef NETWARE +static apr_array_header_t *s_aHooksToSort; +#endif + +typedef struct +{ + const char *szHookName; + apr_array_header_t **paHooks; +} HookSortEntry; + +APR_DECLARE(void) apr_hook_sort_register(const char *szHookName, + apr_array_header_t **paHooks) +{ +#ifdef NETWARE + get_apd +#endif + HookSortEntry *pEntry; + + if(!s_aHooksToSort) + s_aHooksToSort=apr_array_make(apr_hook_global_pool,1,sizeof(HookSortEntry)); + pEntry=apr_array_push(s_aHooksToSort); + pEntry->szHookName=szHookName; + pEntry->paHooks=paHooks; +} + +APR_DECLARE(void) apr_hook_sort_all(void) +{ +#ifdef NETWARE + get_apd +#endif + int n; + + if (!s_aHooksToSort) { + s_aHooksToSort = apr_array_make(apr_hook_global_pool, 1, sizeof(HookSortEntry)); + } + + for(n=0 ; n < s_aHooksToSort->nelts ; ++n) { + HookSortEntry *pEntry=&((HookSortEntry *)s_aHooksToSort->elts)[n]; + *pEntry->paHooks=sort_hook(*pEntry->paHooks,pEntry->szHookName); + } +} + +#ifndef NETWARE +static apr_hash_t *s_phOptionalHooks; +static apr_hash_t *s_phOptionalFunctions; +#endif + +APR_DECLARE(void) apr_hook_deregister_all(void) +{ +#ifdef NETWARE + get_apd +#endif + int n; + + if (!s_aHooksToSort) { + return; + } + + for(n=0 ; n < s_aHooksToSort->nelts ; ++n) { + HookSortEntry *pEntry=&((HookSortEntry *)s_aHooksToSort->elts)[n]; + *pEntry->paHooks=NULL; + } + s_aHooksToSort=NULL; + s_phOptionalHooks=NULL; + s_phOptionalFunctions=NULL; +} + +APR_DECLARE(void) apr_hook_debug_show(const char *szName, + const char * const *aszPre, + const char * const *aszSucc) +{ + int nFirst; + + printf(" Hooked %s",szName); + if(aszPre) { + fputs(" pre(",stdout); + nFirst=1; + while(*aszPre) { + if(!nFirst) + fputc(',',stdout); + nFirst=0; + fputs(*aszPre,stdout); + ++aszPre; + } + fputc(')',stdout); + } + if(aszSucc) { + fputs(" succ(",stdout); + nFirst=1; + while(*aszSucc) { + if(!nFirst) + fputc(',',stdout); + nFirst=0; + fputs(*aszSucc,stdout); + ++aszSucc; + } + fputc(')',stdout); + } + fputc('\n',stdout); +} + +/* Optional hook support */ + +APR_DECLARE_EXTERNAL_HOOK(apr,APR,void,_optional,(void)) + +APR_DECLARE(apr_array_header_t *) apr_optional_hook_get(const char *szName) +{ +#ifdef NETWARE + get_apd +#endif + apr_array_header_t **ppArray; + + if(!s_phOptionalHooks) + return NULL; + ppArray=apr_hash_get(s_phOptionalHooks,szName,strlen(szName)); + if(!ppArray) + return NULL; + return *ppArray; +} + +APR_DECLARE(void) apr_optional_hook_add(const char *szName,void (*pfn)(void), + const char * const *aszPre, + const char * const *aszSucc,int nOrder) +{ +#ifdef NETWARE + get_apd +#endif + apr_array_header_t *pArray=apr_optional_hook_get(szName); + apr_LINK__optional_t *pHook; + + if(!pArray) { + apr_array_header_t **ppArray; + + pArray=apr_array_make(apr_hook_global_pool,1, + sizeof(apr_LINK__optional_t)); + if(!s_phOptionalHooks) + s_phOptionalHooks=apr_hash_make(apr_hook_global_pool); + ppArray=apr_palloc(apr_hook_global_pool,sizeof *ppArray); + *ppArray=pArray; + apr_hash_set(s_phOptionalHooks,szName,strlen(szName),ppArray); + apr_hook_sort_register(szName,ppArray); + } + pHook=apr_array_push(pArray); + pHook->pFunc=pfn; + pHook->aszPredecessors=aszPre; + pHook->aszSuccessors=aszSucc; + pHook->nOrder=nOrder; + pHook->szName=apr_hook_debug_current; + if(apr_hook_debug_enabled) + apr_hook_debug_show(szName,aszPre,aszSucc); +} + +/* optional function support */ + +APR_DECLARE(apr_opt_fn_t *) apr_dynamic_fn_retrieve(const char *szName) +{ +#ifdef NETWARE + get_apd +#endif + if(!s_phOptionalFunctions) + return NULL; + return (void(*)(void))apr_hash_get(s_phOptionalFunctions,szName,strlen(szName)); +} + +/* Deprecated */ +APR_DECLARE_NONSTD(void) apr_dynamic_fn_register(const char *szName, + apr_opt_fn_t *pfn) +{ +#ifdef NETWARE + get_apd +#endif + if(!s_phOptionalFunctions) + s_phOptionalFunctions=apr_hash_make(apr_hook_global_pool); + apr_hash_set(s_phOptionalFunctions,szName,strlen(szName),(void *)pfn); +} + +#if 0 +void main() +{ + const char *aszAPre[]={"b","c",NULL}; + const char *aszBPost[]={"a",NULL}; + const char *aszCPost[]={"b",NULL}; + TSortData t1[]= + { + { "a",aszAPre,NULL }, + { "b",NULL,aszBPost }, + { "c",NULL,aszCPost } + }; + TSort *pResult; + + pResult=prepare(t1,3); + pResult=tsort(pResult,3); + + for( ; pResult ; pResult=pResult->pNext) + printf("%s\n",pResult->pData->szName); +} +#endif diff --git a/i18n/unix/.cvsignore b/i18n/unix/.cvsignore deleted file mode 100644 index f3c7a7c5da6..00000000000 --- a/i18n/unix/.cvsignore +++ /dev/null @@ -1 +0,0 @@ -Makefile diff --git a/i18n/unix/Makefile.in b/i18n/unix/Makefile.in deleted file mode 100644 index 99b72897335..00000000000 --- a/i18n/unix/Makefile.in +++ /dev/null @@ -1,45 +0,0 @@ - -RM=@RM@ -CC=@CC@ -RANLIB=@RANLIB@ -CFLAGS=@CFLAGS@ @OPTIM@ -LIBS=@LIBS@ -LDFLAGS=@LDFLAGS@ $(LIBS) -INCDIR=../../include -INCLUDES=-I$(INCDIR) -I. - -OBJS=xlate.o - -.c.o: - $(CC) $(CFLAGS) -c $(INCLUDES) $< - -all: $(OBJS) - -clean: - $(RM) -f *.o *.a *.so - -distclean: clean - -$(RM) -f Makefile - -$(OBJS): Makefile - -# -# We really don't expect end users to use this rule. It works only with -# gcc, and rebuilds Makefile.tmpl. You have to re-run Configure after -# using it. -# -depend: - cp Makefile.in Makefile.in.bak \ - && sed -ne '1,/^# DO NOT REMOVE/p' Makefile.in > Makefile.new \ - && gcc -MM $(INCLUDES) $(CFLAGS) *.c >> Makefile.new \ - && sed -e '1,$$s: $(INCDIR)/: $$(INCDIR)/:g' \ - -e '1,$$s: $(OSDIR)/: $$(OSDIR)/:g' Makefile.new \ - > Makefile.in \ - && rm Makefile.new - -# DO NOT REMOVE -xlate.o: xlate.c $(INCDIR)/apr_private.h $(INCDIR)/apr_lib.h \ - $(INCDIR)/apr_general.h $(INCDIR)/apr.h \ - $(INCDIR)/apr_errno.h $(INCDIR)/apr_file_io.h \ - $(INCDIR)/apr_time.h $(INCDIR)/apr_thread_proc.h \ - $(INCDIR)/apr_xlate.h diff --git a/i18n/unix/xlate.c b/i18n/unix/xlate.c deleted file mode 100644 index ce9db86c58e..00000000000 --- a/i18n/unix/xlate.c +++ /dev/null @@ -1,282 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#include "apr_private.h" - -#include "apr_lib.h" -#include "apr_xlate.h" - -/* If no implementation is available, don't generate code here since - * apr_xlate.h emitted macros which return APR_ENOTIMPL. - */ - -#if APR_HAS_XLATE - -#ifdef HAVE_ICONV_H -#include <iconv.h> -#endif - -#ifndef min -#define min(x,y) ((x) <= (y) ? (x) : (y)) -#endif - -struct ap_xlate_t { - ap_pool_t *pool; - char *frompage; - char *topage; - char *sbcs_table; -#ifdef HAVE_ICONV - iconv_t ich; -#endif -}; - -/* get_default_codepage() - * - * 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. - */ - -static const char *get_default_codepage(void) -{ -#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 "ISO8859-1"; /* not necessarily true */ - } - - return "unknown"; -} - -static ap_status_t ap_xlate_cleanup(void *convset) -{ -#ifdef HAVE_ICONV - ap_xlate_t *old = convset; - - if (old->ich != (iconv_t)-1) { - if (iconv_close(old->ich)) { - return errno; - } - } -#endif - return APR_SUCCESS; -} - -#ifdef HAVE_ICONV -static void check_sbcs(ap_xlate_t *convset) -{ - char inbuf[256], outbuf[256]; - char *inbufptr = inbuf, *outbufptr = outbuf; - size_t inbytes_left, outbytes_left; - int i; - size_t translated; - - for (i = 0; i < sizeof(inbuf); i++) { - inbuf[i] = i; - } - - inbytes_left = outbytes_left = sizeof(inbuf); - translated = iconv(convset->ich, (const char **)&inbufptr, - &inbytes_left, &outbufptr, &outbytes_left); - if (translated != (size_t) -1 && - inbytes_left == 0 && - outbytes_left == 0) { - /* hurray... this is simple translation; save the table, - * close the iconv descriptor - */ - - convset->sbcs_table = ap_palloc(convset->pool, sizeof(outbuf)); - memcpy(convset->sbcs_table, outbuf, sizeof(outbuf)); - iconv_close(convset->ich); - convset->ich = (iconv_t)-1; - - /* TODO: add the table to the cache */ - } -} -#endif /* HAVE_ICONV */ - -ap_status_t ap_xlate_open(ap_xlate_t **convset, const char *topage, - const char *frompage, ap_pool_t *pool) -{ - ap_status_t status; - ap_xlate_t *new; - int found = 0; - - *convset = NULL; - - if (!topage) { - topage = get_default_codepage(); - } - - if (!frompage) { - frompage = get_default_codepage(); - } - - new = (ap_xlate_t *)ap_palloc(pool, sizeof(ap_xlate_t)); - if (!new) { - return APR_ENOMEM; - } - - new->pool = pool; - new->topage = ap_pstrdup(pool, topage); - new->frompage = ap_pstrdup(pool, frompage); - if (!new->topage || !new->frompage) { - return APR_ENOMEM; - } - -#ifdef TODO - /* search cache of codepage pairs; we may be able to avoid the - * expensive iconv_open() - */ - - set found to non-zero if found in the cache -#endif - -#ifdef HAVE_ICONV - if (!found) { - new->ich = iconv_open(topage, frompage); - if (new->ich == (iconv_t)-1) { - return errno; - } - found = 1; - check_sbcs(new); - } -#endif /* HAVE_ICONV */ - - if (found) { - *convset = new; - ap_register_cleanup(pool, (void *)new, ap_xlate_cleanup, - ap_null_cleanup); - status = APR_SUCCESS; - } - else { - status = EINVAL; /* same as what iconv() would return if it - couldn't handle the pair */ - } - - return status; -} - -ap_status_t ap_xlate_conv_buffer(ap_xlate_t *convset, const char *inbuf, - ap_size_t *inbytes_left, char *outbuf, - ap_size_t *outbytes_left) -{ - ap_status_t status = APR_SUCCESS; -#ifdef HAVE_ICONV - size_t translated; - - if (convset->ich != (iconv_t)-1) { - char *inbufptr = (char *)inbuf; - char *outbufptr = outbuf; - - translated = iconv(convset->ich, (const char **)&inbufptr, - inbytes_left, &outbufptr, outbytes_left); - if (translated == (size_t)-1) { - return errno; - } - } - else -#endif - { - int to_convert = min(*inbytes_left, *outbytes_left); - int converted = to_convert; - char *table = convset->sbcs_table; - - while (to_convert) { - *outbuf = table[(unsigned char)*inbuf]; - ++outbuf; - ++inbuf; - --to_convert; - } - *inbytes_left -= converted; - *outbytes_left -= converted; - } - - return status; -} - -ap_status_t ap_xlate_close(ap_xlate_t *convset) -{ - ap_status_t status; - - if ((status = ap_xlate_cleanup(convset)) == APR_SUCCESS) { - ap_kill_cleanup(convset->pool, convset, ap_xlate_cleanup); - } - - return status; -} - -#endif /* APR_HAS_XLATE */ diff --git a/include/.cvsignore b/include/.cvsignore deleted file mode 100644 index e5db22b8d0b..00000000000 --- a/include/.cvsignore +++ /dev/null @@ -1,3 +0,0 @@ -apr.h -apr_private.h -apr_private.h.in diff --git a/include/apr.h.in b/include/apr.h.in index ce4e597755e..ea936158a50 100644 --- a/include/apr.h.in +++ b/include/apr.h.in @@ -1,6 +1,50 @@ +/* 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. + */ + + #ifndef APR_H #define APR_H +/* GENERATED FILE WARNING! DO NOT EDIT apr.h + * + * You must modify apr.h.in instead. + * + * And please, make an effort to stub apr.hw and apr.hnw in the process. + */ + +/** + * @file apr.h + * @brief APR Platform Definitions + * @remark This is a generated header generated from include/apr.h.in by + * ./configure, or copied from include/apr.hw or include/apr.hnw + * for Win32 or Netware by those build environments, respectively. + */ + +/** + * @defgroup APR Apache Portability Runtime library + * @{ + */ +/** + * @defgroup apr_platform Platform Definitions + * @{ + * @warning + * <strong><em>The actual values of macros and typedefs on this page<br> + * are platform specific and should NOT be relied upon!</em></strong> + */ + /* So that we can use inline on some critical functions, and use * GNUC attributes (such as to get -Wall warnings for printf-like * functions). Only do this in gcc 2.7 or later ... it may work @@ -15,45 +59,228 @@ #if !defined(__GNUC__) || __GNUC__ < 2 || \ (__GNUC__ == 2 && __GNUC_MINOR__ < 7) ||\ defined(NEXT) -#define ap_inline +#ifndef __attribute__ #define __attribute__(__x) -#define ENUM_BITFIELD(e,n,w) signed int n : w +#endif +#define APR_INLINE +#define APR_HAS_INLINE 0 +#else +#define APR_INLINE __inline__ +#define APR_HAS_INLINE 1 +#endif + +#define APR_HAVE_ARPA_INET_H @arpa_ineth@ +#define APR_HAVE_CONIO_H @conioh@ +#define APR_HAVE_CRYPT_H @crypth@ +#define APR_HAVE_CTYPE_H @ctypeh@ +#define APR_HAVE_DIRENT_H @direnth@ +#define APR_HAVE_ERRNO_H @errnoh@ +#define APR_HAVE_FCNTL_H @fcntlh@ +#define APR_HAVE_IFADDRS_H @ifaddrsh@ +#define APR_HAVE_IO_H @ioh@ +#define APR_HAVE_LIMITS_H @limitsh@ +#define APR_HAVE_MSWSOCK_H @mswsockh@ +#define APR_HAVE_NETDB_H @netdbh@ +#define APR_HAVE_NETINET_IN_H @netinet_inh@ +#define APR_HAVE_NETINET_SCTP_H @netinet_sctph@ +#define APR_HAVE_NETINET_SCTP_UIO_H @netinet_sctp_uioh@ +#define APR_HAVE_NETINET_TCP_H @netinet_tcph@ +#define APR_HAVE_PROCESS_H @processh@ +#define APR_HAVE_PTHREAD_H @pthreadh@ +#define APR_HAVE_SEMAPHORE_H @semaphoreh@ +#define APR_HAVE_SIGNAL_H @signalh@ +#define APR_HAVE_STDARG_H @stdargh@ +#define APR_HAVE_STDDEF_H @stddefh@ +#define APR_HAVE_STDINT_H @stdint@ +#define APR_HAVE_STDIO_H @stdioh@ +#define APR_HAVE_STDLIB_H @stdlibh@ +#define APR_HAVE_STRING_H @stringh@ +#define APR_HAVE_STRINGS_H @stringsh@ +#define APR_HAVE_SYS_IOCTL_H @sys_ioctlh@ +#define APR_HAVE_SYS_SENDFILE_H @sys_sendfileh@ +#define APR_HAVE_SYS_SIGNAL_H @sys_signalh@ +#define APR_HAVE_SYS_SOCKET_H @sys_socketh@ +#define APR_HAVE_SYS_SOCKIO_H @sys_sockioh@ +#define APR_HAVE_SYS_SYSLIMITS_H @sys_syslimitsh@ +#define APR_HAVE_SYS_TIME_H @sys_timeh@ +#define APR_HAVE_SYS_TYPES_H @sys_typesh@ +#define APR_HAVE_SYS_UIO_H @sys_uioh@ +#define APR_HAVE_SYS_UN_H @sys_unh@ +#define APR_HAVE_SYS_WAIT_H @sys_waith@ +#define APR_HAVE_TIME_H @timeh@ +#define APR_HAVE_UNISTD_H @unistdh@ +#define APR_HAVE_WINDOWS_H @windowsh@ +#define APR_HAVE_WINSOCK2_H @winsock2h@ +#define APR_HAVE_WS2TCPIP_H @ws2tcpiph@ + +/** @} */ +/** @} */ + +/* We don't include our conditional headers within the doxyblocks + * or the extern "C" namespace + */ + +#if APR_HAVE_WINDOWS_H && defined(WIN32) +/* If windows.h was already included, our preferences don't matter. + * If not, include a restricted set of windows headers to our tastes. + */ +#ifndef _WINDOWS_ + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif + +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x0501 +#endif + +#ifndef NOUSER +#define NOUSER +#endif +#ifndef NOMCX +#define NOMCX +#endif +#ifndef NOIME +#define NOIME +#endif + +/* Impossible to include winsock2.h after winsock.h, while windows.h + * attempts to load winsock. Setting _WINSOCKAPI_ will dodge this. + */ +#if APR_HAVE_WINSOCK2_H +#define _WINSOCKAPI_ +#endif + +#include <windows.h> +#endif /* ndef _WINDOWS_ */ +#endif /* APR_HAVE_WINDOWS_H */ + +#if APR_HAVE_WINSOCK2_H +#include <winsock2.h> + +#if APR_HAVE_WS2TCPIP_H +#include <ws2tcpip.h> +#endif + +#if APR_HAVE_MSWSOCK_H +#include <mswsock.h> +#endif + +#else /* !APR_HAVE_WINSOCK2_H */ + +#if APR_HAVE_WINSOCK_H +#include <winsock.h> +#endif + +#endif /* !APR_HAVE_WINSOCK2_H */ + +#if APR_HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif + +#if APR_HAVE_STDDEF_H +#include <stddef.h> +#endif + +#if APR_HAVE_SYS_SOCKET_H +#include <sys/socket.h> +#endif + +#if defined(__cplusplus) && !defined(__STDC_CONSTANT_MACROS) +/* C99 7.18.4 requires that stdint.h only exposes INT64_C + * and UINT64_C for C++ implementations if this is defined: */ +#define __STDC_CONSTANT_MACROS +#endif + +#if APR_HAVE_STDINT_H +#include <stdint.h> +#endif + +#if APR_HAVE_SYS_WAIT_H +#include <sys/wait.h> +#endif + +#ifdef OS2 +#define INCL_DOS +#define INCL_DOSERRORS +#include <os2.h> +#endif + +/* header files for PATH_MAX, _POSIX_PATH_MAX */ +#if APR_HAVE_LIMITS_H +#include <limits.h> #else -#define ap_inline __inline__ -#define USE_GNU_INLINE -#define ENUM_BITFIELD(e,n,w) e n : w +#if APR_HAVE_SYS_SYSLIMITS_H +#include <sys/syslimits.h> +#endif +#endif + + +#ifdef __cplusplus +extern "C" { #endif -#define APR_HAVE_ERRNO_H @errnoh@ -#define APR_HAVE_DIRENT_H @direnth@ -#define APR_HAVE_FCNTL_H @fcntlh@ -#define APR_HAVE_NETINET_IN_H @netinet_inh@ -#define APR_HAVE_PTHREAD_H @pthreadh@ -#define APR_HAVE_STDARG_H @stdargh@ -#define APR_HAVE_STDIO_H @stdioh@ -#define APR_HAVE_SYS_TYPES_H @sys_typesh@ -#define APR_HAVE_SYS_UIO_H @sys_uioh@ -#define APR_HAVE_SIGNAL_H @signalh@ +/** + * @addtogroup apr_platform + * @ingroup APR + * @{ + */ + +#define APR_HAVE_SHMEM_MMAP_TMP @havemmaptmp@ +#define APR_HAVE_SHMEM_MMAP_SHM @havemmapshm@ +#define APR_HAVE_SHMEM_MMAP_ZERO @havemmapzero@ +#define APR_HAVE_SHMEM_SHMGET_ANON @haveshmgetanon@ +#define APR_HAVE_SHMEM_SHMGET @haveshmget@ +#define APR_HAVE_SHMEM_MMAP_ANON @havemmapanon@ +#define APR_HAVE_SHMEM_BEOS @havebeosarea@ + +#define APR_USE_SHMEM_MMAP_TMP @usemmaptmp@ +#define APR_USE_SHMEM_MMAP_SHM @usemmapshm@ +#define APR_USE_SHMEM_MMAP_ZERO @usemmapzero@ +#define APR_USE_SHMEM_SHMGET_ANON @useshmgetanon@ +#define APR_USE_SHMEM_SHMGET @useshmget@ +#define APR_USE_SHMEM_MMAP_ANON @usemmapanon@ +#define APR_USE_SHMEM_BEOS @usebeosarea@ #define APR_USE_FLOCK_SERIALIZE @flockser@ #define APR_USE_SYSVSEM_SERIALIZE @sysvser@ +#define APR_USE_POSIXSEM_SERIALIZE @posixser@ #define APR_USE_FCNTL_SERIALIZE @fcntlser@ #define APR_USE_PROC_PTHREAD_SERIALIZE @procpthreadser@ #define APR_USE_PTHREAD_SERIALIZE @pthreadser@ -#define APR_USES_ANONYMOUS_SHM @anonymous_shm@ -#define APR_USES_FILEBASED_SHM @filebased_shm@ -#define APR_USES_KEYBASED_SHM @keybased_shm@ +#define APR_HAS_FLOCK_SERIALIZE @hasflockser@ +#define APR_HAS_SYSVSEM_SERIALIZE @hassysvser@ +#define APR_HAS_POSIXSEM_SERIALIZE @hasposixser@ +#define APR_HAS_FCNTL_SERIALIZE @hasfcntlser@ +#define APR_HAS_PROC_PTHREAD_SERIALIZE @hasprocpthreadser@ +#define APR_PROCESS_LOCK_IS_GLOBAL @proclockglobal@ +#define APR_HAVE_CORKABLE_TCP @have_corkable_tcp@ +#define APR_HAVE_GETRLIMIT @have_getrlimit@ #define APR_HAVE_IN_ADDR @have_in_addr@ -#define APR_HAVE_INET_ADDR @inet_addr@ -#define APR_HAVE_INET_NETWORK @inet_network@ +#define APR_HAVE_INET_ADDR @have_inet_addr@ +#define APR_HAVE_INET_NETWORK @have_inet_network@ +#define APR_HAVE_IPV6 @have_ipv6@ +#define APR_HAVE_SOCKADDR_UN @have_sockaddr_un@ +#define APR_HAVE_MEMMOVE @have_memmove@ +#define APR_HAVE_SETRLIMIT @have_setrlimit@ +#define APR_HAVE_SIGACTION @have_sigaction@ +#define APR_HAVE_SIGSUSPEND @have_sigsuspend@ +#define APR_HAVE_SIGWAIT @have_sigwait@ +#define APR_HAVE_SA_STORAGE @have_sa_storage@ +#define APR_HAVE_STRCASECMP @have_strcasecmp@ +#define APR_HAVE_STRDUP @have_strdup@ +#define APR_HAVE_STRICMP @have_stricmp@ +#define APR_HAVE_STRNCASECMP @have_strncasecmp@ +#define APR_HAVE_STRNICMP @have_strnicmp@ +#define APR_HAVE_STRSTR @have_strstr@ +#define APR_HAVE_MEMCHR @have_memchr@ +#define APR_HAVE_STRUCT_RLIMIT @struct_rlimit@ #define APR_HAVE_UNION_SEMUN @have_union_semun@ - -#if APR_HAVE_SYS_TYPES_H -#include <sys/types.h> -#endif +#define APR_HAVE_SCTP @have_sctp@ +#define APR_HAVE_IOVEC @have_iovec@ /* APR Feature Macros */ #define APR_HAS_SHARED_MEMORY @sharedmem@ @@ -62,30 +289,279 @@ #define APR_HAS_MMAP @mmap@ #define APR_HAS_FORK @fork@ #define APR_HAS_RANDOM @rand@ -#define APR_HAS_XLATE @iconv@ +#define APR_HAS_OTHER_CHILD @oc@ +#define APR_HAS_DSO @aprdso@ +#define APR_HAS_SO_ACCEPTFILTER @acceptfilter@ +#define APR_HAS_UNICODE_FS @have_unicode_fs@ +#define APR_HAS_PROC_INVOKED @have_proc_invoked@ +#define APR_HAS_USER @apr_has_user@ +#define APR_HAS_LARGE_FILES @aprlfs@ +#define APR_HAS_XTHREAD_FILES @apr_has_xthread_files@ +#define APR_HAS_OS_UUID @osuuid@ + +#define APR_PROCATTR_USER_SET_REQUIRES_PASSWORD @apr_procattr_user_set_requires_password@ + +/* APR sets APR_FILES_AS_SOCKETS to 1 on systems where it is possible + * to poll on files/pipes. + */ +#define APR_FILES_AS_SOCKETS @file_as_socket@ + +/* This macro indicates whether or not EBCDIC is the native character set. + */ +#define APR_CHARSET_EBCDIC @apr_charset_ebcdic@ + +/* If we have a TCP implementation that can be "corked", what flag + * do we use? + */ +#define APR_TCP_NOPUSH_FLAG @apr_tcp_nopush_flag@ + +/* Is the TCP_NODELAY socket option inherited from listening sockets? +*/ +#define APR_TCP_NODELAY_INHERITED @tcp_nodelay_inherited@ + +/* Is the O_NONBLOCK flag inherited from listening sockets? +*/ +#define APR_O_NONBLOCK_INHERITED @o_nonblock_inherited@ /* Typedefs that APR needs. */ -typedef @short_value@ ap_int16_t; -typedef unsigned @short_value@ ap_uint16_t; - -typedef @int_value@ ap_int32_t; -typedef unsigned @int_value@ ap_uint32_t; - -typedef @long_value@ ap_int64_t; -typedef unsigned @long_value@ ap_uint64_t; +typedef unsigned char apr_byte_t; + +typedef @short_value@ apr_int16_t; +typedef unsigned @short_value@ apr_uint16_t; + +typedef @int_value@ apr_int32_t; +typedef unsigned @int_value@ apr_uint32_t; + +#define APR_SIZEOF_VOIDP @voidp_size@ + +/* + * Darwin 10's default compiler (gcc42) builds for both 64 and + * 32 bit architectures unless specifically told not to. + * In those cases, we need to override types depending on how + * we're being built at compile time. + * NOTE: This is an ugly work-around for Darwin's + * concept of universal binaries, a single package + * (executable, lib, etc...) which contains both 32 + * and 64 bit versions. The issue is that if APR is + * built universally, if something else is compiled + * against it, some bit sizes will depend on whether + * it is 32 or 64 bit. This is determined by the __LP64__ + * flag. Since we need to support both, we have to + * handle OS X unqiuely. + */ +#ifdef DARWIN_10 +#undef APR_SIZEOF_VOIDP +#undef INT64_C +#undef UINT64_C +#ifdef __LP64__ + typedef long apr_int64_t; + typedef unsigned long apr_uint64_t; + #define APR_SIZEOF_VOIDP 8 + #define INT64_C(v) (v ## L) + #define UINT64_C(v) (v ## UL) +#else + typedef long long apr_int64_t; + typedef unsigned long long apr_uint64_t; + #define APR_SIZEOF_VOIDP 4 + #define INT64_C(v) (v ## LL) + #define UINT64_C(v) (v ## ULL) +#endif +#else + typedef @long_value@ apr_int64_t; + typedef unsigned @long_value@ apr_uint64_t; +#endif + +typedef @size_t_value@ apr_size_t; +typedef @ssize_t_value@ apr_ssize_t; +typedef @off_t_value@ apr_off_t; +typedef @socklen_t_value@ apr_socklen_t; +typedef @ino_t_value@ apr_ino_t; + +#if APR_SIZEOF_VOIDP == 8 +typedef apr_uint64_t apr_uintptr_t; +typedef apr_int64_t apr_intptr_t; +#else +typedef apr_uint32_t apr_uintptr_t; +typedef apr_int32_t apr_intptr_t; +#endif + +/* Are we big endian? */ +#define APR_IS_BIGENDIAN @bigendian@ + +/* Mechanisms to properly type numeric literals */ +@int64_literal@ +@uint64_literal@ + +#ifdef INT16_MIN +#define APR_INT16_MIN INT16_MIN +#else +#define APR_INT16_MIN (-0x7fff - 1) +#endif + +#ifdef INT16_MAX +#define APR_INT16_MAX INT16_MAX +#else +#define APR_INT16_MAX (0x7fff) +#endif + +#ifdef UINT16_MAX +#define APR_UINT16_MAX UINT16_MAX +#else +#define APR_UINT16_MAX (0xffff) +#endif + +#ifdef INT32_MIN +#define APR_INT32_MIN INT32_MIN +#else +#define APR_INT32_MIN (-0x7fffffff - 1) +#endif + +#ifdef INT32_MAX +#define APR_INT32_MAX INT32_MAX +#else +#define APR_INT32_MAX 0x7fffffff +#endif + +#ifdef UINT32_MAX +#define APR_UINT32_MAX UINT32_MAX +#else +#define APR_UINT32_MAX (0xffffffffU) +#endif + +#ifdef INT64_MIN +#define APR_INT64_MIN INT64_MIN +#else +#define APR_INT64_MIN (APR_INT64_C(-0x7fffffffffffffff) - 1) +#endif + +#ifdef INT64_MAX +#define APR_INT64_MAX INT64_MAX +#else +#define APR_INT64_MAX APR_INT64_C(0x7fffffffffffffff) +#endif + +#ifdef UINT64_MAX +#define APR_UINT64_MAX UINT64_MAX +#else +#define APR_UINT64_MAX APR_UINT64_C(0xffffffffffffffff) +#endif + +#define APR_SIZE_MAX (~((apr_size_t)0)) -typedef @size_t_value@ ap_size_t; -typedef @ssize_t_value@ ap_ssize_t; -typedef @off_t_value@ ap_off_t; /* Definitions that APR programs need to work properly. */ -#define API_THREAD_FUNC -#define API_EXPORT(type) type -#define API_EXPORT_NONSTD(type) type -#define API_VAR_IMPORT extern -#define API_VAR_EXPORT +/** + * APR public API wrap for C++ compilers. + */ +#ifdef __cplusplus +#define APR_BEGIN_DECLS extern "C" { +#define APR_END_DECLS } +#else +#define APR_BEGIN_DECLS +#define APR_END_DECLS +#endif + +/** + * Thread callbacks from APR functions must be declared with APR_THREAD_FUNC, + * so that they follow the platform's calling convention. + * <PRE> + * + * void* APR_THREAD_FUNC my_thread_entry_fn(apr_thread_t *thd, void *data); + * + * </PRE> + */ +#define APR_THREAD_FUNC @apr_thread_func@ + +#if defined(DOXYGEN) || !defined(WIN32) + +/** + * The public APR functions are declared with APR_DECLARE(), so they may + * use the most appropriate calling convention. Public APR functions with + * variable arguments must use APR_DECLARE_NONSTD(). + * + * @remark Both the declaration and implementations must use the same macro. + * + * <PRE> + * APR_DECLARE(rettype) apr_func(args) + * </PRE> + * @see APR_DECLARE_NONSTD @see APR_DECLARE_DATA + * @remark Note that when APR compiles the library itself, it passes the + * symbol -DAPR_DECLARE_EXPORT to the compiler on some platforms (e.g. Win32) + * to export public symbols from the dynamic library build.\n + * The user must define the APR_DECLARE_STATIC when compiling to target + * the static APR library on some platforms (e.g. Win32.) The public symbols + * are neither exported nor imported when APR_DECLARE_STATIC is defined.\n + * By default, compiling an application and including the APR public + * headers, without defining APR_DECLARE_STATIC, will prepare the code to be + * linked to the dynamic library. + */ +#define APR_DECLARE(type) type + +/** + * The public APR functions using variable arguments are declared with + * APR_DECLARE_NONSTD(), as they must follow the C language calling convention. + * @see APR_DECLARE @see APR_DECLARE_DATA + * @remark Both the declaration and implementations must use the same macro. + * <PRE> + * + * APR_DECLARE_NONSTD(rettype) apr_func(args, ...); + * + * </PRE> + */ +#define APR_DECLARE_NONSTD(type) type + +/** + * The public APR variables are declared with APR_DECLARE_DATA. + * This assures the appropriate indirection is invoked at compile time. + * @see APR_DECLARE @see APR_DECLARE_NONSTD + * @remark Note that the declaration and implementations use different forms, + * but both must include the macro. + * + * <PRE> + * + * extern APR_DECLARE_DATA type apr_variable;\n + * APR_DECLARE_DATA type apr_variable = value; + * + * </PRE> + */ +#define APR_DECLARE_DATA + +#elif defined(APR_DECLARE_STATIC) +#define APR_DECLARE(type) type __stdcall +#define APR_DECLARE_NONSTD(type) type __cdecl +#define APR_DECLARE_DATA +#elif defined(APR_DECLARE_EXPORT) +#define APR_DECLARE(type) __declspec(dllexport) type __stdcall +#define APR_DECLARE_NONSTD(type) __declspec(dllexport) type __cdecl +#define APR_DECLARE_DATA __declspec(dllexport) +#else +#define APR_DECLARE(type) __declspec(dllimport) type __stdcall +#define APR_DECLARE_NONSTD(type) __declspec(dllimport) type __cdecl +#define APR_DECLARE_DATA __declspec(dllimport) +#endif + +#if !defined(WIN32) || defined(APU_MODULE_DECLARE_STATIC) +/** + * Declare a dso module's exported module structure as APR_MODULE_DECLARE_DATA. + * + * Unless APR_MODULE_DECLARE_STATIC is defined at compile time, symbols + * declared with APR_MODULE_DECLARE_DATA are always exported. + * @code + * module APR_MODULE_DECLARE_DATA mod_tag + * @endcode + */ +#define APR_MODULE_DECLARE_DATA +#else +#define APR_MODULE_DECLARE_DATA __declspec(dllexport) +#endif + +/** + * @deprecated + * @see APR_MODULE_DECLARE_DATA + */ +#define APU_MODULE_DECLARE_DATA APR_MODULE_DECLARE_DATA /* Define APR_SSIZE_T_FMT. * If ssize_t is an integer we define it to be "d", @@ -95,25 +571,143 @@ typedef @off_t_value@ ap_off_t; * to find the logic for this definition search for "ssize_t_fmt" in * configure.in. */ + @ssize_t_fmt@ +/* And APR_SIZE_T_FMT */ +@size_t_fmt@ + /* And APR_OFF_T_FMT */ @off_t_fmt@ -/* Define ap_signal and related necessary definitions. - */ -/* We are checking for HAVE_SIGACTION, but autoconf is filling this in - * for us automatically. +/* And APR_PID_T_FMT */ +@pid_t_fmt@ + +/* And APR_INT64_T_FMT */ +@int64_t_fmt@ + +/* And APR_UINT64_T_FMT */ +@uint64_t_fmt@ + +/* And APR_UINT64_T_HEX_FMT */ +@uint64_t_hex_fmt@ + +/* + * Ensure we work with universal binaries on Darwin */ -#if @have_sigaction@ && !defined(NO_USE_SIGACTION) -typedef void Sigfunc(int); -Sigfunc *ap_signal(int signo, Sigfunc * func); +#ifdef DARWIN_10 + +#undef APR_HAS_LARGE_FILES +#undef APR_SIZEOF_VOIDP +#undef APR_INT64_T_FMT +#undef APR_UINT64_T_FMT +#undef APR_UINT64_T_HEX_FMT + +#ifdef __LP64__ + #define APR_HAS_LARGE_FILES 0 + #define APR_SIZEOF_VOIDP 8 + #define APR_INT64_T_FMT "ld" + #define APR_UINT64_T_FMT "lu" + #define APR_UINT64_T_HEX_FMT "lx" +#else + #define APR_HAS_LARGE_FILES 1 + #define APR_SIZEOF_VOIDP 4 + #define APR_INT64_T_FMT "lld" + #define APR_UINT64_T_FMT "llu" + #define APR_UINT64_T_HEX_FMT "llx" +#endif + +#undef APR_IS_BIGENDIAN +#ifdef __BIG_ENDIAN__ + #define APR_IS_BIGENDIAN 1 +#else + #define APR_IS_BIGENDIAN 0 +#endif -#if defined(SIG_ING) && !defined(SIG_ERR) -#define SIG_ERR ((Sigfunc *)-1) +#undef APR_OFF_T_FMT +#define APR_OFF_T_FMT "lld" + +#endif /* DARWIN_10 */ + +/* Does the proc mutex lock threads too */ +#ifdef WIN32 +#define APR_PROC_MUTEX_IS_GLOBAL 1 +#else +#define APR_PROC_MUTEX_IS_GLOBAL @proc_mutex_is_global@ #endif + +/* Local machine definition for console and log output. */ +#define APR_EOL_STR "@eolstr@" + +#if APR_HAVE_SYS_WAIT_H +#ifdef WEXITSTATUS +#define apr_wait_t int +#else +#define apr_wait_t union wait +#define WEXITSTATUS(status) (int)((status).w_retcode) +#define WTERMSIG(status) (int)((status).w_termsig) +#endif /* !WEXITSTATUS */ +#elif defined(__MINGW32__) +typedef int apr_wait_t; +#endif /* HAVE_SYS_WAIT_H */ + +#if defined(PATH_MAX) +#define APR_PATH_MAX PATH_MAX +#elif defined(_POSIX_PATH_MAX) +#define APR_PATH_MAX _POSIX_PATH_MAX #else -#define ap_signal(a,b) signal(a,b) +#error no decision has been made on APR_PATH_MAX for your platform +#endif + +#define APR_DSOPATH "@shlibpath_var@" + +/** @} */ + +/* + * we always have SDBM (it's in our codebase) + */ +#define APU_HAVE_SDBM @apu_have_sdbm@ +#define APU_HAVE_GDBM @apu_have_gdbm@ +#define APU_HAVE_NDBM @apu_have_ndbm@ +#define APU_HAVE_DB @apu_have_db@ + +#if APU_HAVE_DB +#define APU_HAVE_DB_VERSION @apu_db_version@ +#endif + +#define APU_HAVE_PGSQL @apu_have_pgsql@ +#define APU_HAVE_MYSQL @apu_have_mysql@ +#define APU_HAVE_SQLITE3 @apu_have_sqlite3@ +#define APU_HAVE_SQLITE2 @apu_have_sqlite2@ +#define APU_HAVE_ORACLE @apu_have_oracle@ +#define APU_HAVE_ODBC @apu_have_odbc@ + +#define APU_HAVE_CRYPTO @apu_have_crypto@ +#define APU_HAVE_OPENSSL @apu_have_openssl@ +#define APU_HAVE_NSS @apu_have_nss@ +#define APU_HAVE_COMMONCRYPTO @apu_have_commoncrypto@ + +#define APU_HAVE_ICONV @have_iconv@ +#define APR_HAS_XLATE (APU_HAVE_ICONV) + +#define APU_USE_EXPAT @apu_has_expat@ +#define APU_USE_LIBXML2 @apu_has_libxml2@ + +/* Definitions that only Win32 programs need to compile properly. */ + +/* XXX These simply don't belong here, perhaps in apr_portable.h + * based on some APR_HAVE_PID/GID/UID? + */ +#ifdef WIN32 +#ifndef __GNUC__ +typedef int pid_t; +#endif +typedef int uid_t; +typedef int gid_t; +#endif + +#ifdef __cplusplus +} #endif #endif /* APR_H */ diff --git a/include/apr.hnw b/include/apr.hnw new file mode 100644 index 00000000000..120201bcee5 --- /dev/null +++ b/include/apr.hnw @@ -0,0 +1,502 @@ +/* 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. + */ + + +#ifndef APR_H +#define APR_H + +/* GENERATED FILE WARNING! DO NOT EDIT apr.h + * + * You must modify apr.hnw instead. + * + * And please, make an effort to stub apr.hw and apr.h.in in the process. + * + * This is the NetWare specific version of apr.h. It is copied from + * apr.hnw at the start of a NetWare build by the ./build/NWGNmakefile. + */ + +#if defined(NETWARE) || defined(DOXYGEN) + +#undef FD_SETSIZE +#define FD_SETSIZE 1024 + +#include <sys/types.h> +#include <stddef.h> +#include <stdio.h> +#include <time.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <limits.h> +#include <netware.h> +#include <library.h> +#include <nks/thread.h> +#include <nks/synch.h> +#include <nks/time.h> +#include <signal.h> +#ifdef USE_WINSOCK +#include <novsock2.h> +#ifdef NW_BUILD_IPV6 +#include <novtcpip.h> +#endif +#else +#include <sys/socket.h> +#include <sys/select.h> +#endif +#include <sys/types.h> + +#define _POSIX_THREAD_SAFE_FUNCTIONS 1 +#define READDIR_IS_THREAD_SAFE 1 + +/* Keep #include'd headers from within the __cplusplus or doxyblocks */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup apr_platform Platform Definitions + * @ingroup APR + * @{ + */ + +#define APR_INLINE +#define APR_HAS_INLINE 0 +#ifndef __attribute__ +#define __attribute__(__x) +#endif +#define ENUM_BITFIELD(e,n,w) signed int n : w + +#define APR_HAVE_CONIO_H 0 +#define APR_HAVE_CRYPT_H 0 +#define APR_HAVE_CTYPE_H 1 +#define APR_HAVE_DIRENT_H 1 +#define APR_HAVE_ERRNO_H 1 +#define APR_HAVE_FCNTL_H 1 +#define APR_HAVE_IO_H 0 +#define APR_HAVE_LIMITS_H 1 +#ifdef USE_WINSOCK +#define APR_HAVE_ARPA_INET_H 0 +#define APR_HAVE_NETDB_H 0 +#define APR_HAVE_NETINET_IN_H 0 +#else +#define APR_HAVE_ARPA_INET_H 1 +#define APR_HAVE_NETDB_H 1 +#define APR_HAVE_NETINET_IN_H 1 +#endif +#define APR_HAVE_NETINET_SCTP_H 0 +#define APR_HAVE_NETINET_SCTP_UIO_H 0 +#define APR_HAVE_NETINET_TCP_H 0 +#define APR_HAVE_PTHREAD_H 0 +#define APR_HAVE_SIGNAL_H 1 +#define APR_HAVE_STDARG_H 1 +#define APR_HAVE_STDINT_H 0 +#define APR_HAVE_STDIO_H 1 +#define APR_HAVE_STDLIB_H 1 +#define APR_HAVE_STRING_H 1 +#define APR_HAVE_STRINGS_H 0 +#define APR_HAVE_STRTOLL 1 +#define APR_HAVE_SYS_SENDFILE_H 0 +#define APR_HAVE_SYS_SYSLIMITS_H 0 +#ifdef USE_WINSOCK +#define APR_HAVE_SYS_SOCKET_H 0 +#define APR_HAVE_SYS_SOCKIO_H 0 +#define APR_HAVE_SYS_UN_H 0 +#else +#define APR_HAVE_SYS_SOCKET_H 1 +#define APR_HAVE_SYS_SOCKIO_H 1 +#define APR_HAVE_SYS_UN_H 1 +#endif +#define APR_HAVE_SYS_SIGNAL_H 1 +#define APR_HAVE_SYS_TIME_H 1 +#define APR_HAVE_SYS_TYPES_H 1 +#define APR_HAVE_SYS_UIO_H 1 +#define APR_HAVE_SYS_WAIT_H 1 +#define APR_HAVE_TIME_H 1 +#define APR_HAVE_UNISTD_H 1 + +#define APR_HAVE_SHMEM_MMAP_TMP 0 +#define APR_HAVE_SHMEM_MMAP_SHM 0 +#define APR_HAVE_SHMEM_MMAP_ZERO 0 +#define APR_HAVE_SHMEM_SHMGET_ANON 0 +#define APR_HAVE_SHMEM_SHMGET 0 +#define APR_HAVE_SHMEM_MMAP_ANON 0 +#define APR_HAVE_SHMEM_BEOS 0 + +#define APR_USE_SHMEM_MMAP_TMP 0 +#define APR_USE_SHMEM_MMAP_SHM 0 +#define APR_USE_SHMEM_MMAP_ZERO 0 +#define APR_USE_SHMEM_SHMGET_ANON 0 +#define APR_USE_SHMEM_SHMGET 0 +#define APR_USE_SHMEM_MMAP_ANON 0 +#define APR_USE_SHMEM_BEOS 0 + +#define APR_USE_FLOCK_SERIALIZE 0 +#define APR_USE_SYSVSEM_SERIALIZE 0 +#define APR_USE_FCNTL_SERIALIZE 0 +#define APR_USE_PROC_PTHREAD_SERIALIZE 0 +#define APR_USE_PTHREAD_SERIALIZE 0 + +#define APR_HAS_FLOCK_SERIALIZE 0 +#define APR_HAS_SYSVSEM_SERIALIZE 0 +#define APR_HAS_FCNTL_SERIALIZE 0 +#define APR_HAS_PROC_PTHREAD_SERIALIZE 0 +#define APR_HAS_RWLOCK_SERIALIZE 0 + +#define APR_HAS_LOCK_CREATE_NP 0 + +#define APR_PROCESS_LOCK_IS_GLOBAL 1 + +#define APR_FILE_BASED_SHM 0 + +#define APR_HAVE_CORKABLE_TCP 0 +#define APR_HAVE_GETRLIMIT 0 +#define APR_HAVE_ICONV 0 +#define APR_HAVE_IN_ADDR 1 +#define APR_HAVE_INET_ADDR 1 +#define APR_HAVE_INET_NETWORK 0 +#ifdef NW_BUILD_IPV6 +#define APR_HAVE_IPV6 1 +#else +#define APR_HAVE_IPV6 0 +#endif +#ifdef USE_WINSOCK +#define APR_HAVE_SOCKADDR_UN 0 +#else +#define APR_HAVE_SOCKADDR_UN 1 +#endif +#define APR_HAVE_MEMCHR 1 +#define APR_HAVE_MEMMOVE 1 +#define APR_HAVE_SETRLIMIT 0 +#define APR_HAVE_SIGACTION 0 +#define APR_HAVE_SIGSUSPEND 0 +#define APR_HAVE_SIGWAIT 0 +#define APR_HAVE_STRCASECMP 1 +#define APR_HAVE_STRDUP 1 +#define APR_HAVE_STRICMP 1 +#define APR_HAVE_STRNCASECMP 1 +#define APR_HAVE_STRNICMP 1 +#define APR_HAVE_STRSTR 1 +#define APR_HAVE_STRUCT_RLIMIT 0 +#define APR_HAVE_UNION_SEMUN 0 +#define APR_HAVE_SCTP 0 +#define APR_HAVE_IOVEC 1 + +/* APR Feature Macros */ +#define APR_HAS_SHARED_MEMORY 0 +#define APR_HAS_THREADS 1 +#define APR_HAS_SENDFILE 0 +#define APR_HAS_MMAP 0 +#define APR_HAS_FORK 0 +#define APR_HAS_RANDOM 1 +#define APR_HAS_OTHER_CHILD 0 +#define APR_HAS_DSO 1 +#define APR_HAS_SO_ACCEPTFILTER 0 +#define APR_HAS_UNICODE_FS 0 +#define APR_HAS_PROC_INVOKED 0 +#define APR_HAS_USER 1 +#define APR_HAS_LARGE_FILES 1 +#define APR_HAS_XTHREAD_FILES 0 +#define APR_HAS_OS_UUID 0 + +#define APR_PROCATTR_USER_SET_REQUIRES_PASSWORD 0 + +/* Netware can poll on files/pipes. + */ +#define APR_FILES_AS_SOCKETS 1 + +/* This macro indicates whether or not EBCDIC is the native character set. + */ +#define APR_CHARSET_EBCDIC 0 + +/* Is the TCP_NODELAY socket option inherited from listening sockets? + */ +#define APR_TCP_NODELAY_INHERITED 1 + +/* Is the O_NONBLOCK flag inherited from listening sockets? + */ +#define APR_O_NONBLOCK_INHERITED 1 + +/* Typedefs that APR needs. */ + +typedef unsigned char apr_byte_t; + +typedef short apr_int16_t; +typedef unsigned short apr_uint16_t; + +typedef int apr_int32_t; +typedef unsigned int apr_uint32_t; + +typedef long long apr_int64_t; +typedef unsigned long long apr_uint64_t; + +typedef size_t apr_size_t; +typedef ssize_t apr_ssize_t; +#if APR_HAS_LARGE_FILES +typedef off64_t apr_off_t; +#else +typedef off_t apr_off_t; +#endif +#ifdef USE_WINSOCK +typedef int apr_socklen_t; +#else +typedef size_t apr_socklen_t; +#endif +typedef apr_uint64_t apr_ino_t; + +/* Are we big endian? */ +/* XXX: Fatal assumption on Alpha platforms */ +#define APR_IS_BIGENDIAN 0 + +#ifdef UNKNOWN_NETWARE_64BIT_FLAG_NEEDED +#define APR_SIZEOF_VOIDP 8 +#else +#define APR_SIZEOF_VOIDP 4 +#endif + +#if APR_SIZEOF_VOIDP == 8 +typedef apr_uint64_t apr_uintptr_t; +typedef apr_int64_t apr_intptr_t; +#else +typedef apr_uint32_t apr_uintptr_t; +typedef apr_int32_t apr_intptr_t; +#endif + +/* Mechanisms to properly type numeric literals */ +#define APR_INT64_C(val) (val##LL) +#define APR_UINT64_C(val) (val##ULL) + +#ifdef INT16_MIN +#define APR_INT16_MIN INT16_MIN +#else +#define APR_INT16_MIN (-0x7fff - 1) +#endif + +#ifdef INT16_MAX +#define APR_INT16_MAX INT16_MAX +#else +#define APR_INT16_MAX (0x7fff) +#endif + +#ifdef UINT16_MAX +#define APR_UINT16_MAX UINT16_MAX +#else +#define APR_UINT16_MAX (0xffff) +#endif + +#ifdef INT32_MIN +#define APR_INT32_MIN INT32_MIN +#else +#define APR_INT32_MIN (-0x7fffffff - 1) +#endif + +#ifdef INT32_MAX +#define APR_INT32_MAX INT32_MAX +#else +#define APR_INT32_MAX 0x7fffffff +#endif + +#ifdef UINT32_MAX +#define APR_UINT32_MAX UINT32_MAX +#else +#define APR_UINT32_MAX (0xffffffffU) +#endif + +#ifdef INT64_MIN +#define APR_INT64_MIN INT64_MIN +#else +#define APR_INT64_MIN (APR_INT64_C(-0x7fffffffffffffff) - 1) +#endif + +#ifdef INT64_MAX +#define APR_INT64_MAX INT64_MAX +#else +#define APR_INT64_MAX APR_INT64_C(0x7fffffffffffffff) +#endif + +#ifdef UINT64_MAX +#define APR_UINT64_MAX UINT64_MAX +#else +#define APR_UINT64_MAX APR_UINT64_C(0xffffffffffffffff) +#endif + +#define APR_SIZE_MAX (~((apr_size_t)0)) + +/* PROC mutex is a GLOBAL mutex on Netware */ +#define APR_PROC_MUTEX_IS_GLOBAL 1 + +/* Definitions that APR programs need to work properly. */ + +/** + * APR public API wrap for C++ compilers. + */ +#ifdef __cplusplus +#define APR_BEGIN_DECLS extern "C" { +#define APR_END_DECLS } +#else +#define APR_BEGIN_DECLS +#define APR_END_DECLS +#endif + +/** + * Thread callbacks from APR functions must be declared with APR_THREAD_FUNC, + * so that they follow the platform's calling convention. + * @example + */ +/** void* APR_THREAD_FUNC my_thread_entry_fn(apr_thread_t *thd, void *data); + */ +#define APR_THREAD_FUNC + +/** + * The public APR functions are declared with APR_DECLARE(), so they may + * use the most appropriate calling convention. Public APR functions with + * variable arguments must use APR_DECLARE_NONSTD(). + * + * @remark Both the declaration and implementations must use the same macro. + * @example + */ +/** APR_DECLARE(rettype) apr_func(args) + * @see APR_DECLARE_NONSTD @see APR_DECLARE_DATA + * @remark Note that when APR compiles the library itself, it passes the + * symbol -DAPR_DECLARE_EXPORT to the compiler on some platforms (e.g. Win32) + * to export public symbols from the dynamic library build.\n + * The user must define the APR_DECLARE_STATIC when compiling to target + * the static APR library on some platforms (e.g. Win32.) The public symbols + * are neither exported nor imported when APR_DECLARE_STATIC is defined.\n + * By default, compiling an application and including the APR public + * headers, without defining APR_DECLARE_STATIC, will prepare the code to be + * linked to the dynamic library. + */ +#define APR_DECLARE(type) type + +/** + * The public APR functions using variable arguments are declared with + * APR_DECLARE_NONSTD(), as they must follow the C language calling convention. + * @see APR_DECLARE @see APR_DECLARE_DATA + * @remark Both the declaration and implementations must use the same macro. + * @example + */ +/** APR_DECLARE_NONSTD(rettype) apr_func(args, ...); + */ +#define APR_DECLARE_NONSTD(type) type + +/** + * The public APR variables are declared with APR_DECLARE_DATA. + * This assures the appropriate indirection is invoked at compile time. + * @see APR_DECLARE @see APR_DECLARE_NONSTD + * @remark Note that the declaration and implementations use different forms, + * but both must include the macro. + * @example + */ +/** extern APR_DECLARE_DATA type apr_variable;\n + * APR_DECLARE_DATA type apr_variable = value; + */ +#define APR_DECLARE_DATA + +#if !defined(WIN32) || defined(APU_MODULE_DECLARE_STATIC) +/** + * Declare a dso module's exported module structure as APR_MODULE_DECLARE_DATA. + * + * Unless APR_MODULE_DECLARE_STATIC is defined at compile time, symbols + * declared with APR_MODULE_DECLARE_DATA are always exported. + * @code + * module APR_MODULE_DECLARE_DATA mod_tag + * @endcode + */ +#define APR_MODULE_DECLARE_DATA +#else +#define APR_MODULE_DECLARE_DATA __declspec(dllexport) +#endif + +/** + * @deprecated + * @see APR_MODULE_DECLARE_DATA + */ +#define APU_MODULE_DECLARE_DATA APR_MODULE_DECLARE_DATA + +#define APR_SSIZE_T_FMT "d" + +#define APR_SIZE_T_FMT "d" + +#if APR_HAS_LARGE_FILES +#define APR_OFF_T_FMT "lld" +#else +#define APR_OFF_T_FMT "ld" +#endif + +#define APR_PID_T_FMT "d" + +/* Local machine definition for console and log output. */ +#define APR_EOL_STR "\r\n" + +typedef int apr_wait_t; + +#define APR_PATH_MAX PATH_MAX + +#define APR_DSOPATH "PATH" + +#define APR_INT64_T_FMT "lld" +#define APR_UINT64_T_FMT "llu" +#define APR_UINT64_T_HEX_FMT "llx" +#define APR_TIME_T_FMT APR_INT64_T_FMT + +/* + * we always have SDBM (it's in our codebase) + */ +#define APU_HAVE_SDBM 1 + +#ifndef APU_DSO_MODULE_BUILD +#define APU_HAVE_GDBM 0 +#define APU_HAVE_NDBM 0 +#define APU_HAVE_DB 0 + +#if APU_HAVE_DB +#define APU_HAVE_DB_VERSION 0 +#endif +#endif + +/* + * we always enable dynamic driver loads within apr_dbd + */ +#ifndef APU_DSO_MODULE_BUILD +#define APU_HAVE_PGSQL 0 +#define APU_HAVE_MYSQL 0 +#define APU_HAVE_SQLITE3 0 +#define APU_HAVE_SQLITE2 0 +#define APU_HAVE_ORACLE 0 +#define APU_HAVE_ODBC 0 +#endif + +#define APU_HAVE_CRYPTO 0 + +#ifndef APU_DSO_MODULE_BUILD +#define APU_HAVE_OPENSSL 0 +#define APU_HAVE_NSS 0 +#define APU_HAVE_COMMONCRYPTO 0 +#endif + +#define APU_HAVE_ICONV 1 +#define APR_HAS_XLATE (APU_HAVE_ICONV) + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* NETWARE */ + +#endif /* APR_H */ diff --git a/include/apr.hw b/include/apr.hw index fab1dd365ab..6366ba93290 100644 --- a/include/apr.hw +++ b/include/apr.hw @@ -1,149 +1,741 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -/* - * Note: This is a Windows specific version of apr.h. It is renamed to - * apr.h at the start of a Windows build. +/* 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. */ -#ifdef WIN32 + #ifndef APR_H #define APR_H +/* GENERATED FILE WARNING! DO NOT EDIT apr.h + * + * You must modify apr.hw instead. + * + * And please, make an effort to stub apr.hnw and apr.h.in in the process. + * + * This is the Win32 specific version of apr.h. It is copied from + * apr.hw by the apr.dsp and libapr.dsp projects. + */ + +/** + * @file apr.h + * @brief APR Platform Definitions + * @remark This is a generated header generated from include/apr.h.in by + * ./configure, or copied from include/apr.hw or include/apr.hnw + * for Win32 or Netware by those build environments, respectively. + */ + +/* Make sure we have our platform identifier macro defined we ask for later. + */ +#if defined(_WIN32) && !defined(WIN32) +#define WIN32 1 +#endif + +/* Ignore most warnings (back down to /W3) for poorly constructed headers, + * excluded from doxygen parsing + */ +#if defined(_MSC_VER) && _MSC_VER >= 1200 +#pragma warning(push, 3) +#endif + +/* disable or reduce the frequency of... + * C4057: indirection to slightly different base types + * C4075: slight indirection changes (unsigned short* vs short[]) + * C4100: unreferenced formal parameter + * C4127: conditional expression is constant + * C4163: '_rotl64' : not available as an intrinsic function + * C4201: nonstandard extension nameless struct/unions + * C4244: int to char/short - precision loss + * C4514: unreferenced inline function removed + */ +#if defined(_MSC_VER) +#pragma warning(disable: 4100 4127 4163 4201 4514; once: 4057 4075 4244) +#endif + +/* Ignore Microsoft's interpretation of secure development + * and the POSIX string handling API + */ +#if defined(_MSC_VER) && _MSC_VER >= 1400 +#ifndef _CRT_SECURE_NO_DEPRECATE +#define _CRT_SECURE_NO_DEPRECATE +#endif +#pragma warning(disable: 4996) +#endif + +/** + * @file apr.h + * @brief APR Platform Definitions + * @remark This is a generated header generated from include/apr.h.in by + * ./configure, or copied from include/apr.hw or include/apr.hnw + * for Win32 or Netware by those build environments, respectively. + */ + +/** + * @defgroup APR Apache Portability Runtime library + * @{ + */ +/** + * @defgroup apr_platform Platform Definitions + * @{ + * @warning + * <strong><em>The actual values of macros and typedefs on this page<br> + * are platform specific and should NOT be relied upon!</em></strong> + */ + +/* So that we can use inline on some critical functions, and use + * GNUC attributes (such as to get -Wall warnings for printf-like + * functions). Only do this in gcc 2.7 or later ... it may work + * on earlier stuff, but why chance it. + * + * We've since discovered that the gcc shipped with NeXT systems + * as "cc" is completely broken. It claims to be __GNUC__ and so + * on, but it doesn't implement half of the things that __GNUC__ + * means. In particular it's missing inline and the __attribute__ + * stuff. So we hack around it. PR#1613. -djg + */ +#if defined(_MSC_VER) +#define APR_INLINE __inline +#define APR_HAS_INLINE 1 +#ifndef __attribute__ +#define __attribute__(__x) +#endif +#elif !defined(__GNUC__) || __GNUC__ < 2 || \ + (__GNUC__ == 2 && __GNUC_MINOR__ < 7) ||\ + defined(NEXT) +#ifndef __attribute__ +#define __attribute__(__x) +#endif +#define APR_INLINE +#define APR_HAS_INLINE 0 +#else +#define APR_INLINE __inline__ +#define APR_HAS_INLINE 1 +#endif + +#ifdef _WIN32_WCE +#define APR_NOT_IN_WCE 0 +#else +#define APR_NOT_IN_WCE 1 +#endif + +#define APR_HAVE_ARPA_INET_H 0 +#define APR_HAVE_CONIO_H APR_NOT_IN_WCE +#define APR_HAVE_CRYPT_H 0 +#define APR_HAVE_CTYPE_H APR_NOT_IN_WCE +#define APR_HAVE_DIRENT_H 0 +#define APR_HAVE_ERRNO_H APR_NOT_IN_WCE +#define APR_HAVE_FCNTL_H APR_NOT_IN_WCE +#define APR_HAVE_IFADDRS_H 0 +#define APR_HAVE_IO_H APR_NOT_IN_WCE +#define APR_HAVE_LIMITS_H APR_NOT_IN_WCE +#define APR_HAVE_MSWSOCK_H APR_NOT_IN_WCE +#define APR_HAVE_NETDB_H 0 +#define APR_HAVE_NETINET_IN_H 0 +#define APR_HAVE_NETINET_SCTP_H 0 +#define APR_HAVE_NETINET_SCTP_UIO_H 0 +#define APR_HAVE_NETINET_TCP_H 0 +#define APR_HAVE_PROCESS_H 1 +#define APR_HAVE_PTHREAD_H 0 +#define APR_HAVE_SEMAPHORE_H 0 +#define APR_HAVE_SIGNAL_H APR_NOT_IN_WCE +#define APR_HAVE_STDARG_H APR_NOT_IN_WCE +#define APR_HAVE_STDDEF_H APR_NOT_IN_WCE +#define APR_HAVE_STDINT_H 0 +#define APR_HAVE_STDIO_H 1 +#define APR_HAVE_STDLIB_H 1 +#define APR_HAVE_STRING_H 1 +#define APR_HAVE_STRINGS_H 0 +#define APR_HAVE_SYS_IOCTL_H 0 +#define APR_HAVE_SYS_SENDFILE_H 0 +#define APR_HAVE_SYS_SIGNAL_H 0 +#define APR_HAVE_SYS_SOCKET_H 0 +#define APR_HAVE_SYS_SOCKIO_H 0 +#define APR_HAVE_SYS_SYSLIMITS_H 0 +#define APR_HAVE_SYS_TIME_H 0 +#define APR_HAVE_SYS_TYPES_H APR_NOT_IN_WCE +#define APR_HAVE_SYS_UIO_H 0 +#define APR_HAVE_SYS_UN_H 0 +#define APR_HAVE_SYS_WAIT_H 0 +#define APR_HAVE_TIME_H APR_NOT_IN_WCE +#define APR_HAVE_UNISTD_H 0 +#define APR_HAVE_WINDOWS_H 1 +#define APR_HAVE_WINSOCK2_H APR_NOT_IN_WCE +#define APR_HAVE_WS2TCPIP_H APR_NOT_IN_WCE + +/** @} */ +/** @} */ + +/* We don't include our conditional headers within the doxyblocks + * or the extern "C" namespace + */ + +/* If windows.h was already included, our preferences don't matter. + * If not, include a restricted set of windows headers to our tastes. + */ +#if APR_HAVE_WINDOWS_H +#ifndef _WINDOWS_ + #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif + #ifndef _WIN32_WINNT -/* - * Compile the server including all the Windows NT 4.0 header files by - * default. +#define _WIN32_WINNT 0x0501 +#endif + +#ifndef NOUSER +#define NOUSER +#endif +#ifndef NOMCX +#define NOMCX +#endif +#ifndef NOIME +#define NOIME +#endif + +/* Impossible to include winsock2.h after winsock.h, while windows.h + * attempts to load winsock. Setting _WINSOCKAPI_ will dodge this. */ -#define _WIN32_WINNT 0x0400 +#if APR_HAVE_WINSOCK2_H +#define _WINSOCKAPI_ #endif + #include <windows.h> +#endif +#endif + +#if APR_HAVE_WINSOCK2_H #include <winsock2.h> + +#if APR_HAVE_WS2TCPIP_H +#include <ws2tcpip.h> +#endif + +#if APR_HAVE_MSWSOCK_H #include <mswsock.h> +#endif + +#else /* !APR_HAVE_WINSOCK2_H */ + +#if APR_HAVE_WINSOCK_H +#include <winsock.h> +#endif + +#endif /* !APR_HAVE_WINSOCK2_H */ + +#if APR_HAVE_SYS_TYPES_H #include <sys/types.h> +#endif + +#if APR_HAVE_STDDEF_H #include <stddef.h> -#include <stdio.h> -#include <time.h> -#include <process.h> -#include <signal.h> -#include <stdlib.h> +#endif -#define ap_inline -#define __attribute__(__x) -#define ENUM_BITFIELD(e,n,w) signed int n : w +#if APR_HAVE_SYS_SOCKET_H +#include <sys/socket.h> +#endif -#define APR_HAVE_ERRNO_H 1 -#define APR_HAVE_DIRENT_H 0 -#define APR_HAVE_FCNTL_H 0 -#define APR_HAVE_NETINET_IN_H 0 -#define APR_HAVE_PTHREAD_H 0 -#define APR_HAVE_STDARG_H 1 -#define APR_HAVE_STDIO_H 1 -#define APR_HAVE_SYS_TYPES_H 1 -#define APR_HAVE_SYS_UIO_H 0 -#define APR_HAVE_IN_ADDR 1 +#if APR_HAVE_STDINT_H +#include <stdint.h> +#endif + +#if APR_HAVE_SYS_WAIT_H +#include <sys/wait.h> +#endif -#define APR_USE_FLOCK_SERIALIZE 0 +/* header files for PATH_MAX, _POSIX_PATH_MAX */ +#if APR_HAVE_LIMITS_H +#include <limits.h> +#else +#if APR_HAVE_SYS_SYSLIMITS_H +#include <sys/syslimits.h> +#endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @addtogroup apr_platform + * @ingroup APR + * @{ + */ + +#define APR_HAVE_SHMEM_MMAP_TMP 0 +#define APR_HAVE_SHMEM_MMAP_SHM 0 +#define APR_HAVE_SHMEM_MMAP_ZERO 0 +#define APR_HAVE_SHMEM_SHMGET_ANON 0 +#define APR_HAVE_SHMEM_SHMGET 0 +#define APR_HAVE_SHMEM_MMAP_ANON 0 +#define APR_HAVE_SHMEM_BEOS 0 + +#define APR_USE_SHMEM_MMAP_TMP 0 +#define APR_USE_SHMEM_MMAP_SHM 0 +#define APR_USE_SHMEM_MMAP_ZERO 0 +#define APR_USE_SHMEM_SHMGET_ANON 0 +#define APR_USE_SHMEM_SHMGET 0 +#define APR_USE_SHMEM_MMAP_ANON 0 +#define APR_USE_SHMEM_BEOS 0 + +#define APR_USE_FLOCK_SERIALIZE 0 #define APR_USE_SYSVSEM_SERIALIZE 0 +#define APR_USE_POSIXSEM_SERIALIZE 0 #define APR_USE_FCNTL_SERIALIZE 0 -#define APR_USE_PROC_PTHREAD_SERIALIZE 0 -#define APR_USE_PTHREAD_SERIALIZE 0 +#define APR_USE_PROC_PTHREAD_SERIALIZE 0 +#define APR_USE_PTHREAD_SERIALIZE 0 -#if APR_HAVE_SYS_TYPES_H -#include <sys/types.h> -#endif +#define APR_HAS_FLOCK_SERIALIZE 0 +#define APR_HAS_SYSVSEM_SERIALIZE 0 +#define APR_HAS_POSIXSEM_SERIALIZE 0 +#define APR_HAS_FCNTL_SERIALIZE 0 +#define APR_HAS_PROC_PTHREAD_SERIALIZE 0 + +#define APR_PROCESS_LOCK_IS_GLOBAL 0 + +#define APR_HAVE_CORKABLE_TCP 0 +#define APR_HAVE_GETRLIMIT 0 +#define APR_HAVE_ICONV 0 +#define APR_HAVE_IN_ADDR 1 +#define APR_HAVE_INET_ADDR 1 +#define APR_HAVE_INET_NETWORK 0 +#define APR_HAVE_IPV6 1 +#define APR_HAVE_SOCKADDR_UN 0 +#define APR_HAVE_MEMMOVE 1 +#define APR_HAVE_SETRLIMIT 0 +#define APR_HAVE_SIGACTION 0 +#define APR_HAVE_SIGSUSPEND 0 +#define APR_HAVE_SIGWAIT 0 +#define APR_HAVE_SA_STORAGE 0 +#define APR_HAVE_STRCASECMP 0 +#define APR_HAVE_STRDUP 1 +#define APR_HAVE_STRICMP APR_NOT_IN_WCE +#define APR_HAVE_STRNCASECMP 0 +#define APR_HAVE_STRNICMP APR_NOT_IN_WCE +#define APR_HAVE_STRSTR 1 +#define APR_HAVE_MEMCHR 1 +#define APR_HAVE_STRUCT_RLIMIT 0 +#define APR_HAVE_UNION_SEMUN 0 +#define APR_HAVE_SCTP 0 +#define APR_HAVE_IOVEC 0 /* APR Feature Macros */ -#define APR_HAS_THREADS 1 -#define APR_HAS_SENDFILE 1 -#define APR_HAS_MMAP 0 -#define APR_HAS_RANDOM 1 -#define APR_HAS_XLATE 0 +#define APR_HAS_SHARED_MEMORY 1 +#define APR_HAS_THREADS 1 +#define APR_HAS_SENDFILE APR_NOT_IN_WCE +#define APR_HAS_MMAP 1 +#define APR_HAS_FORK 0 +#define APR_HAS_RANDOM 1 +#define APR_HAS_OTHER_CHILD 1 +#define APR_HAS_DSO 1 +#define APR_HAS_SO_ACCEPTFILTER 0 +#define APR_HAS_UNICODE_FS 1 +#define APR_HAS_PROC_INVOKED 1 +#define APR_HAS_USER APR_NOT_IN_WCE +#define APR_HAS_LARGE_FILES APR_NOT_IN_WCE +#define APR_HAS_XTHREAD_FILES APR_NOT_IN_WCE +#define APR_HAS_OS_UUID 1 + +#define APR_PROCATTR_USER_SET_REQUIRES_PASSWORD APR_NOT_IN_WCE + +/* APR sets APR_FILES_AS_SOCKETS to 1 on systems where it is possible + * to poll on files/pipes. + */ +#define APR_FILES_AS_SOCKETS 0 + +/* This macro indicates whether or not EBCDIC is the native character set. + */ +#define APR_CHARSET_EBCDIC 0 + +/* If we have a TCP implementation that can be "corked", what flag + * do we use? + */ +#define APR_TCP_NOPUSH_FLAG 0 + +/* Is the TCP_NODELAY socket option inherited from listening sockets? + */ +#define APR_TCP_NODELAY_INHERITED 1 + +/* Is the O_NONBLOCK flag inherited from listening sockets? + */ +#define APR_O_NONBLOCK_INHERITED 1 /* Typedefs that APR needs. */ -typedef short ap_int16_t; -typedef unsigned short ap_uint16_t; - -typedef int ap_int32_t; -typedef unsigned int ap_uint32_t; - -typedef __int64 ap_int64_t; -typedef unsigned __int64 ap_uint64_t; - -typedef int ap_size_t; -typedef int ap_ssize_t; -typedef _off_t ap_off_t; +typedef unsigned char apr_byte_t; + +typedef short apr_int16_t; +typedef unsigned short apr_uint16_t; + +typedef int apr_int32_t; +typedef unsigned int apr_uint32_t; + +typedef __int64 apr_int64_t; +typedef unsigned __int64 apr_uint64_t; + +typedef size_t apr_size_t; +#if APR_HAVE_STDDEF_H +typedef ptrdiff_t apr_ssize_t; +#else +typedef int apr_ssize_t; +#endif + +#if APR_HAS_LARGE_FILES +typedef __int64 apr_off_t; +#else +typedef long apr_off_t; +#endif +typedef int apr_socklen_t; +typedef apr_uint64_t apr_ino_t; + +#ifdef _WIN64 +#define APR_SIZEOF_VOIDP 8 +#else +#define APR_SIZEOF_VOIDP 4 +#endif + +#if APR_SIZEOF_VOIDP == 8 +typedef apr_uint64_t apr_uintptr_t; +typedef apr_int64_t apr_intptr_t; +#else +typedef apr_uint32_t apr_uintptr_t; +typedef apr_int32_t apr_intptr_t; +#endif + +/* Are we big endian? */ +/* XXX: Fatal assumption on Alpha platforms */ +#define APR_IS_BIGENDIAN 0 + +/* Mechanisms to properly type numeric literals */ + +#ifndef __GNUC__ +#define APR_INT64_C(val) (val##i64) +#define APR_UINT64_C(val) (val##Ui64) +#else +#define APR_INT64_C(val) (val##LL) +#define APR_UINT64_C(val) (val##ULL) +#endif + +#ifdef INT16_MIN +#define APR_INT16_MIN INT16_MIN +#else +#define APR_INT16_MIN (-0x7fff - 1) +#endif + +#ifdef INT16_MAX +#define APR_INT16_MAX INT16_MAX +#else +#define APR_INT16_MAX (0x7fff) +#endif + +#ifdef UINT16_MAX +#define APR_UINT16_MAX UINT16_MAX +#else +#define APR_UINT16_MAX (0xffff) +#endif + +#ifdef INT32_MIN +#define APR_INT32_MIN INT32_MIN +#else +#define APR_INT32_MIN (-0x7fffffff - 1) +#endif + +#ifdef INT32_MAX +#define APR_INT32_MAX INT32_MAX +#else +#define APR_INT32_MAX 0x7fffffff +#endif + +#ifdef UINT32_MAX +#define APR_UINT32_MAX UINT32_MAX +#else +#define APR_UINT32_MAX (0xffffffffU) +#endif + +#ifdef INT64_MIN +#define APR_INT64_MIN INT64_MIN +#else +#define APR_INT64_MIN (APR_INT64_C(-0x7fffffffffffffff) - 1) +#endif + +#ifdef INT64_MAX +#define APR_INT64_MAX INT64_MAX +#else +#define APR_INT64_MAX APR_INT64_C(0x7fffffffffffffff) +#endif + +#ifdef UINT64_MAX +#define APR_UINT64_MAX UINT64_MAX +#else +#define APR_UINT64_MAX APR_UINT64_C(0xffffffffffffffff) +#endif + +#define APR_SIZE_MAX (~((apr_size_t)0)) + +/* Definitions that APR programs need to work properly. */ + +/** + * APR public API wrap for C++ compilers. + */ +#ifdef __cplusplus +#define APR_BEGIN_DECLS extern "C" { +#define APR_END_DECLS } +#else +#define APR_BEGIN_DECLS +#define APR_END_DECLS +#endif + +/** + * Thread callbacks from APR functions must be declared with APR_THREAD_FUNC, + * so that they follow the platform's calling convention. + * <PRE> + * + * void* APR_THREAD_FUNC my_thread_entry_fn(apr_thread_t *thd, void *data); + * + * </PRE> + */ +#define APR_THREAD_FUNC __stdcall + + +#if defined(DOXYGEN) || !defined(WIN32) + +/** + * The public APR functions are declared with APR_DECLARE(), so they may + * use the most appropriate calling convention. Public APR functions with + * variable arguments must use APR_DECLARE_NONSTD(). + * + * @remark Both the declaration and implementations must use the same macro. + * + * <PRE> + * APR_DECLARE(rettype) apr_func(args) + * </PRE> + * @see APR_DECLARE_NONSTD @see APR_DECLARE_DATA + * @remark Note that when APR compiles the library itself, it passes the + * symbol -DAPR_DECLARE_EXPORT to the compiler on some platforms (e.g. Win32) + * to export public symbols from the dynamic library build.\n + * The user must define the APR_DECLARE_STATIC when compiling to target + * the static APR library on some platforms (e.g. Win32.) The public symbols + * are neither exported nor imported when APR_DECLARE_STATIC is defined.\n + * By default, compiling an application and including the APR public + * headers, without defining APR_DECLARE_STATIC, will prepare the code to be + * linked to the dynamic library. + */ +#define APR_DECLARE(type) type + +/** + * The public APR functions using variable arguments are declared with + * APR_DECLARE_NONSTD(), as they must follow the C language calling convention. + * @see APR_DECLARE @see APR_DECLARE_DATA + * @remark Both the declaration and implementations must use the same macro. + * <PRE> + * + * APR_DECLARE_NONSTD(rettype) apr_func(args, ...); + * + * </PRE> + */ +#define APR_DECLARE_NONSTD(type) type + +/** + * The public APR variables are declared with APR_DECLARE_DATA. + * This assures the appropriate indirection is invoked at compile time. + * @see APR_DECLARE @see APR_DECLARE_NONSTD + * @remark Note that the declaration and implementations use different forms, + * but both must include the macro. + * + * <PRE> + * + * extern APR_DECLARE_DATA type apr_variable;\n + * APR_DECLARE_DATA type apr_variable = value; + * + * </PRE> + */ +#define APR_DECLARE_DATA + +#elif defined(APR_DECLARE_STATIC) +#define APR_DECLARE(type) type __stdcall +#define APR_DECLARE_NONSTD(type) type __cdecl +#define APR_DECLARE_DATA +#elif defined(APR_DECLARE_EXPORT) +#define APR_DECLARE(type) __declspec(dllexport) type __stdcall +#define APR_DECLARE_NONSTD(type) __declspec(dllexport) type __cdecl +#define APR_DECLARE_DATA __declspec(dllexport) +#else +#define APR_DECLARE(type) __declspec(dllimport) type __stdcall +#define APR_DECLARE_NONSTD(type) __declspec(dllimport) type __cdecl +#define APR_DECLARE_DATA __declspec(dllimport) +#endif + +#if !defined(WIN32) || defined(APU_MODULE_DECLARE_STATIC) +/** + * Declare a dso module's exported module structure as APR_MODULE_DECLARE_DATA. + * + * Unless APR_MODULE_DECLARE_STATIC is defined at compile time, symbols + * declared with APR_MODULE_DECLARE_DATA are always exported. + * @code + * module APR_MODULE_DECLARE_DATA mod_tag + * @endcode + */ +#define APR_MODULE_DECLARE_DATA +#else +#define APR_MODULE_DECLARE_DATA __declspec(dllexport) +#endif + +/** + * @deprecated + * @see APR_MODULE_DECLARE_DATA + */ +#define APU_MODULE_DECLARE_DATA APR_MODULE_DECLARE_DATA + +/* Define APR_SSIZE_T_FMT. + * If ssize_t is an integer we define it to be "d", + * if ssize_t is a long int we define it to be "ld", + * if ssize_t is 64-bit, we define it to be msvc specific "I64d" + */ +#ifdef _WIN64 +#define APR_SSIZE_T_FMT "I64d" +#define APR_SIZE_T_FMT "I64u" +#else +#define APR_SSIZE_T_FMT "d" +#define APR_SIZE_T_FMT "u" +#endif + +#if APR_HAS_LARGE_FILES +#define APR_OFF_T_FMT "I64d" +#else +#define APR_OFF_T_FMT "d" +#endif + +#define APR_PID_T_FMT "d" + +#define APR_INT64_T_FMT "I64d" +#define APR_UINT64_T_FMT "I64u" +#define APR_UINT64_T_HEX_FMT "I64x" + +/* No difference between PROC and GLOBAL mutex */ +#define APR_PROC_MUTEX_IS_GLOBAL 1 + +/* Local machine definition for console and log output. */ +#define APR_EOL_STR "\r\n" + +typedef int apr_wait_t; + +#if APR_HAS_UNICODE_FS +/* An arbitrary size that is digestable. True max is a bit less than 32000 */ +#define APR_PATH_MAX 8192 +#else /* !APR_HAS_UNICODE_FS */ +#define APR_PATH_MAX MAX_PATH +#endif + +#define APR_DSOPATH "PATH" + +/* + * we always have SDBM (it's in our codebase) + */ +#define APU_HAVE_SDBM 1 + +#ifndef APU_DSO_MODULE_BUILD +#define APU_HAVE_GDBM 0 +#define APU_HAVE_NDBM 0 +#define APU_HAVE_DB 0 + +#if APU_HAVE_DB +#define APU_HAVE_DB_VERSION 0 +#endif +#endif + +/* + * we always enable dynamic driver loads within apr_dbd + * driver builds enable these flags individually + */ +#ifndef APU_DSO_MODULE_BUILD +#define APU_HAVE_PGSQL 0 +#define APU_HAVE_MYSQL 0 +#define APU_HAVE_SQLITE3 0 +#define APU_HAVE_SQLITE2 0 +#define APU_HAVE_ORACLE 0 +#define APU_HAVE_ODBC 0 +#endif + +#define APU_HAVE_CRYPTO 0 + +#ifndef APU_DSO_MODULE_BUILD +#define APU_HAVE_OPENSSL 0 +#define APU_HAVE_NSS 0 +#define APU_HAVE_COMMONCRYPTO 0 +#endif + +#define APU_HAVE_ICONV 0 +#define APR_HAS_XLATE (APU_HAVE_ICONV) + +#define APU_USE_EXPAT 1 +#define APU_USE_LIBXML2 0 + +/** @} */ + +/* Definitions that only Win32 programs need to compile properly. */ + +/* XXX These simply don't belong here, perhaps in apr_portable.h + * based on some APR_HAVE_PID/GID/UID? + */ +#ifdef WIN32 +#ifndef __WATCOMC__ +#ifndef __GNUC__ typedef int pid_t; +#endif typedef int uid_t; typedef int gid_t; +#endif +#endif + +/* Typically defined in stdio.h or unistd.h + */ +#ifndef STDIN_FILENO +#define STDIN_FILENO 0 +#endif +#ifndef STDOUT_FILENO +#define STDOUT_FILENO 1 +#endif +#ifndef STDERR_FILENO +#define STDERR_FILENO 2 +#endif + +#if APR_HAVE_IPV6 + +/* Appears in later flavors, not the originals. */ +#ifndef in_addr6 +#define in6_addr in_addr6 +#endif + +#ifndef WS2TCPIP_INLINE +#define IN6_IS_ADDR_V4MAPPED(a) \ + ( (*(const apr_uint64_t *)(const void *)(&(a)->s6_addr[0]) == 0) \ + && (*(const apr_uint32_t *)(const void *)(&(a)->s6_addr[8]) == ntohl(0x0000ffff))) +#endif + +#endif /* APR_HAVE_IPV6 */ + +#ifdef __cplusplus +} +#endif + +/* Done with badly written headers, leave 'deprecated CRT' undeprecated + */ +#if defined(_MSC_VER) && _MSC_VER >= 1200 +#pragma warning(pop) +#if _MSC_VER >= 1400 +#pragma warning(disable: 4996) +#endif +#endif -/* Definitions that APR programs need to work properly. */ -#define APR_SSIZE_T_FMT "d" -#define API_THREAD_FUNC __stdcall -#define API_EXPORT(type) type -#define API_EXPORT_NONSTD(type) type -#define API_VAR_IMPORT extern _declspec(dllimport) -#define API_VAR_EXPORT - -/* struct iovec is needed to emulate Unix writev */ -struct iovec { - char* iov_base; - int iov_len; -}; #endif /* APR_H */ -#endif /* WIN32 */ diff --git a/include/apr.hwc b/include/apr.hwc new file mode 100644 index 00000000000..061a5299c0c --- /dev/null +++ b/include/apr.hwc @@ -0,0 +1,742 @@ +/* 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. + */ + + +#ifndef APR_H +#define APR_H + +/* GENERATED FILE WARNING! DO NOT EDIT apr.h + * + * You must modify apr.hwc instead. + * + * And please, make an effort to stub apr.hnw and apr.h.in in the process. + * + * This is the Win32 specific version of apr.h. It is copied from + * apr.hw by the apr.dsp and libapr.dsp projects. + */ + +/** + * @file apr.h + * @brief APR Platform Definitions + * @remark This is a generated header generated from include/apr.h.in by + * ./configure, or copied from include/apr.hw or include/apr.hnw + * for Win32 or Netware by those build environments, respectively. + */ + +/* Make sure we have our platform identifier macro defined we ask for later. + */ +#if defined(_WIN32) && !defined(WIN32) +#define WIN32 1 +#endif + +/* Ignore most warnings (back down to /W3) for poorly constructed headers, + * excluded from doxygen parsing + */ +#if defined(_MSC_VER) && _MSC_VER >= 1200 +#pragma warning(push, 3) +#endif + +/* disable or reduce the frequency of... + * C4057: indirection to slightly different base types + * C4075: slight indirection changes (unsigned short* vs short[]) + * C4100: unreferenced formal parameter + * C4127: conditional expression is constant + * C4163: '_rotl64' : not available as an intrinsic function + * C4201: nonstandard extension nameless struct/unions + * C4244: int to char/short - precision loss + * C4514: unreferenced inline function removed + */ +#if defined(_MSC_VER) +#pragma warning(disable: 4100 4127 4163 4201 4514; once: 4057 4075 4244) +#endif + +/* Ignore Microsoft's interpretation of secure development + * and the POSIX string handling API + */ +#if defined(_MSC_VER) && _MSC_VER >= 1400 +#ifndef _CRT_SECURE_NO_DEPRECATE +#define _CRT_SECURE_NO_DEPRECATE +#endif +#pragma warning(disable: 4996) +#endif + +/** + * @file apr.h + * @brief APR Platform Definitions + * @remark This is a generated header generated from include/apr.h.in by + * ./configure, or copied from include/apr.hw or include/apr.hnw + * for Win32 or Netware by those build environments, respectively. + */ + +/** + * @defgroup APR Apache Portability Runtime library + * @{ + */ +/** + * @defgroup apr_platform Platform Definitions + * @{ + * @warning + * <strong><em>The actual values of macros and typedefs on this page<br> + * are platform specific and should NOT be relied upon!</em></strong> + */ + +/* So that we can use inline on some critical functions, and use + * GNUC attributes (such as to get -Wall warnings for printf-like + * functions). Only do this in gcc 2.7 or later ... it may work + * on earlier stuff, but why chance it. + * + * We've since discovered that the gcc shipped with NeXT systems + * as "cc" is completely broken. It claims to be __GNUC__ and so + * on, but it doesn't implement half of the things that __GNUC__ + * means. In particular it's missing inline and the __attribute__ + * stuff. So we hack around it. PR#1613. -djg + */ +#if defined(_MSC_VER) +#define APR_INLINE __inline +#define APR_HAS_INLINE 1 +#ifndef __attribute__ +#define __attribute__(__x) +#endif +#elif !defined(__GNUC__) || __GNUC__ < 2 || \ + (__GNUC__ == 2 && __GNUC_MINOR__ < 7) ||\ + defined(NEXT) +#ifndef __attribute__ +#define __attribute__(__x) +#endif +#define APR_INLINE +#define APR_HAS_INLINE 0 +#else +#define APR_INLINE __inline__ +#define APR_HAS_INLINE 1 +#endif + +#ifdef _WIN32_WCE +#define APR_NOT_IN_WCE 0 +#else +#define APR_NOT_IN_WCE 1 +#endif + +#define APR_HAVE_ARPA_INET_H 0 +#define APR_HAVE_CONIO_H APR_NOT_IN_WCE +#define APR_HAVE_CRYPT_H 0 +#define APR_HAVE_CTYPE_H APR_NOT_IN_WCE +#define APR_HAVE_DIRENT_H 0 +#define APR_HAVE_ERRNO_H APR_NOT_IN_WCE +#define APR_HAVE_FCNTL_H APR_NOT_IN_WCE +#define APR_HAVE_IFADDRS_H 0 +#define APR_HAVE_IO_H APR_NOT_IN_WCE +#define APR_HAVE_LIMITS_H APR_NOT_IN_WCE +#define APR_HAVE_MSWSOCK_H APR_NOT_IN_WCE +#define APR_HAVE_NETDB_H 0 +#define APR_HAVE_NETINET_IN_H 0 +#define APR_HAVE_NETINET_SCTP_H 0 +#define APR_HAVE_NETINET_SCTP_UIO_H 0 +#define APR_HAVE_NETINET_TCP_H 0 +#define APR_HAVE_PROCESS_H 1 +#define APR_HAVE_PTHREAD_H 0 +#define APR_HAVE_SEMAPHORE_H 0 +#define APR_HAVE_SIGNAL_H APR_NOT_IN_WCE +#define APR_HAVE_STDARG_H APR_NOT_IN_WCE +#define APR_HAVE_STDDEF_H APR_NOT_IN_WCE +#define APR_HAVE_STDINT_H 0 +#define APR_HAVE_STDIO_H 1 +#define APR_HAVE_STDLIB_H 1 +#define APR_HAVE_STRING_H 1 +#define APR_HAVE_STRINGS_H 0 +#define APR_HAVE_SYS_IOCTL_H 0 +#define APR_HAVE_SYS_SENDFILE_H 0 +#define APR_HAVE_SYS_SIGNAL_H 0 +#define APR_HAVE_SYS_SOCKET_H 0 +#define APR_HAVE_SYS_SOCKIO_H 0 +#define APR_HAVE_SYS_SYSLIMITS_H 0 +#define APR_HAVE_SYS_TIME_H 0 +#define APR_HAVE_SYS_TYPES_H APR_NOT_IN_WCE +#define APR_HAVE_SYS_UIO_H 0 +#define APR_HAVE_SYS_UN_H 0 +#define APR_HAVE_SYS_WAIT_H 0 +#define APR_HAVE_TIME_H APR_NOT_IN_WCE +#define APR_HAVE_UNISTD_H 0 +#define APR_HAVE_WINDOWS_H 1 +#define APR_HAVE_WINSOCK2_H APR_NOT_IN_WCE +#define APR_HAVE_WS2TCPIP_H APR_NOT_IN_WCE + +/** @} */ +/** @} */ + +/* We don't include our conditional headers within the doxyblocks + * or the extern "C" namespace + */ + +/* If windows.h was already included, our preferences don't matter. + * If not, include a restricted set of windows headers to our tastes. + */ +#if APR_HAVE_WINDOWS_H +#ifndef _WINDOWS_ + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif + +#ifndef _WIN32_WINNT +#define _WIN32_WINNT @win32_winnt_str@ +#endif + +#ifndef NOUSER +#define NOUSER +#endif +#ifndef NOMCX +#define NOMCX +#endif +#ifndef NOIME +#define NOIME +#endif + +/* Impossible to include winsock2.h after winsock.h, while windows.h + * attempts to load winsock. Setting _WINSOCKAPI_ will dodge this. + */ +#if APR_HAVE_WINSOCK2_H +#define _WINSOCKAPI_ +#endif + +#include <windows.h> +#endif +#endif + +#if APR_HAVE_WINSOCK2_H +#include <winsock2.h> + +#if APR_HAVE_WS2TCPIP_H +#include <ws2tcpip.h> +#endif + +#if APR_HAVE_MSWSOCK_H +#include <mswsock.h> +#endif + +#else /* !APR_HAVE_WINSOCK2_H */ + +#if APR_HAVE_WINSOCK_H +#include <winsock.h> +#endif + +#endif /* !APR_HAVE_WINSOCK2_H */ + +#if APR_HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif + +#if APR_HAVE_STDDEF_H +#include <stddef.h> +#endif + +#if APR_HAVE_SYS_SOCKET_H +#include <sys/socket.h> +#endif + +#if APR_HAVE_STDINT_H +#include <stdint.h> +#endif + +#if APR_HAVE_SYS_WAIT_H +#include <sys/wait.h> +#endif + +/* header files for PATH_MAX, _POSIX_PATH_MAX */ +#if APR_HAVE_LIMITS_H +#include <limits.h> +#else +#if APR_HAVE_SYS_SYSLIMITS_H +#include <sys/syslimits.h> +#endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @addtogroup apr_platform + * @ingroup APR + * @{ + */ + +#define APR_HAVE_SHMEM_MMAP_TMP 0 +#define APR_HAVE_SHMEM_MMAP_SHM 0 +#define APR_HAVE_SHMEM_MMAP_ZERO 0 +#define APR_HAVE_SHMEM_SHMGET_ANON 0 +#define APR_HAVE_SHMEM_SHMGET 0 +#define APR_HAVE_SHMEM_MMAP_ANON 0 +#define APR_HAVE_SHMEM_BEOS 0 + +#define APR_USE_SHMEM_MMAP_TMP 0 +#define APR_USE_SHMEM_MMAP_SHM 0 +#define APR_USE_SHMEM_MMAP_ZERO 0 +#define APR_USE_SHMEM_SHMGET_ANON 0 +#define APR_USE_SHMEM_SHMGET 0 +#define APR_USE_SHMEM_MMAP_ANON 0 +#define APR_USE_SHMEM_BEOS 0 + +#define APR_USE_FLOCK_SERIALIZE 0 +#define APR_USE_SYSVSEM_SERIALIZE 0 +#define APR_USE_POSIXSEM_SERIALIZE 0 +#define APR_USE_FCNTL_SERIALIZE 0 +#define APR_USE_PROC_PTHREAD_SERIALIZE 0 +#define APR_USE_PTHREAD_SERIALIZE 0 + +#define APR_HAS_FLOCK_SERIALIZE 0 +#define APR_HAS_SYSVSEM_SERIALIZE 0 +#define APR_HAS_POSIXSEM_SERIALIZE 0 +#define APR_HAS_FCNTL_SERIALIZE 0 +#define APR_HAS_PROC_PTHREAD_SERIALIZE 0 + +#define APR_PROCESS_LOCK_IS_GLOBAL 0 + +#define APR_HAVE_CORKABLE_TCP 0 +#define APR_HAVE_GETRLIMIT 0 +#define APR_HAVE_ICONV 0 +#define APR_HAVE_IN_ADDR 1 +#define APR_HAVE_INET_ADDR 1 +#define APR_HAVE_INET_NETWORK 0 +#define APR_HAVE_IPV6 @apr_have_ipv6_10@ +#define APR_HAVE_SOCKADDR_UN 0 +#define APR_HAVE_MEMMOVE 1 +#define APR_HAVE_SETRLIMIT 0 +#define APR_HAVE_SIGACTION 0 +#define APR_HAVE_SIGSUSPEND 0 +#define APR_HAVE_SIGWAIT 0 +#define APR_HAVE_SA_STORAGE 0 +#define APR_HAVE_STRCASECMP 0 +#define APR_HAVE_STRDUP 1 +#define APR_HAVE_STRICMP APR_NOT_IN_WCE +#define APR_HAVE_STRNCASECMP 0 +#define APR_HAVE_STRNICMP APR_NOT_IN_WCE +#define APR_HAVE_STRSTR 1 +#define APR_HAVE_MEMCHR 1 +#define APR_HAVE_STRUCT_RLIMIT 0 +#define APR_HAVE_UNION_SEMUN 0 +#define APR_HAVE_SCTP 0 +#define APR_HAVE_IOVEC 0 + +/* APR Feature Macros */ +#define APR_HAS_SHARED_MEMORY 1 +#define APR_HAS_THREADS 1 +#define APR_HAS_SENDFILE APR_NOT_IN_WCE +#define APR_HAS_MMAP 1 +#define APR_HAS_FORK 0 +#define APR_HAS_RANDOM 1 +#define APR_HAS_OTHER_CHILD 1 +#define APR_HAS_DSO 1 +#define APR_HAS_SO_ACCEPTFILTER 0 +#define APR_HAS_UNICODE_FS 1 +#define APR_HAS_PROC_INVOKED 1 +#define APR_HAS_USER APR_NOT_IN_WCE +#define APR_HAS_LARGE_FILES APR_NOT_IN_WCE +#define APR_HAS_XTHREAD_FILES APR_NOT_IN_WCE +#define APR_HAS_OS_UUID 1 + +#define APR_PROCATTR_USER_SET_REQUIRES_PASSWORD APR_NOT_IN_WCE + +/* APR sets APR_FILES_AS_SOCKETS to 1 on systems where it is possible + * to poll on files/pipes. + */ +#define APR_FILES_AS_SOCKETS 0 + +/* This macro indicates whether or not EBCDIC is the native character set. + */ +#define APR_CHARSET_EBCDIC 0 + +/* If we have a TCP implementation that can be "corked", what flag + * do we use? + */ +#define APR_TCP_NOPUSH_FLAG 0 + +/* Is the TCP_NODELAY socket option inherited from listening sockets? + */ +#define APR_TCP_NODELAY_INHERITED 1 + +/* Is the O_NONBLOCK flag inherited from listening sockets? + */ +#define APR_O_NONBLOCK_INHERITED 1 + +/* Typedefs that APR needs. */ + +typedef unsigned char apr_byte_t; + +typedef short apr_int16_t; +typedef unsigned short apr_uint16_t; + +typedef int apr_int32_t; +typedef unsigned int apr_uint32_t; + +typedef __int64 apr_int64_t; +typedef unsigned __int64 apr_uint64_t; + +typedef size_t apr_size_t; +#if APR_HAVE_STDDEF_H +typedef ptrdiff_t apr_ssize_t; +#else +typedef int apr_ssize_t; +#endif + +#if APR_HAS_LARGE_FILES +typedef __int64 apr_off_t; +#else +typedef long apr_off_t; +#endif +typedef int apr_socklen_t; +typedef apr_uint64_t apr_ino_t; + +#ifdef _WIN64 +#define APR_SIZEOF_VOIDP 8 +#else +#define APR_SIZEOF_VOIDP 4 +#endif + +#if APR_SIZEOF_VOIDP == 8 +typedef apr_uint64_t apr_uintptr_t; +typedef apr_int64_t apr_intptr_t; +#else +typedef apr_uint32_t apr_uintptr_t; +typedef apr_int32_t apr_intptr_t; +#endif + +/* Are we big endian? */ +/* XXX: Fatal assumption on Alpha platforms */ +#define APR_IS_BIGENDIAN 0 + +/* Mechanisms to properly type numeric literals */ + +#ifndef __GNUC__ +#define APR_INT64_C(val) (val##i64) +#define APR_UINT64_C(val) (val##Ui64) +#else +#define APR_INT64_C(val) (val##LL) +#define APR_UINT64_C(val) (val##ULL) +#endif + +#ifdef INT16_MIN +#define APR_INT16_MIN INT16_MIN +#else +#define APR_INT16_MIN (-0x7fff - 1) +#endif + +#ifdef INT16_MAX +#define APR_INT16_MAX INT16_MAX +#else +#define APR_INT16_MAX (0x7fff) +#endif + +#ifdef UINT16_MAX +#define APR_UINT16_MAX UINT16_MAX +#else +#define APR_UINT16_MAX (0xffff) +#endif + +#ifdef INT32_MIN +#define APR_INT32_MIN INT32_MIN +#else +#define APR_INT32_MIN (-0x7fffffff - 1) +#endif + +#ifdef INT32_MAX +#define APR_INT32_MAX INT32_MAX +#else +#define APR_INT32_MAX 0x7fffffff +#endif + +#ifdef UINT32_MAX +#define APR_UINT32_MAX UINT32_MAX +#else +#define APR_UINT32_MAX (0xffffffffU) +#endif + +#ifdef INT64_MIN +#define APR_INT64_MIN INT64_MIN +#else +#define APR_INT64_MIN (APR_INT64_C(-0x7fffffffffffffff) - 1) +#endif + +#ifdef INT64_MAX +#define APR_INT64_MAX INT64_MAX +#else +#define APR_INT64_MAX APR_INT64_C(0x7fffffffffffffff) +#endif + +#ifdef UINT64_MAX +#define APR_UINT64_MAX UINT64_MAX +#else +#define APR_UINT64_MAX APR_UINT64_C(0xffffffffffffffff) +#endif + +#define APR_SIZE_MAX (~((apr_size_t)0)) + +/* Definitions that APR programs need to work properly. */ + +/** + * APR public API wrap for C++ compilers. + */ +#ifdef __cplusplus +#define APR_BEGIN_DECLS extern "C" { +#define APR_END_DECLS } +#else +#define APR_BEGIN_DECLS +#define APR_END_DECLS +#endif + +/** + * Thread callbacks from APR functions must be declared with APR_THREAD_FUNC, + * so that they follow the platform's calling convention. + * <PRE> + * + * void* APR_THREAD_FUNC my_thread_entry_fn(apr_thread_t *thd, void *data); + * + * </PRE> + */ +#define APR_THREAD_FUNC __stdcall + + +#if defined(DOXYGEN) || !defined(WIN32) + +/** + * The public APR functions are declared with APR_DECLARE(), so they may + * use the most appropriate calling convention. Public APR functions with + * variable arguments must use APR_DECLARE_NONSTD(). + * + * @remark Both the declaration and implementations must use the same macro. + * + * <PRE> + * APR_DECLARE(rettype) apr_func(args) + * </PRE> + * @see APR_DECLARE_NONSTD @see APR_DECLARE_DATA + * @remark Note that when APR compiles the library itself, it passes the + * symbol -DAPR_DECLARE_EXPORT to the compiler on some platforms (e.g. Win32) + * to export public symbols from the dynamic library build.\n + * The user must define the APR_DECLARE_STATIC when compiling to target + * the static APR library on some platforms (e.g. Win32.) The public symbols + * are neither exported nor imported when APR_DECLARE_STATIC is defined.\n + * By default, compiling an application and including the APR public + * headers, without defining APR_DECLARE_STATIC, will prepare the code to be + * linked to the dynamic library. + */ +#define APR_DECLARE(type) type + +/** + * The public APR functions using variable arguments are declared with + * APR_DECLARE_NONSTD(), as they must follow the C language calling convention. + * @see APR_DECLARE @see APR_DECLARE_DATA + * @remark Both the declaration and implementations must use the same macro. + * <PRE> + * + * APR_DECLARE_NONSTD(rettype) apr_func(args, ...); + * + * </PRE> + */ +#define APR_DECLARE_NONSTD(type) type + +/** + * The public APR variables are declared with APR_DECLARE_DATA. + * This assures the appropriate indirection is invoked at compile time. + * @see APR_DECLARE @see APR_DECLARE_NONSTD + * @remark Note that the declaration and implementations use different forms, + * but both must include the macro. + * + * <PRE> + * + * extern APR_DECLARE_DATA type apr_variable;\n + * APR_DECLARE_DATA type apr_variable = value; + * + * </PRE> + */ +#define APR_DECLARE_DATA + +#elif defined(APR_DECLARE_STATIC) +#define APR_DECLARE(type) type __stdcall +#define APR_DECLARE_NONSTD(type) type __cdecl +#define APR_DECLARE_DATA +#elif defined(APR_DECLARE_EXPORT) +#define APR_DECLARE(type) __declspec(dllexport) type __stdcall +#define APR_DECLARE_NONSTD(type) __declspec(dllexport) type __cdecl +#define APR_DECLARE_DATA __declspec(dllexport) +#else +#define APR_DECLARE(type) __declspec(dllimport) type __stdcall +#define APR_DECLARE_NONSTD(type) __declspec(dllimport) type __cdecl +#define APR_DECLARE_DATA __declspec(dllimport) +#endif + +#if !defined(WIN32) || defined(APU_MODULE_DECLARE_STATIC) +/** + * Declare a dso module's exported module structure as APR_MODULE_DECLARE_DATA. + * + * Unless APR_MODULE_DECLARE_STATIC is defined at compile time, symbols + * declared with APR_MODULE_DECLARE_DATA are always exported. + * @code + * module APR_MODULE_DECLARE_DATA mod_tag + * @endcode + */ +#define APR_MODULE_DECLARE_DATA +#else +#define APR_MODULE_DECLARE_DATA __declspec(dllexport) +#endif + +/** + * @deprecated + * @see APR_MODULE_DECLARE_DATA + */ +#define APU_MODULE_DECLARE_DATA APR_MODULE_DECLARE_DATA + +/* Define APR_SSIZE_T_FMT. + * If ssize_t is an integer we define it to be "d", + * if ssize_t is a long int we define it to be "ld", + * if ssize_t is 64-bit, we define it to be msvc specific "I64d" + */ +#ifdef _WIN64 +#define APR_SSIZE_T_FMT "I64d" +#define APR_SIZE_T_FMT "I64u" +#else +#define APR_SSIZE_T_FMT "d" +#define APR_SIZE_T_FMT "u" +#endif + +#if APR_HAS_LARGE_FILES +#define APR_OFF_T_FMT "I64d" +#else +#define APR_OFF_T_FMT "d" +#endif + +#define APR_PID_T_FMT "d" + +#define APR_INT64_T_FMT "I64d" +#define APR_UINT64_T_FMT "I64u" +#define APR_UINT64_T_HEX_FMT "I64x" + +/* No difference between PROC and GLOBAL mutex */ +#define APR_PROC_MUTEX_IS_GLOBAL 1 + +/* Local machine definition for console and log output. */ +#define APR_EOL_STR "\r\n" + +typedef int apr_wait_t; + +#if APR_HAS_UNICODE_FS +/* An arbitrary size that is digestable. True max is a bit less than 32000 */ +#define APR_PATH_MAX 8192 +#else /* !APR_HAS_UNICODE_FS */ +#define APR_PATH_MAX MAX_PATH +#endif + +#define APR_DSOPATH "PATH" + +/* + * we always have SDBM (it's in our codebase) + */ +#define APU_HAVE_SDBM 1 + +#ifndef APU_DSO_MODULE_BUILD +#define APU_HAVE_GDBM 0 +#define APU_HAVE_NDBM 0 +#define APU_HAVE_DB 0 + +#if APU_HAVE_DB +#define APU_HAVE_DB_VERSION 0 +#endif +#endif + +/* + * Windows: Only dynamic driver loads within apr_dbd + * are supported. The driver builds enable + * these flags individually. + */ +#ifndef APU_DSO_MODULE_BUILD +#define APU_HAVE_PGSQL 0 +#define APU_HAVE_MYSQL 0 +#define APU_HAVE_SQLITE3 0 +#define APU_HAVE_SQLITE2 0 +#define APU_HAVE_ORACLE 0 +#define APU_HAVE_ODBC 0 +#endif + +#define APU_HAVE_CRYPTO @apu_have_crypto_10@ + +#ifndef APU_DSO_MODULE_BUILD +#define APU_HAVE_OPENSSL 0 +#define APU_HAVE_NSS 0 +#define APU_HAVE_COMMONCRYPTO 0 +#endif + +#define APU_HAVE_ICONV 0 +#define APR_HAS_XLATE (APU_HAVE_ICONV) + +#define APU_USE_EXPAT @apu_use_expat_10@ +#define APU_USE_LIBXML2 @apu_use_libxml2_10@ + +/** @} */ + +/* Definitions that only Win32 programs need to compile properly. */ + +/* XXX These simply don't belong here, perhaps in apr_portable.h + * based on some APR_HAVE_PID/GID/UID? + */ +#ifdef WIN32 +#ifndef __WATCOMC__ +#ifndef __GNUC__ +typedef int pid_t; +#endif +typedef int uid_t; +typedef int gid_t; +#endif +#endif + +/* Typically defined in stdio.h or unistd.h + */ +#ifndef STDIN_FILENO +#define STDIN_FILENO 0 +#endif +#ifndef STDOUT_FILENO +#define STDOUT_FILENO 1 +#endif +#ifndef STDERR_FILENO +#define STDERR_FILENO 2 +#endif + +#if APR_HAVE_IPV6 + +/* Appears in later flavors, not the originals. */ +#ifndef in_addr6 +#define in6_addr in_addr6 +#endif + +#ifndef WS2TCPIP_INLINE +#define IN6_IS_ADDR_V4MAPPED(a) \ + ( (*(const apr_uint64_t *)(const void *)(&(a)->s6_addr[0]) == 0) \ + && (*(const apr_uint32_t *)(const void *)(&(a)->s6_addr[8]) == ntohl(0x0000ffff))) +#endif + +#endif /* APR_HAVE_IPV6 */ + +#ifdef __cplusplus +} +#endif + +/* Done with badly written headers, leave 'deprecated CRT' undeprecated + */ +#if defined(_MSC_VER) && _MSC_VER >= 1200 +#pragma warning(pop) +#if _MSC_VER >= 1400 +#pragma warning(disable: 4996) +#endif +#endif + +#endif /* APR_H */ diff --git a/include/apr_allocator.h b/include/apr_allocator.h new file mode 100644 index 00000000000..4d9d7622066 --- /dev/null +++ b/include/apr_allocator.h @@ -0,0 +1,194 @@ +/* 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. + */ + +#ifndef APR_ALLOCATOR_H +#define APR_ALLOCATOR_H + +/** + * @file apr_allocator.h + * @brief APR Internal Memory Allocation + */ + +#include "apr.h" +#include "apr_errno.h" +#define APR_WANT_MEMFUNC /**< For no good reason? */ +#include "apr_want.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup apr_allocator Internal Memory Allocation + * @ingroup APR + * @{ + */ + +/** the allocator structure */ +typedef struct apr_allocator_t apr_allocator_t; +/** the structure which holds information about the allocation */ +typedef struct apr_memnode_t apr_memnode_t; + +/** basic memory node structure + * @note The next, ref and first_avail fields are available for use by the + * caller of apr_allocator_alloc(), the remaining fields are read-only. + * The next field has to be used with caution and sensibly set when the + * memnode is passed back to apr_allocator_free(). See apr_allocator_free() + * for details. + * The ref and first_avail fields will be properly restored by + * apr_allocator_free(). + */ +struct apr_memnode_t { + apr_memnode_t *next; /**< next memnode */ + apr_memnode_t **ref; /**< reference to self */ + apr_uint32_t index; /**< size */ + apr_uint32_t free_index; /**< how much free */ + char *first_avail; /**< pointer to first free memory */ + char *endp; /**< pointer to end of free memory */ +}; + +/** The base size of a memory node - aligned. */ +#define APR_MEMNODE_T_SIZE APR_ALIGN_DEFAULT(sizeof(apr_memnode_t)) + +/** Symbolic constants */ +#define APR_ALLOCATOR_MAX_FREE_UNLIMITED 0 + +/** + * Create a new allocator + * @param allocator The allocator we have just created. + * + */ +APR_DECLARE(apr_status_t) apr_allocator_create(apr_allocator_t **allocator) + __attribute__((nonnull(1))); + +/** + * Destroy an allocator + * @param allocator The allocator to be destroyed + * @remark Any memnodes not given back to the allocator prior to destroying + * will _not_ be free()d. + */ +APR_DECLARE(void) apr_allocator_destroy(apr_allocator_t *allocator) + __attribute__((nonnull(1))); + +/** + * Allocate a block of mem from the allocator + * @param allocator The allocator to allocate from + * @param size The size of the mem to allocate (excluding the + * memnode structure) + */ +APR_DECLARE(apr_memnode_t *) apr_allocator_alloc(apr_allocator_t *allocator, + apr_size_t size) + __attribute__((nonnull(1))); + +/** + * Free a list of blocks of mem, giving them back to the allocator. + * The list is typically terminated by a memnode with its next field + * set to NULL. + * @param allocator The allocator to give the mem back to + * @param memnode The memory node to return + */ +APR_DECLARE(void) apr_allocator_free(apr_allocator_t *allocator, + apr_memnode_t *memnode) + __attribute__((nonnull(1,2))); + +/** + * Get the page/boundary size. + * @return The page size + */ +APR_DECLARE(apr_size_t) apr_allocator_page_size(void); + +/** + * Setup the minimum allocation order (in 2^order pages). + * @param order The order to set + * @return APR_SUCCESS, or APR_EINVAL if @a order above 9. + * @note Default is order-1 (e.g. 8K on systems with 4K pages). + * @remark Should be done at initialization time, never concurrently. + */ +APR_DECLARE(apr_status_t) apr_allocator_min_order_set(unsigned int order); + +/** + * Get the true size that would be allocated for the given size (including + * the header and alignment). + * @param list The allocator from which to the memory would be allocated + * @param size The size to align + * @return The aligned size (or zero on apr_size_t overflow) + */ +APR_DECLARE(apr_size_t) apr_allocator_align(apr_allocator_t *allocator, + apr_size_t size); + +#include "apr_pools.h" + +/** + * Set the owner of the allocator + * @param allocator The allocator to set the owner for + * @param pool The pool that is to own the allocator + * @remark Typically pool is the highest level pool using the allocator + */ +/* + * XXX: see if we can come up with something a bit better. Currently + * you can make a pool an owner, but if the pool doesn't use the allocator + * the allocator will never be destroyed. + */ +APR_DECLARE(void) apr_allocator_owner_set(apr_allocator_t *allocator, + apr_pool_t *pool) + __attribute__((nonnull(1))); + +/** + * Get the current owner of the allocator + * @param allocator The allocator to get the owner from + */ +APR_DECLARE(apr_pool_t *) apr_allocator_owner_get(apr_allocator_t *allocator) + __attribute__((nonnull(1))); + +/** + * Set the current threshold at which the allocator should start + * giving blocks back to the system. + * @param allocator The allocator to set the threshold on + * @param size The threshold. 0 == unlimited. + */ +APR_DECLARE(void) apr_allocator_max_free_set(apr_allocator_t *allocator, + apr_size_t size) + __attribute__((nonnull(1))); + +#include "apr_thread_mutex.h" + +#if APR_HAS_THREADS +/** + * Set a mutex for the allocator to use + * @param allocator The allocator to set the mutex for + * @param mutex The mutex + */ +APR_DECLARE(void) apr_allocator_mutex_set(apr_allocator_t *allocator, + apr_thread_mutex_t *mutex) + __attribute__((nonnull(1))); + +/** + * Get the mutex currently set for the allocator + * @param allocator The allocator + */ +APR_DECLARE(apr_thread_mutex_t *) apr_allocator_mutex_get( + apr_allocator_t *allocator) + __attribute__((nonnull(1))); + +#endif /* APR_HAS_THREADS */ + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* !APR_ALLOCATOR_H */ diff --git a/include/apr_anylock.h b/include/apr_anylock.h new file mode 100644 index 00000000000..51e97ff3733 --- /dev/null +++ b/include/apr_anylock.h @@ -0,0 +1,128 @@ +/* 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. + */ + +/** + * @file apr_anylock.h + * @brief APR-Util transparent any lock flavor wrapper + */ +#ifndef APR_ANYLOCK_H +#define APR_ANYLOCK_H + +#include "apr_proc_mutex.h" +#include "apr_thread_mutex.h" +#include "apr_thread_rwlock.h" + +/** Structure that may contain any APR lock type */ +typedef struct apr_anylock_t { + /** Indicates what type of lock is in lock */ + enum tm_lock { + apr_anylock_none, /**< None */ + apr_anylock_procmutex, /**< Process-based */ + apr_anylock_threadmutex, /**< Thread-based */ + apr_anylock_readlock, /**< Read lock */ + apr_anylock_writelock /**< Write lock */ + } type; + /** Union of all possible APR locks */ + union apr_anylock_u_t { + apr_proc_mutex_t *pm; /**< Process mutex */ +#if APR_HAS_THREADS + apr_thread_mutex_t *tm; /**< Thread mutex */ + apr_thread_rwlock_t *rw; /**< Read-write lock */ +#endif + } lock; +} apr_anylock_t; + +#if APR_HAS_THREADS + +/** Lock an apr_anylock_t structure */ +#define APR_ANYLOCK_LOCK(lck) \ + (((lck)->type == apr_anylock_none) \ + ? APR_SUCCESS \ + : (((lck)->type == apr_anylock_threadmutex) \ + ? apr_thread_mutex_lock((lck)->lock.tm) \ + : (((lck)->type == apr_anylock_procmutex) \ + ? apr_proc_mutex_lock((lck)->lock.pm) \ + : (((lck)->type == apr_anylock_readlock) \ + ? apr_thread_rwlock_rdlock((lck)->lock.rw) \ + : (((lck)->type == apr_anylock_writelock) \ + ? apr_thread_rwlock_wrlock((lck)->lock.rw) \ + : APR_EINVAL))))) + +#else /* APR_HAS_THREADS */ + +#define APR_ANYLOCK_LOCK(lck) \ + (((lck)->type == apr_anylock_none) \ + ? APR_SUCCESS \ + : (((lck)->type == apr_anylock_procmutex) \ + ? apr_proc_mutex_lock((lck)->lock.pm) \ + : APR_EINVAL)) + +#endif /* APR_HAS_THREADS */ + +#if APR_HAS_THREADS + +/** Try to lock an apr_anylock_t structure */ +#define APR_ANYLOCK_TRYLOCK(lck) \ + (((lck)->type == apr_anylock_none) \ + ? APR_SUCCESS \ + : (((lck)->type == apr_anylock_threadmutex) \ + ? apr_thread_mutex_trylock((lck)->lock.tm) \ + : (((lck)->type == apr_anylock_procmutex) \ + ? apr_proc_mutex_trylock((lck)->lock.pm) \ + : (((lck)->type == apr_anylock_readlock) \ + ? apr_thread_rwlock_tryrdlock((lck)->lock.rw) \ + : (((lck)->type == apr_anylock_writelock) \ + ? apr_thread_rwlock_trywrlock((lck)->lock.rw) \ + : APR_EINVAL))))) + +#else /* APR_HAS_THREADS */ + +#define APR_ANYLOCK_TRYLOCK(lck) \ + (((lck)->type == apr_anylock_none) \ + ? APR_SUCCESS \ + : (((lck)->type == apr_anylock_procmutex) \ + ? apr_proc_mutex_trylock((lck)->lock.pm) \ + : APR_EINVAL)) + +#endif /* APR_HAS_THREADS */ + +#if APR_HAS_THREADS + +/** Unlock an apr_anylock_t structure */ +#define APR_ANYLOCK_UNLOCK(lck) \ + (((lck)->type == apr_anylock_none) \ + ? APR_SUCCESS \ + : (((lck)->type == apr_anylock_threadmutex) \ + ? apr_thread_mutex_unlock((lck)->lock.tm) \ + : (((lck)->type == apr_anylock_procmutex) \ + ? apr_proc_mutex_unlock((lck)->lock.pm) \ + : ((((lck)->type == apr_anylock_readlock) || \ + ((lck)->type == apr_anylock_writelock)) \ + ? apr_thread_rwlock_unlock((lck)->lock.rw) \ + : APR_EINVAL)))) + +#else /* APR_HAS_THREADS */ + +#define APR_ANYLOCK_UNLOCK(lck) \ + (((lck)->type == apr_anylock_none) \ + ? APR_SUCCESS \ + : (((lck)->type == apr_anylock_procmutex) \ + ? apr_proc_mutex_unlock((lck)->lock.pm) \ + : APR_EINVAL)) + +#endif /* APR_HAS_THREADS */ + +#endif /* !APR_ANYLOCK_H */ diff --git a/include/apr_atomic.h b/include/apr_atomic.h new file mode 100644 index 00000000000..f34fdd2bd2e --- /dev/null +++ b/include/apr_atomic.h @@ -0,0 +1,140 @@ +/* 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. + */ + +#ifndef APR_ATOMIC_H +#define APR_ATOMIC_H + +/** + * @file apr_atomic.h + * @brief APR Atomic Operations + */ + +#include "apr.h" +#include "apr_pools.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup apr_atomic Atomic Operations + * @ingroup APR + * @{ + */ + +/** + * this function is required on some platforms to initialize the + * atomic operation's internal structures + * @param p pool + * @return APR_SUCCESS on successful completion + * @remark Programs do NOT need to call this directly. APR will call this + * automatically from apr_initialize. + * @internal + */ +APR_DECLARE(apr_status_t) apr_atomic_init(apr_pool_t *p); + +/* + * Atomic operations on 32-bit values + * Note: Each of these functions internally implements a memory barrier + * on platforms that require it + */ + +/** + * atomically read an apr_uint32_t from memory + * @param mem the pointer + */ +APR_DECLARE(apr_uint32_t) apr_atomic_read32(volatile apr_uint32_t *mem); + +/** + * atomically set an apr_uint32_t in memory + * @param mem pointer to the object + * @param val value that the object will assume + */ +APR_DECLARE(void) apr_atomic_set32(volatile apr_uint32_t *mem, apr_uint32_t val); + +/** + * atomically add 'val' to an apr_uint32_t + * @param mem pointer to the object + * @param val amount to add + * @return old value pointed to by mem + */ +APR_DECLARE(apr_uint32_t) apr_atomic_add32(volatile apr_uint32_t *mem, apr_uint32_t val); + +/** + * atomically subtract 'val' from an apr_uint32_t + * @param mem pointer to the object + * @param val amount to subtract + */ +APR_DECLARE(void) apr_atomic_sub32(volatile apr_uint32_t *mem, apr_uint32_t val); + +/** + * atomically increment an apr_uint32_t by 1 + * @param mem pointer to the object + * @return old value pointed to by mem + */ +APR_DECLARE(apr_uint32_t) apr_atomic_inc32(volatile apr_uint32_t *mem); + +/** + * atomically decrement an apr_uint32_t by 1 + * @param mem pointer to the atomic value + * @return zero if the value becomes zero on decrement, otherwise non-zero + */ +APR_DECLARE(int) apr_atomic_dec32(volatile apr_uint32_t *mem); + +/** + * compare an apr_uint32_t's value with 'cmp'. + * If they are the same swap the value with 'with' + * @param mem pointer to the value + * @param with what to swap it with + * @param cmp the value to compare it to + * @return the old value of *mem + */ +APR_DECLARE(apr_uint32_t) apr_atomic_cas32(volatile apr_uint32_t *mem, apr_uint32_t with, + apr_uint32_t cmp); + +/** + * exchange an apr_uint32_t's value with 'val'. + * @param mem pointer to the value + * @param val what to swap it with + * @return the old value of *mem + */ +APR_DECLARE(apr_uint32_t) apr_atomic_xchg32(volatile apr_uint32_t *mem, apr_uint32_t val); + +/** + * compare the pointer's value with cmp. + * If they are the same swap the value with 'with' + * @param mem pointer to the pointer + * @param with what to swap it with + * @param cmp the value to compare it to + * @return the old value of the pointer + */ +APR_DECLARE(void*) apr_atomic_casptr(void *volatile *mem, void *with, const void *cmp); + +/** + * exchange a pair of pointer values + * @param mem pointer to the pointer + * @param with what to swap it with + * @return the old value of the pointer + */ +APR_DECLARE(void*) apr_atomic_xchgptr(void *volatile *mem, void *with); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* !APR_ATOMIC_H */ diff --git a/include/apr_base64.h b/include/apr_base64.h new file mode 100644 index 00000000000..406ca368eee --- /dev/null +++ b/include/apr_base64.h @@ -0,0 +1,146 @@ +/* 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 apr_vsnprintf/apr_snprintf functions are based on, and used with the + * permission of, the SIO stdio-replacement strx_* functions by Panos + * Tsirigotis <panos@alumni.cs.colorado.edu> for xinetd. + */ + +/** + * @file apr_base64.h + * @brief APR-UTIL Base64 Encoding + */ +#ifndef APR_BASE64_H +#define APR_BASE64_H + +#include "apu.h" +#include "apr_general.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup APR_Util_Base64 Base64 Encoding + * @ingroup APR + * @{ + */ + +/* Simple BASE64 encode/decode functions. + * + * As we might encode binary strings, hence we require the length of + * the incoming plain source. And return the length of what we decoded. + * + * The decoding function takes any non valid char (i.e. whitespace, \0 + * or anything non A-Z,0-9 etc) as terminal. + * + * The handling of terminating \0 characters differs from function to + * function. + * + */ + +/** + * Given the length of an un-encoded string, get the length of the + * encoded string. + * @param len the length of an unencoded string. + * @return the length of the string after it is encoded, including the + * trailing \0 + */ +APR_DECLARE(int) apr_base64_encode_len(int len) __attribute__((pure)); + +/** + * Encode a text string using base64encoding. On EBCDIC machines, the input + * is first converted to ASCII. + * @param coded_dst The destination string for the encoded string. A \0 is + * appended. + * @param plain_src The original string in plain text + * @param len_plain_src The length of the plain text string + * @return the length of the encoded string, including the trailing \0 + */ +APR_DECLARE(int) apr_base64_encode(char * coded_dst, const char *plain_src, + int len_plain_src) + __attribute__((nonnull(1,2))); + +/** + * Encode an text string using base64encoding. This is the same as + * apr_base64_encode() except on EBCDIC machines, where the conversion of the + * input to ASCII is left out. + * @param coded_dst The destination string for the encoded string. A \0 is + * appended. + * @param plain_src The original string in plain text + * @param len_plain_src The length of the plain text string + * @return the length of the encoded string, including the trailing \0 + */ +APR_DECLARE(int) apr_base64_encode_binary(char * coded_dst, + const unsigned char *plain_src, + int len_plain_src) + __attribute__((nonnull(1,2))); + +/** + * Encode a string into memory allocated from a pool in base 64 format + * @param p The pool to allocate from + * @param string The plaintext string + * @return The encoded string + */ +APR_DECLARE(char *) apr_pbase64_encode(apr_pool_t *p, const char *string) + __attribute__((nonnull(1,2))); + +/** + * Determine the maximum buffer length required to decode the plain text + * string given the encoded string. + * @param coded_src The encoded string + * @return the maximum required buffer length for the plain text string + */ +APR_DECLARE(int) apr_base64_decode_len(const char * coded_src) + __attribute__((nonnull(1))) __attribute__((pure)); + +/** + * Decode a string to plain text. On EBCDIC machines, the result is then + * converted to EBCDIC. + * @param plain_dst The destination string for the plain text. A \0 is + * appended. + * @param coded_src The encoded string + * @return the length of the plain text string (excluding the trailing \0) + */ +APR_DECLARE(int) apr_base64_decode(char * plain_dst, const char *coded_src) + __attribute__((nonnull(1,2))); + +/** + * Decode an string to plain text. This is the same as apr_base64_decode() + * except no \0 is appended and on EBCDIC machines, the conversion of the + * output to EBCDIC is left out. + * @param plain_dst The destination string for the plain text. The string is + * not \0-terminated. + * @param coded_src The encoded string + * @return the length of the plain text string + */ +APR_DECLARE(int) apr_base64_decode_binary(unsigned char * plain_dst, + const char *coded_src) + __attribute__((nonnull(1,2))); + +/** + * Decode a base64 encoded string into memory allocated from a pool + * @param p The pool to allocate from + * @param bufcoded The encoded string + * @return The decoded string + */ +APR_DECLARE(char *) apr_pbase64_decode(apr_pool_t *p, const char *bufcoded) + __attribute__((nonnull(1,2))); + +/** @} */ +#ifdef __cplusplus +} +#endif + +#endif /* !APR_BASE64_H */ diff --git a/include/apr_buckets.h b/include/apr_buckets.h new file mode 100644 index 00000000000..abecd16ef8a --- /dev/null +++ b/include/apr_buckets.h @@ -0,0 +1,1651 @@ +/* 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. + */ +/** + * @file apr_buckets.h + * @brief APR-UTIL Buckets/Bucket Brigades + */ + +#ifndef APR_BUCKETS_H +#define APR_BUCKETS_H + +#if defined(APR_BUCKET_DEBUG) && !defined(APR_RING_DEBUG) +#define APR_RING_DEBUG +#endif + +#include "apu.h" +#include "apr_network_io.h" +#include "apr_file_io.h" +#include "apr_general.h" +#include "apr_mmap.h" +#include "apr_errno.h" +#include "apr_ring.h" +#include "apr.h" +#if APR_HAVE_SYS_UIO_H +#include <sys/uio.h> /* for struct iovec */ +#endif +#if APR_HAVE_STDARG_H +#include <stdarg.h> +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup APR_Util_Bucket_Brigades Bucket Brigades + * @ingroup APR + * @{ + */ + +/** default bucket buffer size - 8KB minus room for memory allocator headers */ +#define APR_BUCKET_BUFF_SIZE 8000 + +/** Determines how a bucket or brigade should be read */ +typedef enum { + APR_BLOCK_READ, /**< block until data becomes available */ + APR_NONBLOCK_READ /**< return immediately if no data is available */ +} apr_read_type_e; + +/** + * The one-sentence buzzword-laden overview: Bucket brigades represent + * a complex data stream that can be passed through a layered IO + * system without unnecessary copying. A longer overview follows... + * + * A bucket brigade is a doubly linked list (ring) of buckets, so we + * aren't limited to inserting at the front and removing at the end. + * Buckets are only passed around as members of a brigade, although + * singleton buckets can occur for short periods of time. + * + * Buckets are data stores of various types. They can refer to data in + * memory, or part of a file or mmap area, or the output of a process, + * etc. Buckets also have some type-dependent accessor functions: + * read, split, copy, setaside, and destroy. + * + * read returns the address and size of the data in the bucket. If the + * data isn't in memory then it is read in and the bucket changes type + * so that it can refer to the new location of the data. If all the + * data doesn't fit in the bucket then a new bucket is inserted into + * the brigade to hold the rest of it. + * + * split divides the data in a bucket into two regions. After a split + * the original bucket refers to the first part of the data and a new + * bucket inserted into the brigade after the original bucket refers + * to the second part of the data. Reference counts are maintained as + * necessary. + * + * setaside ensures that the data in the bucket has a long enough + * lifetime. Sometimes it is convenient to create a bucket referring + * to data on the stack in the expectation that it will be consumed + * (output to the network) before the stack is unwound. If that + * expectation turns out not to be valid, the setaside function is + * called to move the data somewhere safer. + * + * copy makes a duplicate of the bucket structure as long as it's + * possible to have multiple references to a single copy of the + * data itself. Not all bucket types can be copied. + * + * destroy maintains the reference counts on the resources used by a + * bucket and frees them if necessary. + * + * Note: all of the above functions have wrapper macros (apr_bucket_read(), + * apr_bucket_destroy(), etc), and those macros should be used rather + * than using the function pointers directly. + * + * To write a bucket brigade, they are first made into an iovec, so that we + * don't write too little data at one time. Currently we ignore compacting the + * buckets into as few buckets as possible, but if we really want good + * performance, then we need to compact the buckets before we convert to an + * iovec, or possibly while we are converting to an iovec. + */ + +/* + * Forward declaration of the main types. + */ + +/** @see apr_bucket_brigade */ +typedef struct apr_bucket_brigade apr_bucket_brigade; +/** @see apr_bucket */ +typedef struct apr_bucket apr_bucket; +/** @see apr_bucket_alloc_t */ +typedef struct apr_bucket_alloc_t apr_bucket_alloc_t; + +/** @see apr_bucket_type_t */ +typedef struct apr_bucket_type_t apr_bucket_type_t; + +/** + * Basic bucket type + */ +struct apr_bucket_type_t { + /** + * The name of the bucket type + */ + const char *name; + /** + * The number of functions this bucket understands. Can not be less than + * five. + */ + int num_func; + /** + * Whether the bucket contains metadata (ie, information that + * describes the regular contents of the brigade). The metadata + * is not returned by apr_bucket_read() and is not indicated by + * the ->length of the apr_bucket itself. In other words, an + * empty bucket is safe to arbitrarily remove if and only if it + * contains no metadata. In this sense, "data" is just raw bytes + * that are the "content" of the brigade and "metadata" describes + * that data but is not a proper part of it. + */ + enum { + /** This bucket type represents actual data to send to the client. */ + APR_BUCKET_DATA = 0, + /** This bucket type represents metadata. */ + APR_BUCKET_METADATA = 1 + } is_metadata; + /** + * Free the private data and any resources used by the bucket (if they + * aren't shared with another bucket). This function is required to be + * implemented for all bucket types, though it might be a no-op on some + * of them (namely ones that never allocate any private data structures). + * @param data The private data pointer from the bucket to be destroyed + */ + void (*destroy)(void *data); + + /** + * Read the data from the bucket. This is required to be implemented + * for all bucket types. + * @param b The bucket to read from + * @param str A place to store the data read. Allocation should only be + * done if absolutely necessary. + * @param len The amount of data read. + * @param block Should this read function block if there is more data that + * cannot be read immediately. + */ + apr_status_t (*read)(apr_bucket *b, const char **str, apr_size_t *len, + apr_read_type_e block); + + /** + * Make it possible to set aside the data for at least as long as the + * given pool. Buckets containing data that could potentially die before + * this pool (e.g. the data resides on the stack, in a child pool of + * the given pool, or in a disjoint pool) must somehow copy, shift, or + * transform the data to have the proper lifetime. + * @param e The bucket to convert + * @remark Some bucket types contain data that will always outlive the + * bucket itself. For example no data (EOS and FLUSH), or the data + * resides in global, constant memory (IMMORTAL), or the data is on + * the heap (HEAP). For these buckets, apr_bucket_setaside_noop can + * be used. + */ + apr_status_t (*setaside)(apr_bucket *e, apr_pool_t *pool); + + /** + * Split one bucket in two at the specified position by duplicating + * the bucket structure (not the data) and modifying any necessary + * start/end/offset information. If it's not possible to do this + * for the bucket type (perhaps the length of the data is indeterminate, + * as with pipe and socket buckets), then APR_ENOTIMPL is returned. + * @param e The bucket to split + * @param point The offset of the first byte in the new bucket + */ + apr_status_t (*split)(apr_bucket *e, apr_size_t point); + + /** + * Copy the bucket structure (not the data), assuming that this is + * possible for the bucket type. If it's not, APR_ENOTIMPL is returned. + * @param e The bucket to copy + * @param c Returns a pointer to the new bucket + */ + apr_status_t (*copy)(apr_bucket *e, apr_bucket **c); + +}; + +/** + * apr_bucket structures are allocated on the malloc() heap and + * their lifetime is controlled by the parent apr_bucket_brigade + * structure. Buckets can move from one brigade to another e.g. by + * calling APR_BRIGADE_CONCAT(). In general the data in a bucket has + * the same lifetime as the bucket and is freed when the bucket is + * destroyed; if the data is shared by more than one bucket (e.g. + * after a split) the data is freed when the last bucket goes away. + */ +struct apr_bucket { + /** Links to the rest of the brigade */ + APR_RING_ENTRY(apr_bucket) link; + /** The type of bucket. */ + const apr_bucket_type_t *type; + /** The length of the data in the bucket. This could have been implemented + * with a function, but this is an optimization, because the most + * common thing to do will be to get the length. If the length is unknown, + * the value of this field will be (apr_size_t)(-1). + */ + apr_size_t length; + /** The start of the data in the bucket relative to the private base + * pointer. The vast majority of bucket types allow a fixed block of + * data to be referenced by multiple buckets, each bucket pointing to + * a different segment of the data. That segment starts at base+start + * and ends at base+start+length. + * If the length == (apr_size_t)(-1), then start == -1. + */ + apr_off_t start; + /** type-dependent data hangs off this pointer */ + void *data; + /** + * Pointer to function used to free the bucket. This function should + * always be defined and it should be consistent with the memory + * function used to allocate the bucket. For example, if malloc() is + * used to allocate the bucket, this pointer should point to free(). + * @param e Pointer to the bucket being freed + */ + void (*free)(void *e); + /** The freelist from which this bucket was allocated */ + apr_bucket_alloc_t *list; +}; + +/** A list of buckets */ +struct apr_bucket_brigade { + /** The pool to associate the brigade with. The data is not allocated out + * of the pool, but a cleanup is registered with this pool. If the + * brigade is destroyed by some mechanism other than pool destruction, + * the destroying function is responsible for killing the cleanup. + */ + apr_pool_t *p; + /** The buckets in the brigade are on this list. */ + /* + * The apr_bucket_list structure doesn't actually need a name tag + * because it has no existence independent of struct apr_bucket_brigade; + * the ring macros are designed so that you can leave the name tag + * argument empty in this situation but apparently the Windows compiler + * doesn't like that. + */ + APR_RING_HEAD(apr_bucket_list, apr_bucket) list; + /** The freelist from which this bucket was allocated */ + apr_bucket_alloc_t *bucket_alloc; +}; + + +/** + * Function called when a brigade should be flushed + */ +typedef apr_status_t (*apr_brigade_flush)(apr_bucket_brigade *bb, void *ctx); + +/* + * define APR_BUCKET_DEBUG if you want your brigades to be checked for + * validity at every possible instant. this will slow your code down + * substantially but is a very useful debugging tool. + */ +#ifdef APR_BUCKET_DEBUG + +#define APR_BRIGADE_CHECK_CONSISTENCY(b) do { \ + APR_RING_CHECK_CONSISTENCY(&(b)->list, apr_bucket, link); \ + assert(b->p != NULL); \ + assert(b->bucket_alloc != NULL); \ +} while (0) + +#define APR_BUCKET_CHECK_CONSISTENCY(e) \ + APR_RING_CHECK_ELEM_CONSISTENCY((e), apr_bucket, link) + +#else +/** + * checks the ring pointers in a bucket brigade for consistency. an + * abort() will be triggered if any inconsistencies are found. + * note: this is a no-op unless APR_BUCKET_DEBUG is defined. + * @param b The brigade + */ +#define APR_BRIGADE_CHECK_CONSISTENCY(b) +/** + * checks the brigade a bucket is in for ring consistency. an + * abort() will be triggered if any inconsistencies are found. + * note: this is a no-op unless APR_BUCKET_DEBUG is defined. + * @param e The bucket + */ +#define APR_BUCKET_CHECK_CONSISTENCY(e) +#endif + + +/** + * Wrappers around the RING macros to reduce the verbosity of the code + * that handles bucket brigades. + */ +/** + * The magic pointer value that indicates the head of the brigade + * @remark This is used to find the beginning and end of the brigade, eg: + * <pre> + * while (e != APR_BRIGADE_SENTINEL(b)) { + * ... + * e = APR_BUCKET_NEXT(e); + * } + * </pre> + * @param b The brigade + * @return The magic pointer value + */ +#define APR_BRIGADE_SENTINEL(b) APR_RING_SENTINEL(&(b)->list, apr_bucket, link) + +/** + * Determine if the bucket brigade is empty + * @param b The brigade to check + * @return true or false + */ +#define APR_BRIGADE_EMPTY(b) APR_RING_EMPTY(&(b)->list, apr_bucket, link) + +/** + * Return the first bucket in a brigade + * @param b The brigade to query + * @return The first bucket in the brigade + */ +#define APR_BRIGADE_FIRST(b) APR_RING_FIRST(&(b)->list) +/** + * Return the last bucket in a brigade + * @param b The brigade to query + * @return The last bucket in the brigade + */ +#define APR_BRIGADE_LAST(b) APR_RING_LAST(&(b)->list) + +/** + * Insert a single bucket at the front of a brigade + * @param b The brigade to add to + * @param e The bucket to insert + */ +#define APR_BRIGADE_INSERT_HEAD(b, e) do { \ + apr_bucket *ap__b = (e); \ + APR_RING_INSERT_HEAD(&(b)->list, ap__b, apr_bucket, link); \ + APR_BRIGADE_CHECK_CONSISTENCY((b)); \ + } while (0) + +/** + * Insert a single bucket at the end of a brigade + * @param b The brigade to add to + * @param e The bucket to insert + */ +#define APR_BRIGADE_INSERT_TAIL(b, e) do { \ + apr_bucket *ap__b = (e); \ + APR_RING_INSERT_TAIL(&(b)->list, ap__b, apr_bucket, link); \ + APR_BRIGADE_CHECK_CONSISTENCY((b)); \ + } while (0) + +/** + * Concatenate brigade b onto the end of brigade a, leaving brigade b empty + * @param a The first brigade + * @param b The second brigade + */ +#define APR_BRIGADE_CONCAT(a, b) do { \ + APR_RING_CONCAT(&(a)->list, &(b)->list, apr_bucket, link); \ + APR_BRIGADE_CHECK_CONSISTENCY((a)); \ + } while (0) + +/** + * Prepend brigade b onto the beginning of brigade a, leaving brigade b empty + * @param a The first brigade + * @param b The second brigade + */ +#define APR_BRIGADE_PREPEND(a, b) do { \ + APR_RING_PREPEND(&(a)->list, &(b)->list, apr_bucket, link); \ + APR_BRIGADE_CHECK_CONSISTENCY((a)); \ + } while (0) + +/** + * Insert a single bucket before a specified bucket + * @param a The bucket to insert before + * @param b The bucket to insert + */ +#define APR_BUCKET_INSERT_BEFORE(a, b) do { \ + apr_bucket *ap__a = (a), *ap__b = (b); \ + APR_RING_INSERT_BEFORE(ap__a, ap__b, link); \ + APR_BUCKET_CHECK_CONSISTENCY(ap__a); \ + } while (0) + +/** + * Insert a single bucket after a specified bucket + * @param a The bucket to insert after + * @param b The bucket to insert + */ +#define APR_BUCKET_INSERT_AFTER(a, b) do { \ + apr_bucket *ap__a = (a), *ap__b = (b); \ + APR_RING_INSERT_AFTER(ap__a, ap__b, link); \ + APR_BUCKET_CHECK_CONSISTENCY(ap__a); \ + } while (0) + +/** + * Get the next bucket in the list + * @param e The current bucket + * @return The next bucket + */ +#define APR_BUCKET_NEXT(e) APR_RING_NEXT((e), link) +/** + * Get the previous bucket in the list + * @param e The current bucket + * @return The previous bucket + */ +#define APR_BUCKET_PREV(e) APR_RING_PREV((e), link) + +/** + * Remove a bucket from its bucket brigade + * @param e The bucket to remove + */ +#define APR_BUCKET_REMOVE(e) APR_RING_REMOVE((e), link) + +/** + * Initialize a new bucket's prev/next pointers + * @param e The bucket to initialize + */ +#define APR_BUCKET_INIT(e) APR_RING_ELEM_INIT((e), link) + +/** + * Determine if a bucket contains metadata. An empty bucket is + * safe to arbitrarily remove if and only if this is false. + * @param e The bucket to inspect + * @return true or false + */ +#define APR_BUCKET_IS_METADATA(e) ((e)->type->is_metadata) + +/** + * Determine if a bucket is a FLUSH bucket + * @param e The bucket to inspect + * @return true or false + */ +#define APR_BUCKET_IS_FLUSH(e) ((e)->type == &apr_bucket_type_flush) +/** + * Determine if a bucket is an EOS bucket + * @param e The bucket to inspect + * @return true or false + */ +#define APR_BUCKET_IS_EOS(e) ((e)->type == &apr_bucket_type_eos) +/** + * Determine if a bucket is a FILE bucket + * @param e The bucket to inspect + * @return true or false + */ +#define APR_BUCKET_IS_FILE(e) ((e)->type == &apr_bucket_type_file) +/** + * Determine if a bucket is a PIPE bucket + * @param e The bucket to inspect + * @return true or false + */ +#define APR_BUCKET_IS_PIPE(e) ((e)->type == &apr_bucket_type_pipe) +/** + * Determine if a bucket is a SOCKET bucket + * @param e The bucket to inspect + * @return true or false + */ +#define APR_BUCKET_IS_SOCKET(e) ((e)->type == &apr_bucket_type_socket) +/** + * Determine if a bucket is a HEAP bucket + * @param e The bucket to inspect + * @return true or false + */ +#define APR_BUCKET_IS_HEAP(e) ((e)->type == &apr_bucket_type_heap) +/** + * Determine if a bucket is a TRANSIENT bucket + * @param e The bucket to inspect + * @return true or false + */ +#define APR_BUCKET_IS_TRANSIENT(e) ((e)->type == &apr_bucket_type_transient) +/** + * Determine if a bucket is a IMMORTAL bucket + * @param e The bucket to inspect + * @return true or false + */ +#define APR_BUCKET_IS_IMMORTAL(e) ((e)->type == &apr_bucket_type_immortal) +#if APR_HAS_MMAP +/** + * Determine if a bucket is a MMAP bucket + * @param e The bucket to inspect + * @return true or false + */ +#define APR_BUCKET_IS_MMAP(e) ((e)->type == &apr_bucket_type_mmap) +#endif +/** + * Determine if a bucket is a POOL bucket + * @param e The bucket to inspect + * @return true or false + */ +#define APR_BUCKET_IS_POOL(e) ((e)->type == &apr_bucket_type_pool) + +/* + * General-purpose reference counting for the various bucket types. + * + * Any bucket type that keeps track of the resources it uses (i.e. + * most of them except for IMMORTAL, TRANSIENT, and EOS) needs to + * attach a reference count to the resource so that it can be freed + * when the last bucket that uses it goes away. Resource-sharing may + * occur because of bucket splits or buckets that refer to globally + * cached data. */ + +/** @see apr_bucket_refcount */ +typedef struct apr_bucket_refcount apr_bucket_refcount; +/** + * The structure used to manage the shared resource must start with an + * apr_bucket_refcount which is updated by the general-purpose refcount + * code. A pointer to the bucket-type-dependent private data structure + * can be cast to a pointer to an apr_bucket_refcount and vice versa. + */ +struct apr_bucket_refcount { + /** The number of references to this bucket */ + int refcount; +}; + +/* ***** Reference-counted bucket types ***** */ + +/** @see apr_bucket_heap */ +typedef struct apr_bucket_heap apr_bucket_heap; +/** + * A bucket referring to data allocated off the heap. + */ +struct apr_bucket_heap { + /** Number of buckets using this memory */ + apr_bucket_refcount refcount; + /** The start of the data actually allocated. This should never be + * modified, it is only used to free the bucket. + */ + char *base; + /** how much memory was allocated */ + apr_size_t alloc_len; + /** function to use to delete the data */ + void (*free_func)(void *data); +}; + +/** @see apr_bucket_pool */ +typedef struct apr_bucket_pool apr_bucket_pool; +/** + * A bucket referring to data allocated from a pool + */ +struct apr_bucket_pool { + /** The pool bucket must be able to be easily morphed to a heap + * bucket if the pool gets cleaned up before all references are + * destroyed. This apr_bucket_heap structure is populated automatically + * when the pool gets cleaned up, and subsequent calls to pool_read() + * will result in the apr_bucket in question being morphed into a + * regular heap bucket. (To avoid having to do many extra refcount + * manipulations and b->data manipulations, the apr_bucket_pool + * struct actually *contains* the apr_bucket_heap struct that it + * will become as its first element; the two share their + * apr_bucket_refcount members.) + */ + apr_bucket_heap heap; + /** The block of data actually allocated from the pool. + * Segments of this block are referenced by adjusting + * the start and length of the apr_bucket accordingly. + * This will be NULL after the pool gets cleaned up. + */ + const char *base; + /** The pool the data was allocated from. When the pool + * is cleaned up, this gets set to NULL as an indicator + * to pool_read() that the data is now on the heap and + * so it should morph the bucket into a regular heap + * bucket before continuing. + */ + apr_pool_t *pool; + /** The freelist this structure was allocated from, which is + * needed in the cleanup phase in order to allocate space on the heap + */ + apr_bucket_alloc_t *list; +}; + +#if APR_HAS_MMAP +/** @see apr_bucket_mmap */ +typedef struct apr_bucket_mmap apr_bucket_mmap; +/** + * A bucket referring to an mmap()ed file + */ +struct apr_bucket_mmap { + /** Number of buckets using this memory */ + apr_bucket_refcount refcount; + /** The mmap this sub_bucket refers to */ + apr_mmap_t *mmap; +}; +#endif + +/** @see apr_bucket_file */ +typedef struct apr_bucket_file apr_bucket_file; +/** + * A bucket referring to an file + */ +struct apr_bucket_file { + /** Number of buckets using this memory */ + apr_bucket_refcount refcount; + /** The file this bucket refers to */ + apr_file_t *fd; + /** The pool into which any needed structures should + * be created while reading from this file bucket */ + apr_pool_t *readpool; +#if APR_HAS_MMAP + /** Whether this bucket should be memory-mapped if + * a caller tries to read from it */ + int can_mmap; +#endif /* APR_HAS_MMAP */ + /** File read block size */ + apr_size_t read_size; +}; + +/** @see apr_bucket_structs */ +typedef union apr_bucket_structs apr_bucket_structs; +/** + * A union of all bucket structures so we know what + * the max size is. + */ +union apr_bucket_structs { + apr_bucket b; /**< Bucket */ + apr_bucket_heap heap; /**< Heap */ + apr_bucket_pool pool; /**< Pool */ +#if APR_HAS_MMAP + apr_bucket_mmap mmap; /**< MMap */ +#endif + apr_bucket_file file; /**< File */ +}; + +/** + * The amount that apr_bucket_alloc() should allocate in the common case. + * Note: this is twice as big as apr_bucket_structs to allow breathing + * room for third-party bucket types. + */ +#define APR_BUCKET_ALLOC_SIZE APR_ALIGN_DEFAULT(2*sizeof(apr_bucket_structs)) + +/* ***** Bucket Brigade Functions ***** */ +/** + * Create a new bucket brigade. The bucket brigade is originally empty. + * @param p The pool to associate with the brigade. Data is not allocated out + * of the pool, but a cleanup is registered. + * @param list The bucket allocator to use + * @return The empty bucket brigade + */ +APR_DECLARE(apr_bucket_brigade *) apr_brigade_create(apr_pool_t *p, + apr_bucket_alloc_t *list) + __attribute__((nonnull(1,2))); + +/** + * Destroy an entire bucket brigade. This includes destroying all of the + * buckets within the bucket brigade's bucket list. + * @param b The bucket brigade to destroy + */ +APR_DECLARE(apr_status_t) apr_brigade_destroy(apr_bucket_brigade *b) + __attribute__((nonnull(1))); + +/** + * Empty out an entire bucket brigade. This includes destroying all of the + * buckets within the bucket brigade's bucket list. This is similar to + * apr_brigade_destroy(), except that it does not deregister the brigade's + * pool cleanup function. + * @param data The bucket brigade to clean up + * @remark Generally, you should use apr_brigade_destroy(). This function + * can be useful in situations where you have a single brigade that + * you wish to reuse many times by destroying all of the buckets in + * the brigade and putting new buckets into it later. + */ +APR_DECLARE(apr_status_t) apr_brigade_cleanup(void *data) + __attribute__((nonnull(1))); + +/** + * Move the buckets from the tail end of the existing brigade @a b into + * the brigade @a a. If @a a is NULL a new brigade is created. Buckets + * from @a e to the last bucket (inclusively) of brigade @a b are moved + * from @a b to the returned brigade @a a. + * + * @param b The brigade to split + * @param e The first bucket to move + * @param a The brigade which should be used for the result or NULL if + * a new brigade should be created. The brigade @a a will be + * cleared if it is not empty. + * @return The brigade supplied in @a a or a new one if @a a was NULL. + * @warning Note that this function allocates a new brigade if @a a is + * NULL so memory consumption should be carefully considered. + */ +APR_DECLARE(apr_bucket_brigade *) apr_brigade_split_ex(apr_bucket_brigade *b, + apr_bucket *e, + apr_bucket_brigade *a) + __attribute__((nonnull(1,2))); + +/** + * Create a new bucket brigade and move the buckets from the tail end + * of an existing brigade into the new brigade. Buckets from + * @a e to the last bucket (inclusively) of brigade @a b + * are moved from @a b to the returned brigade. + * @param b The brigade to split + * @param e The first bucket to move + * @return The new brigade + * @warning Note that this function always allocates a new brigade + * so memory consumption should be carefully considered. + */ +APR_DECLARE(apr_bucket_brigade *) apr_brigade_split(apr_bucket_brigade *b, + apr_bucket *e) + __attribute__((nonnull(1,2))); + +/** + * Partition a bucket brigade at a given offset (in bytes from the start of + * the brigade). This is useful whenever a filter wants to use known ranges + * of bytes from the brigade; the ranges can even overlap. + * @param b The brigade to partition + * @param point The offset at which to partition the brigade + * @param after_point Returns a pointer to the first bucket after the partition + * @return APR_SUCCESS on success, APR_INCOMPLETE if the contents of the + * brigade were shorter than @a point, or an error code. + * @remark if APR_INCOMPLETE is returned, @a after_point will be set to + * the brigade sentinel. + */ +APR_DECLARE(apr_status_t) apr_brigade_partition(apr_bucket_brigade *b, + apr_off_t point, + apr_bucket **after_point) + __attribute__((nonnull(1,3))); + +/** + * Return the total length of the brigade. + * @param bb The brigade to compute the length of + * @param read_all Read unknown-length buckets to force a size + * @param length Returns the length of the brigade (up to the end, or up + * to a bucket read error), or -1 if the brigade has buckets + * of indeterminate length and read_all is 0. + */ +APR_DECLARE(apr_status_t) apr_brigade_length(apr_bucket_brigade *bb, + int read_all, + apr_off_t *length) + __attribute__((nonnull(1,3))); + +/** + * Take a bucket brigade and store the data in a flat char* + * @param bb The bucket brigade to create the char* from + * @param c The char* to write into + * @param len The maximum length of the char array. On return, it is the + * actual length of the char array. + */ +APR_DECLARE(apr_status_t) apr_brigade_flatten(apr_bucket_brigade *bb, + char *c, + apr_size_t *len) + __attribute__((nonnull(1,2,3))); + +/** + * Creates a pool-allocated string representing a flat bucket brigade + * @param bb The bucket brigade to create the char array from + * @param c On return, the allocated char array + * @param len On return, the length of the char array. + * @param pool The pool to allocate the string from. + */ +APR_DECLARE(apr_status_t) apr_brigade_pflatten(apr_bucket_brigade *bb, + char **c, + apr_size_t *len, + apr_pool_t *pool) + __attribute__((nonnull(1,2,3,4))); + +/** + * Split a brigade to represent one LF line. + * @param bbOut The bucket brigade that will have the LF line appended to. + * @param bbIn The input bucket brigade to search for a LF-line. + * @param block The blocking mode to be used to split the line. + * @param maxbytes The maximum bytes to read. If this many bytes are seen + * without a LF, the brigade will contain a partial line. + */ +APR_DECLARE(apr_status_t) apr_brigade_split_line(apr_bucket_brigade *bbOut, + apr_bucket_brigade *bbIn, + apr_read_type_e block, + apr_off_t maxbytes) + __attribute__((nonnull(1,2))); + +/** + * Create an iovec of the elements in a bucket_brigade... return number + * of elements used. This is useful for writing to a file or to the + * network efficiently. + * @param b The bucket brigade to create the iovec from + * @param vec The iovec to create + * @param nvec The number of elements in the iovec. On return, it is the + * number of iovec elements actually filled out. + */ +APR_DECLARE(apr_status_t) apr_brigade_to_iovec(apr_bucket_brigade *b, + struct iovec *vec, int *nvec) + __attribute__((nonnull(1,2,3))); + +/** + * This function writes a list of strings into a bucket brigade. + * @param b The bucket brigade to add to + * @param flush The flush function to use if the brigade is full + * @param ctx The structure to pass to the flush function + * @param va A list of strings to add + * @return APR_SUCCESS or error code. + */ +APR_DECLARE(apr_status_t) apr_brigade_vputstrs(apr_bucket_brigade *b, + apr_brigade_flush flush, + void *ctx, + va_list va) + __attribute__((nonnull(1))); + +/** + * This function writes a string into a bucket brigade. + * + * The apr_brigade_write function attempts to be efficient with the + * handling of heap buckets. Regardless of the amount of data stored + * inside a heap bucket, heap buckets are a fixed size to promote their + * reuse. + * + * If an attempt is made to write a string to a brigade that already + * ends with a heap bucket, this function will attempt to pack the + * string into the remaining space in the previous heap bucket, before + * allocating a new heap bucket. + * + * This function always returns APR_SUCCESS, unless a flush function is + * passed, in which case the return value of the flush function will be + * returned if used. + * @param b The bucket brigade to add to + * @param flush The flush function to use if the brigade is full + * @param ctx The structure to pass to the flush function + * @param str The string to add + * @param nbyte The number of bytes to write + * @return APR_SUCCESS or error code + */ +APR_DECLARE(apr_status_t) apr_brigade_write(apr_bucket_brigade *b, + apr_brigade_flush flush, void *ctx, + const char *str, apr_size_t nbyte) + __attribute__((nonnull(1,4))); + +/** + * This function writes multiple strings into a bucket brigade. + * @param b The bucket brigade to add to + * @param flush The flush function to use if the brigade is full + * @param ctx The structure to pass to the flush function + * @param vec The strings to add (address plus length for each) + * @param nvec The number of entries in iovec + * @return APR_SUCCESS or error code + */ +APR_DECLARE(apr_status_t) apr_brigade_writev(apr_bucket_brigade *b, + apr_brigade_flush flush, + void *ctx, + const struct iovec *vec, + apr_size_t nvec) + __attribute__((nonnull(1,4))); + +/** + * This function writes a string into a bucket brigade. + * @param bb The bucket brigade to add to + * @param flush The flush function to use if the brigade is full + * @param ctx The structure to pass to the flush function + * @param str The string to add + * @return APR_SUCCESS or error code + */ +APR_DECLARE(apr_status_t) apr_brigade_puts(apr_bucket_brigade *bb, + apr_brigade_flush flush, void *ctx, + const char *str) + __attribute__((nonnull(1,4))); + +/** + * This function writes a character into a bucket brigade. + * @param b The bucket brigade to add to + * @param flush The flush function to use if the brigade is full + * @param ctx The structure to pass to the flush function + * @param c The character to add + * @return APR_SUCCESS or error code + */ +APR_DECLARE(apr_status_t) apr_brigade_putc(apr_bucket_brigade *b, + apr_brigade_flush flush, void *ctx, + const char c) + __attribute__((nonnull(1))); + +/** + * This function writes an unspecified number of strings into a bucket brigade. + * @param b The bucket brigade to add to + * @param flush The flush function to use if the brigade is full + * @param ctx The structure to pass to the flush function + * @param ... The strings to add. The final string must be NULL + * @return APR_SUCCESS or error code + */ +APR_DECLARE_NONSTD(apr_status_t) apr_brigade_putstrs(apr_bucket_brigade *b, + apr_brigade_flush flush, + void *ctx, ...) +#if defined(__GNUC__) && __GNUC__ >= 4 + __attribute__((sentinel)) +#endif + __attribute__((nonnull(1))) + ; + +/** + * Evaluate a printf and put the resulting string at the end + * of the bucket brigade. + * @param b The brigade to write to + * @param flush The flush function to use if the brigade is full + * @param ctx The structure to pass to the flush function + * @param fmt The format of the string to write + * @param ... The arguments to fill out the format + * @return APR_SUCCESS or error code + */ +APR_DECLARE_NONSTD(apr_status_t) apr_brigade_printf(apr_bucket_brigade *b, + apr_brigade_flush flush, + void *ctx, + const char *fmt, ...) + __attribute__((format(printf,4,5))) + __attribute__((nonnull(1))); + +/** + * Evaluate a printf and put the resulting string at the end + * of the bucket brigade. + * @param b The brigade to write to + * @param flush The flush function to use if the brigade is full + * @param ctx The structure to pass to the flush function + * @param fmt The format of the string to write + * @param va The arguments to fill out the format + * @return APR_SUCCESS or error code + */ +APR_DECLARE(apr_status_t) apr_brigade_vprintf(apr_bucket_brigade *b, + apr_brigade_flush flush, + void *ctx, + const char *fmt, va_list va) + __attribute__((nonnull(1,4))); + +/** + * Utility function to insert a file (or a segment of a file) onto the + * end of the brigade. The file is split into multiple buckets if it + * is larger than the maximum size which can be represented by a + * single bucket. + * @param bb the brigade to insert into + * @param f the file to insert + * @param start the offset of the start of the segment + * @param len the length of the segment of the file to insert + * @param p pool from which file buckets are allocated + * @return the last bucket inserted + */ +APR_DECLARE(apr_bucket *) apr_brigade_insert_file(apr_bucket_brigade *bb, + apr_file_t *f, + apr_off_t start, + apr_off_t len, + apr_pool_t *p) + __attribute__((nonnull(1,2,5))); + + + +/* ***** Bucket freelist functions ***** */ +/** + * Create a bucket allocator. + * @param p This pool's underlying apr_allocator_t is used to allocate memory + * for the bucket allocator. When the pool is destroyed, the bucket + * allocator's cleanup routine will free all memory that has been + * allocated from it. + * @remark The reason the allocator gets its memory from the pool's + * apr_allocator_t rather than from the pool itself is because + * the bucket allocator will free large memory blocks back to the + * allocator when it's done with them, thereby preventing memory + * footprint growth that would occur if we allocated from the pool. + * @warning The allocator must never be used by more than one thread at a time. + */ +APR_DECLARE_NONSTD(apr_bucket_alloc_t *) apr_bucket_alloc_create(apr_pool_t *p); + +/** + * Create a bucket allocator. + * @param allocator This apr_allocator_t is used to allocate both the bucket + * allocator and all memory handed out by the bucket allocator. The + * caller is responsible for destroying the bucket allocator and the + * apr_allocator_t -- no automatic cleanups will happen. + * @warning The allocator must never be used by more than one thread at a time. + */ +APR_DECLARE_NONSTD(apr_bucket_alloc_t *) apr_bucket_alloc_create_ex( + apr_allocator_t *allocator) + __attribute__((nonnull(1))); + +/** + * Destroy a bucket allocator. + * @param list The allocator to be destroyed + */ +APR_DECLARE_NONSTD(void) apr_bucket_alloc_destroy(apr_bucket_alloc_t *list) + __attribute__((nonnull(1))); + +/** + * Get the aligned size corresponding to the requested size, but minus the + * allocator(s) overhead such that the allocation would remain in the + * same boundary. + * @param list The allocator from which to the memory would be allocated. + * @param size The requested size. + * @return The corresponding aligned/floored size. + */ +APR_DECLARE_NONSTD(apr_size_t) apr_bucket_alloc_aligned_floor(apr_bucket_alloc_t *list, + apr_size_t size) + __attribute__((nonnull(1))); + +/** + * Allocate memory for use by the buckets. + * @param size The amount to allocate. + * @param list The allocator from which to allocate the memory. + */ +APR_DECLARE_NONSTD(void *) apr_bucket_alloc(apr_size_t size, + apr_bucket_alloc_t *list) + __attribute__((nonnull(2))); + +/** + * Free memory previously allocated with apr_bucket_alloc(). + * @param block The block of memory to be freed. + */ +APR_DECLARE_NONSTD(void) apr_bucket_free(void *block) + __attribute__((nonnull(1))); + + +/* ***** Bucket Functions ***** */ +/** + * Free the resources used by a bucket. If multiple buckets refer to + * the same resource it is freed when the last one goes away. + * @see apr_bucket_delete() + * @param e The bucket to destroy + */ +#define apr_bucket_destroy(e) do { \ + (e)->type->destroy((e)->data); \ + (e)->free(e); \ + } while (0) + +/** + * Delete a bucket by removing it from its brigade (if any) and then + * destroying it. + * @remark This mainly acts as an aid in avoiding code verbosity. It is + * the preferred exact equivalent to: + * <pre> + * APR_BUCKET_REMOVE(e); + * apr_bucket_destroy(e); + * </pre> + * @param e The bucket to delete + */ +#define apr_bucket_delete(e) do { \ + APR_BUCKET_REMOVE(e); \ + apr_bucket_destroy(e); \ + } while (0) + +/** + * Read some data from the bucket. + * + * The apr_bucket_read function returns a convenient amount of data + * from the bucket provided, writing the address and length of the + * data to the pointers provided by the caller. The function tries + * as hard as possible to avoid a memory copy. + * + * Buckets are expected to be a member of a brigade at the time they + * are read. + * + * In typical application code, buckets are read in a loop, and after + * each bucket is read and processed, it is moved or deleted from the + * brigade and the next bucket read. + * + * The definition of "convenient" depends on the type of bucket that + * is being read, and is decided by APR. In the case of memory based + * buckets such as heap and immortal buckets, a pointer will be + * returned to the location of the buffer containing the complete + * contents of the bucket. + * + * Some buckets, such as the socket bucket, might have no concept + * of length. If an attempt is made to read such a bucket, the + * apr_bucket_read function will read a convenient amount of data + * from the socket. The socket bucket is magically morphed into a + * heap bucket containing the just-read data, and a new socket bucket + * is inserted just after this heap bucket. + * + * To understand why apr_bucket_read might do this, consider the loop + * described above to read and process buckets. The current bucket + * is magically morphed into a heap bucket and returned to the caller. + * The caller processes the data, and deletes the heap bucket, moving + * onto the next bucket, the new socket bucket. This process repeats, + * giving the illusion of a bucket brigade that contains potentially + * infinite amounts of data. It is up to the caller to decide at what + * point to stop reading buckets. + * + * Some buckets, such as the file bucket, might have a fixed size, + * but be significantly larger than is practical to store in RAM in + * one go. As with the socket bucket, if an attempt is made to read + * from a file bucket, the file bucket is magically morphed into a + * heap bucket containing a convenient amount of data read from the + * current offset in the file. During the read, the offset will be + * moved forward on the file, and a new file bucket will be inserted + * directly after the current bucket representing the remainder of the + * file. If the heap bucket was large enough to store the whole + * remainder of the file, no more file buckets are inserted, and the + * file bucket will disappear completely. + * + * The pattern for reading buckets described above does create the + * illusion that the code is willing to swallow buckets that might be + * too large for the system to handle in one go. This however is just + * an illusion: APR will always ensure that large (file) or infinite + * (socket) buckets are broken into convenient bite sized heap buckets + * before data is returned to the caller. + * + * There is a potential gotcha to watch for: if buckets are read in a + * loop, and aren't deleted after being processed, the potentially large + * bucket will slowly be converted into RAM resident heap buckets. If + * the file is larger than available RAM, an out of memory condition + * could be caused if the application is not careful to manage this. + * + * @param e The bucket to read from + * @param str The location to store a pointer to the data in + * @param len The location to store the amount of data read + * @param block Whether the read function blocks + */ +#define apr_bucket_read(e,str,len,block) (e)->type->read(e, str, len, block) + +/** + * Setaside data so that stack data is not destroyed on returning from + * the function + * @param e The bucket to setaside + * @param p The pool to setaside into + */ +#define apr_bucket_setaside(e,p) (e)->type->setaside(e,p) + +/** + * Split one bucket in two at the point provided. + * + * Once split, the original bucket becomes the first of the two new buckets. + * + * (It is assumed that the bucket is a member of a brigade when this + * function is called). + * @param e The bucket to split + * @param point The offset to split the bucket at + */ +#define apr_bucket_split(e,point) (e)->type->split(e, point) + +/** + * Copy a bucket. + * @param e The bucket to copy + * @param c Returns a pointer to the new bucket + */ +#define apr_bucket_copy(e,c) (e)->type->copy(e, c) + +/* Bucket type handling */ + +/** + * This function simply returns APR_SUCCESS to denote that the bucket does + * not require anything to happen for its setaside() function. This is + * appropriate for buckets that have "immortal" data -- the data will live + * at least as long as the bucket. + * @param data The bucket to setaside + * @param pool The pool defining the desired lifetime of the bucket data + * @return APR_SUCCESS + */ +APR_DECLARE_NONSTD(apr_status_t) apr_bucket_setaside_noop(apr_bucket *data, + apr_pool_t *pool); + +/** + * A place holder function that signifies that the setaside function was not + * implemented for this bucket + * @param data The bucket to setaside + * @param pool The pool defining the desired lifetime of the bucket data + * @return APR_ENOTIMPL + */ +APR_DECLARE_NONSTD(apr_status_t) apr_bucket_setaside_notimpl(apr_bucket *data, + apr_pool_t *pool); + +/** + * A place holder function that signifies that the split function was not + * implemented for this bucket + * @param data The bucket to split + * @param point The location to split the bucket + * @return APR_ENOTIMPL + */ +APR_DECLARE_NONSTD(apr_status_t) apr_bucket_split_notimpl(apr_bucket *data, + apr_size_t point); + +/** + * A place holder function that signifies that the copy function was not + * implemented for this bucket + * @param e The bucket to copy + * @param c Returns a pointer to the new bucket + * @return APR_ENOTIMPL + */ +APR_DECLARE_NONSTD(apr_status_t) apr_bucket_copy_notimpl(apr_bucket *e, + apr_bucket **c); + +/** + * A place holder function that signifies that this bucket does not need + * to do anything special to be destroyed. That's only the case for buckets + * that either have no data (metadata buckets) or buckets whose data pointer + * points to something that's not a bucket-type-specific structure, as with + * simple buckets where data points to a string and pipe buckets where data + * points directly to the apr_file_t. + * @param data The bucket data to destroy + */ +APR_DECLARE_NONSTD(void) apr_bucket_destroy_noop(void *data); + +/** + * There is no apr_bucket_destroy_notimpl, because destruction is required + * to be implemented (it could be a noop, but only if that makes sense for + * the bucket type) + */ + +/* There is no apr_bucket_read_notimpl, because it is a required function + */ + + +/* All of the bucket types implemented by the core */ +/** + * The flush bucket type. This signifies that all data should be flushed to + * the next filter. The flush bucket should be sent with the other buckets. + */ +APR_DECLARE_DATA extern const apr_bucket_type_t apr_bucket_type_flush; +/** + * The EOS bucket type. This signifies that there will be no more data, ever. + * All filters MUST send all data to the next filter when they receive a + * bucket of this type + */ +APR_DECLARE_DATA extern const apr_bucket_type_t apr_bucket_type_eos; +/** + * The FILE bucket type. This bucket represents a file on disk + */ +APR_DECLARE_DATA extern const apr_bucket_type_t apr_bucket_type_file; +/** + * The HEAP bucket type. This bucket represents a data allocated from the + * heap. + */ +APR_DECLARE_DATA extern const apr_bucket_type_t apr_bucket_type_heap; +#if APR_HAS_MMAP +/** + * The MMAP bucket type. This bucket represents an MMAP'ed file + */ +APR_DECLARE_DATA extern const apr_bucket_type_t apr_bucket_type_mmap; +#endif +/** + * The POOL bucket type. This bucket represents a data that was allocated + * from a pool. IF this bucket is still available when the pool is cleared, + * the data is copied on to the heap. + */ +APR_DECLARE_DATA extern const apr_bucket_type_t apr_bucket_type_pool; +/** + * The PIPE bucket type. This bucket represents a pipe to another program. + */ +APR_DECLARE_DATA extern const apr_bucket_type_t apr_bucket_type_pipe; +/** + * The IMMORTAL bucket type. This bucket represents a segment of data that + * the creator is willing to take responsibility for. The core will do + * nothing with the data in an immortal bucket + */ +APR_DECLARE_DATA extern const apr_bucket_type_t apr_bucket_type_immortal; +/** + * The TRANSIENT bucket type. This bucket represents a data allocated off + * the stack. When the setaside function is called, this data is copied on + * to the heap + */ +APR_DECLARE_DATA extern const apr_bucket_type_t apr_bucket_type_transient; +/** + * The SOCKET bucket type. This bucket represents a socket to another machine + */ +APR_DECLARE_DATA extern const apr_bucket_type_t apr_bucket_type_socket; + + +/* ***** Simple buckets ***** */ + +/** + * Split a simple bucket into two at the given point. Most non-reference + * counting buckets that allow multiple references to the same block of + * data (eg transient and immortal) will use this as their split function + * without any additional type-specific handling. + * @param b The bucket to be split + * @param point The offset of the first byte in the new bucket + * @return APR_EINVAL if the point is not within the bucket; + * APR_ENOMEM if allocation failed; + * or APR_SUCCESS + */ +APR_DECLARE_NONSTD(apr_status_t) apr_bucket_simple_split(apr_bucket *b, + apr_size_t point); + +/** + * Copy a simple bucket. Most non-reference-counting buckets that allow + * multiple references to the same block of data (eg transient and immortal) + * will use this as their copy function without any additional type-specific + * handling. + * @param a The bucket to copy + * @param b Returns a pointer to the new bucket + * @return APR_ENOMEM if allocation failed; + * or APR_SUCCESS + */ +APR_DECLARE_NONSTD(apr_status_t) apr_bucket_simple_copy(apr_bucket *a, + apr_bucket **b); + + +/* ***** Shared, reference-counted buckets ***** */ + +/** + * Initialize a bucket containing reference-counted data that may be + * shared. The caller must allocate the bucket if necessary and + * initialize its type-dependent fields, and allocate and initialize + * its own private data structure. This function should only be called + * by type-specific bucket creation functions. + * @param b The bucket to initialize + * @param data A pointer to the private data structure + * with the reference count at the start + * @param start The start of the data in the bucket + * relative to the private base pointer + * @param length The length of the data in the bucket + * @return The new bucket, or NULL if allocation failed + */ +APR_DECLARE(apr_bucket *) apr_bucket_shared_make(apr_bucket *b, void *data, + apr_off_t start, + apr_size_t length); + +/** + * Decrement the refcount of the data in the bucket. This function + * should only be called by type-specific bucket destruction functions. + * @param data The private data pointer from the bucket to be destroyed + * @return TRUE or FALSE; TRUE if the reference count is now + * zero, indicating that the shared resource itself can + * be destroyed by the caller. + */ +APR_DECLARE(int) apr_bucket_shared_destroy(void *data); + +/** + * Split a bucket into two at the given point, and adjust the refcount + * to the underlying data. Most reference-counting bucket types will + * be able to use this function as their split function without any + * additional type-specific handling. + * @param b The bucket to be split + * @param point The offset of the first byte in the new bucket + * @return APR_EINVAL if the point is not within the bucket; + * APR_ENOMEM if allocation failed; + * or APR_SUCCESS + */ +APR_DECLARE_NONSTD(apr_status_t) apr_bucket_shared_split(apr_bucket *b, + apr_size_t point); + +/** + * Copy a refcounted bucket, incrementing the reference count. Most + * reference-counting bucket types will be able to use this function + * as their copy function without any additional type-specific handling. + * @param a The bucket to copy + * @param b Returns a pointer to the new bucket + * @return APR_ENOMEM if allocation failed; + or APR_SUCCESS + */ +APR_DECLARE_NONSTD(apr_status_t) apr_bucket_shared_copy(apr_bucket *a, + apr_bucket **b); + + +/* ***** Functions to Create Buckets of varying types ***** */ +/* + * Each bucket type foo has two initialization functions: + * apr_bucket_foo_make which sets up some already-allocated memory as a + * bucket of type foo; and apr_bucket_foo_create which allocates memory + * for the bucket, calls apr_bucket_make_foo, and initializes the + * bucket's list pointers. The apr_bucket_foo_make functions are used + * inside the bucket code to change the type of buckets in place; + * other code should call apr_bucket_foo_create. All the initialization + * functions change nothing if they fail. + */ + +/** + * Create an End of Stream bucket. This indicates that there is no more data + * coming from down the filter stack. All filters should flush at this point. + * @param list The freelist from which this bucket should be allocated + * @return The new bucket, or NULL if allocation failed + */ +APR_DECLARE(apr_bucket *) apr_bucket_eos_create(apr_bucket_alloc_t *list); + +/** + * Make the bucket passed in an EOS bucket. This indicates that there is no + * more data coming from down the filter stack. All filters should flush at + * this point. + * @param b The bucket to make into an EOS bucket + * @return The new bucket, or NULL if allocation failed + */ +APR_DECLARE(apr_bucket *) apr_bucket_eos_make(apr_bucket *b) + __attribute__((nonnull(1))); + +/** + * Create a flush bucket. This indicates that filters should flush their + * data. There is no guarantee that they will flush it, but this is the + * best we can do. + * @param list The freelist from which this bucket should be allocated + * @return The new bucket, or NULL if allocation failed + */ +APR_DECLARE(apr_bucket *) apr_bucket_flush_create(apr_bucket_alloc_t *list) + __attribute__((nonnull(1))); + +/** + * Make the bucket passed in a FLUSH bucket. This indicates that filters + * should flush their data. There is no guarantee that they will flush it, + * but this is the best we can do. + * @param b The bucket to make into a FLUSH bucket + * @return The new bucket, or NULL if allocation failed + */ +APR_DECLARE(apr_bucket *) apr_bucket_flush_make(apr_bucket *b) + __attribute__((nonnull(1))); + +/** + * Create a bucket referring to long-lived data. + * @param buf The data to insert into the bucket + * @param nbyte The size of the data to insert. + * @param list The freelist from which this bucket should be allocated + * @return The new bucket, or NULL if allocation failed + */ +APR_DECLARE(apr_bucket *) apr_bucket_immortal_create(const char *buf, + apr_size_t nbyte, + apr_bucket_alloc_t *list) + __attribute__((nonnull(1,3))); + +/** + * Make the bucket passed in a bucket refer to long-lived data + * @param b The bucket to make into a IMMORTAL bucket + * @param buf The data to insert into the bucket + * @param nbyte The size of the data to insert. + * @return The new bucket, or NULL if allocation failed + */ +APR_DECLARE(apr_bucket *) apr_bucket_immortal_make(apr_bucket *b, + const char *buf, + apr_size_t nbyte) + __attribute__((nonnull(1,2))); + +/** + * Create a bucket referring to data on the stack. + * @param buf The data to insert into the bucket + * @param nbyte The size of the data to insert. + * @param list The freelist from which this bucket should be allocated + * @return The new bucket, or NULL if allocation failed + */ +APR_DECLARE(apr_bucket *) apr_bucket_transient_create(const char *buf, + apr_size_t nbyte, + apr_bucket_alloc_t *list) + __attribute__((nonnull(1,3))); + +/** + * Make the bucket passed in a bucket refer to stack data + * @param b The bucket to make into a TRANSIENT bucket + * @param buf The data to insert into the bucket + * @param nbyte The size of the data to insert. + * @return The new bucket, or NULL if allocation failed + */ +APR_DECLARE(apr_bucket *) apr_bucket_transient_make(apr_bucket *b, + const char *buf, + apr_size_t nbyte) + __attribute__((nonnull(1,2))); + +/** + * Create a bucket referring to memory on the heap. If the caller asks + * for the data to be copied, this function always allocates 4K of + * memory so that more data can be added to the bucket without + * requiring another allocation. Therefore not all the data may be put + * into the bucket. If copying is not requested then the bucket takes + * over responsibility for free()ing the memory. + * @param buf The buffer to insert into the bucket + * @param nbyte The size of the buffer to insert. + * @param free_func Function to use to free the data; NULL indicates that the + * bucket should make a copy of the data + * @param list The freelist from which this bucket should be allocated + * @return The new bucket, or NULL if allocation failed + */ +APR_DECLARE(apr_bucket *) apr_bucket_heap_create(const char *buf, + apr_size_t nbyte, + void (*free_func)(void *data), + apr_bucket_alloc_t *list) + __attribute__((nonnull(1,4))); +/** + * Make the bucket passed in a bucket refer to heap data + * @param b The bucket to make into a HEAP bucket + * @param buf The buffer to insert into the bucket + * @param nbyte The size of the buffer to insert. + * @param free_func Function to use to free the data; NULL indicates that the + * bucket should make a copy of the data + * @return The new bucket, or NULL if allocation failed + */ +APR_DECLARE(apr_bucket *) apr_bucket_heap_make(apr_bucket *b, const char *buf, + apr_size_t nbyte, + void (*free_func)(void *data)) + __attribute__((nonnull(1,2))); + +/** + * Create a bucket referring to memory allocated from a pool. + * + * @param buf The buffer to insert into the bucket + * @param length The number of bytes referred to by this bucket + * @param pool The pool the memory was allocated from + * @param list The freelist from which this bucket should be allocated + * @return The new bucket, or NULL if allocation failed + */ +APR_DECLARE(apr_bucket *) apr_bucket_pool_create(const char *buf, + apr_size_t length, + apr_pool_t *pool, + apr_bucket_alloc_t *list) + __attribute__((nonnull(1,3,4))); + +/** + * Make the bucket passed in a bucket refer to pool data + * @param b The bucket to make into a pool bucket + * @param buf The buffer to insert into the bucket + * @param length The number of bytes referred to by this bucket + * @param pool The pool the memory was allocated from + * @return The new bucket, or NULL if allocation failed + */ +APR_DECLARE(apr_bucket *) apr_bucket_pool_make(apr_bucket *b, const char *buf, + apr_size_t length, + apr_pool_t *pool) + __attribute__((nonnull(1,2,4))); + +#if APR_HAS_MMAP +/** + * Create a bucket referring to mmap()ed memory. + * @param mm The mmap to insert into the bucket + * @param start The offset of the first byte in the mmap + * that this bucket refers to + * @param length The number of bytes referred to by this bucket + * @param list The freelist from which this bucket should be allocated + * @return The new bucket, or NULL if allocation failed + */ +APR_DECLARE(apr_bucket *) apr_bucket_mmap_create(apr_mmap_t *mm, + apr_off_t start, + apr_size_t length, + apr_bucket_alloc_t *list) + __attribute__((nonnull(1,4))); + +/** + * Make the bucket passed in a bucket refer to an MMAP'ed file + * @param b The bucket to make into a MMAP bucket + * @param mm The mmap to insert into the bucket + * @param start The offset of the first byte in the mmap + * that this bucket refers to + * @param length The number of bytes referred to by this bucket + * @return The new bucket, or NULL if allocation failed + */ +APR_DECLARE(apr_bucket *) apr_bucket_mmap_make(apr_bucket *b, apr_mmap_t *mm, + apr_off_t start, + apr_size_t length) + __attribute__((nonnull(1,2))); +#endif + +/** + * Create a bucket referring to a socket. + * @param thissock The socket to put in the bucket + * @param list The freelist from which this bucket should be allocated + * @return The new bucket, or NULL if allocation failed + */ +APR_DECLARE(apr_bucket *) apr_bucket_socket_create(apr_socket_t *thissock, + apr_bucket_alloc_t *list) + __attribute__((nonnull(1,2))); +/** + * Make the bucket passed in a bucket refer to a socket + * @param b The bucket to make into a SOCKET bucket + * @param thissock The socket to put in the bucket + * @return The new bucket, or NULL if allocation failed + */ +APR_DECLARE(apr_bucket *) apr_bucket_socket_make(apr_bucket *b, + apr_socket_t *thissock) + __attribute__((nonnull(1,2))); + +/** + * Create a bucket referring to a pipe. + * @param thispipe The pipe to put in the bucket + * @param list The freelist from which this bucket should be allocated + * @return The new bucket, or NULL if allocation failed + */ +APR_DECLARE(apr_bucket *) apr_bucket_pipe_create(apr_file_t *thispipe, + apr_bucket_alloc_t *list) + __attribute__((nonnull(1,2))); + +/** + * Make the bucket passed in a bucket refer to a pipe + * @param b The bucket to make into a PIPE bucket + * @param thispipe The pipe to put in the bucket + * @return The new bucket, or NULL if allocation failed + */ +APR_DECLARE(apr_bucket *) apr_bucket_pipe_make(apr_bucket *b, + apr_file_t *thispipe) + __attribute__((nonnull(1,2))); + +/** + * Create a bucket referring to a file. + * @param fd The file to put in the bucket + * @param offset The offset where the data of interest begins in the file + * @param len The amount of data in the file we are interested in + * @param p The pool into which any needed structures should be created + * while reading from this file bucket + * @param list The freelist from which this bucket should be allocated + * @return The new bucket, or NULL if allocation failed + * @remark If the file is truncated such that the segment of the file + * referenced by the bucket no longer exists, an attempt to read + * from the bucket will fail with APR_EOF. + * @remark apr_brigade_insert_file() should generally be used to + * insert files into brigades, since that function can correctly + * handle large file issues. + */ +APR_DECLARE(apr_bucket *) apr_bucket_file_create(apr_file_t *fd, + apr_off_t offset, + apr_size_t len, + apr_pool_t *p, + apr_bucket_alloc_t *list) + __attribute__((nonnull(1,4,5))); + +/** + * Make the bucket passed in a bucket refer to a file + * @param b The bucket to make into a FILE bucket + * @param fd The file to put in the bucket + * @param offset The offset where the data of interest begins in the file + * @param len The amount of data in the file we are interested in + * @param p The pool into which any needed structures should be created + * while reading from this file bucket + * @return The new bucket, or NULL if allocation failed + */ +APR_DECLARE(apr_bucket *) apr_bucket_file_make(apr_bucket *b, apr_file_t *fd, + apr_off_t offset, + apr_size_t len, apr_pool_t *p) + __attribute__((nonnull(1,2,5))); + +/** + * Enable or disable memory-mapping for a FILE bucket (default is enabled) + * @param b The bucket + * @param enabled Whether memory-mapping should be enabled + * @return APR_SUCCESS normally, or an error code if the operation fails + */ +APR_DECLARE(apr_status_t) apr_bucket_file_enable_mmap(apr_bucket *b, + int enabled) + __attribute__((nonnull(1))); + +/** + * Set the size of the read buffer allocated by a FILE bucket (default + * is @a APR_BUCKET_BUFF_SIZE) + * memory-mapping is disabled only) + * @param b The bucket + * @param size Size of the allocated buffers + * @return APR_SUCCESS normally, or an error code if the operation fails + * @remark Relevant/used only when memory-mapping is disabled (@see + * apr_bucket_file_enable_mmap) + */ +APR_DECLARE(apr_status_t) apr_bucket_file_set_buf_size(apr_bucket *e, + apr_size_t size); + +/** @} */ +#ifdef __cplusplus +} +#endif + +#endif /* !APR_BUCKETS_H */ diff --git a/include/apr_crypto.h b/include/apr_crypto.h new file mode 100644 index 00000000000..68b196ad6e9 --- /dev/null +++ b/include/apr_crypto.h @@ -0,0 +1,506 @@ +/* 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. + */ + +#ifndef APR_CRYPTO_H +#define APR_CRYPTO_H + +#include "apu.h" +#include "apr_pools.h" +#include "apr_tables.h" +#include "apr_hash.h" +#include "apu_errno.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @file apr_crypto.h + * @brief APR-UTIL Crypto library + */ +/** + * @defgroup APR_Util_Crypto Crypto routines + * @ingroup APR + * @{ + */ + +#if APU_HAVE_CRYPTO + +#ifndef APU_CRYPTO_RECOMMENDED_DRIVER +#if APU_HAVE_COMMONCRYPTO +#define APU_CRYPTO_RECOMMENDED_DRIVER "commoncrypto" +#else +#if APU_HAVE_OPENSSL +#define APU_CRYPTO_RECOMMENDED_DRIVER "openssl" +#else +#if APU_HAVE_NSS +#define APU_CRYPTO_RECOMMENDED_DRIVER "nss" +#else +#if APU_HAVE_MSCNG +#define APU_CRYPTO_RECOMMENDED_DRIVER "mscng" +#else +#if APU_HAVE_MSCAPI +#define APU_CRYPTO_RECOMMENDED_DRIVER "mscapi" +#else +#endif +#endif +#endif +#endif +#endif +#endif + +/** + * Symmetric Key types understood by the library. + * + * NOTE: It is expected that this list will grow over time. + * + * Interoperability Matrix: + * + * The matrix is based on the testcrypto.c unit test, which attempts to + * test whether a simple encrypt/decrypt will succeed, as well as testing + * whether an encrypted string by one library can be decrypted by the + * others. + * + * Some libraries will successfully encrypt and decrypt their own data, + * but won't decrypt data from another library. It is hoped that over + * time these anomalies will be found and fixed, but until then it is + * recommended that ciphers are chosen that interoperate across platform. + * + * An X below means the test passes, it does not necessarily mean that + * encryption performed is correct or secure. Applications should stick + * to ciphers that pass the interoperablity tests on the right hand side + * of the table. + * + * Aligned data is data whose length is a multiple of the block size for + * the chosen cipher. Padded data is data that is not aligned by block + * size and must be padded by the crypto library. + * + * OpenSSL CommonCrypto NSS Interop + * Align Pad Align Pad Align Pad Align Pad + * 3DES_192/CBC X X X X X X X X + * 3DES_192/ECB X X X X + * AES_256/CBC X X X X X X X X + * AES_256/ECB X X X X X X + * AES_192/CBC X X X X X X + * AES_192/ECB X X X X X + * AES_128/CBC X X X X X X + * AES_128/ECB X X X X X + * + * Conclusion: for padded data, use 3DES_192/CBC or AES_256/CBC. For + * aligned data, use 3DES_192/CBC, AES_256/CBC or AES_256/ECB. + */ + +typedef enum +{ + APR_KEY_NONE, APR_KEY_3DES_192, /** 192 bit (3-Key) 3DES */ + APR_KEY_AES_128, /** 128 bit AES */ + APR_KEY_AES_192, /** 192 bit AES */ + APR_KEY_AES_256 +/** 256 bit AES */ +} apr_crypto_block_key_type_e; + +typedef enum +{ + APR_MODE_NONE, /** An error condition */ + APR_MODE_ECB, /** Electronic Code Book */ + APR_MODE_CBC +/** Cipher Block Chaining */ +} apr_crypto_block_key_mode_e; + +/* These are opaque structs. Instantiation is up to each backend */ +typedef struct apr_crypto_driver_t apr_crypto_driver_t; +typedef struct apr_crypto_t apr_crypto_t; +typedef struct apr_crypto_config_t apr_crypto_config_t; +typedef struct apr_crypto_key_t apr_crypto_key_t; +typedef struct apr_crypto_block_t apr_crypto_block_t; + +typedef struct apr_crypto_block_key_type_t { + apr_crypto_block_key_type_e type; + int keysize; + int blocksize; + int ivsize; +} apr_crypto_block_key_type_t; + +typedef struct apr_crypto_block_key_mode_t { + apr_crypto_block_key_mode_e mode; +} apr_crypto_block_key_mode_t; + +typedef struct apr_crypto_passphrase_t { + const char *pass; + apr_size_t passLen; + const unsigned char * salt; + apr_size_t saltLen; + int iterations; +} apr_crypto_passphrase_t; + +typedef struct apr_crypto_secret_t { + const unsigned char *secret; + apr_size_t secretLen; +} apr_crypto_secret_t; + +typedef enum { + /** Key is derived from a passphrase */ + APR_CRYPTO_KTYPE_PASSPHRASE = 1, + /** Key is derived from a raw key */ + APR_CRYPTO_KTYPE_SECRET = 2, +} apr_crypto_key_type; + +typedef struct apr_crypto_key_rec_t { + apr_crypto_key_type ktype; + apr_crypto_block_key_type_e type; + apr_crypto_block_key_mode_e mode; + int pad; + union { + apr_crypto_passphrase_t passphrase; + apr_crypto_secret_t secret; + } k; +} apr_crypto_key_rec_t; + +/** + * @brief Perform once-only initialisation. Call once only. + * + * @param pool - pool to register any shutdown cleanups, etc + * @return APR_NOTIMPL in case of no crypto support. + */ +APR_DECLARE(apr_status_t) apr_crypto_init(apr_pool_t *pool); + +/** + * @brief Zero out the buffer provided when the pool is cleaned up. + * + * @param pool - pool to register the cleanup + * @param buffer - buffer to zero out + * @param size - size of the buffer to zero out + */ +APR_DECLARE(apr_status_t) apr_crypto_clear(apr_pool_t *pool, void *buffer, + apr_size_t size); + +/** + * @brief Always zero out the buffer provided, without being optimized out by + * the compiler. + * + * @param buffer - buffer to zero out + * @param size - size of the buffer to zero out + */ +APR_DECLARE(apr_status_t) apr_crypto_memzero(void *buffer, apr_size_t size); + +/** + * @brief Timing attacks safe buffers comparison, where the executing time does + * not depend on the bytes compared but solely on the number of bytes. + * + * @param buf1 - first buffer to compare + * @param buf2 - second buffer to compare + * @param size - size of the buffers to compare + * @return 1 if the buffers are equals, 0 otherwise. + */ +APR_DECLARE(int) apr_crypto_equals(const void *buf1, const void *buf2, + apr_size_t size); + +/** + * @brief Get the driver struct for a name + * + * @param driver - pointer to driver struct. + * @param name - driver name + * @param params - array of initialisation parameters + * @param result - result and error message on failure + * @param pool - (process) pool to register cleanup + * @return APR_SUCCESS for success + * @return APR_ENOTIMPL for no driver (when DSO not enabled) + * @return APR_EDSOOPEN if DSO driver file can't be opened + * @return APR_ESYMNOTFOUND if the driver file doesn't contain a driver + * @remarks NSS: the params can have "dir", "key3", "cert7" and "secmod" + * keys, each followed by an equal sign and a value. Such key/value pairs can + * be delimited by space or tab. If the value contains a space, surround the + * whole key value pair in quotes: "dir=My Directory". + * @remarks OpenSSL: currently no params are supported. + */ +APR_DECLARE(apr_status_t) apr_crypto_get_driver( + const apr_crypto_driver_t **driver, const char *name, + const char *params, const apu_err_t **result, apr_pool_t *pool); + +/** + * @brief Return the name of the driver. + * + * @param driver - The driver in use. + * @return The name of the driver. + */ +APR_DECLARE(const char *) apr_crypto_driver_name( + const apr_crypto_driver_t *driver); + +/** + * @brief Get the result of the last operation on a context. If the result + * is NULL, the operation was successful. + * @param result - the result structure + * @param f - context pointer + * @return APR_SUCCESS for success + */ +APR_DECLARE(apr_status_t) apr_crypto_error(const apu_err_t **result, + const apr_crypto_t *f); + +/** + * @brief Create a context for supporting encryption. Keys, certificates, + * algorithms and other parameters will be set per context. More than + * one context can be created at one time. A cleanup will be automatically + * registered with the given pool to guarantee a graceful shutdown. + * @param f - context pointer will be written here + * @param driver - driver to use + * @param params - array of key parameters + * @param pool - process pool + * @return APR_ENOENGINE when the engine specified does not exist. APR_EINITENGINE + * if the engine cannot be initialised. + * @remarks NSS: currently no params are supported. + * @remarks OpenSSL: the params can have "engine" as a key, followed by an equal + * sign and a value. + */ +APR_DECLARE(apr_status_t) + apr_crypto_make(apr_crypto_t **f, const apr_crypto_driver_t *driver, + const char *params, apr_pool_t *pool); + +/** + * @brief Get a hash table of key types, keyed by the name of the type against + * a pointer to apr_crypto_block_key_type_t, which in turn begins with an + * integer. + * + * @param types - hashtable of key types keyed to constants. + * @param f - encryption context + * @return APR_SUCCESS for success + */ +APR_DECLARE(apr_status_t) apr_crypto_get_block_key_types(apr_hash_t **types, + const apr_crypto_t *f); + +/** + * @brief Get a hash table of key modes, keyed by the name of the mode against + * a pointer to apr_crypto_block_key_mode_t, which in turn begins with an + * integer. + * + * @param modes - hashtable of key modes keyed to constants. + * @param f - encryption context + * @return APR_SUCCESS for success + */ +APR_DECLARE(apr_status_t) apr_crypto_get_block_key_modes(apr_hash_t **modes, + const apr_crypto_t *f); + +/** + * @brief Create a key from the provided secret or passphrase. The key is cleaned + * up when the context is cleaned, and may be reused with multiple encryption + * or decryption operations. + * @note If *key is NULL, a apr_crypto_key_t will be created from a pool. If + * *key is not NULL, *key must point at a previously created structure. + * @param key The key returned, see note. + * @param rec The key record, from which the key will be derived. + * @param f The context to use. + * @param p The pool to use. + * @return Returns APR_ENOKEY if the pass phrase is missing or empty, or if a backend + * error occurred while generating the key. APR_ENOCIPHER if the type or mode + * is not supported by the particular backend. APR_EKEYTYPE if the key type is + * not known. APR_EPADDING if padding was requested but is not supported. + * APR_ENOTIMPL if not implemented. + */ +APR_DECLARE(apr_status_t) apr_crypto_key(apr_crypto_key_t **key, + const apr_crypto_key_rec_t *rec, const apr_crypto_t *f, apr_pool_t *p); + +/** + * @brief Create a key from the given passphrase. By default, the PBKDF2 + * algorithm is used to generate the key from the passphrase. It is expected + * that the same pass phrase will generate the same key, regardless of the + * backend crypto platform used. The key is cleaned up when the context + * is cleaned, and may be reused with multiple encryption or decryption + * operations. + * @note If *key is NULL, a apr_crypto_key_t will be created from a pool. If + * *key is not NULL, *key must point at a previously created structure. + * @param key The key returned, see note. + * @param ivSize The size of the initialisation vector will be returned, based + * on whether an IV is relevant for this type of crypto. + * @param pass The passphrase to use. + * @param passLen The passphrase length in bytes + * @param salt The salt to use. + * @param saltLen The salt length in bytes + * @param type 3DES_192, AES_128, AES_192, AES_256. + * @param mode Electronic Code Book / Cipher Block Chaining. + * @param doPad Pad if necessary. + * @param iterations Number of iterations to use in algorithm + * @param f The context to use. + * @param p The pool to use. + * @return Returns APR_ENOKEY if the pass phrase is missing or empty, or if a backend + * error occurred while generating the key. APR_ENOCIPHER if the type or mode + * is not supported by the particular backend. APR_EKEYTYPE if the key type is + * not known. APR_EPADDING if padding was requested but is not supported. + * APR_ENOTIMPL if not implemented. + * @deprecated Replaced by apr_crypto_key(). + */ +APR_DECLARE(apr_status_t) apr_crypto_passphrase(apr_crypto_key_t **key, + apr_size_t *ivSize, const char *pass, apr_size_t passLen, + const unsigned char * salt, apr_size_t saltLen, + const apr_crypto_block_key_type_e type, + const apr_crypto_block_key_mode_e mode, const int doPad, + const int iterations, const apr_crypto_t *f, apr_pool_t *p); + +/** + * @brief Initialise a context for encrypting arbitrary data using the given key. + * @note If *ctx is NULL, a apr_crypto_block_t will be created from a pool. If + * *ctx is not NULL, *ctx must point at a previously created structure. + * @param ctx The block context returned, see note. + * @param iv Optional initialisation vector. If the buffer pointed to is NULL, + * an IV will be created at random, in space allocated from the pool. + * If the buffer pointed to is not NULL, the IV in the buffer will be + * used. + * @param key The key structure to use. + * @param blockSize The block size of the cipher. + * @param p The pool to use. + * @return Returns APR_ENOIV if an initialisation vector is required but not specified. + * Returns APR_EINIT if the backend failed to initialise the context. Returns + * APR_ENOTIMPL if not implemented. + */ +APR_DECLARE(apr_status_t) apr_crypto_block_encrypt_init( + apr_crypto_block_t **ctx, const unsigned char **iv, + const apr_crypto_key_t *key, apr_size_t *blockSize, apr_pool_t *p); + +/** + * @brief Encrypt data provided by in, write it to out. + * @note The number of bytes written will be written to outlen. If + * out is NULL, outlen will contain the maximum size of the + * buffer needed to hold the data, including any data + * generated by apr_crypto_block_encrypt_finish below. If *out points + * to NULL, a buffer sufficiently large will be created from + * the pool provided. If *out points to a not-NULL value, this + * value will be used as a buffer instead. + * @param out Address of a buffer to which data will be written, + * see note. + * @param outlen Length of the output will be written here. + * @param in Address of the buffer to read. + * @param inlen Length of the buffer to read. + * @param ctx The block context to use. + * @return APR_ECRYPT if an error occurred. Returns APR_ENOTIMPL if + * not implemented. + */ +APR_DECLARE(apr_status_t) apr_crypto_block_encrypt(unsigned char **out, + apr_size_t *outlen, const unsigned char *in, apr_size_t inlen, + apr_crypto_block_t *ctx); + +/** + * @brief Encrypt final data block, write it to out. + * @note If necessary the final block will be written out after being + * padded. Typically the final block will be written to the + * same buffer used by apr_crypto_block_encrypt, offset by the + * number of bytes returned as actually written by the + * apr_crypto_block_encrypt() call. After this call, the context + * is cleaned and can be reused by apr_crypto_block_encrypt_init(). + * @param out Address of a buffer to which data will be written. This + * buffer must already exist, and is usually the same + * buffer used by apr_evp_crypt(). See note. + * @param outlen Length of the output will be written here. + * @param ctx The block context to use. + * @return APR_ECRYPT if an error occurred. + * @return APR_EPADDING if padding was enabled and the block was incorrectly + * formatted. + * @return APR_ENOTIMPL if not implemented. + */ +APR_DECLARE(apr_status_t) apr_crypto_block_encrypt_finish(unsigned char *out, + apr_size_t *outlen, apr_crypto_block_t *ctx); + +/** + * @brief Initialise a context for decrypting arbitrary data using the given key. + * @note If *ctx is NULL, a apr_crypto_block_t will be created from a pool. If + * *ctx is not NULL, *ctx must point at a previously created structure. + * @param ctx The block context returned, see note. + * @param blockSize The block size of the cipher. + * @param iv Optional initialisation vector. + * @param key The key structure to use. + * @param p The pool to use. + * @return Returns APR_ENOIV if an initialisation vector is required but not specified. + * Returns APR_EINIT if the backend failed to initialise the context. Returns + * APR_ENOTIMPL if not implemented. + */ +APR_DECLARE(apr_status_t) apr_crypto_block_decrypt_init( + apr_crypto_block_t **ctx, apr_size_t *blockSize, + const unsigned char *iv, const apr_crypto_key_t *key, apr_pool_t *p); + +/** + * @brief Decrypt data provided by in, write it to out. + * @note The number of bytes written will be written to outlen. If + * out is NULL, outlen will contain the maximum size of the + * buffer needed to hold the data, including any data + * generated by apr_crypto_block_decrypt_finish below. If *out points + * to NULL, a buffer sufficiently large will be created from + * the pool provided. If *out points to a not-NULL value, this + * value will be used as a buffer instead. + * @param out Address of a buffer to which data will be written, + * see note. + * @param outlen Length of the output will be written here. + * @param in Address of the buffer to read. + * @param inlen Length of the buffer to read. + * @param ctx The block context to use. + * @return APR_ECRYPT if an error occurred. Returns APR_ENOTIMPL if + * not implemented. + */ +APR_DECLARE(apr_status_t) apr_crypto_block_decrypt(unsigned char **out, + apr_size_t *outlen, const unsigned char *in, apr_size_t inlen, + apr_crypto_block_t *ctx); + +/** + * @brief Decrypt final data block, write it to out. + * @note If necessary the final block will be written out after being + * padded. Typically the final block will be written to the + * same buffer used by apr_crypto_block_decrypt, offset by the + * number of bytes returned as actually written by the + * apr_crypto_block_decrypt() call. After this call, the context + * is cleaned and can be reused by apr_crypto_block_decrypt_init(). + * @param out Address of a buffer to which data will be written. This + * buffer must already exist, and is usually the same + * buffer used by apr_evp_crypt(). See note. + * @param outlen Length of the output will be written here. + * @param ctx The block context to use. + * @return APR_ECRYPT if an error occurred. + * @return APR_EPADDING if padding was enabled and the block was incorrectly + * formatted. + * @return APR_ENOTIMPL if not implemented. + */ +APR_DECLARE(apr_status_t) apr_crypto_block_decrypt_finish(unsigned char *out, + apr_size_t *outlen, apr_crypto_block_t *ctx); + +/** + * @brief Clean encryption / decryption context. + * @note After cleanup, a context is free to be reused if necessary. + * @param ctx The block context to use. + * @return Returns APR_ENOTIMPL if not supported. + */ +APR_DECLARE(apr_status_t) apr_crypto_block_cleanup(apr_crypto_block_t *ctx); + +/** + * @brief Clean encryption / decryption context. + * @note After cleanup, a context is free to be reused if necessary. + * @param f The context to use. + * @return Returns APR_ENOTIMPL if not supported. + */ +APR_DECLARE(apr_status_t) apr_crypto_cleanup(apr_crypto_t *f); + +/** + * @brief Shutdown the crypto library. + * @note After shutdown, it is expected that the init function can be called again. + * @param driver - driver to use + * @return Returns APR_ENOTIMPL if not supported. + */ +APR_DECLARE(apr_status_t) + apr_crypto_shutdown(const apr_crypto_driver_t *driver); + +#endif /* APU_HAVE_CRYPTO */ + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/apr_cstr.h b/include/apr_cstr.h new file mode 100644 index 00000000000..3f1b1a0995a --- /dev/null +++ b/include/apr_cstr.h @@ -0,0 +1,292 @@ +/* ==================================================================== + * 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. + * ==================================================================== + */ + +/** + * @file apr_cstr.h + * @brief C string goodies. + */ + +#ifndef APR_CSTR_H +#define APR_CSTR_H + +#include <apr.h> /* for apr_size_t */ +#include <apr_pools.h> /* for apr_pool_t */ +#include <apr_tables.h> /* for apr_array_header_t */ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup apr_cstr C (POSIX) locale string functions + * @ingroup apr_strings + * + * The apr_cstr_* functions provide traditional C char * string text handling, + * and notabilty they treat all text in the C (a.k.a. POSIX) locale using the + * minimal POSIX character set, represented in either ASCII or a corresponding + * EBCDIC subset. + * + * Character values outside of that set are treated as opaque bytes, and all + * multi-byte character sequences are handled as individual distinct octets. + * + * Multi-byte characters sequences whose octets fall in the ASCII range cause + * unexpected results, such as in the ISO-2022-JP code page where ASCII octets + * occur within both shift-state and multibyte sequences. + * + * In the case of the UTF-8 encoding, all multibyte characters all fall outside + * of the C/POSIX range of characters, so these functions are generally safe + * to use on UTF-8 strings. The programmer must be aware that each octet may + * not represent a distinct printable character in such encodings. + * + * The standard C99/POSIX string functions, rather than apr_cstr, should be + * used in all cases where the current locale and encoding of the text is + * significant. + * @{ + */ + + +/** Divide @a input into substrings, interpreting any char from @a sep + * as a token separator. + * + * Return an array of copies of those substrings (plain const char*), + * allocating both the array and the copies in @a pool. + * + * None of the elements added to the array contain any of the + * characters in @a sep_chars, and none of the new elements are empty + * (thus, it is possible that the returned array will have length + * zero). + * + * If @a chop_whitespace is TRUE, then remove leading and trailing + * whitespace from the returned strings. + * + * @since New in 1.6 + */ +APR_DECLARE(apr_array_header_t *) apr_cstr_split(const char *input, + const char *sep_chars, + int chop_whitespace, + apr_pool_t *pool); + +/** Like apr_cstr_split(), but append to existing @a array instead of + * creating a new one. Allocate the copied substrings in @a pool + * (i.e., caller decides whether or not to pass @a array->pool as @a pool). + * + * @since New in 1.6 + */ +APR_DECLARE(void) apr_cstr_split_append(apr_array_header_t *array, + const char *input, + const char *sep_chars, + int chop_whitespace, + apr_pool_t *pool); + + +/** Return @c TRUE iff @a str matches any of the elements of @a list, a list + * of zero or more glob patterns. + * + * @since New in 1.6 + */ +APR_DECLARE(int) apr_cstr_match_glob_list(const char *str, + const apr_array_header_t *list); + +/** Return @c TRUE iff @a str exactly matches any of the elements of @a list. + * + * @since New in 1.6 + */ +APR_DECLARE(int) apr_cstr_match_list(const char *str, + const apr_array_header_t *list); + +/** + * Get the next token from @a *str interpreting any char from @a sep as a + * token separator. Separators at the beginning of @a str will be skipped. + * Returns a pointer to the beginning of the first token in @a *str or NULL + * if no token is left. Modifies @a str such that the next call will return + * the next token. + * + * @note The content of @a *str may be modified by this function. + * + * @since New in 1.6. + */ +APR_DECLARE(char *) apr_cstr_tokenize(const char *sep, char **str); + +/** + * Return the number of line breaks in @a msg, allowing any kind of newline + * termination (CR, LF, CRLF, or LFCR), even inconsistent. + * + * @since New in 1.6. + */ +APR_DECLARE(int) apr_cstr_count_newlines(const char *msg); + +#if 0 /* XXX: stringbuf logic is not present in APR */ +/** + * Return a cstring which is the concatenation of @a strings (an array + * of char *) each followed by @a separator (that is, @a separator + * will also end the resulting string). Allocate the result in @a pool. + * If @a strings is empty, then return the empty string. + * + * @since New in 1.6. + */ +APR_DECLARE(char *) apr_cstr_join(const apr_array_header_t *strings, + const char *separator, + apr_pool_t *pool); +#endif + +/** + * Perform a case-insensitive comparison of two strings @a atr1 and @a atr2, + * treating upper and lower case values of the 26 standard C/POSIX alphabetic + * characters as equivalent. Extended latin characters outside of this set + * are treated as unique octets, irrespective of the current locale. + * + * Returns in integer greater than, equal to, or less than 0, + * according to whether @a str1 is considered greater than, equal to, + * or less than @a str2. + * + * @since New in 1.6. + */ +APR_DECLARE(int) apr_cstr_casecmp(const char *str1, const char *str2); + +/** + * Perform a case-insensitive comparison of two strings @a atr1 and @a atr2, + * treating upper and lower case values of the 26 standard C/POSIX alphabetic + * characters as equivalent. Extended latin characters outside of this set + * are treated as unique octets, irrespective of the current locale. + * + * Returns in integer greater than, equal to, or less than 0, + * according to whether @a str1 is considered greater than, equal to, + * or less than @a str2. + * + * @since New in 1.6. + */ +APR_DECLARE(int) apr_cstr_casecmpn(const char *str1, + const char *str2, + apr_size_t n); + +/** + * Parse the C string @a str into a 64 bit number, and return it in @a *n. + * Assume that the number is represented in base @a base. + * Raise an error if conversion fails (e.g. due to overflow), or if the + * converted number is smaller than @a minval or larger than @a maxval. + * + * Leading whitespace in @a str is skipped in a locale-dependent way. + * After that, the string may contain an optional '+' (positive, default) + * or '-' (negative) character, followed by an optional '0x' prefix if + * @a base is 0 or 16, followed by numeric digits appropriate for the base. + * If there are any more characters after the numeric digits, an error is + * returned. + * + * If @a base is zero, then a leading '0x' or '0X' prefix means hexadecimal, + * else a leading '0' means octal (implemented, though not documented, in + * apr_strtoi64() in APR 0.9.0 through 1.5.0), else use base ten. + * + * @since New in 1.6. + */ +APR_DECLARE(apr_status_t) apr_cstr_strtoi64(apr_int64_t *n, const char *str, + apr_int64_t minval, + apr_int64_t maxval, + int base); + +/** + * Parse the C string @a str into a 64 bit number, and return it in @a *n. + * Assume that the number is represented in base 10. + * Raise an error if conversion fails (e.g. due to overflow). + * + * The behaviour otherwise is as described for apr_cstr_strtoi64(). + * + * @since New in 1.6. + */ +APR_DECLARE(apr_status_t) apr_cstr_atoi64(apr_int64_t *n, const char *str); + +/** + * Parse the C string @a str into a 32 bit number, and return it in @a *n. + * Assume that the number is represented in base 10. + * Raise an error if conversion fails (e.g. due to overflow). + * + * The behaviour otherwise is as described for apr_cstr_strtoi64(). + * + * @since New in 1.6. + */ +APR_DECLARE(apr_status_t) apr_cstr_atoi(int *n, const char *str); + +/** + * Parse the C string @a str into an unsigned 64 bit number, and return + * it in @a *n. Assume that the number is represented in base @a base. + * Raise an error if conversion fails (e.g. due to overflow), or if the + * converted number is smaller than @a minval or larger than @a maxval. + * + * Leading whitespace in @a str is skipped in a locale-dependent way. + * After that, the string may contain an optional '+' (positive, default) + * or '-' (negative) character, followed by an optional '0x' prefix if + * @a base is 0 or 16, followed by numeric digits appropriate for the base. + * If there are any more characters after the numeric digits, an error is + * returned. + * + * If @a base is zero, then a leading '0x' or '0X' prefix means hexadecimal, + * else a leading '0' means octal (as implemented, though not documented, in + * apr_strtoi64(), else use base ten. + * + * @warning The implementation returns APR_ERANGE if the parsed number + * is greater than APR_INT64_MAX, even if it is not greater than @a maxval. + * + * @since New in 1.6. + */ +APR_DECLARE(apr_status_t) apr_cstr_strtoui64(apr_uint64_t *n, const char *str, + apr_uint64_t minval, + apr_uint64_t maxval, + int base); + +/** + * Parse the C string @a str into an unsigned 64 bit number, and return + * it in @a *n. Assume that the number is represented in base 10. + * Raise an error if conversion fails (e.g. due to overflow). + * + * The behaviour otherwise is as described for apr_cstr_strtoui64(), + * including the upper limit of APR_INT64_MAX. + * + * @since New in 1.6. + */ +APR_DECLARE(apr_status_t) apr_cstr_atoui64(apr_uint64_t *n, const char *str); + +/** + * Parse the C string @a str into an unsigned 32 bit number, and return + * it in @a *n. Assume that the number is represented in base 10. + * Raise an error if conversion fails (e.g. due to overflow). + * + * The behaviour otherwise is as described for apr_cstr_strtoui64(), + * including the upper limit of APR_INT64_MAX. + * + * @since New in 1.6. + */ +APR_DECLARE(apr_status_t) apr_cstr_atoui(unsigned int *n, const char *str); + +/** + * Skip the common prefix @a prefix from the C string @a str, and return + * a pointer to the next character after the prefix. + * Return @c NULL if @a str does not start with @a prefix. + * + * @since New in 1.6. + */ +APR_DECLARE(const char *) apr_cstr_skip_prefix(const char *str, + const char *prefix); + +/** @} */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* SVN_STRING_H */ diff --git a/include/apr_date.h b/include/apr_date.h new file mode 100644 index 00000000000..52a6d79da25 --- /dev/null +++ b/include/apr_date.h @@ -0,0 +1,106 @@ +/* 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. + */ + +#ifndef APR_DATE_H +#define APR_DATE_H + +/** + * @file apr_date.h + * @brief APR-UTIL date routines + */ + +/** + * @defgroup APR_Util_Date Date routines + * @ingroup APR + * @{ + */ + +/* + * apr_date.h: prototypes for date parsing utility routines + */ + +#include "apu.h" +#include "apr_time.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** A bad date. */ +#define APR_DATE_BAD ((apr_time_t)0) + +/** + * Compare a string to a mask + * @param data The string to compare + * @param mask Mask characters (arbitrary maximum is 256 characters): + * <PRE> + * '\@' - uppercase letter + * '\$' - lowercase letter + * '\&' - hex digit + * '#' - digit + * '~' - digit or space + * '*' - swallow remaining characters + * </PRE> + * @remark The mask tests for an exact match for any other character + * @return 1 if the string matches, 0 otherwise + */ +APR_DECLARE(int) apr_date_checkmask(const char *data, const char *mask); + +/** + * Parses an HTTP date in one of three standard forms: + * <PRE> + * Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123 + * Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036 + * Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() format + * </PRE> + * @param date The date in one of the three formats above + * @return the apr_time_t number of microseconds since 1 Jan 1970 GMT, or + * 0 if this would be out of range or if the date is invalid. + */ +APR_DECLARE(apr_time_t) apr_date_parse_http(const char *date); + +/** + * Parses a string resembling an RFC 822 date. This is meant to be + * leinent in its parsing of dates. Hence, this will parse a wider + * range of dates than apr_date_parse_http. + * + * The prominent mailer (or poster, if mailer is unknown) that has + * been seen in the wild is included for the unknown formats. + * <PRE> + * Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123 + * Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036 + * Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() format + * Sun, 6 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123 + * Sun, 06 Nov 94 08:49:37 GMT ; RFC 822 + * Sun, 6 Nov 94 08:49:37 GMT ; RFC 822 + * Sun, 06 Nov 94 08:49 GMT ; Unknown [drtr\@ast.cam.ac.uk] + * Sun, 6 Nov 94 08:49 GMT ; Unknown [drtr\@ast.cam.ac.uk] + * Sun, 06 Nov 94 8:49:37 GMT ; Unknown [Elm 70.85] + * Sun, 6 Nov 94 8:49:37 GMT ; Unknown [Elm 70.85] + * </PRE> + * + * @param date The date in one of the formats above + * @return the apr_time_t number of microseconds since 1 Jan 1970 GMT, or + * 0 if this would be out of range or if the date is invalid. + */ +APR_DECLARE(apr_time_t) apr_date_parse_rfc(const char *date); + +/** @} */ +#ifdef __cplusplus +} +#endif + +#endif /* !APR_DATE_H */ diff --git a/include/apr_dbd.h b/include/apr_dbd.h new file mode 100644 index 00000000000..6b9032778b0 --- /dev/null +++ b/include/apr_dbd.h @@ -0,0 +1,552 @@ +/* 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. + */ + +/* Overview of what this is and does: + * http://www.apache.org/~niq/dbd.html + */ + +#ifndef APR_DBD_H +#define APR_DBD_H + +#include "apu.h" +#include "apr_pools.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @file apr_dbd.h + * @brief APR-UTIL DBD library + */ +/** + * @defgroup APR_Util_DBD DBD routines + * @ingroup APR + * @{ + */ + +/** + * Mapping of C to SQL types, used for prepared statements. + * @remarks + * For apr_dbd_p[v]query/select functions, in and out parameters are always + * const char * (i.e. regular nul terminated strings). LOB types are passed + * with four (4) arguments: payload, length, table and column, all as const + * char *, where table and column are reserved for future use by Oracle. + * @remarks + * For apr_dbd_p[v]bquery/select functions, in and out parameters are + * described next to each enumeration constant and are generally native binary + * types or some APR data type. LOB types are passed with four (4) arguments: + * payload (char*), length (apr_size_t*), table (char*) and column (char*). + * Table and column are reserved for future use by Oracle. + */ +typedef enum { + APR_DBD_TYPE_NONE, + APR_DBD_TYPE_TINY, /**< \%hhd : in, out: char* */ + APR_DBD_TYPE_UTINY, /**< \%hhu : in, out: unsigned char* */ + APR_DBD_TYPE_SHORT, /**< \%hd : in, out: short* */ + APR_DBD_TYPE_USHORT, /**< \%hu : in, out: unsigned short* */ + APR_DBD_TYPE_INT, /**< \%d : in, out: int* */ + APR_DBD_TYPE_UINT, /**< \%u : in, out: unsigned int* */ + APR_DBD_TYPE_LONG, /**< \%ld : in, out: long* */ + APR_DBD_TYPE_ULONG, /**< \%lu : in, out: unsigned long* */ + APR_DBD_TYPE_LONGLONG, /**< \%lld : in, out: apr_int64_t* */ + APR_DBD_TYPE_ULONGLONG, /**< \%llu : in, out: apr_uint64_t* */ + APR_DBD_TYPE_FLOAT, /**< \%f : in, out: float* */ + APR_DBD_TYPE_DOUBLE, /**< \%lf : in, out: double* */ + APR_DBD_TYPE_STRING, /**< \%s : in: char*, out: char** */ + APR_DBD_TYPE_TEXT, /**< \%pDt : in: char*, out: char** */ + APR_DBD_TYPE_TIME, /**< \%pDi : in: char*, out: char** */ + APR_DBD_TYPE_DATE, /**< \%pDd : in: char*, out: char** */ + APR_DBD_TYPE_DATETIME, /**< \%pDa : in: char*, out: char** */ + APR_DBD_TYPE_TIMESTAMP, /**< \%pDs : in: char*, out: char** */ + APR_DBD_TYPE_ZTIMESTAMP, /**< \%pDz : in: char*, out: char** */ + APR_DBD_TYPE_BLOB, /**< \%pDb : in: char* apr_size_t* char* char*, out: apr_bucket_brigade* */ + APR_DBD_TYPE_CLOB, /**< \%pDc : in: char* apr_size_t* char* char*, out: apr_bucket_brigade* */ + APR_DBD_TYPE_NULL /**< \%pDn : in: void*, out: void** */ +} apr_dbd_type_e; + +/* These are opaque structs. Instantiation is up to each backend */ +typedef struct apr_dbd_driver_t apr_dbd_driver_t; +typedef struct apr_dbd_t apr_dbd_t; +typedef struct apr_dbd_transaction_t apr_dbd_transaction_t; +typedef struct apr_dbd_results_t apr_dbd_results_t; +typedef struct apr_dbd_row_t apr_dbd_row_t; +typedef struct apr_dbd_prepared_t apr_dbd_prepared_t; + +/** apr_dbd_init: perform once-only initialisation. Call once only. + * + * @param pool - pool to register any shutdown cleanups, etc + */ +APR_DECLARE(apr_status_t) apr_dbd_init(apr_pool_t *pool); + +/** apr_dbd_get_driver: get the driver struct for a name + * + * @param pool - (process) pool to register cleanup + * @param name - driver name + * @param driver - pointer to driver struct. + * @return APR_SUCCESS for success + * @return APR_ENOTIMPL for no driver (when DSO not enabled) + * @return APR_EDSOOPEN if DSO driver file can't be opened + * @return APR_ESYMNOTFOUND if the driver file doesn't contain a driver + */ +APR_DECLARE(apr_status_t) apr_dbd_get_driver(apr_pool_t *pool, const char *name, + const apr_dbd_driver_t **driver); + +/** apr_dbd_open_ex: open a connection to a backend + * + * @param driver - driver struct. + * @param pool - working pool + * @param params - arguments to driver (implementation-dependent) + * @param handle - pointer to handle to return + * @param error - descriptive error. + * @return APR_SUCCESS for success + * @return APR_EGENERAL if driver exists but connection failed + * @remarks PostgreSQL: the params is passed directly to the PQconnectdb() + * function (check PostgreSQL documentation for more details on the syntax). + * @remarks SQLite2: the params is split on a colon, with the first part used + * as the filename and second part converted to an integer and used as file + * mode. + * @remarks SQLite3: the params is passed directly to the sqlite3_open() + * function as a filename to be opened (check SQLite3 documentation for more + * details). + * @remarks Oracle: the params can have "user", "pass", "dbname" and "server" + * keys, each followed by an equal sign and a value. Such key/value pairs can + * be delimited by space, CR, LF, tab, semicolon, vertical bar or comma. + * @remarks MySQL: the params can have "host", "port", "user", "pass", + * "dbname", "sock", "flags" "fldsz", "group" and "reconnect" keys, each + * followed by an equal sign and a value. Such key/value pairs can be + * delimited by space, CR, LF, tab, semicolon, vertical bar or comma. For + * now, "flags" can only recognise CLIENT_FOUND_ROWS (check MySQL manual for + * details). The value associated with "fldsz" determines maximum amount of + * memory (in bytes) for each of the fields in the result set of prepared + * statements. By default, this value is 1 MB. The value associated with + * "group" determines which group from configuration file to use (see + * MYSQL_READ_DEFAULT_GROUP option of mysql_options() in MySQL manual). + * Reconnect is set to 1 by default (i.e. true). + * @remarks FreeTDS: the params can have "username", "password", "appname", + * "dbname", "host", "charset", "lang" and "server" keys, each followed by an + * equal sign and a value. + */ +APR_DECLARE(apr_status_t) apr_dbd_open_ex(const apr_dbd_driver_t *driver, + apr_pool_t *pool, const char *params, + apr_dbd_t **handle, + const char **error); + +/** apr_dbd_open: open a connection to a backend + * + * @param driver - driver struct. + * @param pool - working pool + * @param params - arguments to driver (implementation-dependent) + * @param handle - pointer to handle to return + * @return APR_SUCCESS for success + * @return APR_EGENERAL if driver exists but connection failed + * @see apr_dbd_open_ex + */ +APR_DECLARE(apr_status_t) apr_dbd_open(const apr_dbd_driver_t *driver, + apr_pool_t *pool, const char *params, + apr_dbd_t **handle); + +/** apr_dbd_close: close a connection to a backend + * + * @param driver - driver struct. + * @param handle - handle to close + * @return APR_SUCCESS for success or error status + */ +APR_DECLARE(apr_status_t) apr_dbd_close(const apr_dbd_driver_t *driver, + apr_dbd_t *handle); + +/* apr-function-shaped versions of things */ + +/** apr_dbd_name: get the name of the driver + * + * @param driver - the driver + * @return - name + */ +APR_DECLARE(const char*) apr_dbd_name(const apr_dbd_driver_t *driver); + +/** apr_dbd_native_handle: get native database handle of the underlying db + * + * @param driver - the driver + * @param handle - apr_dbd handle + * @return - native handle + */ +APR_DECLARE(void*) apr_dbd_native_handle(const apr_dbd_driver_t *driver, + apr_dbd_t *handle); + +/** check_conn: check status of a database connection + * + * @param driver - the driver + * @param pool - working pool + * @param handle - the connection to check + * @return APR_SUCCESS or error + */ +APR_DECLARE(int) apr_dbd_check_conn(const apr_dbd_driver_t *driver, apr_pool_t *pool, + apr_dbd_t *handle); + +/** apr_dbd_set_dbname: select database name. May be a no-op if not supported. + * + * @param driver - the driver + * @param pool - working pool + * @param handle - the connection + * @param name - the database to select + * @return 0 for success or error code + */ +APR_DECLARE(int) apr_dbd_set_dbname(const apr_dbd_driver_t *driver, apr_pool_t *pool, + apr_dbd_t *handle, const char *name); + +/** apr_dbd_transaction_start: start a transaction. May be a no-op. + * + * @param driver - the driver + * @param pool - a pool to use for error messages (if any). + * @param handle - the db connection + * @param trans - ptr to a transaction. May be null on entry + * @return 0 for success or error code + * @remarks Note that transaction modes, set by calling + * apr_dbd_transaction_mode_set(), will affect all query/select calls within + * a transaction. By default, any error in query/select during a transaction + * will cause the transaction to inherit the error code and any further + * query/select calls will fail immediately. Put transaction in "ignore + * errors" mode to avoid that. Use "rollback" mode to do explicit rollback. + */ +APR_DECLARE(int) apr_dbd_transaction_start(const apr_dbd_driver_t *driver, + apr_pool_t *pool, + apr_dbd_t *handle, + apr_dbd_transaction_t **trans); + +/** apr_dbd_transaction_end: end a transaction + * (commit on success, rollback on error). + * May be a no-op. + * + * @param driver - the driver + * @param pool - working pool + * @param trans - the transaction + * @return 0 for success or error code + */ +APR_DECLARE(int) apr_dbd_transaction_end(const apr_dbd_driver_t *driver, + apr_pool_t *pool, + apr_dbd_transaction_t *trans); + +#define APR_DBD_TRANSACTION_COMMIT 0x00 /**< commit the transaction */ +#define APR_DBD_TRANSACTION_ROLLBACK 0x01 /**< rollback the transaction */ +#define APR_DBD_TRANSACTION_IGNORE_ERRORS 0x02 /**< ignore transaction errors */ + +/** apr_dbd_transaction_mode_get: get the mode of transaction + * + * @param driver - the driver + * @param trans - the transaction + * @return mode of transaction + */ +APR_DECLARE(int) apr_dbd_transaction_mode_get(const apr_dbd_driver_t *driver, + apr_dbd_transaction_t *trans); + +/** apr_dbd_transaction_mode_set: set the mode of transaction + * + * @param driver - the driver + * @param trans - the transaction + * @param mode - new mode of the transaction + * @return the mode of transaction in force after the call + */ +APR_DECLARE(int) apr_dbd_transaction_mode_set(const apr_dbd_driver_t *driver, + apr_dbd_transaction_t *trans, + int mode); + +/** apr_dbd_query: execute an SQL query that doesn't return a result set + * + * @param driver - the driver + * @param handle - the connection + * @param nrows - number of rows affected. + * @param statement - the SQL statement to execute + * @return 0 for success or error code + */ +APR_DECLARE(int) apr_dbd_query(const apr_dbd_driver_t *driver, apr_dbd_t *handle, + int *nrows, const char *statement); + +/** apr_dbd_select: execute an SQL query that returns a result set + * + * @param driver - the driver + * @param pool - pool to allocate the result set + * @param handle - the connection + * @param res - pointer to result set pointer. May point to NULL on entry + * @param statement - the SQL statement to execute + * @param random - 1 to support random access to results (seek any row); + * 0 to support only looping through results in order + * (async access - faster) + * @return 0 for success or error code + */ +APR_DECLARE(int) apr_dbd_select(const apr_dbd_driver_t *driver, apr_pool_t *pool, + apr_dbd_t *handle, apr_dbd_results_t **res, + const char *statement, int random); + +/** apr_dbd_num_cols: get the number of columns in a results set + * + * @param driver - the driver + * @param res - result set. + * @return number of columns + */ +APR_DECLARE(int) apr_dbd_num_cols(const apr_dbd_driver_t *driver, + apr_dbd_results_t *res); + +/** apr_dbd_num_tuples: get the number of rows in a results set + * of a synchronous select + * + * @param driver - the driver + * @param res - result set. + * @return number of rows, or -1 if the results are asynchronous + */ +APR_DECLARE(int) apr_dbd_num_tuples(const apr_dbd_driver_t *driver, + apr_dbd_results_t *res); + +/** apr_dbd_get_row: get a row from a result set + * + * @param driver - the driver + * @param pool - pool to allocate the row + * @param res - result set pointer + * @param row - pointer to row pointer. May point to NULL on entry + * @param rownum - row number (counting from 1), or -1 for "next row". + * Ignored if random access is not supported. + * @return 0 for success, -1 for rownum out of range or data finished + */ +APR_DECLARE(int) apr_dbd_get_row(const apr_dbd_driver_t *driver, apr_pool_t *pool, + apr_dbd_results_t *res, apr_dbd_row_t **row, + int rownum); + +/** apr_dbd_get_entry: get an entry from a row + * + * @param driver - the driver + * @param row - row pointer + * @param col - entry number + * @return value from the row, or NULL if col is out of bounds. + */ +APR_DECLARE(const char*) apr_dbd_get_entry(const apr_dbd_driver_t *driver, + apr_dbd_row_t *row, int col); + +/** apr_dbd_get_name: get an entry name from a result set + * + * @param driver - the driver + * @param res - result set pointer + * @param col - entry number + * @return name of the entry, or NULL if col is out of bounds. + */ +APR_DECLARE(const char*) apr_dbd_get_name(const apr_dbd_driver_t *driver, + apr_dbd_results_t *res, int col); + + +/** apr_dbd_error: get current error message (if any) + * + * @param driver - the driver + * @param handle - the connection + * @param errnum - error code from operation that returned an error + * @return the database current error message, or message for errnum + * (implementation-dependent whether errnum is ignored) + */ +APR_DECLARE(const char*) apr_dbd_error(const apr_dbd_driver_t *driver, + apr_dbd_t *handle, int errnum); + +/** apr_dbd_escape: escape a string so it is safe for use in query/select + * + * @param driver - the driver + * @param pool - pool to alloc the result from + * @param string - the string to escape + * @param handle - the connection + * @return the escaped, safe string + */ +APR_DECLARE(const char*) apr_dbd_escape(const apr_dbd_driver_t *driver, + apr_pool_t *pool, const char *string, + apr_dbd_t *handle); + +/** apr_dbd_prepare: prepare a statement + * + * @param driver - the driver + * @param pool - pool to alloc the result from + * @param handle - the connection + * @param query - the SQL query + * @param label - A label for the prepared statement. + * use NULL for temporary prepared statements + * (eg within a Request in httpd) + * @param statement - statement to prepare. May point to null on entry. + * @return 0 for success or error code + * @remarks To specify parameters of the prepared query, use \%s, \%d etc. + * (see below for full list) in place of database specific parameter syntax + * (e.g. for PostgreSQL, this would be $1, $2, for SQLite3 this would be ? + * etc.). For instance: "SELECT name FROM customers WHERE name=%s" would be + * a query that this function understands. + * @remarks Here is the full list of format specifiers that this function + * understands and what they map to in SQL: \%hhd (TINY INT), \%hhu (UNSIGNED + * TINY INT), \%hd (SHORT), \%hu (UNSIGNED SHORT), \%d (INT), \%u (UNSIGNED + * INT), \%ld (LONG), \%lu (UNSIGNED LONG), \%lld (LONG LONG), \%llu + * (UNSIGNED LONG LONG), \%f (FLOAT, REAL), \%lf (DOUBLE PRECISION), \%s + * (VARCHAR), \%pDt (TEXT), \%pDi (TIME), \%pDd (DATE), \%pDa (DATETIME), + * \%pDs (TIMESTAMP), \%pDz (TIMESTAMP WITH TIME ZONE), \%pDb (BLOB), \%pDc + * (CLOB) and \%pDn (NULL). Not all databases have support for all these + * types, so the underlying driver will attempt the "best match" where + * possible. A \% followed by any letter not in the above list will be + * interpreted as VARCHAR (i.e. \%s). + */ +APR_DECLARE(int) apr_dbd_prepare(const apr_dbd_driver_t *driver, apr_pool_t *pool, + apr_dbd_t *handle, const char *query, + const char *label, + apr_dbd_prepared_t **statement); + + +/** apr_dbd_pquery: query using a prepared statement + args + * + * @param driver - the driver + * @param pool - working pool + * @param handle - the connection + * @param nrows - number of rows affected. + * @param statement - the prepared statement to execute + * @param nargs - ignored (for backward compatibility only) + * @param args - args to prepared statement + * @return 0 for success or error code + */ +APR_DECLARE(int) apr_dbd_pquery(const apr_dbd_driver_t *driver, apr_pool_t *pool, + apr_dbd_t *handle, int *nrows, + apr_dbd_prepared_t *statement, int nargs, + const char **args); + +/** apr_dbd_pselect: select using a prepared statement + args + * + * @param driver - the driver + * @param pool - working pool + * @param handle - the connection + * @param res - pointer to query results. May point to NULL on entry + * @param statement - the prepared statement to execute + * @param random - Whether to support random-access to results + * @param nargs - ignored (for backward compatibility only) + * @param args - args to prepared statement + * @return 0 for success or error code + */ +APR_DECLARE(int) apr_dbd_pselect(const apr_dbd_driver_t *driver, apr_pool_t *pool, + apr_dbd_t *handle, apr_dbd_results_t **res, + apr_dbd_prepared_t *statement, int random, + int nargs, const char **args); + +/** apr_dbd_pvquery: query using a prepared statement + args + * + * @param driver - the driver + * @param pool - working pool + * @param handle - the connection + * @param nrows - number of rows affected. + * @param statement - the prepared statement to execute + * @param ... - varargs list + * @return 0 for success or error code + */ +APR_DECLARE_NONSTD(int) apr_dbd_pvquery(const apr_dbd_driver_t *driver, + apr_pool_t *pool, + apr_dbd_t *handle, int *nrows, + apr_dbd_prepared_t *statement, ...); + +/** apr_dbd_pvselect: select using a prepared statement + args + * + * @param driver - the driver + * @param pool - working pool + * @param handle - the connection + * @param res - pointer to query results. May point to NULL on entry + * @param statement - the prepared statement to execute + * @param random - Whether to support random-access to results + * @param ... - varargs list + * @return 0 for success or error code + */ +APR_DECLARE_NONSTD(int) apr_dbd_pvselect(const apr_dbd_driver_t *driver, + apr_pool_t *pool, apr_dbd_t *handle, + apr_dbd_results_t **res, + apr_dbd_prepared_t *statement, + int random, ...); + +/** apr_dbd_pbquery: query using a prepared statement + binary args + * + * @param driver - the driver + * @param pool - working pool + * @param handle - the connection + * @param nrows - number of rows affected. + * @param statement - the prepared statement to execute + * @param args - binary args to prepared statement + * @return 0 for success or error code + */ +APR_DECLARE(int) apr_dbd_pbquery(const apr_dbd_driver_t *driver, + apr_pool_t *pool, apr_dbd_t *handle, + int *nrows, apr_dbd_prepared_t *statement, + const void **args); + +/** apr_dbd_pbselect: select using a prepared statement + binary args + * + * @param driver - the driver + * @param pool - working pool + * @param handle - the connection + * @param res - pointer to query results. May point to NULL on entry + * @param statement - the prepared statement to execute + * @param random - Whether to support random-access to results + * @param args - binary args to prepared statement + * @return 0 for success or error code + */ +APR_DECLARE(int) apr_dbd_pbselect(const apr_dbd_driver_t *driver, + apr_pool_t *pool, + apr_dbd_t *handle, apr_dbd_results_t **res, + apr_dbd_prepared_t *statement, int random, + const void **args); + +/** apr_dbd_pvbquery: query using a prepared statement + binary args + * + * @param driver - the driver + * @param pool - working pool + * @param handle - the connection + * @param nrows - number of rows affected. + * @param statement - the prepared statement to execute + * @param ... - varargs list of binary args + * @return 0 for success or error code + */ +APR_DECLARE_NONSTD(int) apr_dbd_pvbquery(const apr_dbd_driver_t *driver, + apr_pool_t *pool, + apr_dbd_t *handle, int *nrows, + apr_dbd_prepared_t *statement, ...); + +/** apr_dbd_pvbselect: select using a prepared statement + binary args + * + * @param driver - the driver + * @param pool - working pool + * @param handle - the connection + * @param res - pointer to query results. May point to NULL on entry + * @param statement - the prepared statement to execute + * @param random - Whether to support random-access to results + * @param ... - varargs list of binary args + * @return 0 for success or error code + */ +APR_DECLARE_NONSTD(int) apr_dbd_pvbselect(const apr_dbd_driver_t *driver, + apr_pool_t *pool, apr_dbd_t *handle, + apr_dbd_results_t **res, + apr_dbd_prepared_t *statement, + int random, ...); + +/** apr_dbd_datum_get: get a binary entry from a row + * + * @param driver - the driver + * @param row - row pointer + * @param col - entry number + * @param type - type of data to get + * @param data - pointer to data, allocated by the caller + * @return APR_SUCCESS on success, APR_ENOENT if data is NULL or APR_EGENERAL + */ +APR_DECLARE(apr_status_t) apr_dbd_datum_get(const apr_dbd_driver_t *driver, + apr_dbd_row_t *row, int col, + apr_dbd_type_e type, void *data); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/apr_dbm.h b/include/apr_dbm.h new file mode 100644 index 00000000000..017b9edea54 --- /dev/null +++ b/include/apr_dbm.h @@ -0,0 +1,227 @@ +/* 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. + */ + +#ifndef APR_DBM_H +#define APR_DBM_H + +#include "apu.h" +#include "apr.h" +#include "apr_errno.h" +#include "apr_pools.h" +#include "apr_file_info.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @file apr_dbm.h + * @brief APR-UTIL DBM library + */ +/** + * @defgroup APR_Util_DBM DBM routines + * @ingroup APR + * @{ + */ +/** + * Structure for referencing a dbm + */ +typedef struct apr_dbm_t apr_dbm_t; + +/** + * Structure for referencing the datum record within a dbm + */ +typedef struct +{ + /** pointer to the 'data' to retrieve/store in the DBM */ + char *dptr; + /** size of the 'data' to retrieve/store in the DBM */ + apr_size_t dsize; +} apr_datum_t; + +/* modes to open the DB */ +#define APR_DBM_READONLY 1 /**< open for read-only access */ +#define APR_DBM_READWRITE 2 /**< open for read-write access */ +#define APR_DBM_RWCREATE 3 /**< open for r/w, create if needed */ +#define APR_DBM_RWTRUNC 4 /**< open for r/w, truncating an existing + DB if present */ +/** + * Open a dbm file by file name and type of DBM + * @param dbm The newly opened database + * @param type The type of the DBM (not all may be available at run time) + * <pre> + * db for Berkeley DB files + * gdbm for GDBM files + * ndbm for NDBM files + * sdbm for SDBM files (always available) + * default for the default DBM type + * </pre> + * @param name The dbm file name to open + * @param mode The flag value + * <PRE> + * APR_DBM_READONLY open for read-only access + * APR_DBM_READWRITE open for read-write access + * APR_DBM_RWCREATE open for r/w, create if needed + * APR_DBM_RWTRUNC open for r/w, truncate if already there + * </PRE> + * @param perm Permissions to apply to if created + * @param cntxt The pool to use when creating the dbm + * @remark The dbm name may not be a true file name, as many dbm packages + * append suffixes for seperate data and index files. + * @bug In apr-util 0.9 and 1.x, the type arg was case insensitive. This + * was highly inefficient, and as of 2.x the dbm name must be provided in + * the correct case (lower case for all bundled providers) + */ + +APR_DECLARE(apr_status_t) apr_dbm_open_ex(apr_dbm_t **dbm, const char* type, + const char *name, + apr_int32_t mode, apr_fileperms_t perm, + apr_pool_t *cntxt); + + +/** + * Open a dbm file by file name + * @param dbm The newly opened database + * @param name The dbm file name to open + * @param mode The flag value + * <PRE> + * APR_DBM_READONLY open for read-only access + * APR_DBM_READWRITE open for read-write access + * APR_DBM_RWCREATE open for r/w, create if needed + * APR_DBM_RWTRUNC open for r/w, truncate if already there + * </PRE> + * @param perm Permissions to apply to if created + * @param cntxt The pool to use when creating the dbm + * @remark The dbm name may not be a true file name, as many dbm packages + * append suffixes for seperate data and index files. + */ +APR_DECLARE(apr_status_t) apr_dbm_open(apr_dbm_t **dbm, const char *name, + apr_int32_t mode, apr_fileperms_t perm, + apr_pool_t *cntxt); + +/** + * Close a dbm file previously opened by apr_dbm_open + * @param dbm The database to close + */ +APR_DECLARE(void) apr_dbm_close(apr_dbm_t *dbm); + +/** + * Fetch a dbm record value by key + * @param dbm The database + * @param key The key datum to find this record + * @param pvalue The value datum retrieved for this record + */ +APR_DECLARE(apr_status_t) apr_dbm_fetch(apr_dbm_t *dbm, apr_datum_t key, + apr_datum_t *pvalue); +/** + * Store a dbm record value by key + * @param dbm The database + * @param key The key datum to store this record by + * @param value The value datum to store in this record + */ +APR_DECLARE(apr_status_t) apr_dbm_store(apr_dbm_t *dbm, apr_datum_t key, + apr_datum_t value); + +/** + * Delete a dbm record value by key + * @param dbm The database + * @param key The key datum of the record to delete + * @remark It is not an error to delete a non-existent record. + */ +APR_DECLARE(apr_status_t) apr_dbm_delete(apr_dbm_t *dbm, apr_datum_t key); + +/** + * Search for a key within the dbm + * @param dbm The database + * @param key The datum describing a key to test + */ +APR_DECLARE(int) apr_dbm_exists(apr_dbm_t *dbm, apr_datum_t key); + +/** + * Retrieve the first record key from a dbm + * @param dbm The database + * @param pkey The key datum of the first record + */ +APR_DECLARE(apr_status_t) apr_dbm_firstkey(apr_dbm_t *dbm, apr_datum_t *pkey); + +/** + * Retrieve the next record key from a dbm + * @param dbm The database + * @param pkey The key datum of the next record + */ +APR_DECLARE(apr_status_t) apr_dbm_nextkey(apr_dbm_t *dbm, apr_datum_t *pkey); + +/** + * Proactively toss any memory associated with the apr_datum_t. + * @param dbm The database + * @param data The datum to free. + */ +APR_DECLARE(void) apr_dbm_freedatum(apr_dbm_t *dbm, apr_datum_t data); + +/** + * Report more information when an apr_dbm function fails. + * @param dbm The database + * @param errcode A DBM-specific value for the error (for logging). If this + * isn't needed, it may be NULL. + * @param errbuf Location to store the error text + * @param errbufsize The size of the provided buffer + * @return The errbuf parameter, for convenience. + */ +APR_DECLARE(char *) apr_dbm_geterror(apr_dbm_t *dbm, int *errcode, + char *errbuf, apr_size_t errbufsize); +/** + * If the specified file/path were passed to apr_dbm_open(), return the + * actual file/path names which would be (created and) used. At most, two + * files may be used; used2 may be NULL if only one file is used. + * @param pool The pool for allocating used1 and used2. + * @param type The type of DBM you require info on @see apr_dbm_open_ex + * @param pathname The path name to generate used-names from. + * @param used1 The first pathname used by the apr_dbm implementation. + * @param used2 The second pathname used by apr_dbm. If only one file is + * used by the specific implementation, this will be set to NULL. + * @return An error if the specified type is invalid. + * @remark The dbm file(s) don't need to exist. This function only manipulates + * the pathnames. + */ +APR_DECLARE(apr_status_t) apr_dbm_get_usednames_ex(apr_pool_t *pool, + const char *type, + const char *pathname, + const char **used1, + const char **used2); + +/** + * If the specified file/path were passed to apr_dbm_open(), return the + * actual file/path names which would be (created and) used. At most, two + * files may be used; used2 may be NULL if only one file is used. + * @param pool The pool for allocating used1 and used2. + * @param pathname The path name to generate used-names from. + * @param used1 The first pathname used by the apr_dbm implementation. + * @param used2 The second pathname used by apr_dbm. If only one file is + * used by the specific implementation, this will be set to NULL. + * @remark The dbm file(s) don't need to exist. This function only manipulates + * the pathnames. + */ +APR_DECLARE(void) apr_dbm_get_usednames(apr_pool_t *pool, + const char *pathname, + const char **used1, + const char **used2); + +/** @} */ +#ifdef __cplusplus +} +#endif + +#endif /* !APR_DBM_H */ diff --git a/include/apr_dso.h b/include/apr_dso.h index 01f71c34ca1..ac701cfdf55 100644 --- a/include/apr_dso.h +++ b/include/apr_dso.h @@ -1,121 +1,92 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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. */ #ifndef APR_DSO_DOT_H #define APR_DSO_DOT_H -#include "apr_general.h" +/** + * @file apr_dso.h + * @brief APR Dynamic Object Handling Routines + */ + +#include "apr.h" +#include "apr_pools.h" #include "apr_errno.h" #ifdef __cplusplus extern "C" { #endif -typedef struct ap_dso_handle_t ap_dso_handle_t; -typedef void * ap_dso_handle_sym_t; - -/* - -=head1 ap_status_t ap_dso_init(void) - -B<Initialize the underlying DSO library.> - -=cut +/** + * @defgroup apr_dso Dynamic Object Handling + * @ingroup APR + * @{ */ -ap_status_t ap_dso_init(void); -/* +#if APR_HAS_DSO || defined(DOXYGEN) -=head1 ap_status_t ap_dso_load(ap_dso_handle_t **res_handle, const char *path, ap_pool_t *ctx) - -B<Load a DSO library.> - - arg 1) Location to store new handle for the DSO. - arg 2) Path to the DSO library - arg 3) Pool to use. - -=cut +/** + * Structure for referencing dynamic objects */ -ap_status_t ap_dso_load(ap_dso_handle_t **res_handle, const char *path, - ap_pool_t *ctx); - -/* - -=head1 ap_status_t ap_dso_unload(ap_dso_handle_t *handle) - -B<Close a DSO library.> +typedef struct apr_dso_handle_t apr_dso_handle_t; - arg 1) handle to close. - -=cut +/** + * Structure for referencing symbols from dynamic objects + */ +typedef void * apr_dso_handle_sym_t; + +/** + * Load a DSO library. + * @param res_handle Location to store new handle for the DSO. + * @param path Path to the DSO library + * @param ctx Pool to use. + * @bug We aught to provide an alternative to RTLD_GLOBAL, which + * is the only supported method of loading DSOs today. */ -ap_status_t ap_dso_unload(ap_dso_handle_t *handle); +APR_DECLARE(apr_status_t) apr_dso_load(apr_dso_handle_t **res_handle, + const char *path, apr_pool_t *ctx); -/* +/** + * Close a DSO library. + * @param handle handle to close. + */ +APR_DECLARE(apr_status_t) apr_dso_unload(apr_dso_handle_t *handle); -=head1 ap_status_t ap_dso_sym(ap_dso_handle_sym_t *ressym, ap_dso_handle_t *handle *, const char *symname) +/** + * Load a symbol from a DSO handle. + * @param ressym Location to store the loaded symbol + * @param handle handle to load the symbol from. + * @param symname Name of the symbol to load. + */ +APR_DECLARE(apr_status_t) apr_dso_sym(apr_dso_handle_sym_t *ressym, + apr_dso_handle_t *handle, + const char *symname); + +/** + * Report more information when a DSO function fails. + * @param dso The dso handle that has been opened + * @param buf Location to store the dso error + * @param bufsize The size of the provided buffer + */ +APR_DECLARE(const char *) apr_dso_error(apr_dso_handle_t *dso, char *buf, apr_size_t bufsize); -B<Load a symbol from a DSO handle.> +#endif /* APR_HAS_DSO */ - arg 1) Location to store the loaded symbol - arg 2) handle to load from. - arg 3) Name of the symbol to load. +/** @} */ -=cut - */ -ap_status_t ap_dso_sym(ap_dso_handle_sym_t *ressym, ap_dso_handle_t *handle, - const char *symname); #ifdef __cplusplus } #endif diff --git a/include/apr_env.h b/include/apr_env.h new file mode 100644 index 00000000000..85ab67041fa --- /dev/null +++ b/include/apr_env.h @@ -0,0 +1,67 @@ +/* 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. + */ + +#ifndef APR_ENV_H +#define APR_ENV_H +/** + * @file apr_env.h + * @brief APR Environment functions + */ +#include "apr_errno.h" +#include "apr_pools.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup apr_env Functions for manipulating the environment + * @ingroup APR + * @{ + */ + +/** + * Get the value of an environment variable + * @param value the returned value, allocated from @a pool + * @param envvar the name of the environment variable + * @param pool where to allocate @a value and any temporary storage from + */ +APR_DECLARE(apr_status_t) apr_env_get(char **value, const char *envvar, + apr_pool_t *pool); + +/** + * Set the value of an environment variable + * @param envvar the name of the environment variable + * @param value the value to set + * @param pool where to allocate temporary storage from + */ +APR_DECLARE(apr_status_t) apr_env_set(const char *envvar, const char *value, + apr_pool_t *pool); + +/** + * Delete a variable from the environment + * @param envvar the name of the environment variable + * @param pool where to allocate temporary storage from + */ +APR_DECLARE(apr_status_t) apr_env_delete(const char *envvar, apr_pool_t *pool); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* ! APR_ENV_H */ diff --git a/include/apr_errno.h b/include/apr_errno.h index 9eb186e41fd..d2abfb18f8b 100644 --- a/include/apr_errno.h +++ b/include/apr_errno.h @@ -1,249 +1,1342 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. +/* 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. */ #ifndef APR_ERRNO_H #define APR_ERRNO_H +/** + * @file apr_errno.h + * @brief APR Error Codes + */ + #include "apr.h" + +#if APR_HAVE_ERRNO_H #include <errno.h> +#endif #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ -typedef int ap_status_t; +/** + * @defgroup apr_errno Error Codes + * @ingroup APR + * @{ + */ + +/** + * Type for specifying an error or status code. + */ +typedef int apr_status_t; + +/** + * Return a human readable string describing the specified error. + * @param statcode The error code to get a string for. + * @param buf A buffer to hold the error string. + * @param bufsize Size of the buffer to hold the string. + */ +APR_DECLARE(char *) apr_strerror(apr_status_t statcode, char *buf, + apr_size_t bufsize); + +#if defined(DOXYGEN) +/** + * @def APR_FROM_OS_ERROR(os_err_type syserr) + * Fold a platform specific error into an apr_status_t code. + * @return apr_status_t + * @param e The platform os error code. + * @warning macro implementation; the syserr argument may be evaluated + * multiple times. + */ +#define APR_FROM_OS_ERROR(e) (e == 0 ? APR_SUCCESS : e + APR_OS_START_SYSERR) + +/** + * @def APR_TO_OS_ERROR(apr_status_t statcode) + * @return os_err_type + * Fold an apr_status_t code back to the native platform defined error. + * @param e The apr_status_t folded platform os error code. + * @warning macro implementation; the statcode argument may be evaluated + * multiple times. If the statcode was not created by apr_get_os_error + * or APR_FROM_OS_ERROR, the results are undefined. + */ +#define APR_TO_OS_ERROR(e) (e == 0 ? APR_SUCCESS : e - APR_OS_START_SYSERR) -int ap_canonical_error(ap_status_t err); +/** @def apr_get_os_error() + * @return apr_status_t the last platform error, folded into apr_status_t, on most platforms + * @remark This retrieves errno, or calls a GetLastError() style function, and + * folds it with APR_FROM_OS_ERROR. Some platforms (such as OS2) have no + * such mechanism, so this call may be unsupported. Do NOT use this + * call for socket errors from socket, send, recv etc! + */ + +/** @def apr_set_os_error(e) + * Reset the last platform error, unfolded from an apr_status_t, on some platforms + * @param e The OS error folded in a prior call to APR_FROM_OS_ERROR() + * @warning This is a macro implementation; the statcode argument may be evaluated + * multiple times. If the statcode was not created by apr_get_os_error + * or APR_FROM_OS_ERROR, the results are undefined. This macro sets + * errno, or calls a SetLastError() style function, unfolding statcode + * with APR_TO_OS_ERROR. Some platforms (such as OS2) have no such + * mechanism, so this call may be unsupported. + */ +/** @def apr_get_netos_error() + * Return the last socket error, folded into apr_status_t, on all platforms + * @remark This retrieves errno or calls a GetLastSocketError() style function, + * and folds it with APR_FROM_OS_ERROR. + */ -/* APR_OS_START_ERROR is where the APR specific error values should start. - * APR_OS_START_STATUS is where the APR specific status codes should start. - * APR_OS_START_USEERR are reserved for applications that use APR that - * layer their own error codes along with APR's. - * APR_OS_START_SYSERR should be used for system error values on - * each platform. +/** @def apr_set_netos_error(e) + * Reset the last socket error, unfolded from an apr_status_t + * @param e The socket error folded in a prior call to APR_FROM_OS_ERROR() + * @warning This is a macro implementation; the statcode argument may be evaluated + * multiple times. If the statcode was not created by apr_get_os_error + * or APR_FROM_OS_ERROR, the results are undefined. This macro sets + * errno, or calls a WSASetLastError() style function, unfolding + * socketcode with APR_TO_OS_ERROR. */ -#define APR_OS_START_ERROR 1000 -#define APR_OS_START_STATUS (APR_OS_START_ERROR + 500) -#define APR_OS_START_USEERR (APR_OS_START_STATUS + 500) -#define APR_OS_START_CANONERR (APR_OS_START_USEERR + 500) -#define APR_OS_START_SYSERR (APR_OS_START_CANONERR + 500) -#define APR_OS2_STATUS(e) (e == 0 ? APR_SUCCESS : e + APR_OS_START_SYSERR) +#endif /* defined(DOXYGEN) */ + +/** + * APR_OS_START_ERROR is where the APR specific error values start. + */ +#define APR_OS_START_ERROR 20000 +/** + * APR_OS_ERRSPACE_SIZE is the maximum number of errors you can fit + * into one of the error/status ranges below -- except for + * APR_OS_START_USERERR, which see. + */ +#define APR_OS_ERRSPACE_SIZE 50000 +/** + * APR_UTIL_ERRSPACE_SIZE is the size of the space that is reserved for + * use within apr-util. This space is reserved above that used by APR + * internally. + * @note This number MUST be smaller than APR_OS_ERRSPACE_SIZE by a + * large enough amount that APR has sufficient room for its + * codes. + */ +#define APR_UTIL_ERRSPACE_SIZE 20000 +/** + * APR_OS_START_STATUS is where the APR specific status codes start. + */ +#define APR_OS_START_STATUS (APR_OS_START_ERROR + APR_OS_ERRSPACE_SIZE) +/** + * APR_UTIL_START_STATUS is where APR-Util starts defining its + * status codes. + */ +#define APR_UTIL_START_STATUS (APR_OS_START_STATUS + \ + (APR_OS_ERRSPACE_SIZE - APR_UTIL_ERRSPACE_SIZE)) +/** + * APR_OS_START_USERERR are reserved for applications that use APR that + * layer their own error codes along with APR's. Note that the + * error immediately following this one is set ten times farther + * away than usual, so that users of apr have a lot of room in + * which to declare custom error codes. + * + * In general applications should try and create unique error codes. To try + * and assist in finding suitable ranges of numbers to use, the following + * ranges are known to be used by the listed applications. If your + * application defines error codes please advise the range of numbers it + * uses to dev@apr.apache.org for inclusion in this list. + * + * Ranges shown are in relation to APR_OS_START_USERERR + * + * Subversion - Defined ranges, of less than 100, at intervals of 5000 + * starting at an offset of 5000, e.g. + * +5000 to 5100, +10000 to 10100 + * + * Apache HTTPD - +2000 to 2999 + */ +#define APR_OS_START_USERERR (APR_OS_START_STATUS + APR_OS_ERRSPACE_SIZE) +/** + * APR_OS_START_USEERR is obsolete, defined for compatibility only. + * Use APR_OS_START_USERERR instead. + */ +#define APR_OS_START_USEERR APR_OS_START_USERERR +/** + * APR_OS_START_CANONERR is where APR versions of errno values are defined + * on systems which don't have the corresponding errno. + */ +#define APR_OS_START_CANONERR (APR_OS_START_USERERR \ + + (APR_OS_ERRSPACE_SIZE * 10)) +/** + * APR_OS_START_EAIERR folds EAI_ error codes from getaddrinfo() into + * apr_status_t values. + */ +#define APR_OS_START_EAIERR (APR_OS_START_CANONERR + APR_OS_ERRSPACE_SIZE) +/** + * APR_OS_START_SYSERR folds platform-specific system error values into + * apr_status_t values. + */ +#define APR_OS_START_SYSERR (APR_OS_START_EAIERR + APR_OS_ERRSPACE_SIZE) +/** + * @defgroup APR_ERROR_map APR Error Space + * <PRE> + * The following attempts to show the relation of the various constants + * used for mapping APR Status codes. + * + * 0 + * + * 20,000 APR_OS_START_ERROR + * + * + APR_OS_ERRSPACE_SIZE (50,000) + * + * 70,000 APR_OS_START_STATUS + * + * + APR_OS_ERRSPACE_SIZE - APR_UTIL_ERRSPACE_SIZE (30,000) + * + * 100,000 APR_UTIL_START_STATUS + * + * + APR_UTIL_ERRSPACE_SIZE (20,000) + * + * 120,000 APR_OS_START_USERERR + * + * + 10 x APR_OS_ERRSPACE_SIZE (50,000 * 10) + * + * 620,000 APR_OS_START_CANONERR + * + * + APR_OS_ERRSPACE_SIZE (50,000) + * + * 670,000 APR_OS_START_EAIERR + * + * + APR_OS_ERRSPACE_SIZE (50,000) + * + * 720,000 APR_OS_START_SYSERR + * + * </PRE> + */ + +/** no error. */ #define APR_SUCCESS 0 -/* APR ERROR VALUES */ +/** + * @defgroup APR_Error APR Error Values + * <PRE> + * <b>APR ERROR VALUES</b> + * APR_ENOSTAT APR was unable to perform a stat on the file + * APR_ENOPOOL APR was not provided a pool with which to allocate memory + * APR_EBADDATE APR was given an invalid date + * APR_EINVALSOCK APR was given an invalid socket + * APR_ENOPROC APR was not given a process structure + * APR_ENOTIME APR was not given a time structure + * APR_ENODIR APR was not given a directory structure + * APR_ENOLOCK APR was not given a lock structure + * APR_ENOPOLL APR was not given a poll structure + * APR_ENOSOCKET APR was not given a socket + * APR_ENOTHREAD APR was not given a thread structure + * APR_ENOTHDKEY APR was not given a thread key structure + * APR_ENOSHMAVAIL There is no more shared memory available + * APR_EDSOOPEN APR was unable to open the dso object. For more + * information call apr_dso_error(). + * APR_EGENERAL General failure (specific information not available) + * APR_EBADIP The specified IP address is invalid + * APR_EBADMASK The specified netmask is invalid + * APR_ESYMNOTFOUND Could not find the requested symbol + * APR_ENOTENOUGHENTROPY Not enough entropy to continue + * </PRE> + * + * <PRE> + * <b>APR STATUS VALUES</b> + * APR_INCHILD Program is currently executing in the child + * APR_INPARENT Program is currently executing in the parent + * APR_DETACH The thread is detached + * APR_NOTDETACH The thread is not detached + * APR_CHILD_DONE The child has finished executing + * APR_CHILD_NOTDONE The child has not finished executing + * APR_TIMEUP The operation did not finish before the timeout + * APR_INCOMPLETE The operation was incomplete although some processing + * was performed and the results are partially valid + * APR_BADCH Getopt found an option not in the option string + * APR_BADARG Getopt found an option that is missing an argument + * and an argument was specified in the option string + * APR_EOF APR has encountered the end of the file + * APR_NOTFOUND APR was unable to find the socket in the poll structure + * APR_ANONYMOUS APR is using anonymous shared memory + * APR_FILEBASED APR is using a file name as the key to the shared memory + * APR_KEYBASED APR is using a shared key as the key to the shared memory + * APR_EINIT Ininitalizer value. If no option has been found, but + * the status variable requires a value, this should be used + * APR_ENOTIMPL The APR function has not been implemented on this + * platform, either because nobody has gotten to it yet, + * or the function is impossible on this platform. + * APR_EMISMATCH Two passwords do not match. + * APR_EABSOLUTE The given path was absolute. + * APR_ERELATIVE The given path was relative. + * APR_EINCOMPLETE The given path was neither relative nor absolute. + * APR_EABOVEROOT The given path was above the root path. + * APR_EBUSY The given lock was busy. + * APR_EPROC_UNKNOWN The given process wasn't recognized by APR + * </PRE> + * @{ + */ +/** @see APR_STATUS_IS_ENOSTAT */ #define APR_ENOSTAT (APR_OS_START_ERROR + 1) +/** @see APR_STATUS_IS_ENOPOOL */ #define APR_ENOPOOL (APR_OS_START_ERROR + 2) -#define APR_ENOFILE (APR_OS_START_ERROR + 3) +/* empty slot: +3 */ +/** @see APR_STATUS_IS_EBADDATE */ #define APR_EBADDATE (APR_OS_START_ERROR + 4) +/** @see APR_STATUS_IS_EINVALSOCK */ #define APR_EINVALSOCK (APR_OS_START_ERROR + 5) +/** @see APR_STATUS_IS_ENOPROC */ #define APR_ENOPROC (APR_OS_START_ERROR + 6) +/** @see APR_STATUS_IS_ENOTIME */ #define APR_ENOTIME (APR_OS_START_ERROR + 7) +/** @see APR_STATUS_IS_ENODIR */ #define APR_ENODIR (APR_OS_START_ERROR + 8) +/** @see APR_STATUS_IS_ENOLOCK */ #define APR_ENOLOCK (APR_OS_START_ERROR + 9) +/** @see APR_STATUS_IS_ENOPOLL */ #define APR_ENOPOLL (APR_OS_START_ERROR + 10) +/** @see APR_STATUS_IS_ENOSOCKET */ #define APR_ENOSOCKET (APR_OS_START_ERROR + 11) +/** @see APR_STATUS_IS_ENOTHREAD */ #define APR_ENOTHREAD (APR_OS_START_ERROR + 12) +/** @see APR_STATUS_IS_ENOTHDKEY */ #define APR_ENOTHDKEY (APR_OS_START_ERROR + 13) -/* empty slot: +14 */ +/** @see APR_STATUS_IS_EGENERAL */ +#define APR_EGENERAL (APR_OS_START_ERROR + 14) +/** @see APR_STATUS_IS_ENOSHMAVAIL */ #define APR_ENOSHMAVAIL (APR_OS_START_ERROR + 15) -/* empty slot: +16 */ -/* empty slot: +17 */ +/** @see APR_STATUS_IS_EBADIP */ +#define APR_EBADIP (APR_OS_START_ERROR + 16) +/** @see APR_STATUS_IS_EBADMASK */ +#define APR_EBADMASK (APR_OS_START_ERROR + 17) /* empty slot: +18 */ +/** @see APR_STATUS_IS_EDSOPEN */ #define APR_EDSOOPEN (APR_OS_START_ERROR + 19) +/** @see APR_STATUS_IS_EABSOLUTE */ +#define APR_EABSOLUTE (APR_OS_START_ERROR + 20) +/** @see APR_STATUS_IS_ERELATIVE */ +#define APR_ERELATIVE (APR_OS_START_ERROR + 21) +/** @see APR_STATUS_IS_EINCOMPLETE */ +#define APR_EINCOMPLETE (APR_OS_START_ERROR + 22) +/** @see APR_STATUS_IS_EABOVEROOT */ +#define APR_EABOVEROOT (APR_OS_START_ERROR + 23) +/** @see APR_STATUS_IS_EBADPATH */ +#define APR_EBADPATH (APR_OS_START_ERROR + 24) +/** @see APR_STATUS_IS_EPATHWILD */ +#define APR_EPATHWILD (APR_OS_START_ERROR + 25) +/** @see APR_STATUS_IS_ESYMNOTFOUND */ +#define APR_ESYMNOTFOUND (APR_OS_START_ERROR + 26) +/** @see APR_STATUS_IS_EPROC_UNKNOWN */ +#define APR_EPROC_UNKNOWN (APR_OS_START_ERROR + 27) +/** @see APR_STATUS_IS_ENOTENOUGHENTROPY */ +#define APR_ENOTENOUGHENTROPY (APR_OS_START_ERROR + 28) +/** @} */ + +/** + * @defgroup APR_STATUS_IS Status Value Tests + * @warning For any particular error condition, more than one of these tests + * may match. This is because platform-specific error codes may not + * always match the semantics of the POSIX codes these tests (and the + * corresponding APR error codes) are named after. A notable example + * are the APR_STATUS_IS_ENOENT and APR_STATUS_IS_ENOTDIR tests on + * Win32 platforms. The programmer should always be aware of this and + * adjust the order of the tests accordingly. + * @{ + */ +/** + * APR was unable to perform a stat on the file + * @warning always use this test, as platform-specific variances may meet this + * more than one error code + */ +#define APR_STATUS_IS_ENOSTAT(s) ((s) == APR_ENOSTAT) +/** + * APR was not provided a pool with which to allocate memory + * @warning always use this test, as platform-specific variances may meet this + * more than one error code + */ +#define APR_STATUS_IS_ENOPOOL(s) ((s) == APR_ENOPOOL) +/** APR was given an invalid date */ +#define APR_STATUS_IS_EBADDATE(s) ((s) == APR_EBADDATE) +/** APR was given an invalid socket */ +#define APR_STATUS_IS_EINVALSOCK(s) ((s) == APR_EINVALSOCK) +/** APR was not given a process structure */ +#define APR_STATUS_IS_ENOPROC(s) ((s) == APR_ENOPROC) +/** APR was not given a time structure */ +#define APR_STATUS_IS_ENOTIME(s) ((s) == APR_ENOTIME) +/** APR was not given a directory structure */ +#define APR_STATUS_IS_ENODIR(s) ((s) == APR_ENODIR) +/** APR was not given a lock structure */ +#define APR_STATUS_IS_ENOLOCK(s) ((s) == APR_ENOLOCK) +/** APR was not given a poll structure */ +#define APR_STATUS_IS_ENOPOLL(s) ((s) == APR_ENOPOLL) +/** APR was not given a socket */ +#define APR_STATUS_IS_ENOSOCKET(s) ((s) == APR_ENOSOCKET) +/** APR was not given a thread structure */ +#define APR_STATUS_IS_ENOTHREAD(s) ((s) == APR_ENOTHREAD) +/** APR was not given a thread key structure */ +#define APR_STATUS_IS_ENOTHDKEY(s) ((s) == APR_ENOTHDKEY) +/** Generic Error which can not be put into another spot */ +#define APR_STATUS_IS_EGENERAL(s) ((s) == APR_EGENERAL) +/** There is no more shared memory available */ +#define APR_STATUS_IS_ENOSHMAVAIL(s) ((s) == APR_ENOSHMAVAIL) +/** The specified IP address is invalid */ +#define APR_STATUS_IS_EBADIP(s) ((s) == APR_EBADIP) +/** The specified netmask is invalid */ +#define APR_STATUS_IS_EBADMASK(s) ((s) == APR_EBADMASK) +/* empty slot: +18 */ +/** + * APR was unable to open the dso object. + * For more information call apr_dso_error(). + */ +#if defined(WIN32) +#define APR_STATUS_IS_EDSOOPEN(s) ((s) == APR_EDSOOPEN \ + || APR_TO_OS_ERROR(s) == ERROR_MOD_NOT_FOUND) +#elif defined(OS2) +#define APR_STATUS_IS_EDSOOPEN(s) ((s) == APR_EDSOOPEN \ + || APR_TO_OS_ERROR(s) == ERROR_FILE_NOT_FOUND) +#else +#define APR_STATUS_IS_EDSOOPEN(s) ((s) == APR_EDSOOPEN) +#endif +/** The given path was absolute. */ +#define APR_STATUS_IS_EABSOLUTE(s) ((s) == APR_EABSOLUTE) +/** The given path was relative. */ +#define APR_STATUS_IS_ERELATIVE(s) ((s) == APR_ERELATIVE) +/** The given path was neither relative nor absolute. */ +#define APR_STATUS_IS_EINCOMPLETE(s) ((s) == APR_EINCOMPLETE) +/** The given path was above the root path. */ +#define APR_STATUS_IS_EABOVEROOT(s) ((s) == APR_EABOVEROOT) +/** The given path was bad. */ +#define APR_STATUS_IS_EBADPATH(s) ((s) == APR_EBADPATH) +/** The given path contained wildcards. */ +#define APR_STATUS_IS_EPATHWILD(s) ((s) == APR_EPATHWILD) +/** Could not find the requested symbol. + * For more information call apr_dso_error(). + */ +#if defined(WIN32) +#define APR_STATUS_IS_ESYMNOTFOUND(s) ((s) == APR_ESYMNOTFOUND \ + || APR_TO_OS_ERROR(s) == ERROR_PROC_NOT_FOUND) +#elif defined(OS2) +#define APR_STATUS_IS_ESYMNOTFOUND(s) ((s) == APR_ESYMNOTFOUND \ + || APR_TO_OS_ERROR(s) == ERROR_INVALID_NAME) +#else +#define APR_STATUS_IS_ESYMNOTFOUND(s) ((s) == APR_ESYMNOTFOUND) +#endif +/** The given process was not recognized by APR. */ +#define APR_STATUS_IS_EPROC_UNKNOWN(s) ((s) == APR_EPROC_UNKNOWN) +/** APR could not gather enough entropy to continue. */ +#define APR_STATUS_IS_ENOTENOUGHENTROPY(s) ((s) == APR_ENOTENOUGHENTROPY) -/* APR STATUS VALUES */ +/** @} */ + +/** + * @addtogroup APR_Error + * @{ + */ +/** @see APR_STATUS_IS_INCHILD */ #define APR_INCHILD (APR_OS_START_STATUS + 1) +/** @see APR_STATUS_IS_INPARENT */ #define APR_INPARENT (APR_OS_START_STATUS + 2) +/** @see APR_STATUS_IS_DETACH */ #define APR_DETACH (APR_OS_START_STATUS + 3) +/** @see APR_STATUS_IS_NOTDETACH */ #define APR_NOTDETACH (APR_OS_START_STATUS + 4) +/** @see APR_STATUS_IS_CHILD_DONE */ #define APR_CHILD_DONE (APR_OS_START_STATUS + 5) +/** @see APR_STATUS_IS_CHILD_NOTDONE */ #define APR_CHILD_NOTDONE (APR_OS_START_STATUS + 6) +/** @see APR_STATUS_IS_TIMEUP */ #define APR_TIMEUP (APR_OS_START_STATUS + 7) -/* empty slot: +8 */ +/** @see APR_STATUS_IS_INCOMPLETE */ +#define APR_INCOMPLETE (APR_OS_START_STATUS + 8) /* empty slot: +9 */ /* empty slot: +10 */ /* empty slot: +11 */ +/** @see APR_STATUS_IS_BADCH */ #define APR_BADCH (APR_OS_START_STATUS + 12) +/** @see APR_STATUS_IS_BADARG */ #define APR_BADARG (APR_OS_START_STATUS + 13) +/** @see APR_STATUS_IS_EOF */ #define APR_EOF (APR_OS_START_STATUS + 14) +/** @see APR_STATUS_IS_NOTFOUND */ #define APR_NOTFOUND (APR_OS_START_STATUS + 15) /* empty slot: +16 */ /* empty slot: +17 */ /* empty slot: +18 */ +/** @see APR_STATUS_IS_ANONYMOUS */ #define APR_ANONYMOUS (APR_OS_START_STATUS + 19) +/** @see APR_STATUS_IS_FILEBASED */ #define APR_FILEBASED (APR_OS_START_STATUS + 20) +/** @see APR_STATUS_IS_KEYBASED */ #define APR_KEYBASED (APR_OS_START_STATUS + 21) - -/* A simple value to be used to initialze a status variable. */ +/** @see APR_STATUS_IS_EINIT */ #define APR_EINIT (APR_OS_START_STATUS + 22) - -/* Not implemented either because we haven't gotten to it yet, or - * because it is not possible to do correctly. - */ +/** @see APR_STATUS_IS_ENOTIMPL */ #define APR_ENOTIMPL (APR_OS_START_STATUS + 23) +/** @see APR_STATUS_IS_EMISMATCH */ +#define APR_EMISMATCH (APR_OS_START_STATUS + 24) +/** @see APR_STATUS_IS_EBUSY */ +#define APR_EBUSY (APR_OS_START_STATUS + 25) +/** @} */ -/* Passwords do not match. +/** + * @addtogroup APR_STATUS_IS + * @{ */ -#define APR_EMISMATCH (APR_OS_START_STATUS + 24) +/** + * Program is currently executing in the child + * @warning + * always use this test, as platform-specific variances may meet this + * more than one error code */ +#define APR_STATUS_IS_INCHILD(s) ((s) == APR_INCHILD) +/** + * Program is currently executing in the parent + * @warning + * always use this test, as platform-specific variances may meet this + * more than one error code + */ +#define APR_STATUS_IS_INPARENT(s) ((s) == APR_INPARENT) +/** + * The thread is detached + * @warning + * always use this test, as platform-specific variances may meet this + * more than one error code + */ +#define APR_STATUS_IS_DETACH(s) ((s) == APR_DETACH) +/** + * The thread is not detached + * @warning + * always use this test, as platform-specific variances may meet this + * more than one error code + */ +#define APR_STATUS_IS_NOTDETACH(s) ((s) == APR_NOTDETACH) +/** + * The child has finished executing + * @warning + * always use this test, as platform-specific variances may meet this + * more than one error code + */ +#define APR_STATUS_IS_CHILD_DONE(s) ((s) == APR_CHILD_DONE) +/** + * The child has not finished executing + * @warning + * always use this test, as platform-specific variances may meet this + * more than one error code + */ +#define APR_STATUS_IS_CHILD_NOTDONE(s) ((s) == APR_CHILD_NOTDONE) +/** + * The operation did not finish before the timeout + * @warning + * always use this test, as platform-specific variances may meet this + * more than one error code + */ +#define APR_STATUS_IS_TIMEUP(s) ((s) == APR_TIMEUP) +/** + * The operation was incomplete although some processing was performed + * and the results are partially valid. + * @warning + * always use this test, as platform-specific variances may meet this + * more than one error code + */ +#define APR_STATUS_IS_INCOMPLETE(s) ((s) == APR_INCOMPLETE) +/* empty slot: +9 */ +/* empty slot: +10 */ +/* empty slot: +11 */ +/** + * Getopt found an option not in the option string + * @warning + * always use this test, as platform-specific variances may meet this + * more than one error code + */ +#define APR_STATUS_IS_BADCH(s) ((s) == APR_BADCH) +/** + * Getopt found an option not in the option string and an argument was + * specified in the option string + * @warning + * always use this test, as platform-specific variances may meet this + * more than one error code + */ +#define APR_STATUS_IS_BADARG(s) ((s) == APR_BADARG) +/** + * APR has encountered the end of the file + * @warning + * always use this test, as platform-specific variances may meet this + * more than one error code + */ +#define APR_STATUS_IS_EOF(s) ((s) == APR_EOF) +/** + * APR was unable to find the socket in the poll structure + * @warning + * always use this test, as platform-specific variances may meet this + * more than one error code + */ +#define APR_STATUS_IS_NOTFOUND(s) ((s) == APR_NOTFOUND) +/* empty slot: +16 */ +/* empty slot: +17 */ +/* empty slot: +18 */ +/** + * APR is using anonymous shared memory + * @warning + * always use this test, as platform-specific variances may meet this + * more than one error code + */ +#define APR_STATUS_IS_ANONYMOUS(s) ((s) == APR_ANONYMOUS) +/** + * APR is using a file name as the key to the shared memory + * @warning + * always use this test, as platform-specific variances may meet this + * more than one error code + */ +#define APR_STATUS_IS_FILEBASED(s) ((s) == APR_FILEBASED) +/** + * APR is using a shared key as the key to the shared memory + * @warning + * always use this test, as platform-specific variances may meet this + * more than one error code + */ +#define APR_STATUS_IS_KEYBASED(s) ((s) == APR_KEYBASED) +/** + * Ininitalizer value. If no option has been found, but + * the status variable requires a value, this should be used + * @warning + * always use this test, as platform-specific variances may meet this + * more than one error code + */ +#define APR_STATUS_IS_EINIT(s) ((s) == APR_EINIT) +/** + * The APR function has not been implemented on this + * platform, either because nobody has gotten to it yet, + * or the function is impossible on this platform. + * @warning + * always use this test, as platform-specific variances may meet this + * more than one error code + */ +#define APR_STATUS_IS_ENOTIMPL(s) ((s) == APR_ENOTIMPL) +/** + * Two passwords do not match. + * @warning + * always use this test, as platform-specific variances may meet this + * more than one error code + */ +#define APR_STATUS_IS_EMISMATCH(s) ((s) == APR_EMISMATCH) +/** + * The given lock was busy + * @warning always use this test, as platform-specific variances may meet this + * more than one error code + */ +#define APR_STATUS_IS_EBUSY(s) ((s) == APR_EBUSY) +/** @} */ +/** + * @addtogroup APR_Error APR Error Values + * @{ + */ /* APR CANONICAL ERROR VALUES */ +/** @see APR_STATUS_IS_EACCES */ #ifdef EACCES #define APR_EACCES EACCES #else #define APR_EACCES (APR_OS_START_CANONERR + 1) #endif +/** @see APR_STATUS_IS_EEXIST */ #ifdef EEXIST #define APR_EEXIST EEXIST #else #define APR_EEXIST (APR_OS_START_CANONERR + 2) #endif +/** @see APR_STATUS_IS_ENAMETOOLONG */ #ifdef ENAMETOOLONG #define APR_ENAMETOOLONG ENAMETOOLONG #else #define APR_ENAMETOOLONG (APR_OS_START_CANONERR + 3) #endif +/** @see APR_STATUS_IS_ENOENT */ #ifdef ENOENT #define APR_ENOENT ENOENT #else #define APR_ENOENT (APR_OS_START_CANONERR + 4) #endif +/** @see APR_STATUS_IS_ENOTDIR */ #ifdef ENOTDIR #define APR_ENOTDIR ENOTDIR #else #define APR_ENOTDIR (APR_OS_START_CANONERR + 5) #endif +/** @see APR_STATUS_IS_ENOSPC */ #ifdef ENOSPC #define APR_ENOSPC ENOSPC #else #define APR_ENOSPC (APR_OS_START_CANONERR + 6) #endif -#ifdef ENONOMEM +/** @see APR_STATUS_IS_ENOMEM */ +#ifdef ENOMEM #define APR_ENOMEM ENOMEM #else #define APR_ENOMEM (APR_OS_START_CANONERR + 7) #endif +/** @see APR_STATUS_IS_EMFILE */ #ifdef EMFILE #define APR_EMFILE EMFILE #else #define APR_EMFILE (APR_OS_START_CANONERR + 8) #endif +/** @see APR_STATUS_IS_ENFILE */ #ifdef ENFILE #define APR_ENFILE ENFILE #else #define APR_ENFILE (APR_OS_START_CANONERR + 9) #endif +/** @see APR_STATUS_IS_EBADF */ #ifdef EBADF #define APR_EBADF EBADF #else #define APR_EBADF (APR_OS_START_CANONERR + 10) #endif +/** @see APR_STATUS_IS_EINVAL */ #ifdef EINVAL #define APR_EINVAL EINVAL #else #define APR_EINVAL (APR_OS_START_CANONERR + 11) #endif +/** @see APR_STATUS_IS_ESPIPE */ #ifdef ESPIPE #define APR_ESPIPE ESPIPE #else #define APR_ESPIPE (APR_OS_START_CANONERR + 12) #endif +/** + * @see APR_STATUS_IS_EAGAIN + * @warning use APR_STATUS_IS_EAGAIN instead of just testing this value + */ #ifdef EAGAIN #define APR_EAGAIN EAGAIN +#elif defined(EWOULDBLOCK) +#define APR_EAGAIN EWOULDBLOCK #else #define APR_EAGAIN (APR_OS_START_CANONERR + 13) #endif +/** @see APR_STATUS_IS_EINTR */ #ifdef EINTR #define APR_EINTR EINTR #else #define APR_EINTR (APR_OS_START_CANONERR + 14) #endif +/** @see APR_STATUS_IS_ENOTSOCK */ #ifdef ENOTSOCK #define APR_ENOTSOCK ENOTSOCK #else #define APR_ENOTSOCK (APR_OS_START_CANONERR + 15) #endif +/** @see APR_STATUS_IS_ECONNREFUSED */ #ifdef ECONNREFUSED #define APR_ECONNREFUSED ECONNREFUSED #else #define APR_ECONNREFUSED (APR_OS_START_CANONERR + 16) #endif +/** @see APR_STATUS_IS_EINPROGRESS */ #ifdef EINPROGRESS #define APR_EINPROGRESS EINPROGRESS #else #define APR_EINPROGRESS (APR_OS_START_CANONERR + 17) #endif +/** + * @see APR_STATUS_IS_ECONNABORTED + * @warning use APR_STATUS_IS_ECONNABORTED instead of just testing this value + */ + +#ifdef ECONNABORTED +#define APR_ECONNABORTED ECONNABORTED +#else +#define APR_ECONNABORTED (APR_OS_START_CANONERR + 18) +#endif + +/** @see APR_STATUS_IS_ECONNRESET */ +#ifdef ECONNRESET +#define APR_ECONNRESET ECONNRESET +#else +#define APR_ECONNRESET (APR_OS_START_CANONERR + 19) +#endif + +/** @see APR_STATUS_IS_ETIMEDOUT + * @deprecated */ +#ifdef ETIMEDOUT +#define APR_ETIMEDOUT ETIMEDOUT +#else +#define APR_ETIMEDOUT (APR_OS_START_CANONERR + 20) +#endif + +/** @see APR_STATUS_IS_EHOSTUNREACH */ +#ifdef EHOSTUNREACH +#define APR_EHOSTUNREACH EHOSTUNREACH +#else +#define APR_EHOSTUNREACH (APR_OS_START_CANONERR + 21) +#endif + +/** @see APR_STATUS_IS_ENETUNREACH */ +#ifdef ENETUNREACH +#define APR_ENETUNREACH ENETUNREACH +#else +#define APR_ENETUNREACH (APR_OS_START_CANONERR + 22) +#endif + +/** @see APR_STATUS_IS_EFTYPE */ +#ifdef EFTYPE +#define APR_EFTYPE EFTYPE +#else +#define APR_EFTYPE (APR_OS_START_CANONERR + 23) +#endif + +/** @see APR_STATUS_IS_EPIPE */ +#ifdef EPIPE +#define APR_EPIPE EPIPE +#else +#define APR_EPIPE (APR_OS_START_CANONERR + 24) +#endif + +/** @see APR_STATUS_IS_EXDEV */ +#ifdef EXDEV +#define APR_EXDEV EXDEV +#else +#define APR_EXDEV (APR_OS_START_CANONERR + 25) +#endif + +/** @see APR_STATUS_IS_ENOTEMPTY */ +#ifdef ENOTEMPTY +#define APR_ENOTEMPTY ENOTEMPTY +#else +#define APR_ENOTEMPTY (APR_OS_START_CANONERR + 26) +#endif + +/** @see APR_STATUS_IS_EAFNOSUPPORT */ +#ifdef EAFNOSUPPORT +#define APR_EAFNOSUPPORT EAFNOSUPPORT +#else +#define APR_EAFNOSUPPORT (APR_OS_START_CANONERR + 27) +#endif + +/** @see APR_STATUS_IS_EOPNOTSUPP */ +#ifdef EOPNOTSUPP +#define APR_EOPNOTSUPP EOPNOTSUPP +#else +#define APR_EOPNOTSUPP (APR_OS_START_CANONERR + 28) +#endif + +/** @see APR_STATUS_IS_ERANGE */ +#ifdef ERANGE +#define APR_ERANGE ERANGE +#else +#define APR_ERANGE (APR_OS_START_CANONERR + 29) +#endif + +/** @} */ + +#if defined(OS2) && !defined(DOXYGEN) + +#define APR_FROM_OS_ERROR(e) (e == 0 ? APR_SUCCESS : e + APR_OS_START_SYSERR) +#define APR_TO_OS_ERROR(e) (e == 0 ? APR_SUCCESS : e - APR_OS_START_SYSERR) + +#define INCL_DOSERRORS +#define INCL_DOS + +/* Leave these undefined. + * OS2 doesn't rely on the errno concept. + * The API calls always return a result codes which + * should be filtered through APR_FROM_OS_ERROR(). + * + * #define apr_get_os_error() (APR_FROM_OS_ERROR(GetLastError())) + * #define apr_set_os_error(e) (SetLastError(APR_TO_OS_ERROR(e))) + */ + +/* A special case, only socket calls require this; + */ +#define apr_get_netos_error() (APR_FROM_OS_ERROR(errno)) +#define apr_set_netos_error(e) (errno = APR_TO_OS_ERROR(e)) + +/* These can't sit in a private header, so in spite of the extra size, + * they need to be made available here. + */ +#define SOCBASEERR 10000 +#define SOCEPERM (SOCBASEERR+1) /* Not owner */ +#define SOCESRCH (SOCBASEERR+3) /* No such process */ +#define SOCEINTR (SOCBASEERR+4) /* Interrupted system call */ +#define SOCENXIO (SOCBASEERR+6) /* No such device or address */ +#define SOCEBADF (SOCBASEERR+9) /* Bad file number */ +#define SOCEACCES (SOCBASEERR+13) /* Permission denied */ +#define SOCEFAULT (SOCBASEERR+14) /* Bad address */ +#define SOCEINVAL (SOCBASEERR+22) /* Invalid argument */ +#define SOCEMFILE (SOCBASEERR+24) /* Too many open files */ +#define SOCEPIPE (SOCBASEERR+32) /* Broken pipe */ +#define SOCEOS2ERR (SOCBASEERR+100) /* OS/2 Error */ +#define SOCEWOULDBLOCK (SOCBASEERR+35) /* Operation would block */ +#define SOCEINPROGRESS (SOCBASEERR+36) /* Operation now in progress */ +#define SOCEALREADY (SOCBASEERR+37) /* Operation already in progress */ +#define SOCENOTSOCK (SOCBASEERR+38) /* Socket operation on non-socket */ +#define SOCEDESTADDRREQ (SOCBASEERR+39) /* Destination address required */ +#define SOCEMSGSIZE (SOCBASEERR+40) /* Message too long */ +#define SOCEPROTOTYPE (SOCBASEERR+41) /* Protocol wrong type for socket */ +#define SOCENOPROTOOPT (SOCBASEERR+42) /* Protocol not available */ +#define SOCEPROTONOSUPPORT (SOCBASEERR+43) /* Protocol not supported */ +#define SOCESOCKTNOSUPPORT (SOCBASEERR+44) /* Socket type not supported */ +#define SOCEOPNOTSUPP (SOCBASEERR+45) /* Operation not supported on socket */ +#define SOCEPFNOSUPPORT (SOCBASEERR+46) /* Protocol family not supported */ +#define SOCEAFNOSUPPORT (SOCBASEERR+47) /* Address family not supported by protocol family */ +#define SOCEADDRINUSE (SOCBASEERR+48) /* Address already in use */ +#define SOCEADDRNOTAVAIL (SOCBASEERR+49) /* Can't assign requested address */ +#define SOCENETDOWN (SOCBASEERR+50) /* Network is down */ +#define SOCENETUNREACH (SOCBASEERR+51) /* Network is unreachable */ +#define SOCENETRESET (SOCBASEERR+52) /* Network dropped connection on reset */ +#define SOCECONNABORTED (SOCBASEERR+53) /* Software caused connection abort */ +#define SOCECONNRESET (SOCBASEERR+54) /* Connection reset by peer */ +#define SOCENOBUFS (SOCBASEERR+55) /* No buffer space available */ +#define SOCEISCONN (SOCBASEERR+56) /* Socket is already connected */ +#define SOCENOTCONN (SOCBASEERR+57) /* Socket is not connected */ +#define SOCESHUTDOWN (SOCBASEERR+58) /* Can't send after socket shutdown */ +#define SOCETOOMANYREFS (SOCBASEERR+59) /* Too many references: can't splice */ +#define SOCETIMEDOUT (SOCBASEERR+60) /* Connection timed out */ +#define SOCECONNREFUSED (SOCBASEERR+61) /* Connection refused */ +#define SOCELOOP (SOCBASEERR+62) /* Too many levels of symbolic links */ +#define SOCENAMETOOLONG (SOCBASEERR+63) /* File name too long */ +#define SOCEHOSTDOWN (SOCBASEERR+64) /* Host is down */ +#define SOCEHOSTUNREACH (SOCBASEERR+65) /* No route to host */ +#define SOCENOTEMPTY (SOCBASEERR+66) /* Directory not empty */ + +/* APR CANONICAL ERROR TESTS */ +#define APR_STATUS_IS_EACCES(s) ((s) == APR_EACCES \ + || (s) == APR_OS_START_SYSERR + ERROR_ACCESS_DENIED \ + || (s) == APR_OS_START_SYSERR + ERROR_SHARING_VIOLATION) +#define APR_STATUS_IS_EEXIST(s) ((s) == APR_EEXIST \ + || (s) == APR_OS_START_SYSERR + ERROR_OPEN_FAILED \ + || (s) == APR_OS_START_SYSERR + ERROR_FILE_EXISTS \ + || (s) == APR_OS_START_SYSERR + ERROR_ALREADY_EXISTS \ + || (s) == APR_OS_START_SYSERR + ERROR_ACCESS_DENIED) +#define APR_STATUS_IS_ENAMETOOLONG(s) ((s) == APR_ENAMETOOLONG \ + || (s) == APR_OS_START_SYSERR + ERROR_FILENAME_EXCED_RANGE \ + || (s) == APR_OS_START_SYSERR + SOCENAMETOOLONG) +#define APR_STATUS_IS_ENOENT(s) ((s) == APR_ENOENT \ + || (s) == APR_OS_START_SYSERR + ERROR_FILE_NOT_FOUND \ + || (s) == APR_OS_START_SYSERR + ERROR_PATH_NOT_FOUND \ + || (s) == APR_OS_START_SYSERR + ERROR_NO_MORE_FILES \ + || (s) == APR_OS_START_SYSERR + ERROR_OPEN_FAILED) +#define APR_STATUS_IS_ENOTDIR(s) ((s) == APR_ENOTDIR) +#define APR_STATUS_IS_ENOSPC(s) ((s) == APR_ENOSPC \ + || (s) == APR_OS_START_SYSERR + ERROR_DISK_FULL) +#define APR_STATUS_IS_ENOMEM(s) ((s) == APR_ENOMEM) +#define APR_STATUS_IS_EMFILE(s) ((s) == APR_EMFILE \ + || (s) == APR_OS_START_SYSERR + ERROR_TOO_MANY_OPEN_FILES) +#define APR_STATUS_IS_ENFILE(s) ((s) == APR_ENFILE) +#define APR_STATUS_IS_EBADF(s) ((s) == APR_EBADF \ + || (s) == APR_OS_START_SYSERR + ERROR_INVALID_HANDLE) +#define APR_STATUS_IS_EINVAL(s) ((s) == APR_EINVAL \ + || (s) == APR_OS_START_SYSERR + ERROR_INVALID_PARAMETER \ + || (s) == APR_OS_START_SYSERR + ERROR_INVALID_FUNCTION) +#define APR_STATUS_IS_ESPIPE(s) ((s) == APR_ESPIPE \ + || (s) == APR_OS_START_SYSERR + ERROR_NEGATIVE_SEEK) +#define APR_STATUS_IS_EAGAIN(s) ((s) == APR_EAGAIN \ + || (s) == APR_OS_START_SYSERR + ERROR_NO_DATA \ + || (s) == APR_OS_START_SYSERR + SOCEWOULDBLOCK \ + || (s) == APR_OS_START_SYSERR + ERROR_LOCK_VIOLATION) +#define APR_STATUS_IS_EINTR(s) ((s) == APR_EINTR \ + || (s) == APR_OS_START_SYSERR + SOCEINTR) +#define APR_STATUS_IS_ENOTSOCK(s) ((s) == APR_ENOTSOCK \ + || (s) == APR_OS_START_SYSERR + SOCENOTSOCK) +#define APR_STATUS_IS_ECONNREFUSED(s) ((s) == APR_ECONNREFUSED \ + || (s) == APR_OS_START_SYSERR + SOCECONNREFUSED) +#define APR_STATUS_IS_EINPROGRESS(s) ((s) == APR_EINPROGRESS \ + || (s) == APR_OS_START_SYSERR + SOCEINPROGRESS) +#define APR_STATUS_IS_ECONNABORTED(s) ((s) == APR_ECONNABORTED \ + || (s) == APR_OS_START_SYSERR + SOCECONNABORTED) +#define APR_STATUS_IS_ECONNRESET(s) ((s) == APR_ECONNRESET \ + || (s) == APR_OS_START_SYSERR + SOCECONNRESET) +/* XXX deprecated */ +#define APR_STATUS_IS_ETIMEDOUT(s) ((s) == APR_ETIMEDOUT \ + || (s) == APR_OS_START_SYSERR + SOCETIMEDOUT) +#undef APR_STATUS_IS_TIMEUP +#define APR_STATUS_IS_TIMEUP(s) ((s) == APR_TIMEUP \ + || (s) == APR_OS_START_SYSERR + SOCETIMEDOUT) +#define APR_STATUS_IS_EHOSTUNREACH(s) ((s) == APR_EHOSTUNREACH \ + || (s) == APR_OS_START_SYSERR + SOCEHOSTUNREACH) +#define APR_STATUS_IS_ENETUNREACH(s) ((s) == APR_ENETUNREACH \ + || (s) == APR_OS_START_SYSERR + SOCENETUNREACH) +#define APR_STATUS_IS_EFTYPE(s) ((s) == APR_EFTYPE) +#define APR_STATUS_IS_EPIPE(s) ((s) == APR_EPIPE \ + || (s) == APR_OS_START_SYSERR + ERROR_BROKEN_PIPE \ + || (s) == APR_OS_START_SYSERR + SOCEPIPE) +#define APR_STATUS_IS_EXDEV(s) ((s) == APR_EXDEV \ + || (s) == APR_OS_START_SYSERR + ERROR_NOT_SAME_DEVICE) +#define APR_STATUS_IS_ENOTEMPTY(s) ((s) == APR_ENOTEMPTY \ + || (s) == APR_OS_START_SYSERR + ERROR_DIR_NOT_EMPTY \ + || (s) == APR_OS_START_SYSERR + ERROR_ACCESS_DENIED) +#define APR_STATUS_IS_EAFNOSUPPORT(s) ((s) == APR_AFNOSUPPORT \ + || (s) == APR_OS_START_SYSERR + SOCEAFNOSUPPORT) +#define APR_STATUS_IS_EOPNOTSUPP(s) ((s) == APR_EOPNOTSUPP \ + || (s) == APR_OS_START_SYSERR + SOCEOPNOTSUPP) +#define APR_STATUS_IS_ERANGE(s) ((s) == APR_ERANGE) + +/* + Sorry, too tired to wrap this up for OS2... feel free to + fit the following into their best matches. + + { ERROR_NO_SIGNAL_SENT, ESRCH }, + { SOCEALREADY, EALREADY }, + { SOCEDESTADDRREQ, EDESTADDRREQ }, + { SOCEMSGSIZE, EMSGSIZE }, + { SOCEPROTOTYPE, EPROTOTYPE }, + { SOCENOPROTOOPT, ENOPROTOOPT }, + { SOCEPROTONOSUPPORT, EPROTONOSUPPORT }, + { SOCESOCKTNOSUPPORT, ESOCKTNOSUPPORT }, + { SOCEPFNOSUPPORT, EPFNOSUPPORT }, + { SOCEADDRINUSE, EADDRINUSE }, + { SOCEADDRNOTAVAIL, EADDRNOTAVAIL }, + { SOCENETDOWN, ENETDOWN }, + { SOCENETRESET, ENETRESET }, + { SOCENOBUFS, ENOBUFS }, + { SOCEISCONN, EISCONN }, + { SOCENOTCONN, ENOTCONN }, + { SOCESHUTDOWN, ESHUTDOWN }, + { SOCETOOMANYREFS, ETOOMANYREFS }, + { SOCELOOP, ELOOP }, + { SOCEHOSTDOWN, EHOSTDOWN }, + { SOCENOTEMPTY, ENOTEMPTY }, + { SOCEPIPE, EPIPE } +*/ + +#elif defined(WIN32) && !defined(DOXYGEN) /* !defined(OS2) */ + +#define APR_FROM_OS_ERROR(e) (e == 0 ? APR_SUCCESS : e + APR_OS_START_SYSERR) +#define APR_TO_OS_ERROR(e) (e == 0 ? APR_SUCCESS : e - APR_OS_START_SYSERR) + +#define apr_get_os_error() (APR_FROM_OS_ERROR(GetLastError())) +#define apr_set_os_error(e) (SetLastError(APR_TO_OS_ERROR(e))) + +/* A special case, only socket calls require this: + */ +#define apr_get_netos_error() (APR_FROM_OS_ERROR(WSAGetLastError())) +#define apr_set_netos_error(e) (WSASetLastError(APR_TO_OS_ERROR(e))) + +/* APR CANONICAL ERROR TESTS */ +#define APR_STATUS_IS_EACCES(s) ((s) == APR_EACCES \ + || (s) == APR_OS_START_SYSERR + ERROR_ACCESS_DENIED \ + || (s) == APR_OS_START_SYSERR + ERROR_CANNOT_MAKE \ + || (s) == APR_OS_START_SYSERR + ERROR_CURRENT_DIRECTORY \ + || (s) == APR_OS_START_SYSERR + ERROR_DRIVE_LOCKED \ + || (s) == APR_OS_START_SYSERR + ERROR_FAIL_I24 \ + || (s) == APR_OS_START_SYSERR + ERROR_LOCK_VIOLATION \ + || (s) == APR_OS_START_SYSERR + ERROR_LOCK_FAILED \ + || (s) == APR_OS_START_SYSERR + ERROR_NOT_LOCKED \ + || (s) == APR_OS_START_SYSERR + ERROR_NETWORK_ACCESS_DENIED \ + || (s) == APR_OS_START_SYSERR + ERROR_SHARING_VIOLATION) +#define APR_STATUS_IS_EEXIST(s) ((s) == APR_EEXIST \ + || (s) == APR_OS_START_SYSERR + ERROR_FILE_EXISTS \ + || (s) == APR_OS_START_SYSERR + ERROR_ALREADY_EXISTS) +#define APR_STATUS_IS_ENAMETOOLONG(s) ((s) == APR_ENAMETOOLONG \ + || (s) == APR_OS_START_SYSERR + ERROR_FILENAME_EXCED_RANGE \ + || (s) == APR_OS_START_SYSERR + WSAENAMETOOLONG) +#define APR_STATUS_IS_ENOENT(s) ((s) == APR_ENOENT \ + || (s) == APR_OS_START_SYSERR + ERROR_FILE_NOT_FOUND \ + || (s) == APR_OS_START_SYSERR + ERROR_PATH_NOT_FOUND \ + || (s) == APR_OS_START_SYSERR + ERROR_OPEN_FAILED \ + || (s) == APR_OS_START_SYSERR + ERROR_NO_MORE_FILES) +#define APR_STATUS_IS_ENOTDIR(s) ((s) == APR_ENOTDIR \ + || (s) == APR_OS_START_SYSERR + ERROR_PATH_NOT_FOUND \ + || (s) == APR_OS_START_SYSERR + ERROR_BAD_NETPATH \ + || (s) == APR_OS_START_SYSERR + ERROR_BAD_NET_NAME \ + || (s) == APR_OS_START_SYSERR + ERROR_BAD_PATHNAME \ + || (s) == APR_OS_START_SYSERR + ERROR_INVALID_DRIVE \ + || (s) == APR_OS_START_SYSERR + ERROR_DIRECTORY) +#define APR_STATUS_IS_ENOSPC(s) ((s) == APR_ENOSPC \ + || (s) == APR_OS_START_SYSERR + ERROR_DISK_FULL) +#define APR_STATUS_IS_ENOMEM(s) ((s) == APR_ENOMEM \ + || (s) == APR_OS_START_SYSERR + ERROR_ARENA_TRASHED \ + || (s) == APR_OS_START_SYSERR + ERROR_NOT_ENOUGH_MEMORY \ + || (s) == APR_OS_START_SYSERR + ERROR_INVALID_BLOCK \ + || (s) == APR_OS_START_SYSERR + ERROR_NOT_ENOUGH_QUOTA \ + || (s) == APR_OS_START_SYSERR + ERROR_OUTOFMEMORY) +#define APR_STATUS_IS_EMFILE(s) ((s) == APR_EMFILE \ + || (s) == APR_OS_START_SYSERR + ERROR_TOO_MANY_OPEN_FILES) +#define APR_STATUS_IS_ENFILE(s) ((s) == APR_ENFILE) +#define APR_STATUS_IS_EBADF(s) ((s) == APR_EBADF \ + || (s) == APR_OS_START_SYSERR + ERROR_INVALID_HANDLE \ + || (s) == APR_OS_START_SYSERR + ERROR_INVALID_TARGET_HANDLE) +#define APR_STATUS_IS_EINVAL(s) ((s) == APR_EINVAL \ + || (s) == APR_OS_START_SYSERR + ERROR_INVALID_ACCESS \ + || (s) == APR_OS_START_SYSERR + ERROR_INVALID_DATA \ + || (s) == APR_OS_START_SYSERR + ERROR_INVALID_FUNCTION \ + || (s) == APR_OS_START_SYSERR + ERROR_INVALID_HANDLE \ + || (s) == APR_OS_START_SYSERR + ERROR_INVALID_PARAMETER \ + || (s) == APR_OS_START_SYSERR + ERROR_NEGATIVE_SEEK) +#define APR_STATUS_IS_ESPIPE(s) ((s) == APR_ESPIPE \ + || (s) == APR_OS_START_SYSERR + ERROR_SEEK_ON_DEVICE \ + || (s) == APR_OS_START_SYSERR + ERROR_NEGATIVE_SEEK) +#define APR_STATUS_IS_EAGAIN(s) ((s) == APR_EAGAIN \ + || (s) == APR_OS_START_SYSERR + ERROR_NO_DATA \ + || (s) == APR_OS_START_SYSERR + ERROR_NO_PROC_SLOTS \ + || (s) == APR_OS_START_SYSERR + ERROR_NESTING_NOT_ALLOWED \ + || (s) == APR_OS_START_SYSERR + ERROR_MAX_THRDS_REACHED \ + || (s) == APR_OS_START_SYSERR + ERROR_LOCK_VIOLATION \ + || (s) == APR_OS_START_SYSERR + WSAEWOULDBLOCK) +#define APR_STATUS_IS_EINTR(s) ((s) == APR_EINTR \ + || (s) == APR_OS_START_SYSERR + WSAEINTR) +#define APR_STATUS_IS_ENOTSOCK(s) ((s) == APR_ENOTSOCK \ + || (s) == APR_OS_START_SYSERR + WSAENOTSOCK) +#define APR_STATUS_IS_ECONNREFUSED(s) ((s) == APR_ECONNREFUSED \ + || (s) == APR_OS_START_SYSERR + WSAECONNREFUSED) +#define APR_STATUS_IS_EINPROGRESS(s) ((s) == APR_EINPROGRESS \ + || (s) == APR_OS_START_SYSERR + WSAEINPROGRESS) +#define APR_STATUS_IS_ECONNABORTED(s) ((s) == APR_ECONNABORTED \ + || (s) == APR_OS_START_SYSERR + WSAECONNABORTED) +#define APR_STATUS_IS_ECONNRESET(s) ((s) == APR_ECONNRESET \ + || (s) == APR_OS_START_SYSERR + ERROR_NETNAME_DELETED \ + || (s) == APR_OS_START_SYSERR + WSAECONNRESET) +/* XXX deprecated */ +#define APR_STATUS_IS_ETIMEDOUT(s) ((s) == APR_ETIMEDOUT \ + || (s) == APR_OS_START_SYSERR + WSAETIMEDOUT \ + || (s) == APR_OS_START_SYSERR + WAIT_TIMEOUT) +#undef APR_STATUS_IS_TIMEUP +#define APR_STATUS_IS_TIMEUP(s) ((s) == APR_TIMEUP \ + || (s) == APR_OS_START_SYSERR + WSAETIMEDOUT \ + || (s) == APR_OS_START_SYSERR + WAIT_TIMEOUT) +#define APR_STATUS_IS_EHOSTUNREACH(s) ((s) == APR_EHOSTUNREACH \ + || (s) == APR_OS_START_SYSERR + WSAEHOSTUNREACH) +#define APR_STATUS_IS_ENETUNREACH(s) ((s) == APR_ENETUNREACH \ + || (s) == APR_OS_START_SYSERR + WSAENETUNREACH) +#define APR_STATUS_IS_EFTYPE(s) ((s) == APR_EFTYPE \ + || (s) == APR_OS_START_SYSERR + ERROR_EXE_MACHINE_TYPE_MISMATCH \ + || (s) == APR_OS_START_SYSERR + ERROR_INVALID_DLL \ + || (s) == APR_OS_START_SYSERR + ERROR_INVALID_MODULETYPE \ + || (s) == APR_OS_START_SYSERR + ERROR_BAD_EXE_FORMAT \ + || (s) == APR_OS_START_SYSERR + ERROR_INVALID_EXE_SIGNATURE \ + || (s) == APR_OS_START_SYSERR + ERROR_FILE_CORRUPT \ + || (s) == APR_OS_START_SYSERR + ERROR_BAD_FORMAT) +#define APR_STATUS_IS_EPIPE(s) ((s) == APR_EPIPE \ + || (s) == APR_OS_START_SYSERR + ERROR_BROKEN_PIPE) +#define APR_STATUS_IS_EXDEV(s) ((s) == APR_EXDEV \ + || (s) == APR_OS_START_SYSERR + ERROR_NOT_SAME_DEVICE) +#define APR_STATUS_IS_ENOTEMPTY(s) ((s) == APR_ENOTEMPTY \ + || (s) == APR_OS_START_SYSERR + ERROR_DIR_NOT_EMPTY) +#define APR_STATUS_IS_EAFNOSUPPORT(s) ((s) == APR_EAFNOSUPPORT \ + || (s) == APR_OS_START_SYSERR + WSAEAFNOSUPPORT) +#define APR_STATUS_IS_EOPNOTSUPP(s) ((s) == APR_EOPNOTSUPP \ + || (s) == APR_OS_START_SYSERR + WSAEOPNOTSUPP) +#define APR_STATUS_IS_ERANGE(s) ((s) == APR_ERANGE) + +#elif defined(NETWARE) && defined(USE_WINSOCK) && !defined(DOXYGEN) /* !defined(OS2) && !defined(WIN32) */ + +#define APR_FROM_OS_ERROR(e) (e == 0 ? APR_SUCCESS : e + APR_OS_START_SYSERR) +#define APR_TO_OS_ERROR(e) (e == 0 ? APR_SUCCESS : e - APR_OS_START_SYSERR) + +#define apr_get_os_error() (errno) +#define apr_set_os_error(e) (errno = (e)) + +/* A special case, only socket calls require this: */ +#define apr_get_netos_error() (APR_FROM_OS_ERROR(WSAGetLastError())) +#define apr_set_netos_error(e) (WSASetLastError(APR_TO_OS_ERROR(e))) + +/* APR CANONICAL ERROR TESTS */ +#define APR_STATUS_IS_EACCES(s) ((s) == APR_EACCES) +#define APR_STATUS_IS_EEXIST(s) ((s) == APR_EEXIST) +#define APR_STATUS_IS_ENAMETOOLONG(s) ((s) == APR_ENAMETOOLONG) +#define APR_STATUS_IS_ENOENT(s) ((s) == APR_ENOENT) +#define APR_STATUS_IS_ENOTDIR(s) ((s) == APR_ENOTDIR) +#define APR_STATUS_IS_ENOSPC(s) ((s) == APR_ENOSPC) +#define APR_STATUS_IS_ENOMEM(s) ((s) == APR_ENOMEM) +#define APR_STATUS_IS_EMFILE(s) ((s) == APR_EMFILE) +#define APR_STATUS_IS_ENFILE(s) ((s) == APR_ENFILE) +#define APR_STATUS_IS_EBADF(s) ((s) == APR_EBADF) +#define APR_STATUS_IS_EINVAL(s) ((s) == APR_EINVAL) +#define APR_STATUS_IS_ESPIPE(s) ((s) == APR_ESPIPE) + +#define APR_STATUS_IS_EAGAIN(s) ((s) == APR_EAGAIN \ + || (s) == EWOULDBLOCK \ + || (s) == APR_OS_START_SYSERR + WSAEWOULDBLOCK) +#define APR_STATUS_IS_EINTR(s) ((s) == APR_EINTR \ + || (s) == APR_OS_START_SYSERR + WSAEINTR) +#define APR_STATUS_IS_ENOTSOCK(s) ((s) == APR_ENOTSOCK \ + || (s) == APR_OS_START_SYSERR + WSAENOTSOCK) +#define APR_STATUS_IS_ECONNREFUSED(s) ((s) == APR_ECONNREFUSED \ + || (s) == APR_OS_START_SYSERR + WSAECONNREFUSED) +#define APR_STATUS_IS_EINPROGRESS(s) ((s) == APR_EINPROGRESS \ + || (s) == APR_OS_START_SYSERR + WSAEINPROGRESS) +#define APR_STATUS_IS_ECONNABORTED(s) ((s) == APR_ECONNABORTED \ + || (s) == APR_OS_START_SYSERR + WSAECONNABORTED) +#define APR_STATUS_IS_ECONNRESET(s) ((s) == APR_ECONNRESET \ + || (s) == APR_OS_START_SYSERR + WSAECONNRESET) +/* XXX deprecated */ +#define APR_STATUS_IS_ETIMEDOUT(s) ((s) == APR_ETIMEDOUT \ + || (s) == APR_OS_START_SYSERR + WSAETIMEDOUT \ + || (s) == APR_OS_START_SYSERR + WAIT_TIMEOUT) +#undef APR_STATUS_IS_TIMEUP +#define APR_STATUS_IS_TIMEUP(s) ((s) == APR_TIMEUP \ + || (s) == APR_OS_START_SYSERR + WSAETIMEDOUT \ + || (s) == APR_OS_START_SYSERR + WAIT_TIMEOUT) +#define APR_STATUS_IS_EHOSTUNREACH(s) ((s) == APR_EHOSTUNREACH \ + || (s) == APR_OS_START_SYSERR + WSAEHOSTUNREACH) +#define APR_STATUS_IS_ENETUNREACH(s) ((s) == APR_ENETUNREACH \ + || (s) == APR_OS_START_SYSERR + WSAENETUNREACH) +#define APR_STATUS_IS_ENETDOWN(s) ((s) == APR_OS_START_SYSERR + WSAENETDOWN) +#define APR_STATUS_IS_EFTYPE(s) ((s) == APR_EFTYPE) +#define APR_STATUS_IS_EPIPE(s) ((s) == APR_EPIPE) +#define APR_STATUS_IS_EXDEV(s) ((s) == APR_EXDEV) +#define APR_STATUS_IS_ENOTEMPTY(s) ((s) == APR_ENOTEMPTY) +#define APR_STATUS_IS_EAFNOSUPPORT(s) ((s) == APR_EAFNOSUPPORT \ + || (s) == APR_OS_START_SYSERR + WSAEAFNOSUPPORT) +#define APR_STATUS_IS_EOPNOTSUPP(s) ((s) == APR_EOPNOTSUPP \ + || (s) == APR_OS_START_SYSERR + WSAEOPNOTSUPP) +#define APR_STATUS_IS_ERANGE(s) ((s) == APR_ERANGE) + +#else /* !defined(NETWARE) && !defined(OS2) && !defined(WIN32) */ + +/* + * os error codes are clib error codes + */ +#define APR_FROM_OS_ERROR(e) (e) +#define APR_TO_OS_ERROR(e) (e) + +#define apr_get_os_error() (errno) +#define apr_set_os_error(e) (errno = (e)) + +/* A special case, only socket calls require this: + */ +#define apr_get_netos_error() (errno) +#define apr_set_netos_error(e) (errno = (e)) + +/** + * @addtogroup APR_STATUS_IS + * @{ + */ + +/** permission denied */ +#define APR_STATUS_IS_EACCES(s) ((s) == APR_EACCES) +/** file exists */ +#define APR_STATUS_IS_EEXIST(s) ((s) == APR_EEXIST) +/** path name is too long */ +#define APR_STATUS_IS_ENAMETOOLONG(s) ((s) == APR_ENAMETOOLONG) +/** + * no such file or directory + * @remark + * EMVSCATLG can be returned by the automounter on z/OS for + * paths which do not exist. + */ +#ifdef EMVSCATLG +#define APR_STATUS_IS_ENOENT(s) ((s) == APR_ENOENT \ + || (s) == EMVSCATLG) +#else +#define APR_STATUS_IS_ENOENT(s) ((s) == APR_ENOENT) +#endif +/** not a directory */ +#define APR_STATUS_IS_ENOTDIR(s) ((s) == APR_ENOTDIR) +/** no space left on device */ +#ifdef EDQUOT +#define APR_STATUS_IS_ENOSPC(s) ((s) == APR_ENOSPC \ + || (s) == EDQUOT) +#else +#define APR_STATUS_IS_ENOSPC(s) ((s) == APR_ENOSPC) +#endif +/** not enough memory */ +#define APR_STATUS_IS_ENOMEM(s) ((s) == APR_ENOMEM) +/** too many open files */ +#define APR_STATUS_IS_EMFILE(s) ((s) == APR_EMFILE) +/** file table overflow */ +#define APR_STATUS_IS_ENFILE(s) ((s) == APR_ENFILE) +/** bad file # */ +#define APR_STATUS_IS_EBADF(s) ((s) == APR_EBADF) +/** invalid argument */ +#define APR_STATUS_IS_EINVAL(s) ((s) == APR_EINVAL) +/** illegal seek */ +#define APR_STATUS_IS_ESPIPE(s) ((s) == APR_ESPIPE) + +/** operation would block */ +#if !defined(EWOULDBLOCK) || !defined(EAGAIN) +#define APR_STATUS_IS_EAGAIN(s) ((s) == APR_EAGAIN) +#elif (EWOULDBLOCK == EAGAIN) +#define APR_STATUS_IS_EAGAIN(s) ((s) == APR_EAGAIN) +#else +#define APR_STATUS_IS_EAGAIN(s) ((s) == APR_EAGAIN \ + || (s) == EWOULDBLOCK) +#endif + +/** interrupted system call */ +#define APR_STATUS_IS_EINTR(s) ((s) == APR_EINTR) +/** socket operation on a non-socket */ +#define APR_STATUS_IS_ENOTSOCK(s) ((s) == APR_ENOTSOCK) +/** Connection Refused */ +#define APR_STATUS_IS_ECONNREFUSED(s) ((s) == APR_ECONNREFUSED) +/** operation now in progress */ +#define APR_STATUS_IS_EINPROGRESS(s) ((s) == APR_EINPROGRESS) + +/** + * Software caused connection abort + * @remark + * EPROTO on certain older kernels really means ECONNABORTED, so we need to + * ignore it for them. See discussion in new-httpd archives nh.9701 & nh.9603 + * + * There is potentially a bug in Solaris 2.x x<6, and other boxes that + * implement tcp sockets in userland (i.e. on top of STREAMS). On these + * systems, EPROTO can actually result in a fatal loop. See PR#981 for + * example. It's hard to handle both uses of EPROTO. + */ +#ifdef EPROTO +#define APR_STATUS_IS_ECONNABORTED(s) ((s) == APR_ECONNABORTED \ + || (s) == EPROTO) +#else +#define APR_STATUS_IS_ECONNABORTED(s) ((s) == APR_ECONNABORTED) +#endif + +/** Connection Reset by peer */ +#define APR_STATUS_IS_ECONNRESET(s) ((s) == APR_ECONNRESET) +/** Operation timed out + * @deprecated */ +#define APR_STATUS_IS_ETIMEDOUT(s) ((s) == APR_ETIMEDOUT) +/** no route to host */ +#define APR_STATUS_IS_EHOSTUNREACH(s) ((s) == APR_EHOSTUNREACH) +/** network is unreachable */ +#define APR_STATUS_IS_ENETUNREACH(s) ((s) == APR_ENETUNREACH) +/** inappropriate file type or format */ +#define APR_STATUS_IS_EFTYPE(s) ((s) == APR_EFTYPE) +/** broken pipe */ +#define APR_STATUS_IS_EPIPE(s) ((s) == APR_EPIPE) +/** cross device link */ +#define APR_STATUS_IS_EXDEV(s) ((s) == APR_EXDEV) +/** Directory Not Empty */ +#define APR_STATUS_IS_ENOTEMPTY(s) ((s) == APR_ENOTEMPTY || \ + (s) == APR_EEXIST) +/** Address Family not supported */ +#define APR_STATUS_IS_EAFNOSUPPORT(s) ((s) == APR_EAFNOSUPPORT) +/** Socket operation not supported */ +#define APR_STATUS_IS_EOPNOTSUPP(s) ((s) == APR_EOPNOTSUPP) + +/** Numeric value not representable */ +#define APR_STATUS_IS_ERANGE(s) ((s) == APR_ERANGE) +/** @} */ + +#endif /* !defined(NETWARE) && !defined(OS2) && !defined(WIN32) */ + +/** @} */ + #ifdef __cplusplus } #endif diff --git a/include/apr_escape.h b/include/apr_escape.h new file mode 100644 index 00000000000..6d4e08be0f3 --- /dev/null +++ b/include/apr_escape.h @@ -0,0 +1,418 @@ +/* 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. + */ +/** + * @file apr_escape.h + * @brief APR-UTIL Escaping + */ +#ifndef APR_ESCAPE_H +#define APR_ESCAPE_H +#include "apu.h" +#include "apr_general.h" +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup APR_Util_Escaping Escape functions + * @ingroup APR + * @{ + */ + +/* Simple escape/unescape functions. + * + */ + +/** + * When passing a string to one of the escape functions, this value can be + * passed to indicate a string-valued key, and have the length computed + * automatically. + */ +#define APR_ESCAPE_STRING (-1) + +/** + * Apply LDAP distinguished name escaping as per RFC4514. + */ +#define APR_ESCAPE_LDAP_DN (0x01) + +/** + * Apply LDAP filter escaping as per RFC4515. + */ +#define APR_ESCAPE_LDAP_FILTER (0x02) + +/** + * Apply both RFC4514 and RFC4515 LDAP escaping. + */ +#define APR_ESCAPE_LDAP_ALL (0x03) + +/** + * Perform shell escaping on the provided string. + * + * Shell escaping causes characters to be prefixed with a '\' character. + * @param escaped Optional buffer to write the encoded string, can be + * NULL + * @param str The original string + * @param slen The length of the original string, or APR_ESCAPE_STRING + * @param len If present, returns the length of the string + * @return APR_SUCCESS, or APR_NOTFOUND if no changes to the string were + * detected or the string was NULL + */ +APR_DECLARE(apr_status_t) apr_escape_shell(char *escaped, const char *str, + apr_ssize_t slen, apr_size_t *len); + +/** + * Perform shell escaping on the provided string, returning the result + * from the pool. + * + * Shell escaping causes characters to be prefixed with a '\' character. + * + * If no characters were escaped, the original string is returned. + * @param p Pool to allocate from + * @param str The original string + * @return the encoded string, allocated from the pool, or the original + * string if no escaping took place or the string was NULL. + */ +APR_DECLARE(const char *) apr_pescape_shell(apr_pool_t *p, const char *str) + __attribute__((nonnull(1))); + +/** + * Unescapes a URL, leaving reserved characters intact. + * @param escaped Optional buffer to write the encoded string, can be + * NULL + * @param url String to be unescaped + * @param slen The length of the original url, or APR_ESCAPE_STRING + * @param forbid Optional list of forbidden characters, in addition to + * 0x00 + * @param reserved Optional list of reserved characters that will be + * left unescaped + * @param plus If non zero, '+' is converted to ' ' as per + * application/x-www-form-urlencoded encoding + * @param len If set, the length of the escaped string will be returned + * @return APR_SUCCESS on success, APR_NOTFOUND if no characters are + * decoded or the string is NULL, APR_EINVAL if a bad escape sequence is + * found, APR_BADCH if a character on the forbid list is found. + */ +APR_DECLARE(apr_status_t) apr_unescape_url(char *escaped, const char *url, + apr_ssize_t slen, const char *forbid, const char *reserved, int plus, + apr_size_t *len); + +/** + * Unescapes a URL, leaving reserved characters intact, returning the + * result from a pool. + * @param p Pool to allocate from + * @param url String to be unescaped in place + * @param forbid Optional list of forbidden characters, in addition to + * 0x00 + * @param reserved Optional list of reserved characters that will be + * left unescaped + * @param plus If non zero, '+' is converted to ' ' as per + * application/x-www-form-urlencoded encoding + * @return A string allocated from the pool on success, the original string + * if no characters are decoded, or NULL if a bad escape sequence is found + * or if a character on the forbid list is found, or if the original string + * was NULL. + */ +APR_DECLARE(const char *) apr_punescape_url(apr_pool_t *p, const char *url, + const char *forbid, const char *reserved, int plus) + __attribute__((nonnull(1))); + +/** + * Escape a path segment, as defined in RFC1808. + * @param escaped Optional buffer to write the encoded string, can be + * NULL + * @param str The original string + * @param slen The length of the original string, or APR_ESCAPE_STRING + * @param len If present, returns the length of the string + * @return APR_SUCCESS, or APR_NOTFOUND if no changes to the string were + * detected or the string was NULL + */ +APR_DECLARE(apr_status_t) apr_escape_path_segment(char *escaped, + const char *str, apr_ssize_t slen, apr_size_t *len); + +/** + * Escape a path segment, as defined in RFC1808, returning the result from a + * pool. + * @param p Pool to allocate from + * @param str String to be escaped + * @return A string allocated from the pool on success, the original string + * if no characters are encoded or the string is NULL. + */ +APR_DECLARE(const char *) apr_pescape_path_segment(apr_pool_t *p, + const char *str) __attribute__((nonnull(1))); + +/** + * Converts an OS path to a URL, in an OS dependent way, as defined in RFC1808. + * In all cases if a ':' occurs before the first '/' in the URL, the URL should + * be prefixed with "./" (or the ':' escaped). In the case of Unix, this means + * leaving '/' alone, but otherwise doing what escape_path_segment() does. For + * efficiency reasons, we don't use escape_path_segment(), which is provided for + * reference. Again, RFC 1808 is where this stuff is defined. + * + * If partial is set, os_escape_path() assumes that the path will be appended to + * something with a '/' in it (and thus does not prefix "./"). + * @param escaped Optional buffer to write the encoded string, can be + * NULL + * @param path The original string + * @param slen The length of the original string, or APR_ESCAPE_STRING + * @param partial If non zero, suppresses the prepending of "./" + * @param len If present, returns the length of the string + * @return APR_SUCCESS, or APR_NOTFOUND if no changes to the string were + * detected or if the string was NULL + */ +APR_DECLARE(apr_status_t) apr_escape_path(char *escaped, const char *path, + apr_ssize_t slen, int partial, apr_size_t *len); + +/** + * Converts an OS path to a URL, in an OS dependent way, as defined in RFC1808, + * returning the result from a pool. + * + * In all cases if a ':' occurs before the first '/' in the URL, the URL should + * be prefixed with "./" (or the ':' escaped). In the case of Unix, this means + * leaving '/' alone, but otherwise doing what escape_path_segment() does. For + * efficiency reasons, we don't use escape_path_segment(), which is provided for + * reference. Again, RFC 1808 is where this stuff is defined. + * + * If partial is set, os_escape_path() assumes that the path will be appended to + * something with a '/' in it (and thus does not prefix "./"). + * @param p Pool to allocate from + * @param str The original string + * @param partial If non zero, suppresses the prepending of "./" + * @return A string allocated from the pool on success, the original string + * if no characters are encoded or if the string was NULL. + */ +APR_DECLARE(const char *) apr_pescape_path(apr_pool_t *p, const char *str, + int partial) __attribute__((nonnull(1))); + +/** + * Urlencode a string, as defined in + * http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4.1. + * @param escaped Optional buffer to write the encoded string, can be + * NULL + * @param str The original string + * @param slen The length of the original string, or APR_ESCAPE_STRING + * @param len If present, returns the length of the string + * @return APR_SUCCESS, or APR_NOTFOUND if no changes to the string were + * detected or if the stirng was NULL + */ +APR_DECLARE(apr_status_t) apr_escape_urlencoded(char *escaped, const char *str, + apr_ssize_t slen, apr_size_t *len); + +/** + * Urlencode a string, as defined in + * http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4.1, returning + * the result from a pool. + * @param p Pool to allocate from + * @param str String to be escaped + * @return A string allocated from the pool on success, the original string + * if no characters are encoded or if the string was NULL. + */ +APR_DECLARE(const char *) apr_pescape_urlencoded(apr_pool_t *p, + const char *str) __attribute__((nonnull(1))); + +/** + * Apply entity encoding to a string. Characters are replaced as follows: + * '<' becomes '<', '>' becomes '>', '&' becomes '&', the + * double quote becomes '"" and the single quote becomes '''. + * + * If toasc is not zero, any non ascii character will be encoded as + * '%\#ddd;', where ddd is the decimal code of the character. + * @param escaped Optional buffer to write the encoded string, can be + * NULL + * @param str The original string + * @param slen The length of the original string, or APR_ESCAPE_STRING + * @param toasc If non zero, encode non ascii characters + * @param len If present, returns the length of the string + * @return APR_SUCCESS, or APR_NOTFOUND if no changes to the string were + * detected or the string was NULL + */ +APR_DECLARE(apr_status_t) apr_escape_entity(char *escaped, const char *str, + apr_ssize_t slen, int toasc, apr_size_t *len); + +/** + * Apply entity encoding to a string, returning the result from a pool. + * Characters are replaced as follows: '<' becomes '<', '>' becomes + * '>', '&' becomes '&', the double quote becomes '"" and the + * single quote becomes '''. + * @param p Pool to allocate from + * @param str The original string + * @param toasc If non zero, encode non ascii characters + * @return A string allocated from the pool on success, the original string + * if no characters are encoded or the string is NULL. + */ +APR_DECLARE(const char *) apr_pescape_entity(apr_pool_t *p, const char *str, + int toasc) __attribute__((nonnull(1))); + +/** + * Decodes html entities or numeric character references in a string. If + * the string to be unescaped is syntactically incorrect, then the + * following fixups will be made: + * unknown entities will be left undecoded; + * references to unused numeric characters will be deleted. + * In particular, � will not be decoded, but will be deleted. + * @param unescaped Optional buffer to write the encoded string, can be + * NULL + * @param str The original string + * @param slen The length of the original string, or APR_ESCAPE_STRING + * @param len If present, returns the length of the string + * @return APR_SUCCESS, or APR_NOTFOUND if no changes to the string were + * detected or the string was NULL + */ +APR_DECLARE(apr_status_t) apr_unescape_entity(char *unescaped, const char *str, + apr_ssize_t slen, apr_size_t *len); + +/** + * Decodes html entities or numeric character references in a string. If + * the string to be unescaped is syntactically incorrect, then the + * following fixups will be made: + * unknown entities will be left undecoded; + * references to unused numeric characters will be deleted. + * In particular, � will not be decoded, but will be deleted. + * @param p Pool to allocate from + * @param str The original string + * @return A string allocated from the pool on success, the original string + * if no characters are encoded or the string is NULL. + */ +APR_DECLARE(const char *) apr_punescape_entity(apr_pool_t *p, const char *str) + __attribute__((nonnull(1))); + +/** + * Escape control characters in a string, as performed by the shell's + * 'echo' command. Characters are replaced as follows: + * \\a alert (bell), \\b backspace, \\f form feed, \\n new line, \\r carriage + * return, \\t horizontal tab, \\v vertical tab, \\ backslash. + * + * Any non ascii character will be encoded as '\\xHH', where HH is the hex + * code of the character. + * + * If quote is not zero, the double quote character will also be escaped. + * @param escaped Optional buffer to write the encoded string, can be + * NULL + * @param str The original string + * @param slen The length of the original string, or APR_ESCAPE_STRING + * @param quote If non zero, encode double quotes + * @param len If present, returns the length of the string + * @return APR_SUCCESS, or APR_NOTFOUND if no changes to the string were + * detected or the string was NULL + */ +APR_DECLARE(apr_status_t) apr_escape_echo(char *escaped, const char *str, + apr_ssize_t slen, int quote, apr_size_t *len); + +/** + * Escape control characters in a string, as performed by the shell's + * 'echo' command, and return the results from a pool. Characters are + * replaced as follows: \\a alert (bell), \\b backspace, \\f form feed, + * \\n new line, \\r carriage return, \\t horizontal tab, \\v vertical tab, + * \\ backslash. + * + * Any non ascii character will be encoded as '\\xHH', where HH is the hex + * code of the character. + * + * If quote is not zero, the double quote character will also be escaped. + * @param p Pool to allocate from + * @param str The original string + * @param quote If non zero, encode double quotes + * @return A string allocated from the pool on success, the original string + * if no characters are encoded or the string is NULL. + */ +APR_DECLARE(const char *) apr_pescape_echo(apr_pool_t *p, const char *str, + int quote); + +/** + * Convert binary data to a hex encoding. + * @param dest The destination buffer, can be NULL + * @param src The original buffer + * @param srclen The length of the original buffer + * @param colon If not zero, insert colon characters between hex digits. + * @param len If present, returns the length of the string + * @return APR_SUCCESS, or APR_NOTFOUND if the string was NULL + */ +APR_DECLARE(apr_status_t) apr_escape_hex(char *dest, const void *src, + apr_size_t srclen, int colon, apr_size_t *len); + +/** + * Convert binary data to a hex encoding, and return the results from a + * pool. + * @param p Pool to allocate from + * @param src The original buffer + * @param slen The length of the original buffer + * @param colon If not zero, insert colon characters between hex digits. + * @return A zero padded buffer allocated from the pool on success, or + * NULL if src was NULL. + */ +APR_DECLARE(const char *) apr_pescape_hex(apr_pool_t *p, const void *src, + apr_size_t slen, int colon) __attribute__((nonnull(1))); + +/** + * Convert hex encoded string to binary data. + * @param dest The destination buffer, can be NULL + * @param str The original buffer + * @param slen The length of the original buffer + * @param colon If not zero, ignore colon characters between hex digits. + * @param len If present, returns the length of the string + * @return APR_SUCCESS, or APR_NOTFOUND if the string was NULL, or APR_BADCH + * if a non hex character is present. + */ +APR_DECLARE(apr_status_t) apr_unescape_hex(void *dest, const char *str, + apr_ssize_t slen, int colon, apr_size_t *len); + +/** + * Convert hex encoding to binary data, and return the results from a pool. + * If the colon character appears between pairs of hex digits, it will be + * ignored. + * @param p Pool to allocate from + * @param str The original string + * @param colon If not zero, ignore colon characters between hex digits. + * @param len If present, returns the length of the final buffer + * @return A buffer allocated from the pool on success, or NULL if src was + * NULL, or a bad character was present. + */ +APR_DECLARE(const void *) apr_punescape_hex(apr_pool_t *p, const char *str, + int colon, apr_size_t *len); + +/** + * Apply LDAP escaping to binary data. Characters from RFC4514 and RFC4515 + * are escaped with their hex equivalents. + * @param dest The destination buffer, can be NULL + * @param src The original buffer + * @param srclen The length of the original buffer + * @param flags APR_ESCAPE_LDAP_DN for RFC4514, APR_ESCAPE_LDAP_FILTER for + * RFC4515, APR_ESCAPE_LDAP_ALL for both + * @param len If present, returns the length of the string + * @return APR_SUCCESS, or APR_NOTFOUND if the string was NULL + */ +APR_DECLARE(apr_status_t) apr_escape_ldap(char *dest, const void *src, + apr_ssize_t srclen, int flags, apr_size_t *len); + +/** + * Apply LDAP escaping to binary data, and return the results from a + * pool. Characters from RFC4514 and RFC4515 are escaped with their hex + * equivalents. + * @param p Pool to allocate from + * @param src The original buffer + * @param slen The length of the original buffer + * @param flags APR_ESCAPE_LDAP_DN for RFC4514, APR_ESCAPE_LDAP_FILTER for + * RFC4515, APR_ESCAPE_LDAP_ALL for both + * @return A zero padded buffer allocated from the pool on success, or + * NULL if src was NULL. + */ +APR_DECLARE(const char *) apr_pescape_ldap(apr_pool_t *p, const void *src, + apr_ssize_t slen, int flags) __attribute__((nonnull(1))); + +/** @} */ +#ifdef __cplusplus +} +#endif + +#endif /* !APR_ESCAPE_H */ diff --git a/include/apr_file_info.h b/include/apr_file_info.h new file mode 100644 index 00000000000..1d19eb6a3f4 --- /dev/null +++ b/include/apr_file_info.h @@ -0,0 +1,428 @@ +/* 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. + */ + +#ifndef APR_FILE_INFO_H +#define APR_FILE_INFO_H + +/** + * @file apr_file_info.h + * @brief APR File Information + */ + +#include "apr.h" +#include "apr_user.h" +#include "apr_pools.h" +#include "apr_tables.h" +#include "apr_time.h" +#include "apr_errno.h" + +#if APR_HAVE_SYS_UIO_H +#include <sys/uio.h> +#endif + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup apr_file_info File Information + * @ingroup APR + * @{ + */ + +/* Many applications use the type member to determine the + * existance of a file or initialization of the file info, + * so the APR_NOFILE value must be distinct from APR_UNKFILE. + */ + +/** apr_filetype_e values for the filetype member of the + * apr_file_info_t structure + * @warning: Not all of the filetypes below can be determined. + * For example, a given platform might not correctly report + * a socket descriptor as APR_SOCK if that type isn't + * well-identified on that platform. In such cases where + * a filetype exists but cannot be described by the recognized + * flags below, the filetype will be APR_UNKFILE. If the + * filetype member is not determined, the type will be APR_NOFILE. + */ + +typedef enum { + APR_NOFILE = 0, /**< no file type determined */ + APR_REG, /**< a regular file */ + APR_DIR, /**< a directory */ + APR_CHR, /**< a character device */ + APR_BLK, /**< a block device */ + APR_PIPE, /**< a FIFO / pipe */ + APR_LNK, /**< a symbolic link */ + APR_SOCK, /**< a [unix domain] socket */ + APR_UNKFILE = 127 /**< a file of some other unknown type */ +} apr_filetype_e; + +/** + * @defgroup apr_file_permissions File Permissions flags + * @{ + */ + +#define APR_FPROT_USETID 0x8000 /**< Set user id */ +#define APR_FPROT_UREAD 0x0400 /**< Read by user */ +#define APR_FPROT_UWRITE 0x0200 /**< Write by user */ +#define APR_FPROT_UEXECUTE 0x0100 /**< Execute by user */ + +#define APR_FPROT_GSETID 0x4000 /**< Set group id */ +#define APR_FPROT_GREAD 0x0040 /**< Read by group */ +#define APR_FPROT_GWRITE 0x0020 /**< Write by group */ +#define APR_FPROT_GEXECUTE 0x0010 /**< Execute by group */ + +#define APR_FPROT_WSTICKY 0x2000 /**< Sticky bit */ +#define APR_FPROT_WREAD 0x0004 /**< Read by others */ +#define APR_FPROT_WWRITE 0x0002 /**< Write by others */ +#define APR_FPROT_WEXECUTE 0x0001 /**< Execute by others */ + +#define APR_FPROT_OS_DEFAULT 0x0FFF /**< use OS's default permissions */ + +/* additional permission flags for apr_file_copy and apr_file_append */ +#define APR_FPROT_FILE_SOURCE_PERMS 0x1000 /**< Copy source file's permissions */ + +/* backcompat */ +#define APR_USETID APR_FPROT_USETID /**< @deprecated @see APR_FPROT_USETID */ +#define APR_UREAD APR_FPROT_UREAD /**< @deprecated @see APR_FPROT_UREAD */ +#define APR_UWRITE APR_FPROT_UWRITE /**< @deprecated @see APR_FPROT_UWRITE */ +#define APR_UEXECUTE APR_FPROT_UEXECUTE /**< @deprecated @see APR_FPROT_UEXECUTE */ +#define APR_GSETID APR_FPROT_GSETID /**< @deprecated @see APR_FPROT_GSETID */ +#define APR_GREAD APR_FPROT_GREAD /**< @deprecated @see APR_FPROT_GREAD */ +#define APR_GWRITE APR_FPROT_GWRITE /**< @deprecated @see APR_FPROT_GWRITE */ +#define APR_GEXECUTE APR_FPROT_GEXECUTE /**< @deprecated @see APR_FPROT_GEXECUTE */ +#define APR_WSTICKY APR_FPROT_WSTICKY /**< @deprecated @see APR_FPROT_WSTICKY */ +#define APR_WREAD APR_FPROT_WREAD /**< @deprecated @see APR_FPROT_WREAD */ +#define APR_WWRITE APR_FPROT_WWRITE /**< @deprecated @see APR_FPROT_WWRITE */ +#define APR_WEXECUTE APR_FPROT_WEXECUTE /**< @deprecated @see APR_FPROT_WEXECUTE */ +#define APR_OS_DEFAULT APR_FPROT_OS_DEFAULT /**< @deprecated @see APR_FPROT_OS_DEFAULT */ +#define APR_FILE_SOURCE_PERMS APR_FPROT_FILE_SOURCE_PERMS /**< @deprecated @see APR_FPROT_FILE_SOURCE_PERMS */ + +/** @} */ + + +/** + * Structure for referencing directories. + */ +typedef struct apr_dir_t apr_dir_t; +/** + * Structure for determining file permissions. + */ +typedef apr_int32_t apr_fileperms_t; +#if (defined WIN32) || (defined NETWARE) +/** + * Structure for determining the device the file is on. + */ +typedef apr_uint32_t apr_dev_t; +#else +/** + * Structure for determining the device the file is on. + */ +typedef dev_t apr_dev_t; +#endif + +/** + * @defgroup apr_file_stat Stat Functions + * @{ + */ +/** file info structure */ +typedef struct apr_finfo_t apr_finfo_t; + +#define APR_FINFO_LINK 0x00000001 /**< Stat the link not the file itself if it is a link */ +#define APR_FINFO_MTIME 0x00000010 /**< Modification Time */ +#define APR_FINFO_CTIME 0x00000020 /**< Creation or inode-changed time */ +#define APR_FINFO_ATIME 0x00000040 /**< Access Time */ +#define APR_FINFO_SIZE 0x00000100 /**< Size of the file */ +#define APR_FINFO_CSIZE 0x00000200 /**< Storage size consumed by the file */ +#define APR_FINFO_DEV 0x00001000 /**< Device */ +#define APR_FINFO_INODE 0x00002000 /**< Inode */ +#define APR_FINFO_NLINK 0x00004000 /**< Number of links */ +#define APR_FINFO_TYPE 0x00008000 /**< Type */ +#define APR_FINFO_USER 0x00010000 /**< User */ +#define APR_FINFO_GROUP 0x00020000 /**< Group */ +#define APR_FINFO_UPROT 0x00100000 /**< User protection bits */ +#define APR_FINFO_GPROT 0x00200000 /**< Group protection bits */ +#define APR_FINFO_WPROT 0x00400000 /**< World protection bits */ +#define APR_FINFO_ICASE 0x01000000 /**< if dev is case insensitive */ +#define APR_FINFO_NAME 0x02000000 /**< ->name in proper case */ + +#define APR_FINFO_MIN 0x00008170 /**< type, mtime, ctime, atime, size */ +#define APR_FINFO_IDENT 0x00003000 /**< dev and inode */ +#define APR_FINFO_OWNER 0x00030000 /**< user and group */ +#define APR_FINFO_PROT 0x00700000 /**< all protections */ +#define APR_FINFO_NORM 0x0073b170 /**< an atomic unix apr_stat() */ +#define APR_FINFO_DIRENT 0x02000000 /**< an atomic unix apr_dir_read() */ + +/** + * The file information structure. This is analogous to the POSIX + * stat structure. + */ +struct apr_finfo_t { + /** Allocates memory and closes lingering handles in the specified pool */ + apr_pool_t *pool; + /** The bitmask describing valid fields of this apr_finfo_t structure + * including all available 'wanted' fields and potentially more */ + apr_int32_t valid; + /** The access permissions of the file. Mimics Unix access rights. */ + apr_fileperms_t protection; + /** The type of file. One of APR_REG, APR_DIR, APR_CHR, APR_BLK, APR_PIPE, + * APR_LNK or APR_SOCK. If the type is undetermined, the value is APR_NOFILE. + * If the type cannot be determined, the value is APR_UNKFILE. + */ + apr_filetype_e filetype; + /** The user id that owns the file */ + apr_uid_t user; + /** The group id that owns the file */ + apr_gid_t group; + /** The inode of the file. */ + apr_ino_t inode; + /** The id of the device the file is on. */ + apr_dev_t device; + /** The number of hard links to the file. */ + apr_int32_t nlink; + /** The size of the file */ + apr_off_t size; + /** The storage size consumed by the file */ + apr_off_t csize; + /** The time the file was last accessed */ + apr_time_t atime; + /** The time the file was last modified */ + apr_time_t mtime; + /** The time the file was created, or the inode was last changed */ + apr_time_t ctime; + /** The pathname of the file (possibly unrooted) */ + const char *fname; + /** The file's name (no path) in filesystem case */ + const char *name; + /** Unused */ + struct apr_file_t *filehand; +}; + +/** + * get the specified file's stats. The file is specified by filename, + * instead of using a pre-opened file. + * @param finfo Where to store the information about the file, which is + * never touched if the call fails. + * @param fname The name of the file to stat. + * @param wanted The desired apr_finfo_t fields, as a bit flag of APR_FINFO_ + values + * @param pool the pool to use to allocate the new file. + * + * @note If @c APR_INCOMPLETE is returned all the fields in @a finfo may + * not be filled in, and you need to check the @c finfo->valid bitmask + * to verify that what you're looking for is there. + */ +APR_DECLARE(apr_status_t) apr_stat(apr_finfo_t *finfo, const char *fname, + apr_int32_t wanted, apr_pool_t *pool); + +/** @} */ +/** + * @defgroup apr_dir Directory Manipulation Functions + * @{ + */ + +/** + * Open the specified directory. + * @param new_dir The opened directory descriptor. + * @param dirname The full path to the directory (use / on all systems) + * @param pool The pool to use. + */ +APR_DECLARE(apr_status_t) apr_dir_open(apr_dir_t **new_dir, + const char *dirname, + apr_pool_t *pool); + +/** + * close the specified directory. + * @param thedir the directory descriptor to close. + */ +APR_DECLARE(apr_status_t) apr_dir_close(apr_dir_t *thedir); + +/** + * Read the next entry from the specified directory. + * @param finfo the file info structure and filled in by apr_dir_read + * @param wanted The desired apr_finfo_t fields, as a bit flag of APR_FINFO_ + values + * @param thedir the directory descriptor returned from apr_dir_open + * @remark No ordering is guaranteed for the entries read. + * + * @note If @c APR_INCOMPLETE is returned all the fields in @a finfo may + * not be filled in, and you need to check the @c finfo->valid bitmask + * to verify that what you're looking for is there. When no more + * entries are available, APR_ENOENT is returned. + */ +APR_DECLARE(apr_status_t) apr_dir_read(apr_finfo_t *finfo, apr_int32_t wanted, + apr_dir_t *thedir); + +/** + * Rewind the directory to the first entry. + * @param thedir the directory descriptor to rewind. + */ +APR_DECLARE(apr_status_t) apr_dir_rewind(apr_dir_t *thedir); +/** @} */ + +/** + * @defgroup apr_filepath Filepath Manipulation Functions + * @{ + */ + +/** Cause apr_filepath_merge to fail if addpath is above rootpath + * @bug in APR 0.9 and 1.x, this flag's behavior is undefined + * if the rootpath is NULL or empty. In APR 2.0 this should be + * changed to imply NOTABSOLUTE if the rootpath is NULL or empty. + */ +#define APR_FILEPATH_NOTABOVEROOT 0x01 + +/** internal: Only meaningful with APR_FILEPATH_NOTABOVEROOT */ +#define APR_FILEPATH_SECUREROOTTEST 0x02 + +/** Cause apr_filepath_merge to fail if addpath is above rootpath, + * even given a rootpath /foo/bar and an addpath ../bar/bash + */ +#define APR_FILEPATH_SECUREROOT 0x03 + +/** Fail apr_filepath_merge if the merged path is relative */ +#define APR_FILEPATH_NOTRELATIVE 0x04 + +/** Fail apr_filepath_merge if the merged path is absolute */ +#define APR_FILEPATH_NOTABSOLUTE 0x08 + +/** Return the file system's native path format (e.g. path delimiters + * of ':' on MacOS9, '\' on Win32, etc.) */ +#define APR_FILEPATH_NATIVE 0x10 + +/** Resolve the true case of existing directories and file elements + * of addpath, (resolving any aliases on Win32) and append a proper + * trailing slash if a directory + */ +#define APR_FILEPATH_TRUENAME 0x20 + +/** + * Extract the rootpath from the given filepath + * @param rootpath the root file path returned with APR_SUCCESS or APR_EINCOMPLETE + * @param filepath the pathname to parse for its root component + * @param flags the desired rules to apply, from + * <PRE> + * APR_FILEPATH_NATIVE Use native path separators (e.g. '\' on Win32) + * APR_FILEPATH_TRUENAME Tests that the root exists, and makes it proper + * </PRE> + * @param p the pool to allocate the new path string from + * @remark on return, filepath points to the first non-root character in the + * given filepath. In the simplest example, given a filepath of "/foo", + * returns the rootpath of "/" and filepath points at "foo". This is far + * more complex on other platforms, which will canonicalize the root form + * to a consistant format, given the APR_FILEPATH_TRUENAME flag, and also + * test for the validity of that root (e.g., that a drive d:/ or network + * share //machine/foovol/). + * The function returns APR_ERELATIVE if filepath isn't rooted (an + * error), APR_EINCOMPLETE if the root path is ambiguous (but potentially + * legitimate, e.g. "/" on Windows is incomplete because it doesn't specify + * the drive letter), or APR_EBADPATH if the root is simply invalid. + * APR_SUCCESS is returned if filepath is an absolute path. + */ +APR_DECLARE(apr_status_t) apr_filepath_root(const char **rootpath, + const char **filepath, + apr_int32_t flags, + apr_pool_t *p); + +/** + * Merge additional file path onto the previously processed rootpath + * @param newpath the merged paths returned + * @param rootpath the root file path (NULL uses the current working path) + * @param addpath the path to add to the root path + * @param flags the desired APR_FILEPATH_ rules to apply when merging + * @param p the pool to allocate the new path string from + * @remark if the flag APR_FILEPATH_TRUENAME is given, and the addpath + * contains wildcard characters ('*', '?') on platforms that don't support + * such characters within filenames, the paths will be merged, but the + * result code will be APR_EPATHWILD, and all further segments will not + * reflect the true filenames including the wildcard and following segments. + */ +APR_DECLARE(apr_status_t) apr_filepath_merge(char **newpath, + const char *rootpath, + const char *addpath, + apr_int32_t flags, + apr_pool_t *p); + +/** + * Split a search path into separate components + * @param pathelts the returned components of the search path + * @param liststr the search path (e.g., <tt>getenv("PATH")</tt>) + * @param p the pool to allocate the array and path components from + * @remark empty path components do not become part of @a pathelts. + * @remark the path separator in @a liststr is system specific; + * e.g., ':' on Unix, ';' on Windows, etc. + */ +APR_DECLARE(apr_status_t) apr_filepath_list_split(apr_array_header_t **pathelts, + const char *liststr, + apr_pool_t *p); + +/** + * Merge a list of search path components into a single search path + * @param liststr the returned search path; may be NULL if @a pathelts is empty + * @param pathelts the components of the search path + * @param p the pool to allocate the search path from + * @remark emtpy strings in the source array are ignored. + * @remark the path separator in @a liststr is system specific; + * e.g., ':' on Unix, ';' on Windows, etc. + */ +APR_DECLARE(apr_status_t) apr_filepath_list_merge(char **liststr, + apr_array_header_t *pathelts, + apr_pool_t *p); + +/** + * Return the default file path (for relative file names) + * @param path the default path string returned + * @param flags optional flag APR_FILEPATH_NATIVE to retrieve the + * default file path in os-native format. + * @param p the pool to allocate the default path string from + */ +APR_DECLARE(apr_status_t) apr_filepath_get(char **path, apr_int32_t flags, + apr_pool_t *p); + +/** + * Set the default file path (for relative file names) + * @param path the default path returned + * @param p the pool to allocate any working storage + */ +APR_DECLARE(apr_status_t) apr_filepath_set(const char *path, apr_pool_t *p); + +/** The FilePath character encoding is unknown */ +#define APR_FILEPATH_ENCODING_UNKNOWN 0 + +/** The FilePath character encoding is locale-dependent */ +#define APR_FILEPATH_ENCODING_LOCALE 1 + +/** The FilePath character encoding is UTF-8 */ +#define APR_FILEPATH_ENCODING_UTF8 2 + +/** + * Determine the encoding used internally by the FilePath functions + * @param style points to a variable which receives the encoding style flag + * @param p the pool to allocate any working storage + * @remark Use @c apr_os_locale_encoding and/or @c apr_os_default_encoding + * to get the name of the path encoding if it's not UTF-8. + */ +APR_DECLARE(apr_status_t) apr_filepath_encoding(int *style, apr_pool_t *p); +/** @} */ + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* ! APR_FILE_INFO_H */ diff --git a/include/apr_file_io.h b/include/apr_file_io.h index 3bee3987e33..4611b1a153a 100644 --- a/include/apr_file_io.h +++ b/include/apr_file_io.h @@ -1,687 +1,1029 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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. */ #ifndef APR_FILE_IO_H #define APR_FILE_IO_H -#include "apr_general.h" +/** + * @file apr_file_io.h + * @brief APR File I/O Handling + */ + +#include "apr.h" +#include "apr_pools.h" #include "apr_time.h" #include "apr_errno.h" -#if APR_HAVE_SYS_UIO_H -#include <sys/uio.h> -#endif +#include "apr_file_info.h" +#include "apr_inherit.h" + +#define APR_WANT_STDIO /**< for SEEK_* */ +#define APR_WANT_IOVEC /**< for apr_file_writev */ +#include "apr_want.h" #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ -typedef enum {APR_NOFILE, APR_REG, APR_DIR, APR_CHR, APR_BLK, APR_PIPE, APR_LNK, - APR_SOCK} ap_filetype_e; - -/* Flags for ap_open */ -#define APR_READ 1 /* Open the file for reading */ -#define APR_WRITE 2 /* Open the file for writing */ -#define APR_CREATE 4 /* Create the file if not there */ -#define APR_APPEND 8 /* Append to the end of the file */ -#define APR_TRUNCATE 16 /* Open the file and truncate to 0 length */ -#define APR_BINARY 32 /* Open the file in binary mode */ -#define APR_EXCL 64 /* Open should fail if APR_CREATE and file - exists. */ -#define APR_BUFFERED 128 /* Open the file for buffered I/O */ -#define APR_DELONCLOSE 256 /* Delete the file after close */ - -/* flags for ap_seek */ -#define APR_SET SEEK_SET -#define APR_CUR SEEK_CUR -#define APR_END SEEK_END - -/* Permissions flags */ -#define APR_UREAD 0x400 -#define APR_UWRITE 0x200 -#define APR_UEXECUTE 0x100 - -#define APR_GREAD 0x040 -#define APR_GWRITE 0x020 -#define APR_GEXECUTE 0x010 - -#define APR_WREAD 0x004 -#define APR_WWRITE 0x002 -#define APR_WEXECUTE 0x001 - -#define APR_OS_DEFAULT 0xFFF - -/* should be same as whence type in lseek, POSIX defines this as int */ -typedef ap_int32_t ap_seek_where_t; - -typedef struct ap_file_t ap_file_t; -typedef struct ap_finfo_t ap_finfo_t; -typedef struct ap_dir_t ap_dir_t; -typedef ap_int32_t ap_fileperms_t; -typedef uid_t ap_uid_t; -typedef gid_t ap_gid_t; -typedef ino_t ap_ino_t; - -struct ap_finfo_t { - ap_fileperms_t protection; - ap_filetype_e filetype; - ap_uid_t user; - ap_gid_t group; - ap_ino_t inode; - ap_off_t size; - ap_time_t atime; - ap_time_t mtime; - ap_time_t ctime; -}; - -/* Function definitions */ -/* - -=head1 ap_status_t ap_open(ap_file_t **new, char *fname, ap_int32 flag, ap_fileperms perm, ap_pool_t *cont) - -B<Open the specified file.> - - arg 1) The opened file descriptor. - arg 2) The full path to the file (using / on all systems) - arg 3) Or'ed value of: - APR_READ open for reading - APR_WRITE open for writing - APR_CREATE create the file if not there - APR_APPEND file ptr is set to end prior to all writes - APR_TRUNCATE set length to zero if file exists - APR_BINARY not a text file (This flag is ignored on - UNIX because it has no meaning) - APR_BUFFERED buffer the data. Default is non-buffered - APR_EXCL return error if APR_CREATE and file exists - APR_DELONCLOSE delete the file after closing. - arg 4) Access permissions for file. - arg 5) The pool to use. - -B<NOTE>: If perm is APR_OS_DEFAULT and the file is being created, appropriate - default permissions will be used. *arg1 must point to a valid file_t, - or NULL (in which case it will be allocated) - -=cut +/** + * @defgroup apr_file_io File I/O Handling Functions + * @ingroup APR + * @{ */ -ap_status_t ap_open(ap_file_t **new, const char *fname, ap_int32_t flag, - ap_fileperms_t perm, ap_pool_t *cont); - -/* - -=head1 ap_status_t ap_close(ap_file_t *file) -B<Close the specified file.> - - arg 1) The file descriptor to close. - -=cut +/** + * @defgroup apr_file_open_flags File Open Flags/Routines + * @{ */ -ap_status_t ap_close(ap_file_t *file); - -/* - -=head1 ap_status_t ap_remove_file(char *path, ap_pool_t *cont) -B<delete the specified file.> - - arg 1) The full path to the file (using / on all systems) - arg 2) The pool to use. - -B<NOTE>: If the file is open, it won't be removed until all instances are - closed. - -=cut +/* Note to implementors: Values in the range 0x00100000--0x80000000 + are reserved for platform-specific values. */ + +#define APR_FOPEN_READ 0x00001 /**< Open the file for reading */ +#define APR_FOPEN_WRITE 0x00002 /**< Open the file for writing */ +#define APR_FOPEN_CREATE 0x00004 /**< Create the file if not there */ +#define APR_FOPEN_APPEND 0x00008 /**< Append to the end of the file */ +#define APR_FOPEN_TRUNCATE 0x00010 /**< Open the file and truncate + to 0 length */ +#define APR_FOPEN_BINARY 0x00020 /**< Open the file in binary mode + (This flag is ignored on UNIX + because it has no meaning)*/ +#define APR_FOPEN_EXCL 0x00040 /**< Open should fail if #APR_FOPEN_CREATE + and file exists. */ +#define APR_FOPEN_BUFFERED 0x00080 /**< Open the file for buffered I/O */ +#define APR_FOPEN_DELONCLOSE 0x00100 /**< Delete the file after close */ +#define APR_FOPEN_XTHREAD 0x00200 /**< Platform dependent tag to open + the file for use across multiple + threads */ +#define APR_FOPEN_SHARELOCK 0x00400 /**< Platform dependent support for + higher level locked read/write + access to support writes across + process/machines */ +#define APR_FOPEN_NOCLEANUP 0x00800 /**< Do not register a cleanup + when the file is opened. The + apr_os_file_t handle in apr_file_t + will not be closed when the pool + is destroyed. */ +#define APR_FOPEN_SENDFILE_ENABLED 0x01000 /**< Advisory flag that this + file should support + apr_socket_sendfile operation */ +#define APR_FOPEN_LARGEFILE 0x04000 /**< Platform dependent flag to enable + * large file support, see WARNING below + */ + +#define APR_FOPEN_SPARSE 0x08000 /**< Platform dependent flag to enable + * sparse file support, see WARNING below + */ + +#define APR_FOPEN_ROTATING 0x10000 /**< Do file file rotation checking */ + +#define APR_FOPEN_MANUAL_ROTATE 0x20000 /**< Enable Manual rotation */ + +#define APR_FOPEN_NONBLOCK 0x40000 /**< Platform dependent flag to enable + * non blocking file io */ + + + +/* backcompat */ +#define APR_READ APR_FOPEN_READ /**< @deprecated @see APR_FOPEN_READ */ +#define APR_WRITE APR_FOPEN_WRITE /**< @deprecated @see APR_FOPEN_WRITE */ +#define APR_CREATE APR_FOPEN_CREATE /**< @deprecated @see APR_FOPEN_CREATE */ +#define APR_APPEND APR_FOPEN_APPEND /**< @deprecated @see APR_FOPEN_APPEND */ +#define APR_TRUNCATE APR_FOPEN_TRUNCATE /**< @deprecated @see APR_FOPEN_TRUNCATE */ +#define APR_BINARY APR_FOPEN_BINARY /**< @deprecated @see APR_FOPEN_BINARY */ +#define APR_EXCL APR_FOPEN_EXCL /**< @deprecated @see APR_FOPEN_EXCL */ +#define APR_BUFFERED APR_FOPEN_BUFFERED /**< @deprecated @see APR_FOPEN_BUFFERED */ +#define APR_DELONCLOSE APR_FOPEN_DELONCLOSE /**< @deprecated @see APR_FOPEN_DELONCLOSE */ +#define APR_XTHREAD APR_FOPEN_XTHREAD /**< @deprecated @see APR_FOPEN_XTHREAD */ +#define APR_SHARELOCK APR_FOPEN_SHARELOCK /**< @deprecated @see APR_FOPEN_SHARELOCK */ +#define APR_FILE_NOCLEANUP APR_FOPEN_NOCLEANUP /**< @deprecated @see APR_FOPEN_NOCLEANUP */ +#define APR_SENDFILE_ENABLED APR_FOPEN_SENDFILE_ENABLED /**< @deprecated @see APR_FOPEN_SENDFILE_ENABLED */ +#define APR_LARGEFILE APR_FOPEN_LARGEFILE /**< @deprecated @see APR_FOPEN_LARGEFILE */ + +/** @def APR_FOPEN_LARGEFILE + * @warning APR_FOPEN_LARGEFILE flag only has effect on some + * platforms where sizeof(apr_off_t) == 4. Where implemented, it + * allows opening and writing to a file which exceeds the size which + * can be represented by apr_off_t (2 gigabytes). When a file's size + * does exceed 2Gb, apr_file_info_get() will fail with an error on the + * descriptor, likewise apr_stat()/apr_lstat() will fail on the + * filename. apr_dir_read() will fail with #APR_INCOMPLETE on a + * directory entry for a large file depending on the particular + * APR_FINFO_* flags. Generally, it is not recommended to use this + * flag. + * + * @def APR_FOPEN_SPARSE + * @warning APR_FOPEN_SPARSE may, depending on platform, convert a + * normal file to a sparse file. Some applications may be unable + * to decipher a sparse file, so it's critical that the sparse file + * flag should only be used for files accessed only by APR or other + * applications known to be able to decipher them. APR does not + * guarantee that it will compress the file into sparse segments + * if it was previously created and written without the sparse flag. + * On platforms which do not understand, or on file systems which + * cannot handle sparse files, the flag is ignored by apr_file_open(). + * + * @def APR_FOPEN_NONBLOCK + * @warning APR_FOPEN_NONBLOCK is not implemented on all platforms. + * Callers should be prepared for it to fail with #APR_ENOTIMPL. */ -ap_status_t ap_remove_file(char *path, ap_pool_t *cont); - -/* - -=head1 ap_status_t ap_eof(ap_file_t *fptr) - -B<Are we at the end of the file> - - arg 1) The apr file we are testing. -B<NOTE>: Returns APR_EOF if we are at the end of file, APR_SUCCESS otherwise. +/** @} */ -=cut +/** + * @defgroup apr_file_seek_flags File Seek Flags + * @{ */ -ap_status_t ap_eof(ap_file_t *fptr); -/* - -=head1 ap_status_t ap_ferror(ap_file_t *fptr) - -B<Is there an error on the stream?> - - arg 1) The apr file we are testing. - -B<NOTE>: Returns -1 if the error indicator is set, APR_SUCCESS otherwise. +/* flags for apr_file_seek */ +/** Set the file position */ +#define APR_SET SEEK_SET +/** Current */ +#define APR_CUR SEEK_CUR +/** Go to end of file */ +#define APR_END SEEK_END +/** @} */ -=cut +/** + * @defgroup apr_file_attrs_set_flags File Attribute Flags + * @{ */ -ap_status_t ap_ferror(ap_file_t *fptr); - -/* -=head1 ap_status_t ap_open_stderr(ap_file_t **thefile, ap_pool_t *cont) +/* flags for apr_file_attrs_set */ +#define APR_FILE_ATTR_READONLY 0x01 /**< File is read-only */ +#define APR_FILE_ATTR_EXECUTABLE 0x02 /**< File is executable */ +#define APR_FILE_ATTR_HIDDEN 0x04 /**< File is hidden */ +/** @} */ -B<open standard error as an apr file pointer.> - - arg 1) The apr file to use as stderr. - arg 2) The pool to allocate the file out of. - -=cut +/** + * @defgroup apr_file_writev{_full} max iovec size + * @{ */ -ap_status_t ap_open_stderr(ap_file_t **thefile, ap_pool_t *cont); - -/* - -=head1 ap_status_t ap_read(ap_file_t *thefile, void *buf, ap_ssize_t *nbytes) - -B<Read data from the specified file.> +#if defined(DOXYGEN) +#define APR_MAX_IOVEC_SIZE 1024 /**< System dependent maximum + size of an iovec array */ +#elif defined(IOV_MAX) +#define APR_MAX_IOVEC_SIZE IOV_MAX +#elif defined(MAX_IOVEC) +#define APR_MAX_IOVEC_SIZE MAX_IOVEC +#else +#define APR_MAX_IOVEC_SIZE 1024 +#endif +/** @} */ - arg 1) The file descriptor to read from. - arg 2) The buffer to store the data to. - arg 3) On entry, the number of bytes to read; on exit, the number - of bytes read. +/** File attributes */ +typedef apr_uint32_t apr_fileattrs_t; -B<NOTE>: ap_read will read up to the specified number of bytes, but never - more. If there isn't enough data to fill that number of bytes, all of - the available data is read. The third argument is modified to reflect the - number of bytes read. If a char was put back into the stream via - ungetc, it will be the first character returned. - - It is possible for both bytes to be read and an APR_EOF or other error - to be returned. - - APR_EINTR is never returned. +/** Type to pass as whence argument to apr_file_seek. */ +typedef int apr_seek_where_t; -=cut +/** + * Structure for referencing files. */ -ap_status_t ap_read(ap_file_t *thefile, void *buf, ap_ssize_t *nbytes); - -/* - -=head1 ap_status_t ap_write(ap_file_t *thefile, void *buf, ap_ssize_t *nbytes) +typedef struct apr_file_t apr_file_t; -B<Write data to the specified file.> - - arg 1) The file descriptor to write to. - arg 2) The buffer which contains the data. - arg 3) On entry, the number of bytes to write; on exit, the number - of bytes write. - -B<NOTE>: ap_write will write up to the specified number of bytes, but never - more. If the OS cannot write that many bytes, it will write as many as it - can. The third argument is modified to reflect the * number of bytes - written. - - It is possible for both bytes to be written and an error to be - returned. - - APR_EINTR is never returned. - -=cut +/* File lock types/flags */ +/** + * @defgroup apr_file_lock_types File Lock Types + * @{ */ -ap_status_t ap_write(ap_file_t *thefile, void *buf, ap_ssize_t *nbytes); - -/* -=head1 ap_status_t ap_writev(ap_file_t *thefile, struct iovec *vec, ap_size_t nvec, ap_ssize_t *nbytes) - -B<Write data from iovec array to the specified file.> - - arg 1) The file descriptor to write to. - arg 2) The array from which to get the data to write to the file. - arg 3) The number of elements in the struct iovec array. This must be - smaller than AP_MAX_IOVEC_SIZE. If it isn't, the function will - fail with APR_EINVAL. - arg 4) The number of bytes written. - - It is possible for both bytes to be written and an error to be - returned. - - APR_EINTR is never returned. - - ap_writev is available even if the underlying operating system - doesn't provide writev(). - -=cut +#define APR_FLOCK_SHARED 1 /**< Shared lock. More than one process + or thread can hold a shared lock + at any given time. Essentially, + this is a "read lock", preventing + writers from establishing an + exclusive lock. */ +#define APR_FLOCK_EXCLUSIVE 2 /**< Exclusive lock. Only one process + may hold an exclusive lock at any + given time. This is analogous to + a "write lock". */ + +#define APR_FLOCK_TYPEMASK 0x000F /**< mask to extract lock type */ +#define APR_FLOCK_NONBLOCK 0x0010 /**< do not block while acquiring the + file lock */ +/** @} */ + +/** + * Open the specified file. + * @param newf The opened file descriptor. + * @param fname The full path to the file (using / on all systems) + * @param flag Or'ed value of: + * @li #APR_FOPEN_READ open for reading + * @li #APR_FOPEN_WRITE open for writing + * @li #APR_FOPEN_CREATE create the file if not there + * @li #APR_FOPEN_APPEND file ptr is set to end prior to all writes + * @li #APR_FOPEN_TRUNCATE set length to zero if file exists + * @li #APR_FOPEN_BINARY not a text file + * @li #APR_FOPEN_BUFFERED buffer the data. Default is non-buffered + * @li #APR_FOPEN_EXCL return error if #APR_FOPEN_CREATE and file exists + * @li #APR_FOPEN_DELONCLOSE delete the file after closing + * @li #APR_FOPEN_XTHREAD Platform dependent tag to open the file + * for use across multiple threads + * @li #APR_FOPEN_SHARELOCK Platform dependent support for higher + * level locked read/write access to support + * writes across process/machines + * @li #APR_FOPEN_NOCLEANUP Do not register a cleanup with the pool + * passed in on the @a pool argument (see below) + * @li #APR_FOPEN_SENDFILE_ENABLED Open with appropriate platform semantics + * for sendfile operations. Advisory only, + * apr_socket_sendfile does not check this flag + * @li #APR_FOPEN_LARGEFILE Platform dependent flag to enable large file + * support, see WARNING below + * @li #APR_FOPEN_SPARSE Platform dependent flag to enable sparse file + * support, see WARNING below + * @li #APR_FOPEN_ROTATING Do file file rotation checking + * @li #APR_FOPEN_MANUAL_ROTATE Enable Manual rotation + * @li #APR_FOPEN_NONBLOCK Platform dependent flag to enable + * non blocking file io + * @param perm Access permissions for file. + * @param pool The pool to use. + * @remark If perm is #APR_FPROT_OS_DEFAULT and the file is being created, + * appropriate default permissions will be used. + * @remark By default, the returned file descriptor will not be + * inherited by child processes created by apr_proc_create(). This + * can be changed using apr_file_inherit_set(). */ -ap_status_t ap_writev(ap_file_t *thefile, const struct iovec *vec, - ap_size_t nvec, ap_ssize_t *nbytes); - -/* +APR_DECLARE(apr_status_t) apr_file_open(apr_file_t **newf, const char *fname, + apr_int32_t flag, apr_fileperms_t perm, + apr_pool_t *pool); -=head1 ap_status_t ap_putc(char ch, ap_file_t *thefile) - -B<put a character into the specified file.> - - arg 1) The character to write. - arg 2) The file descriptor to write to - -=cut +/** + * Close the specified file. + * @param file The file descriptor to close. */ -ap_status_t ap_putc(char ch, ap_file_t *thefile); - -/* - -=head1 ap_status_t ap_getc(char *ch, ap_file_t *thefil) - -B<get a character from the specified file.> - - arg 1) The character to write. - arg 2) The file descriptor to write to - -=cut +APR_DECLARE(apr_status_t) apr_file_close(apr_file_t *file); + +/** + * Delete the specified file. + * @param path The full path to the file (using / on all systems) + * @param pool The pool to use. + * @remark If the file is open, it won't be removed until all + * instances are closed. */ -ap_status_t ap_getc(char *ch, ap_file_t *thefile); - -/* - -=head1 ap_status_t ap_ungetc(char ch, ap_file_t *thefile) - -B<put a character back onto a specified stream.> - - arg 1) The character to write. - arg 2) The file descriptor to write to - -=cut +APR_DECLARE(apr_status_t) apr_file_remove(const char *path, apr_pool_t *pool); + +/** + * Rename the specified file. + * @param from_path The full path to the original file (using / on all systems) + * @param to_path The full path to the new file (using / on all systems) + * @param pool The pool to use. + * @warning If a file exists at the new location, then it will be + * overwritten. Moving files or directories across devices may not be + * possible. */ -ap_status_t ap_ungetc(char ch, ap_file_t *thefile); - -/* - -=head1 ap_status_t ap_fgets(char *str, int len, ap_file_t *thefile) - -B<Get a string from a specified file.> - - arg 1) The buffer to store the string in. - arg 2) The length of the string - arg 3) The file descriptor to read from - -=cut +APR_DECLARE(apr_status_t) apr_file_rename(const char *from_path, + const char *to_path, + apr_pool_t *pool); + +/** + * Create a hard link to the specified file. + * @param from_path The full path to the original file (using / on all systems) + * @param to_path The full path to the new file (using / on all systems) + * @remark Both files must reside on the same device. */ -ap_status_t ap_fgets(char *str, int len, ap_file_t *thefile); - -/* - -=head1 ap_status_t ap_puts(char *str, ap_file_t *thefile) - -B<Put the string into a specified file.> - - arg 1) The string to write. - arg 2) The file descriptor to write to from - -=cut +APR_DECLARE(apr_status_t) apr_file_link(const char *from_path, + const char *to_path); + +/** + * Copy the specified file to another file. + * @param from_path The full path to the original file (using / on all systems) + * @param to_path The full path to the new file (using / on all systems) + * @param perms Access permissions for the new file if it is created. + * In place of the usual or'd combination of file permissions, the + * value #APR_FPROT_FILE_SOURCE_PERMS may be given, in which case the source + * file's permissions are copied. + * @param pool The pool to use. + * @remark The new file does not need to exist, it will be created if required. + * @warning If the new file already exists, its contents will be overwritten. */ -ap_status_t ap_puts(char *str, ap_file_t *thefile); - -/* - -=head1 ap_status_t ap_flush(ap_file_t *thefile) - -B<Flush the file's buffer.> - - arg 1) The file descriptor to flush - -=cut +APR_DECLARE(apr_status_t) apr_file_copy(const char *from_path, + const char *to_path, + apr_fileperms_t perms, + apr_pool_t *pool); + +/** + * Append the specified file to another file. + * @param from_path The full path to the source file (use / on all systems) + * @param to_path The full path to the destination file (use / on all systems) + * @param perms Access permissions for the destination file if it is created. + * In place of the usual or'd combination of file permissions, the + * value #APR_FPROT_FILE_SOURCE_PERMS may be given, in which case the source + * file's permissions are copied. + * @param pool The pool to use. + * @remark The new file does not need to exist, it will be created if required. + * @remark Note that advanced filesystem permissions such as ACLs are not + * duplicated by this API. The target permissions (including duplicating the + * source file permissions) are assigned only when the target file does not yet + * exist. */ -ap_status_t ap_flush(ap_file_t *thefile); -API_EXPORT(int) ap_fprintf(ap_file_t *fptr, const char *format, ...) - __attribute__((format(printf,2,3))); +APR_DECLARE(apr_status_t) apr_file_append(const char *from_path, + const char *to_path, + apr_fileperms_t perms, + apr_pool_t *pool); + +/** + * Are we at the end of the file + * @param fptr The apr file we are testing. + * @remark Returns #APR_EOF if we are at the end of file, #APR_SUCCESS otherwise. + */ +APR_DECLARE(apr_status_t) apr_file_eof(apr_file_t *fptr); + +/** + * Open standard error as an apr file pointer. + * @param thefile The apr file to use as stderr. + * @param pool The pool to allocate the file out of. + * + * @remark The only reason that the apr_file_open_std* functions exist + * is that you may not always have a stderr/out/in on Windows. This + * is generally a problem with newer versions of Windows and services. + * + * @remark The other problem is that the C library functions generally work + * differently on Windows and Unix. So, by using apr_file_open_std* + * functions, you can get a handle to an APR struct that works with + * the APR functions which are supposed to work identically on all + * platforms. + */ +APR_DECLARE(apr_status_t) apr_file_open_stderr(apr_file_t **thefile, + apr_pool_t *pool); + +/** + * open standard output as an apr file pointer. + * @param thefile The apr file to use as stdout. + * @param pool The pool to allocate the file out of. + * + * @remark See remarks for apr_file_open_stderr(). + */ +APR_DECLARE(apr_status_t) apr_file_open_stdout(apr_file_t **thefile, + apr_pool_t *pool); + +/** + * open standard input as an apr file pointer. + * @param thefile The apr file to use as stdin. + * @param pool The pool to allocate the file out of. + * + * @remark See remarks for apr_file_open_stderr(). + */ +APR_DECLARE(apr_status_t) apr_file_open_stdin(apr_file_t **thefile, + apr_pool_t *pool); + +/** + * open standard error as an apr file pointer, with flags. + * @param thefile The apr file to use as stderr. + * @param flags The flags to open the file with. Only the + * @li #APR_FOPEN_EXCL + * @li #APR_FOPEN_BUFFERED + * @li #APR_FOPEN_XTHREAD + * @li #APR_FOPEN_SHARELOCK + * @li #APR_FOPEN_SENDFILE_ENABLED + * @li #APR_FOPEN_LARGEFILE + * + * flags should be used. The #APR_FOPEN_WRITE flag will + * be set unconditionally. + * @param pool The pool to allocate the file out of. + * + * @remark See remarks for apr_file_open_stderr(). + */ +APR_DECLARE(apr_status_t) apr_file_open_flags_stderr(apr_file_t **thefile, + apr_int32_t flags, + apr_pool_t *pool); + +/** + * open standard output as an apr file pointer, with flags. + * @param thefile The apr file to use as stdout. + * @param flags The flags to open the file with. Only the + * @li #APR_FOPEN_EXCL + * @li #APR_FOPEN_BUFFERED + * @li #APR_FOPEN_XTHREAD + * @li #APR_FOPEN_SHARELOCK + * @li #APR_FOPEN_SENDFILE_ENABLED + * @li #APR_FOPEN_LARGEFILE + * + * flags should be used. The #APR_FOPEN_WRITE flag will + * be set unconditionally. + * @param pool The pool to allocate the file out of. + * + * @remark See remarks for apr_file_open_stderr(). + */ +APR_DECLARE(apr_status_t) apr_file_open_flags_stdout(apr_file_t **thefile, + apr_int32_t flags, + apr_pool_t *pool); + +/** + * open standard input as an apr file pointer, with flags. + * @param thefile The apr file to use as stdin. + * @param flags The flags to open the file with. Only the + * @li #APR_FOPEN_EXCL + * @li #APR_FOPEN_BUFFERED + * @li #APR_FOPEN_XTHREAD + * @li #APR_FOPEN_SHARELOCK + * @li #APR_FOPEN_SENDFILE_ENABLED + * @li #APR_FOPEN_LARGEFILE + * + * flags should be used. The #APR_FOPEN_WRITE flag will + * be set unconditionally. + * @param pool The pool to allocate the file out of. + * + * @remark See remarks for apr_file_open_stderr(). + */ +APR_DECLARE(apr_status_t) apr_file_open_flags_stdin(apr_file_t **thefile, + apr_int32_t flags, + apr_pool_t *pool); + +/** + * Read data from the specified file. + * @param thefile The file descriptor to read from. + * @param buf The buffer to store the data to. + * @param nbytes On entry, the number of bytes to read; on exit, the number + * of bytes read. + * + * @remark apr_file_read() will read up to the specified number of + * bytes, but never more. If there isn't enough data to fill that + * number of bytes, all of the available data is read. The third + * argument is modified to reflect the number of bytes read. If a + * char was put back into the stream via ungetc, it will be the first + * character returned. + * + * @remark It is not possible for both bytes to be read and an #APR_EOF + * or other error to be returned. #APR_EINTR is never returned. + */ +APR_DECLARE(apr_status_t) apr_file_read(apr_file_t *thefile, void *buf, + apr_size_t *nbytes); + +/** + * Write data to the specified file. + * @param thefile The file descriptor to write to. + * @param buf The buffer which contains the data. + * @param nbytes On entry, the number of bytes to write; on exit, the number + * of bytes written. + * + * @remark apr_file_write() will write up to the specified number of + * bytes, but never more. If the OS cannot write that many bytes, it + * will write as many as it can. The third argument is modified to + * reflect the * number of bytes written. + * + * @remark It is possible for both bytes to be written and an error to + * be returned. #APR_EINTR is never returned. + */ +APR_DECLARE(apr_status_t) apr_file_write(apr_file_t *thefile, const void *buf, + apr_size_t *nbytes); + +/** + * Write data from iovec array to the specified file. + * @param thefile The file descriptor to write to. + * @param vec The array from which to get the data to write to the file. + * @param nvec The number of elements in the struct iovec array. This must + * be smaller than #APR_MAX_IOVEC_SIZE. If it isn't, the function + * will fail with #APR_EINVAL. + * @param nbytes The number of bytes written. + * + * @remark It is possible for both bytes to be written and an error to + * be returned. #APR_EINTR is never returned. + * + * @remark apr_file_writev() is available even if the underlying + * operating system doesn't provide writev(). + */ +APR_DECLARE(apr_status_t) apr_file_writev(apr_file_t *thefile, + const struct iovec *vec, + apr_size_t nvec, apr_size_t *nbytes); + +/** + * Read data from the specified file, ensuring that the buffer is filled + * before returning. + * @param thefile The file descriptor to read from. + * @param buf The buffer to store the data to. + * @param nbytes The number of bytes to read. + * @param bytes_read If non-NULL, this will contain the number of bytes read. + * + * @remark apr_file_read_full() will read up to the specified number of + * bytes, but never more. If there isn't enough data to fill that + * number of bytes, then the process/thread will block until it is + * available or EOF is reached. If a char was put back into the + * stream via ungetc, it will be the first character returned. + * + * @remark It is possible for both bytes to be read and an error to be + * returned. And if *bytes_read is less than nbytes, an accompanying + * error is _always_ returned. + * + * @remark #APR_EINTR is never returned. + */ +APR_DECLARE(apr_status_t) apr_file_read_full(apr_file_t *thefile, void *buf, + apr_size_t nbytes, + apr_size_t *bytes_read); + +/** + * Write data to the specified file, ensuring that all of the data is + * written before returning. + * @param thefile The file descriptor to write to. + * @param buf The buffer which contains the data. + * @param nbytes The number of bytes to write. + * @param bytes_written If non-NULL, set to the number of bytes written. + * + * @remark apr_file_write_full() will write up to the specified number of + * bytes, but never more. If the OS cannot write that many bytes, the + * process/thread will block until they can be written. Exceptional + * error such as "out of space" or "pipe closed" will terminate with + * an error. + * + * @remark It is possible for both bytes to be written and an error to + * be returned. And if *bytes_written is less than nbytes, an + * accompanying error is _always_ returned. + * + * @remark #APR_EINTR is never returned. + */ +APR_DECLARE(apr_status_t) apr_file_write_full(apr_file_t *thefile, + const void *buf, + apr_size_t nbytes, + apr_size_t *bytes_written); + + +/** + * Write data from iovec array to the specified file, ensuring that all of the + * data is written before returning. + * @param thefile The file descriptor to write to. + * @param vec The array from which to get the data to write to the file. + * @param nvec The number of elements in the struct iovec array. This must + * be smaller than #APR_MAX_IOVEC_SIZE. If it isn't, the function + * will fail with #APR_EINVAL. + * @param nbytes The number of bytes written. + * + * @remark apr_file_writev_full() is available even if the underlying + * operating system doesn't provide writev(). + */ +APR_DECLARE(apr_status_t) apr_file_writev_full(apr_file_t *thefile, + const struct iovec *vec, + apr_size_t nvec, + apr_size_t *nbytes); +/** + * Write a character into the specified file. + * @param ch The character to write. + * @param thefile The file descriptor to write to + */ +APR_DECLARE(apr_status_t) apr_file_putc(char ch, apr_file_t *thefile); -/* +/** + * Read a character from the specified file. + * @param ch The character to read into + * @param thefile The file descriptor to read from + */ +APR_DECLARE(apr_status_t) apr_file_getc(char *ch, apr_file_t *thefile); -=head1 ap_status_t ap_dupfile(ap_file_t **new_file, ap_file_t *old_file, ap_pool_t *p) +/** + * Put a character back onto a specified stream. + * @param ch The character to write. + * @param thefile The file descriptor to write to + */ +APR_DECLARE(apr_status_t) apr_file_ungetc(char ch, apr_file_t *thefile); + +/** + * Read a line from the specified file + * @param str The buffer to store the string in. + * @param len The length of the string + * @param thefile The file descriptor to read from + * @remark The buffer will be NUL-terminated if any characters are stored. + * The newline at the end of the line will not be stripped. + */ +APR_DECLARE(apr_status_t) apr_file_gets(char *str, int len, + apr_file_t *thefile); -B<duplicate the specified file descriptor.> +/** + * Write the string into the specified file. + * @param str The string to write. + * @param thefile The file descriptor to write to + */ +APR_DECLARE(apr_status_t) apr_file_puts(const char *str, apr_file_t *thefile); + +/** + * Wait for a pipe to be ready for input or output + * @param thepipe the pipe to wait on + * @param direction whether to wait for reading or writing to be ready + * Can be either #APR_WAIT_READ or #APR_WAIT_WRITE + * @remark Will time out if thepipe has a time out set for it + */ +APR_DECLARE(apr_status_t) apr_file_pipe_wait(apr_file_t *thepipe, + apr_wait_type_t direction); - arg 1) The structure to duplicate into. - arg 2) The file to duplicate. - arg 3) The pool to use for the new file. +/** + * Flush the file's buffer. + * @param thefile The file descriptor to flush + */ +APR_DECLARE(apr_status_t) apr_file_flush(apr_file_t *thefile); -B<NOTE>: *arg1 must point to a valid ap_file_t, or point to NULL +/** + * Transfer all file modified data and metadata to disk. + * @param thefile The file descriptor to sync + */ +APR_DECLARE(apr_status_t) apr_file_sync(apr_file_t *thefile); -=cut +/** + * Transfer all file modified data to disk. + * @param thefile The file descriptor to sync + */ +APR_DECLARE(apr_status_t) apr_file_datasync(apr_file_t *thefile); + +/** + * Duplicate the specified file descriptor. + * @param new_file The structure to duplicate into. + * @param old_file The file to duplicate. + * @param p The pool to use for the new file. + * @remark *new_file must point to a valid apr_file_t, or point to NULL. */ -ap_status_t ap_dupfile(ap_file_t **new_file, ap_file_t *old_file, ap_pool_t *p); - -/* - -=head1 ap_status_t ap_getfileinfo(ap_finfo_t *finfo, ap_file_t *thefile) - -B<get the specified file's stats..> - - arg 1) Where to store the information about the file. - arg 2) The file to get information about. - -=cut - */ -ap_status_t ap_getfileinfo(ap_finfo_t *finfo, ap_file_t *thefile); -ap_status_t ap_stat(ap_finfo_t *finfo, const char *fname, ap_pool_t *cont); - -/* - -=head1 ap_status_t ap_stat(ap_file_t **finfo, char *fname, ap_pool_t *cont) - -B<get the specified file's stats. The file is specified by filename, instead of using a pre-opened file.> - - arg 1) Where to store the information about the file. - arg 2) The name of the file to stat. - arg 3) the pool to use to allocate the new file. - -=cut - */ -ap_status_t ap_stat(ap_finfo_t *finfo, const char *fname, ap_pool_t *cont); - -/* - -=head1 ap_status_t ap_seek(ap_file_t *thefile, ap_seek_where_t where, ap_off_t *offset) - -B<Move the read/write file offset to a specified byte within a file.> - - arg 1) The file descriptor - arg 2) How to move the pointer, one of: - APR_SET -- set the offset to offset - APR_CUR -- add the offset to the current position - APR_END -- add the offset to the current file size - arg 3) The offset to move the pointer to. +APR_DECLARE(apr_status_t) apr_file_dup(apr_file_t **new_file, + apr_file_t *old_file, + apr_pool_t *p); + +/** + * Duplicate the specified file descriptor and close the original + * @param new_file The old file that is to be closed and reused + * @param old_file The file to duplicate + * @param p The pool to use for the new file + * + * @remark new_file MUST point at a valid apr_file_t. It cannot be NULL. + */ +APR_DECLARE(apr_status_t) apr_file_dup2(apr_file_t *new_file, + apr_file_t *old_file, + apr_pool_t *p); + +/** + * Move the specified file descriptor to a new pool + * @param new_file Pointer in which to return the new apr_file_t + * @param old_file The file to move + * @param p The pool to which the descriptor is to be moved + * @remark Unlike apr_file_dup2(), this function doesn't do an + * OS dup() operation on the underlying descriptor; it just + * moves the descriptor's apr_file_t wrapper to a new pool. + * @remark The new pool need not be an ancestor of old_file's pool. + * @remark After calling this function, old_file may not be used + */ +APR_DECLARE(apr_status_t) apr_file_setaside(apr_file_t **new_file, + apr_file_t *old_file, + apr_pool_t *p); + +/** + * Give the specified apr file handle a new buffer + * @param thefile The file handle that is to be modified + * @param buffer The buffer + * @param bufsize The size of the buffer + * @remark It is possible to add a buffer to previously unbuffered + * file handles, the #APR_FOPEN_BUFFERED flag will be added to + * the file handle's flags. Likewise, with buffer=NULL and + * bufsize=0 arguments it is possible to make a previously + * buffered file handle unbuffered. + */ +APR_DECLARE(apr_status_t) apr_file_buffer_set(apr_file_t *thefile, + char * buffer, + apr_size_t bufsize); -B<NOTE>: The third argument is modified to be the offset the pointer +/** + * Get the size of any buffer for the specified apr file handle + * @param thefile The file handle + */ +APR_DECLARE(apr_size_t) apr_file_buffer_size_get(apr_file_t *thefile); + +/** + * Move the read/write file offset to a specified byte within a file. + * @param thefile The file descriptor + * @param where How to move the pointer, one of: + * @li #APR_SET -- set the offset to offset + * @li #APR_CUR -- add the offset to the current position + * @li #APR_END -- add the offset to the current file size + * @param offset The offset to move the pointer to. + * @remark The third argument is modified to be the offset the pointer was actually moved to. - -=cut */ -ap_status_t ap_seek(ap_file_t *thefile, ap_seek_where_t where,ap_off_t *offset); - -/* - -=head1 ap_status_t ap_opendir(ap_dir_t **new, char *dirname, ap_pool_t *cont) - -B<Open the specified directory.> - - arg 1) The opened directory descriptor. - arg 2) The full path to the directory (use / on all systems) - arg 3) The pool to use. - -=cut - */ -ap_status_t ap_opendir(ap_dir_t **new, const char *dirname, ap_pool_t *cont); - -/* - -=head1 ap_status_t ap_closedir(ap_dir_t *thedir) - -B<close the specified directory.> - - arg 1) the directory descriptor to close. - -=cut - */ -ap_status_t ap_closedir(ap_dir_t *thedir); - -/* - -=head1 ap_status_t ap_readdir(ap_dir_t *thedir) - -B<Read the next entry from the specified directory.> - - arg 1) the directory descriptor to read from, and fill out. - -B<NOTE>: All systems return . and .. as the first two files. - -=cut - */ -ap_status_t ap_readdir(ap_dir_t *thedir); - -/* - -=head1 ap_status_t ap_rewinddir(ap_dir_t *thedir) - -B<Rewind the directory to the first entry.> - - arg 1) the directory descriptor to rewind. - -=cut - */ -ap_status_t ap_rewinddir(ap_dir_t *thedir); - -/* - -=head1 ap_status_t ap_make_dir(const char *path, ap_fileperms_t perm, ap_pool_t *cont) - -B<Create a new directory on the file system.> - - arg 1) the path for the directory to be created. (use / on all systems) - arg 2) Permissions for the new direcoty. - arg 3) the pool to use. - -=cut - */ -ap_status_t ap_make_dir(const char *path, ap_fileperms_t perm, - ap_pool_t *cont); - -/* - -=head1 ap_status_t ap_remove_dir(const char *path, ap_pool_t *cont) - -B<Remove directory from the file system.> - - arg 1) the path for the directory to be removed. (use / on all systems) - arg 2) the pool to use. - -=cut - */ -ap_status_t ap_remove_dir(const char *path, ap_pool_t *cont); - -/* - -=head1 ap_status_t ap_create_pipe(ap_file_t **in, ap_file_t **out, ap_pool_t *cont) - -B<Create an anonymous pipe.> - - arg 1) The file descriptor to use as input to the pipe. - arg 2) The file descriptor to use as output from the pipe. - arg 3) The pool to operate on. - -=cut +APR_DECLARE(apr_status_t) apr_file_seek(apr_file_t *thefile, + apr_seek_where_t where, + apr_off_t *offset); + +/** + * Create an anonymous pipe. + * @param in The newly created pipe's file for reading. + * @param out The newly created pipe's file for writing. + * @param pool The pool to operate on. + * @remark By default, the returned file descriptors will be inherited + * by child processes created using apr_proc_create(). This can be + * changed using apr_file_inherit_unset(). + * @bug Some platforms cannot toggle between blocking and nonblocking, + * and when passing a pipe as a standard handle to an application which + * does not expect it, a non-blocking stream will fluxor the client app. + * @deprecated @see apr_file_pipe_create_pools() */ -ap_status_t ap_create_pipe(ap_file_t **in, ap_file_t **out, ap_pool_t *cont); - -/* - -=head1 ap_status_t ap_create_namedpipe(char *filename, ap_fileperms_t perm, ap_pool_t *cont) - -B<Create a named pipe.> - - arg 1) The filename of the named pipe - arg 2) The permissions for the newly created pipe. - arg 3) The pool to operate on. - -=cut +APR_DECLARE(apr_status_t) apr_file_pipe_create(apr_file_t **in, + apr_file_t **out, + apr_pool_t *pool); + +/** + * Create an anonymous pipe which portably supports async timeout options. + * @param in The newly created pipe's file for reading. + * @param out The newly created pipe's file for writing. + * @param blocking one of these values defined in apr_thread_proc.h; + * @li #APR_FULL_BLOCK + * @li #APR_READ_BLOCK + * @li #APR_WRITE_BLOCK + * @li #APR_FULL_NONBLOCK + * @param pool The pool to operate on. + * @remark By default, the returned file descriptors will be inherited + * by child processes created using apr_proc_create(). This can be + * changed using apr_file_inherit_unset(). + * @remark Some platforms cannot toggle between blocking and nonblocking, + * and when passing a pipe as a standard handle to an application which + * does not expect it, a non-blocking stream will fluxor the client app. + * Use this function rather than apr_file_pipe_create() to create pipes + * where one or both ends require non-blocking semantics. + * @deprecated @see apr_file_pipe_create_pools() */ -ap_status_t ap_create_namedpipe(char *filename, ap_fileperms_t perm, - ap_pool_t *cont); - -/* - -=head1 ap_status_t ap_set_pipe_timeout(ap_file_t *thepipe, ap_int32_t timeout) - -B<Set the timeout value for a pipe.> - - arg 1) The pipe we are setting a timeout on. - arg 2) The timeout value in seconds. Values < 0 mean wait forever, 0 - means do not wait at all. - -=cut +APR_DECLARE(apr_status_t) apr_file_pipe_create_ex(apr_file_t **in, + apr_file_t **out, + apr_int32_t blocking, + apr_pool_t *pool); + +/** + * Create an anonymous pipe which portably supports async timeout options, + * placing each side of the pipe in a different pool. + * @param in The newly created pipe's file for reading. + * @param out The newly created pipe's file for writing. + * @param blocking one of these values defined in apr_thread_proc.h; + * @li #APR_FULL_BLOCK + * @li #APR_READ_BLOCK + * @li #APR_WRITE_BLOCK + * @li #APR_FULL_NONBLOCK + * @param pool_in The pool for the reading pipe. + * @param pool_out The pool for the writing pipe. + * @remark By default, the returned file descriptors will be inherited + * by child processes created using apr_proc_create(). This can be + * changed using apr_file_inherit_unset(). + * @remark Some platforms cannot toggle between blocking and nonblocking, + * and when passing a pipe as a standard handle to an application which + * does not expect it, a non-blocking stream will fluxor the client app. + * Use this function rather than apr_file_pipe_create() to create pipes + * where one or both ends require non-blocking semantics. */ -ap_status_t ap_set_pipe_timeout(ap_file_t *thepipe, ap_interval_time_t timeout); - -/* - -=head1 ap_status_t ap_block_pipe(ap_file_t *thepipe) - -B<Set a pipe to use blocking I/O.> - - arg 1) The pipe to operate on. - -=cut +APR_DECLARE(apr_status_t) apr_file_pipe_create_pools(apr_file_t **in, + apr_file_t **out, + apr_int32_t blocking, + apr_pool_t *pool_in, + apr_pool_t *pool_out); + +/** + * Create a named pipe. + * @param filename The filename of the named pipe + * @param perm The permissions for the newly created pipe. + * @param pool The pool to operate on. */ -ap_status_t ap_block_pipe(ap_file_t *thepipe); - -/*accessor and general file_io functions. */ - -/* - -=head1 ap_status_t ap_get_filename(char **new, ap_file_t *thefile) +APR_DECLARE(apr_status_t) apr_file_namedpipe_create(const char *filename, + apr_fileperms_t perm, + apr_pool_t *pool); + +/** + * Get the timeout value for a pipe or manipulate the blocking state. + * @param thepipe The pipe we are getting a timeout for. + * @param timeout The current timeout value in microseconds. + */ +APR_DECLARE(apr_status_t) apr_file_pipe_timeout_get(apr_file_t *thepipe, + apr_interval_time_t *timeout); + +/** + * Set the timeout value for a pipe or manipulate the blocking state. + * @param thepipe The pipe we are setting a timeout on. + * @param timeout The timeout value in microseconds. Values < 0 mean wait + * forever, 0 means do not wait at all. + */ +APR_DECLARE(apr_status_t) apr_file_pipe_timeout_set(apr_file_t *thepipe, + apr_interval_time_t timeout); + +/** file (un)locking functions. */ + +/** + * Establish a lock on the specified, open file. The lock may be advisory + * or mandatory, at the discretion of the platform. The lock applies to + * the file as a whole, rather than a specific range. Locks are established + * on a per-thread/process basis; a second lock by the same thread will not + * block. + * @param thefile The file to lock. + * @param type The type of lock to establish on the file. + */ +APR_DECLARE(apr_status_t) apr_file_lock(apr_file_t *thefile, int type); -B<return the file name of the current file.> +/** + * Remove any outstanding locks on the file. + * @param thefile The file to unlock. + */ +APR_DECLARE(apr_status_t) apr_file_unlock(apr_file_t *thefile); - arg 1) The path of the file. - arg 2) The currently open file. +/**accessor and general file_io functions. */ -=cut +/** + * return the file name of the current file. + * @param new_path The path of the file. + * @param thefile The currently open file. */ -ap_status_t ap_get_filename(char **new, ap_file_t *thefile); - -/* - -=head1 ap_status_t ap_get_dir_filename(char **new, ap_dir_t *thedir) - -B<Get the file name of the current directory entry.> - - arg 1) the file name of the directory entry. - arg 2) the currently open directory. - -=cut - */ -ap_status_t ap_get_dir_filename(char **new, ap_dir_t *thedir); - -/* - -=head1 ap_status_t ap_get_filedata(void **data, char *key, ap_file_t *file) - -B<Return the data associated with the current file.> - - arg 1) The user data associated with the file. - arg 2) The key to use for retreiving data associated with this file. - arg 3) The currently open file. - -=cut +APR_DECLARE(apr_status_t) apr_file_name_get(const char **new_path, + apr_file_t *thefile); + +/** + * Return the data associated with the current file. + * @param data The user data associated with the file. + * @param key The key to use for retrieving data associated with this file. + * @param file The currently open file. */ -ap_status_t ap_get_filedata(void **data, char *key, ap_file_t *file); - -/* - -=head1 ap_status_t ap_set_filedata(ap_file_t *file, void *data, char *key, ap_status (*cleanup) (void *)) - -B<Set the data associated with the current file.> - - arg 1) The currently open file. - arg 2) The user data to associate with the file. - arg 3) The key to use for assocaiteing data with the file. - arg 4) The cleanup routine to use when the file is destroyed. - -=cut +APR_DECLARE(apr_status_t) apr_file_data_get(void **data, const char *key, + apr_file_t *file); + +/** + * Set the data associated with the current file. + * @param file The currently open file. + * @param data The user data to associate with the file. + * @param key The key to use for associating data with the file. + * @param cleanup The cleanup routine to use when the file is destroyed. */ -ap_status_t ap_set_filedata(ap_file_t *file, void *data, char *key, - ap_status_t (*cleanup) (void *)); - -/* - -=head1 ap_status_t ap_dir_entry_size(ap_ssize_t *size, ap_dir_t *thedir) - -B<Get the size of the current directory entry.> - - arg 1) the size of the directory entry. - arg 2) the currently open directory. +APR_DECLARE(apr_status_t) apr_file_data_set(apr_file_t *file, void *data, + const char *key, + apr_status_t (*cleanup)(void *)); + +/** + * Write a string to a file using a printf format. + * @param fptr The file to write to. + * @param format The format string + * @param ... The values to substitute in the format string + * @return The number of bytes written + */ +APR_DECLARE_NONSTD(int) apr_file_printf(apr_file_t *fptr, + const char *format, ...) + __attribute__((format(printf,2,3))); -=cut +/** + * set the specified file's permission bits. + * @param fname The file (name) to apply the permissions to. + * @param perms The permission bits to apply to the file. + * + * @warning Some platforms may not be able to apply all of the + * available permission bits; #APR_INCOMPLETE will be returned if some + * permissions are specified which could not be set. + * + * @warning Platforms which do not implement this feature will return + * #APR_ENOTIMPL. + */ +APR_DECLARE(apr_status_t) apr_file_perms_set(const char *fname, + apr_fileperms_t perms); + +/** + * Set attributes of the specified file. + * @param fname The full path to the file (using / on all systems) + * @param attributes Or'd combination of + * @li #APR_FILE_ATTR_READONLY - make the file readonly + * @li #APR_FILE_ATTR_EXECUTABLE - make the file executable + * @li #APR_FILE_ATTR_HIDDEN - make the file hidden + * @param attr_mask Mask of valid bits in attributes. + * @param pool the pool to use. + * @remark This function should be used in preference to explicit manipulation + * of the file permissions, because the operations to provide these + * attributes are platform specific and may involve more than simply + * setting permission bits. + * @warning Platforms which do not implement this feature will return + * #APR_ENOTIMPL. + */ +APR_DECLARE(apr_status_t) apr_file_attrs_set(const char *fname, + apr_fileattrs_t attributes, + apr_fileattrs_t attr_mask, + apr_pool_t *pool); + +/** + * Set the mtime of the specified file. + * @param fname The full path to the file (using / on all systems) + * @param mtime The mtime to apply to the file. + * @param pool The pool to use. + * @warning Platforms which do not implement this feature will return + * #APR_ENOTIMPL. + */ +APR_DECLARE(apr_status_t) apr_file_mtime_set(const char *fname, + apr_time_t mtime, + apr_pool_t *pool); + +/** + * Create a new directory on the file system. + * @param path the path for the directory to be created. (use / on all systems) + * @param perm Permissions for the new directory. + * @param pool the pool to use. + */ +APR_DECLARE(apr_status_t) apr_dir_make(const char *path, apr_fileperms_t perm, + apr_pool_t *pool); + +/** Creates a new directory on the file system, but behaves like + * 'mkdir -p'. Creates intermediate directories as required. No error + * will be reported if PATH already exists. + * @param path the path for the directory to be created. (use / on all systems) + * @param perm Permissions for the new directory. + * @param pool the pool to use. + */ +APR_DECLARE(apr_status_t) apr_dir_make_recursive(const char *path, + apr_fileperms_t perm, + apr_pool_t *pool); + +/** + * Remove directory from the file system. + * @param path the path for the directory to be removed. (use / on all systems) + * @param pool the pool to use. + * @remark Removing a directory which is in-use (e.g., the current working + * directory, or during apr_dir_read, or with an open file) is not portable. */ -ap_status_t ap_dir_entry_size(ap_ssize_t *size, ap_dir_t *thedir); +APR_DECLARE(apr_status_t) apr_dir_remove(const char *path, apr_pool_t *pool); -/* +/** + * get the specified file's stats. + * @param finfo Where to store the information about the file. + * @param wanted The desired apr_finfo_t fields, as a bit flag of APR_FINFO_* values + * @param thefile The file to get information about. + */ +APR_DECLARE(apr_status_t) apr_file_info_get(apr_finfo_t *finfo, + apr_int32_t wanted, + apr_file_t *thefile); + + +/** + * Truncate the file's length to the specified offset + * @param fp The file to truncate + * @param offset The offset to truncate to. + * @remark The read/write file offset is repositioned to offset. + */ +APR_DECLARE(apr_status_t) apr_file_trunc(apr_file_t *fp, apr_off_t offset); -=head1 ap_status_t ap_dir_entry_mtime(ap_time_t *mtime, ap_dir_t *thedir) +/** + * Retrieve the flags that were passed into apr_file_open() + * when the file was opened. + * @return apr_int32_t the flags + */ +APR_DECLARE(apr_int32_t) apr_file_flags_get(apr_file_t *f); -B<Get the last modified time of the current directory entry.> +/** + * Get the pool used by the file. + */ +APR_POOL_DECLARE_ACCESSOR(file); - arg 1) the last modified time of the directory entry. - arg 2) the currently open directory. +/** + * Set a file to be inherited by child processes. + * + */ +APR_DECLARE_INHERIT_SET(file); -=cut - */ -ap_status_t ap_dir_entry_mtime(ap_time_t *mtime, ap_dir_t *thedir); +/** + * Unset a file from being inherited by child processes. + */ +APR_DECLARE_INHERIT_UNSET(file); + +/** + * Open a temporary file + * @param fp The apr file to use as a temporary file. + * @param templ The template to use when creating a temp file. + * @param flags The flags to open the file with. If this is zero, + * the file is opened with + * #APR_FOPEN_CREATE | #APR_FOPEN_READ | #APR_FOPEN_WRITE | + * #APR_FOPEN_EXCL | #APR_FOPEN_DELONCLOSE + * @param p The pool to allocate the file out of. + * @remark + * This function generates a unique temporary file name from template. + * The last six characters of template must be XXXXXX and these are replaced + * with a string that makes the filename unique. Since it will be modified, + * template must not be a string constant, but should be declared as a character + * array. + * + */ +APR_DECLARE(apr_status_t) apr_file_mktemp(apr_file_t **fp, char *templ, + apr_int32_t flags, apr_pool_t *p); -/* -=head1 ap_status_t ap_dir_entry_ftype(ap_filetype_e *type, ap_dir_t *thedir) +/** + * Find an existing directory suitable as a temporary storage location. + * @param temp_dir The temp directory. + * @param p The pool to use for any necessary allocations. + * @remark + * This function uses an algorithm to search for a directory that an + * an application can use for temporary storage. + * + */ +APR_DECLARE(apr_status_t) apr_temp_dir_get(const char **temp_dir, + apr_pool_t *p); + -B<Get the file type of the current directory entry.> +APR_DECLARE(apr_status_t) apr_file_rotating_check(apr_file_t *thefile); +APR_DECLARE(apr_status_t) apr_file_rotating_manual_check(apr_file_t *thefile, apr_time_t time); - arg 1) the file type of the directory entry. - arg 2) the currently open directory. +/** @} */ -=cut - */ -ap_status_t ap_dir_entry_ftype(ap_filetype_e *type, ap_dir_t *thedir); #ifdef __cplusplus } #endif #endif /* ! APR_FILE_IO_H */ - - diff --git a/include/apr_fnmatch.h b/include/apr_fnmatch.h index c0300b6389b..f8c26cf3e1b 100644 --- a/include/apr_fnmatch.h +++ b/include/apr_fnmatch.h @@ -1,4 +1,4 @@ -/*- +/* * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. * @@ -37,28 +37,117 @@ #ifndef _APR_FNMATCH_H_ #define _APR_FNMATCH_H_ +/** + * @file apr_fnmatch.h + * @brief APR FNMatch Functions + */ + #include "apr_errno.h" +#include "apr_tables.h" #ifdef __cplusplus extern "C" { #endif -#define FNM_NOMATCH 1 /* Match failed. */ +/** + * @defgroup apr_fnmatch Filename Matching Functions + * @ingroup APR + * @{ + */ + +#define APR_FNM_NOMATCH 1 /**< Match failed. */ + +#define APR_FNM_NOESCAPE 0x01 /**< Disable backslash escaping. */ +#define APR_FNM_PATHNAME 0x02 /**< Slash must be matched by slash. */ +#define APR_FNM_PERIOD 0x04 /**< Leading period must be matched by period. */ +#define APR_FNM_CASE_BLIND 0x08 /**< Compare characters case-insensitively. */ + +/** + * Try to match the string to the given pattern, return APR_SUCCESS if + * match, else return APR_FNM_NOMATCH. Note that there is no such thing as + * an illegal pattern. + * + * With all flags unset, a pattern is interpreted as such: + * + * PATTERN: Backslash followed by any character, including another + * backslash.<br/> + * MATCHES: That character exactly. + * + * <p> + * PATTERN: ?<br/> + * MATCHES: Any single character. + * </p> + * + * <p> + * PATTERN: *<br/> + * MATCHES: Any sequence of zero or more characters. (Note that multiple + * *s in a row are equivalent to one.) + * + * PATTERN: Any character other than \?*[ or a \ at the end of the pattern<br/> + * MATCHES: That character exactly. (Case sensitive.) + * + * PATTERN: [ followed by a class description followed by ]<br/> + * MATCHES: A single character described by the class description. + * (Never matches, if the class description reaches until the + * end of the string without a ].) If the first character of + * the class description is ^ or !, the sense of the description + * is reversed. The rest of the class description is a list of + * single characters or pairs of characters separated by -. Any + * of those characters can have a backslash in front of them, + * which is ignored; this lets you use the characters ] and - + * in the character class, as well as ^ and ! at the + * beginning. The pattern matches a single character if it + * is one of the listed characters or falls into one of the + * listed ranges (inclusive, case sensitive). Ranges with + * the first character larger than the second are legal but + * never match. Edge cases: [] never matches, and [^] and [!] + * always match without consuming a character. + * + * Note that these patterns attempt to match the entire string, not + * just find a substring matching the pattern. + * + * @param pattern The pattern to match to + * @param strings The string we are trying to match + * @param flags flags to use in the match. Bitwise OR of: + * <pre> + * APR_FNM_NOESCAPE Disable backslash escaping + * APR_FNM_PATHNAME Slash must be matched by slash + * APR_FNM_PERIOD Leading period must be matched by period + * APR_FNM_CASE_BLIND Compare characters case-insensitively. + * </pre> + */ + +APR_DECLARE(apr_status_t) apr_fnmatch(const char *pattern, + const char *strings, int flags); -#define FNM_NOESCAPE 0x01 /* Disable backslash escaping. */ -#define FNM_PATHNAME 0x02 /* Slash must be matched by slash. */ -#define FNM_PERIOD 0x04 /* Period must be matched by period. */ -/* This flag is an Apache addition */ -#define FNM_CASE_BLIND 0x08 /* Compare characters case ap_pool_t nsensitively. */ +/** + * Determine if the given pattern is a regular expression. + * @param pattern The pattern to search for glob characters. + * @return non-zero if pattern has any glob characters in it + */ +APR_DECLARE(int) apr_fnmatch_test(const char *pattern); -API_EXPORT(ap_status_t) ap_fnmatch(const char *pattern, const char *strings, - int flags); +/** + * Find all files that match a specified pattern in a directory. + * @param dir_pattern The pattern to use for finding files, appended + * to the search directory. The pattern is anything following the + * final forward or backward slash in the parameter. If no slash + * is found, the current directory is searched. + * @param result Array to use when storing the results + * @param p The pool to use. + * @return APR_SUCCESS if no processing errors occurred, APR error + * code otherwise + * @remark The returned array may be empty even if APR_SUCCESS was + * returned. + */ +APR_DECLARE(apr_status_t) apr_match_glob(const char *dir_pattern, + apr_array_header_t **result, + apr_pool_t *p); -/* this function is an Apache addition */ -API_EXPORT(int) ap_is_fnmatch(const char *pattern); +/** @} */ #ifdef __cplusplus } #endif -#endif /* !_FNMATCH_H_ */ +#endif /* !_APR_FNMATCH_H_ */ diff --git a/include/apr_general.h b/include/apr_general.h index 5e86b6bc58d..07b49f59fbe 100644 --- a/include/apr_general.h +++ b/include/apr_general.h @@ -1,375 +1,253 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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. */ #ifndef APR_GENERAL_H #define APR_GENERAL_H +/** + * @file apr_general.h + * This is collection of oddballs that didn't fit anywhere else, + * and might move to more appropriate headers with the release + * of APR 1.0. + * @brief APR Miscellaneous library routines + */ + #include "apr.h" +#include "apr_pools.h" +#include "apr_errno.h" -#if APR_HAVE_STDIO_H -#include <stdio.h> -#endif -#if APR_HAVE_SYS_TYPES_H -#include <sys/types.h> -#endif #if APR_HAVE_SIGNAL_H #include <signal.h> #endif -#include "apr_errno.h" #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ -#define TRUE 1 -#define FALSE 0 - -#define MAXIMUM_WAIT_OBJECTS 64 - -typedef int ap_signum_t; +/** + * @defgroup apr_general Miscellaneous library routines + * @ingroup APR + * This is collection of oddballs that didn't fit anywhere else, + * and might move to more appropriate headers with the release + * of APR 1.0. + * @{ + */ -#ifdef SIGHUP -#define APR_SIGHUP SIGHUP -#endif -#ifdef SIGINT -#define APR_SIGINT SIGINT -#endif -#ifdef SIGQUIT -#define APR_SIGQUIT SIGQUIT -#endif -#ifdef SIGILL -#define APR_SIGILL SIGILL -#endif -#ifdef SIGTRAP -#define APR_SIGTRAP SIGTRAP -#endif -#ifdef SIGABRT -#define APR_SIGABRT SIGABRT -#endif -#ifdef SIGIOT -#define APR_SIGIOT SIGIOT -#endif -#ifdef SIGBUS -#define APR_SIGBUS SIGBUS -#endif -#ifdef SIGFPE -#define APR_SIGFPE SIGFPE -#endif -#ifdef SIGKILL -#define APR_SIGKILL SIGKILL -#endif -#ifdef SIGUSR1 -#define APR_SIGUSR1 SIGUSR1 -#endif -#ifdef SIGSEGV -#define APR_SIGSEGV SIGSEGV -#endif -#ifdef SIGUSR2 -#define APR_SIGUSR2 SIGUSR2 -#endif -#ifdef SIGPIPE -#define APR_SIGPIPE SIGPIPE -#endif -#ifdef SIGALRM -#define APR_SIGALRM SIGALRM -#endif -#ifdef SIGTERM -#define APR_SIGTERM SIGTERM -#endif -#ifdef SIGSTKFLT -#define APR_SIGSTKFLT SIGSTKFLT -#endif -#ifdef SIGCHLD -#define APR_SIGCHLD SIGCHLD -#endif -#ifdef SIGCONT -#define APR_SIGCONT SIGCONT -#endif -#ifdef SIGSTOP -#define APR_SIGSTOP SIGSTOP -#endif -#ifdef SIGTSTP -#define APR_SIGTSTP SIGTSTP -#endif -#ifdef SIGTTIN -#define APR_SIGTTIN SIGTTIN -#endif -#ifdef SIGTTOU -#define APR_SIGTTOU SIGTTOU -#endif -#ifdef SIGURG -#define APR_SIGURG SIGURG -#endif -#ifdef SIGXCPU -#define APR_SIGXCPU SIGXCPU -#endif -#ifdef SIGXFSZ -#define APR_SIGXFSZ SIGXFSZ -#endif -#ifdef SIGVTALRM -#define APR_SIGVTALRM SIGVTALRM -#endif -#ifdef SIGPROF -#define APR_SIGPROF SIGPROF -#endif -#ifdef SIGWINCH -#define APR_SIGWINCH SIGWINCH +/** FALSE */ +#ifndef FALSE +#define FALSE 0 #endif -#ifdef SIGIO -#define APR_SIGIO SIGIO +/** TRUE */ +#ifndef TRUE +#define TRUE (!FALSE) #endif -#ifdef WIN32 -#define APR_INLINE __inline -#elif defined(__GNUC__) && defined(__GNUC__) && \ - __GNUC__ >= 2 && __GNUC_MINOR__ >= 7 -#define APR_INLINE __inline__ -#else -#define APR_INLINE /*nop*/ -#endif +/** a space */ +#define APR_ASCII_BLANK '\040' +/** a carrige return */ +#define APR_ASCII_CR '\015' +/** a line feed */ +#define APR_ASCII_LF '\012' +/** a tab */ +#define APR_ASCII_TAB '\011' + +/** signal numbers typedef */ +typedef int apr_signum_t; + +/* Type of I/O to wait for */ +typedef enum { APR_WAIT_READ, APR_WAIT_WRITE } apr_wait_type_t; -/* Finding offsets of elements within structures. +/** + * Finding offsets of elements within structures. * Taken from the X code... they've sweated portability of this stuff * so we don't have to. Sigh... + * @param p_type pointer type name + * @param field data field within the structure pointed to + * @return offset */ -#if defined(CRAY) || (defined(__arm) && !defined(LINUX)) +#if defined(CRAY) || (defined(__arm) && !(defined(LINUX) || defined(__FreeBSD__))) #ifdef __STDC__ -#define XtOffset(p_type,field) _Offsetof(p_type,field) +#define APR_OFFSET(p_type,field) _Offsetof(p_type,field) #else #ifdef CRAY2 -#define XtOffset(p_type,field) \ +#define APR_OFFSET(p_type,field) \ (sizeof(int)*((unsigned int)&(((p_type)NULL)->field))) #else /* !CRAY2 */ -#define XtOffset(p_type,field) ((unsigned int)&(((p_type)NULL)->field)) +#define APR_OFFSET(p_type,field) ((unsigned int)&(((p_type)NULL)->field)) #endif /* !CRAY2 */ #endif /* __STDC__ */ #else /* ! (CRAY || __arm) */ -#define XtOffset(p_type,field) \ +#define APR_OFFSET(p_type,field) \ ((long) (((char *) (&(((p_type)NULL)->field))) - ((char *) NULL))) #endif /* !CRAY */ -#ifdef offsetof -#define XtOffsetOf(s_type,field) offsetof(s_type,field) +/** + * Finding offsets of elements within structures. + * @param s_type structure type name + * @param field data field within the structure + * @return offset + */ +#if defined(offsetof) && !defined(__cplusplus) +#define APR_OFFSETOF(s_type,field) offsetof(s_type,field) #else -#define XtOffsetOf(s_type,field) XtOffset(s_type*,field) +#define APR_OFFSETOF(s_type,field) APR_OFFSET(s_type*,field) #endif -#if APR_HAS_RANDOM -/* - -=head1 ap_status_t ap_generate_random_bytes(unsigned char * buf, int length) - -B<Generate a string of random bytes.> +#ifndef DOXYGEN - arg 1) Random bytes go here - arg 2) size of the buffer - -=cut +/* A couple of prototypes for functions in case some platform doesn't + * have it */ -/* TODO: I'm not sure this is the best place to put this prototype...*/ -ap_status_t ap_generate_random_bytes(unsigned char * buf, int length); +#if (!APR_HAVE_STRCASECMP) && (APR_HAVE_STRICMP) +#define strcasecmp(s1, s2) stricmp(s1, s2) +#elif (!APR_HAVE_STRCASECMP) +int strcasecmp(const char *a, const char *b); #endif -typedef struct ap_pool_t { - union block_hdr *first; - union block_hdr *last; - struct cleanup *cleanups; - struct process_chain *subprocesses; - struct ap_pool_t *sub_pools; - struct ap_pool_t *sub_next; - struct ap_pool_t *sub_prev; - struct ap_pool_t *parent; - char *free_first_avail; -#ifdef ALLOC_USE_MALLOC - void *allocation_list; +#if (!APR_HAVE_STRNCASECMP) && (APR_HAVE_STRNICMP) +#define strncasecmp(s1, s2, n) strnicmp(s1, s2, n) +#elif (!APR_HAVE_STRNCASECMP) +int strncasecmp(const char *a, const char *b, size_t n); #endif -#ifdef POOL_DEBUG - ap_pool_t *joined; -#endif - int (*apr_abort)(int retcode); - struct datastruct *prog_data; -}ap_pool_t; - -/* pool functions */ -/* - -=head1 ap_status_t ap_create_pool(ap_pool_t **newcont, ap_pool_t *cont) - -B<Create a new pool.> - arg 1) The pool we have just created. - arg 2) The parent pool. If this is NULL, the new pool is a root - pool. If it is non-NULL, the new pool will inherit all - of it's parent pool's attributes, except the ap_pool_t will - be a sub-pool. +#endif -=cut +/** + * Alignment macros */ -ap_status_t ap_create_pool(ap_pool_t **newcont, ap_pool_t *cont); - -/* -=head1 ap_status_t ap_destroy_pool(ap_pool_t *cont) +/* APR_ALIGN() is only to be used to align on a power of 2 boundary */ +#define APR_ALIGN(size, boundary) \ + (((size) + ((boundary) - 1)) & ~((boundary) - 1)) -B<Free the pool and all of it's child pools'.> +/** Default alignment */ +#define APR_ALIGN_DEFAULT(size) APR_ALIGN(size, 8) - arg 1) The pool to free. -=cut +/** + * String and memory functions */ -ap_status_t ap_exit(ap_pool_t *); - -/* - -=head1 ap_status_t ap_set_userdata(void *data, char *key, ap_status_t (*cleanup) (void *), ap_pool_t *cont) - -B<Set the data associated with the current pool>. +/* APR_STRINGIFY is defined here, and also in apr_release.h, so wrap it */ +#ifndef APR_STRINGIFY +/** Properly quote a value as a string in the C preprocessor */ +#define APR_STRINGIFY(n) APR_STRINGIFY_HELPER(n) +/** Helper macro for APR_STRINGIFY */ +#define APR_STRINGIFY_HELPER(n) #n +#endif - arg 1) The user data associated with the pool. - arg 2) The key to use for association - arg 3) The cleanup program to use to cleanup the data; - arg 4) The current pool. +#if (!APR_HAVE_MEMMOVE) +#define memmove(a,b,c) bcopy(b,a,c) +#endif -B<NOTE>: The data to be attached to the pool should have the same - life span as the pool it is being attached to. - - Users of APR must take EXTREME care when choosing a key to - use for their data. It is possible to accidentally overwrite - data by choosing a key that another part of the program is using - It is advised that steps are taken to ensure that a unique - key is used at all times. +#if (!APR_HAVE_MEMCHR) +void *memchr(const void *s, int c, size_t n); +#endif -=cut +/** + * Macro to provide a way to turn an incomplete type into a complete + * type containing common pointers for a provider. */ -ap_status_t ap_set_userdata(void *data, char *key, - ap_status_t (*cleanup) (void *), - ap_pool_t *cont); +#define APR_TYPEDEF_STRUCT(type, incompletion) \ +struct type { \ + incompletion \ + void *unk[]; \ +}; -/* +/** @} */ -=head1 ap_status_t ap_get_userdata(void **data, char *key, ap_pool_t *cont) - -B<Return the data associated with the current pool.> - - arg 1) The key for the data to retrieve - arg 2) The user data associated with the pool. - arg 3) The current pool. - -=cut +/** + * @defgroup apr_library Library initialization and termination + * @{ */ -ap_status_t ap_get_userdata(void **, char *key, ap_pool_t *cont); - -/* - -=head1 ap_status_t ap_initialize(void) - -B<Setup any APR internal data structures. This MUST be the first function called for any APR program.> -=cut +/** + * Setup any APR internal data structures. This MUST be the first function + * called for any APR library. It is safe to call apr_initialize several + * times as long as apr_terminate is called the same number of times. + * @remark See apr_app_initialize if this is an application, rather than + * a library consumer of apr. */ -ap_status_t ap_initialize(void); - -/* - -=head1 void ap_terminate(void) - -B<Tear down any APR internal data structures which aren't torn down automatically.> - -B<NOTE>: An APR program must call this function at termination once it - has stopped using APR services. - -=cut +APR_DECLARE(apr_status_t) apr_initialize(void); + +/** + * Set up an application with normalized argc, argv (and optionally env) in + * order to deal with platform-specific oddities, such as Win32 services, + * code pages and signals. This must be the first function called for any + * APR program. + * @param argc Pointer to the argc that may be corrected + * @param argv Pointer to the argv that may be corrected + * @param env Pointer to the env that may be corrected, may be NULL + * @remark See apr_initialize if this is a library consumer of apr. + * Otherwise, this call is identical to apr_initialize, and must be closed + * with a call to apr_terminate at the end of program execution. */ -void ap_terminate(void); - -/* - -=head1 ap_status_t ap_set_abort(int (*apr_abort)(int retcode), ap_pool_t *cont) - -B<Set the APR_ABORT function.> - -B<NOTE>: This is in for backwards compatability. If the program using - APR wants APR to exit on a memory allocation error, then this - function should be called to set the function to use in order - to actually exit the program. If this function is not called, - then APR will return an error and expect the calling program to - deal with the error accordingly. - -=cut +APR_DECLARE(apr_status_t) apr_app_initialize(int *argc, + char const * const * *argv, + char const * const * *env); + +/** + * Tear down any APR internal data structures which aren't torn down + * automatically. apr_terminate must be called once for every call to + * apr_initialize() or apr_app_initialize(). + * @remark An APR program must call this function at termination once it + * has stopped using APR services. The APR developers suggest using + * atexit to ensure this is called. When using APR from a language + * other than C that has problems with the calling convention, use + * apr_terminate2() instead. */ -ap_status_t ap_set_abort(int (*apr_abort)(int retcode), ap_pool_t *cont); - -/* +APR_DECLARE_NONSTD(void) apr_terminate(void); + +/** + * Tear down any APR internal data structures which aren't torn down + * automatically, same as apr_terminate + * @remark An APR program must call either the apr_terminate or apr_terminate2 + * function once it it has finished using APR services. The APR + * developers suggest using atexit(apr_terminate) to ensure this is done. + * apr_terminate2 exists to allow non-c language apps to tear down apr, + * while apr_terminate is recommended from c language applications. + */ +APR_DECLARE(void) apr_terminate2(void); -=head1 char *ap_strerror(ap_status_t statcode, char *buf, ap_size_t bufsize) +/** @} */ -B<Return a human readable string describing the specified error.> +/** + * @defgroup apr_random Random Functions + * @{ + */ - arg 1) The error code the get a string for. - arg 2) A buffer to hold the error string. - arg 3) Size of the buffer to hold the string. +#if APR_HAS_RANDOM || defined(DOXYGEN) -=cut +/* TODO: I'm not sure this is the best place to put this prototype...*/ +/** + * Generate random bytes. + * @param buf Buffer to fill with random bytes + * @param length Length of buffer in bytes */ -char *ap_strerror(ap_status_t statcode, char *buf, ap_size_t bufsize); +APR_DECLARE(apr_status_t) apr_generate_random_bytes(unsigned char * buf, + apr_size_t length); + +#endif +/** @} */ #ifdef __cplusplus } diff --git a/include/apr_getopt.h b/include/apr_getopt.h index f9ae7603f91..75ad5663a0c 100644 --- a/include/apr_getopt.h +++ b/include/apr_getopt.h @@ -1,95 +1,160 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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. */ #ifndef APR_GETOPT_H #define APR_GETOPT_H -API_VAR_IMPORT int - ap_opterr, /* if error message should be printed */ - ap_optind, /* index into parent argv vector */ - ap_optopt, /* character checked for validity */ - ap_optreset; /* reset getopt */ -API_VAR_IMPORT char * - ap_optarg; /* argument associated with option */ +/** + * @file apr_getopt.h + * @brief APR Command Arguments (getopt) + */ + +#include "apr_pools.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ -/* +/** + * @defgroup apr_getopt Command Argument Parsing + * @ingroup APR + * @{ + */ -=head1 ap_status_t ap_getopt(ap_int32_t nargc, char *const *nargv, const char *ostr, ap_int32_t *rv, ap_pool_t *cont) +/** + * An @c apr_getopt_t error callback function. + * + * @a arg is this @c apr_getopt_t's @c errarg member. + */ +typedef void (apr_getopt_err_fn_t)(void *arg, const char *err, ...); -B<Parse the command line options passed to the program.> +/** @see apr_getopt_t */ +typedef struct apr_getopt_t apr_getopt_t; - arg 1) The number of arguments passed to ap_getopt to parse - arg 2) The array of command line options to parse - arg 3) A string of characters that are acceptable options to the program. - characters followed by ":" are required to have an option - associated - arg 4) The next option found. There are four potential values for - this variable on exit. They are: - APR_EOF -- No more options to parse - APR_BADCH -- Found a bad option character - APR_BADARG -- Missing parameter for the found option - Other -- The next option found. - arg 5) The pool to operate on. +/** + * Structure to store command line argument information. + */ +struct apr_getopt_t { + /** context for processing */ + apr_pool_t *cont; + /** function to print error message (NULL == no messages) */ + apr_getopt_err_fn_t *errfn; + /** user defined first arg to pass to error message */ + void *errarg; + /** index into parent argv vector */ + int ind; + /** character checked for validity */ + int opt; + /** reset getopt */ + int reset; + /** count of arguments */ + int argc; + /** array of pointers to arguments */ + const char **argv; + /** argument associated with option */ + char const* place; + /** set to nonzero to support interleaving options with regular args */ + int interleave; + /** start of non-option arguments skipped for interleaving */ + int skip_start; + /** end of non-option arguments skipped for interleaving */ + int skip_end; +}; -B<NOTE>: Arguments 2 and 3 are most commonly argc and argv from - main(argc, argv) +/** @see apr_getopt_option_t */ +typedef struct apr_getopt_option_t apr_getopt_option_t; -=cut +/** + * Structure used to describe options that getopt should search for. */ -ap_status_t ap_getopt(ap_int32_t nargc, char *const *nargv, const char *ostr, - ap_int32_t *rv, ap_pool_t *cont); +struct apr_getopt_option_t { + /** long option name, or NULL if option has no long name */ + const char *name; + /** option letter, or a value greater than 255 if option has no letter */ + int optch; + /** nonzero if option takes an argument */ + int has_arg; + /** a description of the option */ + const char *description; +}; -#endif /* ! APR_GETOPT_H */ +/** + * Initialize the arguments for parsing by apr_getopt(). + * @param os The options structure created for apr_getopt() + * @param cont The pool to operate on + * @param argc The number of arguments to parse + * @param argv The array of arguments to parse + * @remark Arguments 3 and 4 are most commonly argc and argv from main(argc, argv) + * The (*os)->errfn is initialized to fprintf(stderr... but may be overridden. + */ +APR_DECLARE(apr_status_t) apr_getopt_init(apr_getopt_t **os, apr_pool_t *cont, + int argc, const char * const *argv); +/** + * Parse the options initialized by apr_getopt_init(). + * @param os The apr_opt_t structure returned by apr_getopt_init() + * @param opts A string of characters that are acceptable options to the + * program. Characters followed by ":" are required to have an + * option associated + * @param option_ch The next option character parsed + * @param option_arg The argument following the option character: + * @return There are four potential status values on exit. They are: + * <PRE> + * APR_EOF -- No more options to parse + * APR_BADCH -- Found a bad option character + * APR_BADARG -- No argument followed the option flag + * APR_SUCCESS -- The next option was found. + * </PRE> + */ +APR_DECLARE(apr_status_t) apr_getopt(apr_getopt_t *os, const char *opts, + char *option_ch, const char **option_arg); + +/** + * Parse the options initialized by apr_getopt_init(), accepting long + * options beginning with "--" in addition to single-character + * options beginning with "-". + * @param os The apr_getopt_t structure created by apr_getopt_init() + * @param opts A pointer to a list of apr_getopt_option_t structures, which + * can be initialized with { "name", optch, has_args }. has_args + * is nonzero if the option requires an argument. A structure + * with an optch value of 0 terminates the list. + * @param option_ch Receives the value of "optch" from the apr_getopt_option_t + * structure corresponding to the next option matched. + * @param option_arg Receives the argument following the option, if any. + * @return There are four potential status values on exit. They are: + * <PRE> + * APR_EOF -- No more options to parse + * APR_BADCH -- Found a bad option character + * APR_BADARG -- No argument followed the option flag + * APR_SUCCESS -- The next option was found. + * </PRE> + * When APR_SUCCESS is returned, os->ind gives the index of the first + * non-option argument. On error, a message will be printed to stdout unless + * os->err is set to 0. If os->interleave is set to nonzero, options can come + * after arguments, and os->argv will be permuted to leave non-option arguments + * at the end (the original argv is unaffected). + */ +APR_DECLARE(apr_status_t) apr_getopt_long(apr_getopt_t *os, + const apr_getopt_option_t *opts, + int *option_ch, + const char **option_arg); +/** @} */ +#ifdef __cplusplus +} +#endif + +#endif /* ! APR_GETOPT_H */ diff --git a/include/apr_global_mutex.h b/include/apr_global_mutex.h new file mode 100644 index 00000000000..d57ca453d9f --- /dev/null +++ b/include/apr_global_mutex.h @@ -0,0 +1,196 @@ +/* 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. + */ + +#ifndef APR_GLOBAL_MUTEX_H +#define APR_GLOBAL_MUTEX_H + +/** + * @file apr_global_mutex.h + * @brief APR Global Locking Routines + */ + +#include "apr.h" +#include "apr_proc_mutex.h" /* only for apr_lockmech_e */ +#include "apr_pools.h" +#include "apr_errno.h" +#if APR_PROC_MUTEX_IS_GLOBAL +#include "apr_proc_mutex.h" +#endif +#include "apr_time.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup APR_GlobalMutex Global Locking Routines + * @ingroup APR + * @{ + */ + +#if !APR_PROC_MUTEX_IS_GLOBAL || defined(DOXYGEN) + +/** Opaque global mutex structure. */ +typedef struct apr_global_mutex_t apr_global_mutex_t; + +/* Function definitions */ + +/** + * Create and initialize a mutex that can be used to synchronize both + * processes and threads. Note: There is considerable overhead in using + * this API if only cross-process or cross-thread mutual exclusion is + * required. See apr_proc_mutex.h and apr_thread_mutex.h for more + * specialized lock routines. + * @param mutex the memory address where the newly created mutex will be + * stored. + * @param fname A file name to use if the lock mechanism requires one. This + * argument should always be provided. The lock code itself will + * determine if it should be used. + * @param mech The mechanism to use for the interprocess lock, if any; one of + * <PRE> + * APR_LOCK_FCNTL + * APR_LOCK_FLOCK + * APR_LOCK_SYSVSEM + * APR_LOCK_POSIXSEM + * APR_LOCK_PROC_PTHREAD + * APR_LOCK_DEFAULT pick the default mechanism for the platform + * APR_LOCK_DEFAULT_TIMED pick the default timed mechanism + * </PRE> + * @param pool the pool from which to allocate the mutex. + * @warning Check APR_HAS_foo_SERIALIZE defines to see if the platform supports + * APR_LOCK_foo. Only APR_LOCK_DEFAULT is portable. + */ +APR_DECLARE(apr_status_t) apr_global_mutex_create(apr_global_mutex_t **mutex, + const char *fname, + apr_lockmech_e mech, + apr_pool_t *pool); + +/** + * Re-open a mutex in a child process. + * @param mutex The newly re-opened mutex structure. + * @param fname A file name to use if the mutex mechanism requires one. This + * argument should always be provided. The mutex code itself will + * determine if it should be used. This filename should be the + * same one that was passed to apr_global_mutex_create(). + * @param pool The pool to operate on. + * @remark This function must be called to maintain portability, even + * if the underlying lock mechanism does not require it. + */ +APR_DECLARE(apr_status_t) apr_global_mutex_child_init( + apr_global_mutex_t **mutex, + const char *fname, + apr_pool_t *pool); + +/** + * Acquire the lock for the given mutex. If the mutex is already locked, + * the current thread will be put to sleep until the lock becomes available. + * @param mutex the mutex on which to acquire the lock. + */ +APR_DECLARE(apr_status_t) apr_global_mutex_lock(apr_global_mutex_t *mutex); + +/** + * Attempt to acquire the lock for the given mutex. If the mutex has already + * been acquired, the call returns immediately with APR_EBUSY. Note: it + * is important that the APR_STATUS_IS_EBUSY(s) macro be used to determine + * if the return value was APR_EBUSY, for portability reasons. + * @param mutex the mutex on which to attempt the lock acquiring. + */ +APR_DECLARE(apr_status_t) apr_global_mutex_trylock(apr_global_mutex_t *mutex); + +/** + * Attempt to acquire the lock for the given mutex until timeout expires. + * If the acquisition time outs, the call returns with APR_TIMEUP. + * @param mutex the mutex on which to attempt the lock acquiring. + * @param timeout the relative timeout (microseconds). + * @note A negative or nul timeout means immediate attempt, returning + * APR_TIMEUP without blocking if it the lock is already acquired. + */ +APR_DECLARE(apr_status_t) apr_global_mutex_timedlock(apr_global_mutex_t *mutex, + apr_interval_time_t timeout); + +/** + * Release the lock for the given mutex. + * @param mutex the mutex from which to release the lock. + */ +APR_DECLARE(apr_status_t) apr_global_mutex_unlock(apr_global_mutex_t *mutex); + +/** + * Destroy the mutex and free the memory associated with the lock. + * @param mutex the mutex to destroy. + */ +APR_DECLARE(apr_status_t) apr_global_mutex_destroy(apr_global_mutex_t *mutex); + +/** + * Return the name of the lockfile for the mutex, or NULL + * if the mutex doesn't use a lock file + */ + +APR_DECLARE(const char *) apr_global_mutex_lockfile(apr_global_mutex_t *mutex); + +/** + * Get the mechanism of the mutex, as it relates to the actual method + * used for the underlying apr_proc_mutex_t. + * @param mutex the mutex to get the mechanism from. + */ +APR_DECLARE(apr_lockmech_e) apr_global_mutex_mech(apr_global_mutex_t *mutex); + +/** + * Get the mechanism's name of the mutex, as it relates to the actual method + * used for the underlying apr_proc_mutex_t. + * @param mutex the mutex to get the mechanism's name from. + */ +APR_DECLARE(const char *) apr_global_mutex_name(apr_global_mutex_t *mutex); + +/** + * Set mutex permissions. + */ +APR_PERMS_SET_IMPLEMENT(global_mutex); + +/** + * Get the pool used by this global_mutex. + * @return apr_pool_t the pool + */ +APR_POOL_DECLARE_ACCESSOR(global_mutex); + +#else /* APR_PROC_MUTEX_IS_GLOBAL */ + +/* Some platforms [e.g. Win32] have cross process locks that are truly + * global locks, since there isn't the concept of cross-process locks. + * Define these platforms in terms of an apr_proc_mutex_t. + */ + +#define apr_global_mutex_t apr_proc_mutex_t +#define apr_global_mutex_create apr_proc_mutex_create +#define apr_global_mutex_child_init apr_proc_mutex_child_init +#define apr_global_mutex_lock apr_proc_mutex_lock +#define apr_global_mutex_trylock apr_proc_mutex_trylock +#define apr_global_mutex_unlock apr_proc_mutex_unlock +#define apr_global_mutex_destroy apr_proc_mutex_destroy +#define apr_global_mutex_lockfile apr_proc_mutex_lockfile +#define apr_global_mutex_mech apr_proc_mutex_mech +#define apr_global_mutex_name apr_proc_mutex_name +#define apr_global_mutex_perms_set apr_proc_mutex_perms_set +#define apr_global_mutex_pool_get apr_proc_mutex_pool_get + +#endif + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* ndef APR_GLOBAL_MUTEX_H */ diff --git a/include/apr_hash.h b/include/apr_hash.h new file mode 100644 index 00000000000..10922de8f14 --- /dev/null +++ b/include/apr_hash.h @@ -0,0 +1,297 @@ +/* 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. + */ + +#ifndef APR_HASH_H +#define APR_HASH_H + +/** + * @file apr_hash.h + * @brief APR Hash Tables + */ + +#include "apr_pools.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup apr_hash Hash Tables + * @ingroup APR + * @{ + */ + +/** + * When passing a key to apr_hash_set or apr_hash_get, this value can be + * passed to indicate a string-valued key, and have apr_hash compute the + * length automatically. + * + * @remark apr_hash will use strlen(key) for the length. The NUL terminator + * is not included in the hash value (why throw a constant in?). + * Since the hash table merely references the provided key (rather + * than copying it), apr_hash_this() will return the NUL-term'd key. + */ +#define APR_HASH_KEY_STRING (-1) + +/** + * Abstract type for hash tables. + */ +typedef struct apr_hash_t apr_hash_t; + +/** + * Abstract type for scanning hash tables. + */ +typedef struct apr_hash_index_t apr_hash_index_t; + +/** + * Callback functions for calculating hash values. + * @param key The key. + * @param klen The length of the key, or APR_HASH_KEY_STRING to use the string + * length. If APR_HASH_KEY_STRING then returns the actual key length. + */ +typedef unsigned int (*apr_hashfunc_t)(const char *key, apr_ssize_t *klen); + +/** + * The default hash function. + */ +APR_DECLARE_NONSTD(unsigned int) apr_hashfunc_default(const char *key, + apr_ssize_t *klen); + +/** + * Create a hash table. + * @param pool The pool to allocate the hash table out of + * @return The hash table just created + */ +APR_DECLARE(apr_hash_t *) apr_hash_make(apr_pool_t *pool); + +/** + * Create a hash table with a custom hash function + * @param pool The pool to allocate the hash table out of + * @param hash_func A custom hash function. + * @return The hash table just created + */ +APR_DECLARE(apr_hash_t *) apr_hash_make_custom(apr_pool_t *pool, + apr_hashfunc_t hash_func); + +/** + * Make a copy of a hash table + * @param pool The pool from which to allocate the new hash table + * @param h The hash table to clone + * @return The hash table just created + * @remark Makes a shallow copy + */ +APR_DECLARE(apr_hash_t *) apr_hash_copy(apr_pool_t *pool, + const apr_hash_t *h); + +/** + * Associate a value with a key in a hash table. + * @param ht The hash table + * @param key Pointer to the key + * @param klen Length of the key. Can be APR_HASH_KEY_STRING to use the string length. + * @param val Value to associate with the key + * @remark If the value is NULL the hash entry is deleted. The key is stored as is, + * and so must have a lifetime at least as long as the hash table's pool. + */ +APR_DECLARE(void) apr_hash_set(apr_hash_t *ht, const void *key, + apr_ssize_t klen, const void *val); + +/** + * Look up the value associated with a key in a hash table. + * @param ht The hash table + * @param key Pointer to the key + * @param klen Length of the key. Can be APR_HASH_KEY_STRING to use the string length. + * @return Returns NULL if the key is not present. + */ +APR_DECLARE(void *) apr_hash_get(apr_hash_t *ht, const void *key, + apr_ssize_t klen); + +/** + * Look up the value associated with a key in a hash table, or if none exists + * associate a value. + * @param ht The hash table + * @param key Pointer to the key + * @param klen Length of the key. Can be APR_HASH_KEY_STRING to use the string + * length. + * @param val Value to associate with the key (if none exists). + * @return Returns the existing value if any, the given value otherwise. + * @remark If the given value is NULL and a hash entry exists, nothing is done. + */ +APR_DECLARE(void *) apr_hash_get_or_set(apr_hash_t *ht, const void *key, + apr_ssize_t klen, const void *val); + +/** + * Start iterating over the entries in a hash table. + * @param p The pool to allocate the apr_hash_index_t iterator. If this + * pool is NULL, then an internal, non-thread-safe iterator is used. + * @param ht The hash table + * @return The iteration state + * @remark There is no restriction on adding or deleting hash entries during + * an iteration (although the results may be unpredictable unless all you do + * is delete the current entry) and multiple iterations can be in + * progress at the same time. + * + * @par Example: + * + * @code + * int sum_values(apr_pool_t *p, apr_hash_t *ht) + * { + * apr_hash_index_t *hi; + * void *val; + * int sum = 0; + * for (hi = apr_hash_first(p, ht); hi; hi = apr_hash_next(hi)) { + * apr_hash_this(hi, NULL, NULL, &val); + * sum += *(int *)val; + * } + * return sum; + * } + * @endcode + */ +APR_DECLARE(apr_hash_index_t *) apr_hash_first(apr_pool_t *p, apr_hash_t *ht); + +/** + * Continue iterating over the entries in a hash table. + * @param hi The iteration state + * @return a pointer to the updated iteration state. NULL if there are no more + * entries. + */ +APR_DECLARE(apr_hash_index_t *) apr_hash_next(apr_hash_index_t *hi); + +/** + * Get the current entry's details from the iteration state. + * @param hi The iteration state + * @param key Return pointer for the pointer to the key. + * @param klen Return pointer for the key length. + * @param val Return pointer for the associated value. + * @remark The return pointers should point to a variable that will be set to the + * corresponding data, or they may be NULL if the data isn't interesting. + */ +APR_DECLARE(void) apr_hash_this(apr_hash_index_t *hi, const void **key, + apr_ssize_t *klen, void **val); + +/** + * Get the current entry's key from the iteration state. + * @param hi The iteration state + * @return The pointer to the key + */ +APR_DECLARE(const void*) apr_hash_this_key(apr_hash_index_t *hi); + +/** + * Get the current entry's key length from the iteration state. + * @param hi The iteration state + * @return The key length + */ +APR_DECLARE(apr_ssize_t) apr_hash_this_key_len(apr_hash_index_t *hi); + +/** + * Get the current entry's value from the iteration state. + * @param hi The iteration state + * @return The pointer to the value + */ +APR_DECLARE(void*) apr_hash_this_val(apr_hash_index_t *hi); + +/** + * Get the number of key/value pairs in the hash table. + * @param ht The hash table + * @return The number of key/value pairs in the hash table. + */ +APR_DECLARE(unsigned int) apr_hash_count(apr_hash_t *ht); + +/** + * Clear any key/value pairs in the hash table. + * @param ht The hash table + */ +APR_DECLARE(void) apr_hash_clear(apr_hash_t *ht); + +/** + * Merge two hash tables into one new hash table. The values of the overlay + * hash override the values of the base if both have the same key. Both + * hash tables must use the same hash function. + * @param p The pool to use for the new hash table + * @param overlay The table to add to the initial table + * @param base The table that represents the initial values of the new table + * @return A new hash table containing all of the data from the two passed in + */ +APR_DECLARE(apr_hash_t *) apr_hash_overlay(apr_pool_t *p, + const apr_hash_t *overlay, + const apr_hash_t *base); + +/** + * Merge two hash tables into one new hash table. If the same key + * is present in both tables, call the supplied merge function to + * produce a merged value for the key in the new table. Both + * hash tables must use the same hash function. + * @param p The pool to use for the new hash table + * @param h1 The first of the tables to merge + * @param h2 The second of the tables to merge + * @param merger A callback function to merge values, or NULL to + * make values from h1 override values from h2 (same semantics as + * apr_hash_overlay()) + * @param data Client data to pass to the merger function + * @return A new hash table containing all of the data from the two passed in + */ +APR_DECLARE(apr_hash_t *) apr_hash_merge(apr_pool_t *p, + const apr_hash_t *h1, + const apr_hash_t *h2, + void * (*merger)(apr_pool_t *p, + const void *key, + apr_ssize_t klen, + const void *h1_val, + const void *h2_val, + const void *data), + const void *data); + +/** + * Declaration prototype for the iterator callback function of apr_hash_do(). + * + * @param rec The data passed as the first argument to apr_hash_[v]do() + * @param key The key from this iteration of the hash table + * @param klen The key length from this iteration of the hash table + * @param value The value from this iteration of the hash table + * @remark Iteration continues while this callback function returns non-zero. + * To export the callback function for apr_hash_do() it must be declared + * in the _NONSTD convention. + */ +typedef int (apr_hash_do_callback_fn_t)(void *rec, const void *key, + apr_ssize_t klen, + const void *value); + +/** + * Iterate over a hash table running the provided function once for every + * element in the hash table. The @param comp function will be invoked for + * every element in the hash table. + * + * @param comp The function to run + * @param rec The data to pass as the first argument to the function + * @param ht The hash table to iterate over + * @return FALSE if one of the comp() iterations returned zero; TRUE if all + * iterations returned non-zero + * @see apr_hash_do_callback_fn_t + */ +APR_DECLARE(int) apr_hash_do(apr_hash_do_callback_fn_t *comp, + void *rec, const apr_hash_t *ht); + +/** + * Get a pointer to the pool which the hash table was created in + */ +APR_POOL_DECLARE_ACCESSOR(hash); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* !APR_HASH_H */ diff --git a/include/apr_hooks.h b/include/apr_hooks.h new file mode 100644 index 00000000000..896ea72f3c2 --- /dev/null +++ b/include/apr_hooks.h @@ -0,0 +1,358 @@ +/* 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. + */ + +#ifndef APR_HOOKS_H +#define APR_HOOKS_H + +#include "apu.h" +/* For apr_array_header_t */ +#include "apr_tables.h" + +/** + * @file apr_hooks.h + * @brief Apache hook functions + */ + +#ifdef __cplusplus +extern "C" { +#endif +/** + * @defgroup APR_Util_Hook Hook Functions + * @ingroup APR + * @{ + */ + +/** + * @defgroup apr_hook_probes Hook probe capability + * APR hooks provide a trace probe capability for capturing + * the flow of control and return values with hooks. + * + * In order to use this facility, the application must define + * the symbol APR_HOOK_PROBES_ENABLED and the four APR_HOOK_PROBE_ + * macros described below before including apr_hooks.h in files + * that use the APR_IMPLEMENT_EXTERNAL_HOOK_* macros. + * + * This probe facility is not provided for APR optional hooks. + * @{ + */ + +#ifdef APR_HOOK_PROBES_ENABLED +#define APR_HOOK_INT_DCL_UD void *ud = NULL +#else +/** internal implementation detail to avoid the ud declaration when + * hook probes are not used + */ +#define APR_HOOK_INT_DCL_UD +/** + * User-defined hook probe macro that is invoked when the hook + * is run, before calling any hook functions. + * @param ud A void * user data field that should be filled in by + * this macro, and will be provided to the other hook probe macros. + * @param ns The namespace prefix of the hook functions + * @param name The name of the hook + * @param args The argument list to the hook functions, with enclosing + * parens. + */ +#define APR_HOOK_PROBE_ENTRY(ud,ns,name,args) +/** + * User-defined hook probe macro that is invoked after the hook + * has run. + * @param ud A void * user data field that was filled in by the user- + * provided APR_HOOK_PROBE_ENTRY(). + * @param ns The namespace prefix of the hook functions + * @param name The name of the hook + * @param rv The return value of the hook, or 0 if the hook is void. + * @param args The argument list to the hook functions, with enclosing + * parens. + */ +#define APR_HOOK_PROBE_RETURN(ud,ns,name,rv,args) +/** + * User-defined hook probe macro that is invoked before calling a + * hook function. + * @param ud A void * user data field that was filled in by the user- + * provided APR_HOOK_PROBE_ENTRY(). + * @param ns The namespace prefix of the hook functions + * @param name The name of the hook + * @param src The value of apr_hook_debug_current at the time the function + * was hooked (usually the source file implementing the hook function). + * @param args The argument list to the hook functions, with enclosing + * parens. + */ +#define APR_HOOK_PROBE_INVOKE(ud,ns,name,src,args) +/** + * User-defined hook probe macro that is invoked after calling a + * hook function. + * @param ud A void * user data field that was filled in by the user- + * provided APR_HOOK_PROBE_ENTRY(). + * @param ns The namespace prefix of the hook functions + * @param name The name of the hook + * @param src The value of apr_hook_debug_current at the time the function + * was hooked (usually the source file implementing the hook function). + * @param rv The return value of the hook function, or 0 if the hook is void. + * @param args The argument list to the hook functions, with enclosing + * parens. + */ +#define APR_HOOK_PROBE_COMPLETE(ud,ns,name,src,rv,args) +#endif + +/** @} */ + +/** macro to return the prototype of the hook function */ +#define APR_IMPLEMENT_HOOK_GET_PROTO(ns,link,name) \ +link##_DECLARE(apr_array_header_t *) ns##_hook_get_##name(void) + +/** macro to declare the hook correctly */ +#define APR_DECLARE_EXTERNAL_HOOK(ns,link,ret,name,args) \ +typedef ret ns##_HOOK_##name##_t args; \ +link##_DECLARE(void) ns##_hook_##name(ns##_HOOK_##name##_t *pf, \ + const char * const *aszPre, \ + const char * const *aszSucc, int nOrder); \ +link##_DECLARE(ret) ns##_run_##name args; \ +APR_IMPLEMENT_HOOK_GET_PROTO(ns,link,name); \ +typedef struct ns##_LINK_##name##_t \ + { \ + ns##_HOOK_##name##_t *pFunc; \ + const char *szName; \ + const char * const *aszPredecessors; \ + const char * const *aszSuccessors; \ + int nOrder; \ + } ns##_LINK_##name##_t; + +/** macro to declare the hook structure */ +#define APR_HOOK_STRUCT(members) \ +static struct { members } _hooks; + +/** macro to link the hook structure */ +#define APR_HOOK_LINK(name) \ + apr_array_header_t *link_##name; + +/** macro to implement the hook */ +#define APR_IMPLEMENT_EXTERNAL_HOOK_BASE(ns,link,name) \ +link##_DECLARE(void) ns##_hook_##name(ns##_HOOK_##name##_t *pf,const char * const *aszPre, \ + const char * const *aszSucc,int nOrder) \ + { \ + ns##_LINK_##name##_t *pHook; \ + if(!_hooks.link_##name) \ + { \ + _hooks.link_##name=apr_array_make(apr_hook_global_pool,1,sizeof(ns##_LINK_##name##_t)); \ + apr_hook_sort_register(#name,&_hooks.link_##name); \ + } \ + pHook=apr_array_push(_hooks.link_##name); \ + pHook->pFunc=pf; \ + pHook->aszPredecessors=aszPre; \ + pHook->aszSuccessors=aszSucc; \ + pHook->nOrder=nOrder; \ + pHook->szName=apr_hook_debug_current; \ + if(apr_hook_debug_enabled) \ + apr_hook_debug_show(#name,aszPre,aszSucc); \ + } \ + APR_IMPLEMENT_HOOK_GET_PROTO(ns,link,name) \ + { \ + return _hooks.link_##name; \ + } + +/** + * Implement a hook that has no return code, and therefore runs all of the + * registered functions + * @param ns The namespace prefix of the hook functions + * @param link The linkage declaration prefix of the hook + * @param name The name of the hook + * @param args_decl The declaration of the arguments for the hook + * @param args_use The names for the arguments for the hook + * @note The link prefix FOO corresponds to FOO_DECLARE() macros, which + * provide export linkage from the module that IMPLEMENTs the hook, and + * import linkage from external modules that link to the hook's module. + */ +#define APR_IMPLEMENT_EXTERNAL_HOOK_VOID(ns,link,name,args_decl,args_use) \ +APR_IMPLEMENT_EXTERNAL_HOOK_BASE(ns,link,name) \ +link##_DECLARE(void) ns##_run_##name args_decl \ + { \ + ns##_LINK_##name##_t *pHook; \ + int n; \ + APR_HOOK_INT_DCL_UD; \ +\ + APR_HOOK_PROBE_ENTRY(ud, ns, name, args_use); \ +\ + if(_hooks.link_##name) \ + { \ + pHook=(ns##_LINK_##name##_t *)_hooks.link_##name->elts; \ + for(n=0 ; n < _hooks.link_##name->nelts ; ++n) \ + { \ + APR_HOOK_PROBE_INVOKE(ud, ns, name, (char *)pHook[n].szName, args_use); \ + pHook[n].pFunc args_use; \ + APR_HOOK_PROBE_COMPLETE(ud, ns, name, (char *)pHook[n].szName, 0, args_use); \ + } \ + } \ +\ + APR_HOOK_PROBE_RETURN(ud, ns, name, 0, args_use); \ +\ + } + +/* FIXME: note that this returns ok when nothing is run. I suspect it should + really return decline, but that breaks Apache currently - Ben +*/ +/** + * Implement a hook that runs until one of the functions returns something + * other than OK or DECLINE + * @param ns The namespace prefix of the hook functions + * @param link The linkage declaration prefix of the hook + * @param ret Type to return + * @param name The name of the hook + * @param args_decl The declaration of the arguments for the hook + * @param args_use The names for the arguments for the hook + * @param ok Success value + * @param decline Decline value + * @note The link prefix FOO corresponds to FOO_DECLARE() macros, which + * provide export linkage from the module that IMPLEMENTs the hook, and + * import linkage from external modules that link to the hook's module. + */ +#define APR_IMPLEMENT_EXTERNAL_HOOK_RUN_ALL(ns,link,ret,name,args_decl,args_use,ok,decline) \ +APR_IMPLEMENT_EXTERNAL_HOOK_BASE(ns,link,name) \ +link##_DECLARE(ret) ns##_run_##name args_decl \ + { \ + ns##_LINK_##name##_t *pHook; \ + int n; \ + ret rv = ok; \ + APR_HOOK_INT_DCL_UD; \ +\ + APR_HOOK_PROBE_ENTRY(ud, ns, name, args_use); \ +\ + if(_hooks.link_##name) \ + { \ + pHook=(ns##_LINK_##name##_t *)_hooks.link_##name->elts; \ + for(n=0 ; n < _hooks.link_##name->nelts ; ++n) \ + { \ + APR_HOOK_PROBE_INVOKE(ud, ns, name, (char *)pHook[n].szName, args_use); \ + rv=pHook[n].pFunc args_use; \ + APR_HOOK_PROBE_COMPLETE(ud, ns, name, (char *)pHook[n].szName, rv, args_use); \ + if(rv != ok && rv != decline) \ + break; \ + rv = ok; \ + } \ + } \ +\ + APR_HOOK_PROBE_RETURN(ud, ns, name, rv, args_use); \ +\ + return rv; \ + } + + +/** + * Implement a hook that runs until the first function returns something + * other than the value of decline + * @param ns The namespace prefix of the hook functions + * @param link The linkage declaration prefix of the hook + * @param name The name of the hook + * @param ret Type to return + * @param args_decl The declaration of the arguments for the hook + * @param args_use The names for the arguments for the hook + * @param decline Decline value + * @note The link prefix FOO corresponds to FOO_DECLARE() macros, which + * provide export linkage from the module that IMPLEMENTs the hook, and + * import linkage from external modules that link to the hook's module. + */ +#define APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(ns,link,ret,name,args_decl,args_use,decline) \ +APR_IMPLEMENT_EXTERNAL_HOOK_BASE(ns,link,name) \ +link##_DECLARE(ret) ns##_run_##name args_decl \ + { \ + ns##_LINK_##name##_t *pHook; \ + int n; \ + ret rv = decline; \ + APR_HOOK_INT_DCL_UD; \ +\ + APR_HOOK_PROBE_ENTRY(ud, ns, name, args_use); \ +\ + if(_hooks.link_##name) \ + { \ + pHook=(ns##_LINK_##name##_t *)_hooks.link_##name->elts; \ + for(n=0 ; n < _hooks.link_##name->nelts ; ++n) \ + { \ + APR_HOOK_PROBE_INVOKE(ud, ns, name, (char *)pHook[n].szName, args_use); \ + rv=pHook[n].pFunc args_use; \ + APR_HOOK_PROBE_COMPLETE(ud, ns, name, (char *)pHook[n].szName, rv, args_use); \ +\ + if(rv != decline) \ + break; \ + } \ + } \ +\ + APR_HOOK_PROBE_RETURN(ud, ns, name, rv, args_use); \ +\ + return rv; \ + } + + /* Hook orderings */ +/** run this hook first, before ANYTHING */ +#define APR_HOOK_REALLY_FIRST (-10) +/** run this hook first */ +#define APR_HOOK_FIRST 0 +/** run this hook somewhere */ +#define APR_HOOK_MIDDLE 10 +/** run this hook after every other hook which is defined*/ +#define APR_HOOK_LAST 20 +/** run this hook last, after EVERYTHING */ +#define APR_HOOK_REALLY_LAST 30 + +/** + * The global pool used to allocate any memory needed by the hooks. + */ +APR_DECLARE_DATA extern apr_pool_t *apr_hook_global_pool; + +/** + * A global variable to determine if debugging information about the + * hooks functions should be printed. + */ +APR_DECLARE_DATA extern int apr_hook_debug_enabled; + +/** + * The name of the module that is currently registering a function. + */ +APR_DECLARE_DATA extern const char *apr_hook_debug_current; + +/** + * Register a hook function to be sorted. + * @param szHookName The name of the Hook the function is registered for + * @param aHooks The array which stores all of the functions for this hook + */ +APR_DECLARE(void) apr_hook_sort_register(const char *szHookName, + apr_array_header_t **aHooks); +/** + * Sort all of the registered functions for a given hook. + */ +APR_DECLARE(void) apr_hook_sort_all(void); + +/** + * Print all of the information about the current hook. This is used for + * debugging purposes. + * @param szName The name of the hook + * @param aszPre All of the functions in the predecessor array + * @param aszSucc All of the functions in the successor array + */ +APR_DECLARE(void) apr_hook_debug_show(const char *szName, + const char * const *aszPre, + const char * const *aszSucc); + +/** + * Remove all currently registered functions. + */ +APR_DECLARE(void) apr_hook_deregister_all(void); + +/** @} */ +#ifdef __cplusplus +} +#endif + +#endif /* APR_HOOKS_H */ diff --git a/include/apr_inherit.h b/include/apr_inherit.h new file mode 100644 index 00000000000..b9fe56fe449 --- /dev/null +++ b/include/apr_inherit.h @@ -0,0 +1,51 @@ +/* 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. + */ + +#ifndef APR_INHERIT_H +#define APR_INHERIT_H + +/** + * @file apr_inherit.h + * @brief APR File Handle Inheritance Helpers + * @remark This internal header includes internal declaration helpers + * for other headers to declare apr_foo_inherit_[un]set functions. + */ + +/** + * Prototype for type-specific declarations of apr_foo_inherit_set + * functions. + * @remark Doxygen unwraps this macro (via doxygen.conf) to provide + * actual help for each specific occurrence of apr_foo_inherit_set. + * @remark the linkage is specified for APR. It would be possible to expand + * the macros to support other linkages. + */ +#define APR_DECLARE_INHERIT_SET(type) \ + APR_DECLARE(apr_status_t) apr_##type##_inherit_set( \ + apr_##type##_t *the##type) + +/** + * Prototype for type-specific declarations of apr_foo_inherit_unset + * functions. + * @remark Doxygen unwraps this macro (via doxygen.conf) to provide + * actual help for each specific occurrence of apr_foo_inherit_unset. + * @remark the linkage is specified for APR. It would be possible to expand + * the macros to support other linkages. + */ +#define APR_DECLARE_INHERIT_UNSET(type) \ + APR_DECLARE(apr_status_t) apr_##type##_inherit_unset( \ + apr_##type##_t *the##type) + +#endif /* ! APR_INHERIT_H */ diff --git a/include/apr_lib.h b/include/apr_lib.h index 4b9153b8540..c86217f9195 100644 --- a/include/apr_lib.h +++ b/include/apr_lib.h @@ -1,373 +1,238 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. +/* 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. */ #ifndef APR_LIB_H #define APR_LIB_H -#include "apr_general.h" -#include "apr_file_io.h" -#include "apr_thread_proc.h" +/** + * @file apr_lib.h + * This is collection of oddballs that didn't fit anywhere else, + * and might move to more appropriate headers with the release + * of APR 1.0. + * @brief APR general purpose library routines + */ + +#include "apr.h" +#include "apr_errno.h" +#if APR_HAVE_CTYPE_H +#include <ctype.h> +#endif #if APR_HAVE_STDARG_H #include <stdarg.h> #endif -#if APR_HAVE_SYS_TYPES_H -#include <sys/types.h> -#endif #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ +/** + * @defgroup apr_lib General Purpose Library Routines + * @ingroup APR + * This is collection of oddballs that didn't fit anywhere else, + * and might move to more appropriate headers with the release + * of APR 1.0. + * @{ + */ + +/** A constant representing a 'large' string. */ #define HUGE_STRING_LEN 8192 /* * Define the structures used by the APR general-purpose library. */ -/* - * Memory allocation stuff, like pools, arrays, and tables. Pools - * and tables are opaque structures to applications, but arrays are - * published. - */ -typedef struct ap_table_t ap_table_t; -typedef struct ap_child_info_t ap_child_info_t; -typedef void ap_mutex_t; -typedef struct ap_array_header_t { - ap_pool_t *cont; - int elt_size; - int nelts; - int nalloc; - char *elts; -} ap_array_header_t; - -typedef struct ap_table_entry_t { - char *key; /* maybe NULL in future; - * check when iterating thru table_elts - */ - char *val; -} ap_table_entry_t; - -/* XXX: these know about the definition of struct ap_table_t in alloc.c. That - * definition is not here because it is supposed to be private, and by not - * placing it here we are able to get compile-time diagnostics from modules - * written which assume that a ap_table_t is the same as an ap_array_header_t. -djg - */ -#define ap_table_elts(t) ((ap_array_header_t *)(t)) -#define ap_is_empty_table(t) (((t) == NULL)||(((ap_array_header_t *)(t))->nelts == 0)) +/** @see apr_vformatter_buff_t */ +typedef struct apr_vformatter_buff_t apr_vformatter_buff_t; -/* +/** * Structure used by the variable-formatter routines. */ -typedef struct ap_vformatter_buff_t { +struct apr_vformatter_buff_t { + /** The current position */ char *curpos; + /** The end position of the format string */ char *endpos; -} ap_vformatter_buff_t; - -enum kill_conditions { - kill_never, /* process is never sent any signals */ - kill_always, /* process is sent SIGKILL on ap_pool_t cleanup */ - kill_after_timeout, /* SIGTERM, wait 3 seconds, SIGKILL */ - just_wait, /* wait forever for the process to complete */ - kill_only_once /* send SIGTERM and then wait */ }; -/* - * Define the prototypes for the various APR GP routines. +/** + * return the final element of the pathname + * @param pathname The path to get the final element of + * @return the final element of the path + * @remark + * <PRE> + * For example: + * "/foo/bar/gum" -> "gum" + * "/foo/bar/gum/" -> "" + * "gum" -> "gum" + * "bs\\path\\stuff" -> "stuff" + * </PRE> */ -API_EXPORT(char *) ap_cpystrn(char *d, const char *s, size_t l); -API_EXPORT(ap_status_t) ap_tokenize_to_argv(char *arg_str, char ***argv_out, - ap_pool_t *token_context); -API_EXPORT(const char *) ap_filename_of_pathname(const char *pathname); -API_EXPORT(char *) ap_collapse_spaces(char *dest, const char *src); - -/*API_EXPORT(ap_mutex_t *) ap_create_mutex(void *m);*/ -API_EXPORT(int) ap_slack(int l, int h); -API_EXPORT_NONSTD(ap_status_t) ap_execle(const char *c, const char *a, ...); -API_EXPORT_NONSTD(ap_status_t) ap_execve(const char *c, const char *argv[], - const char *envp[]); - -#define ap_create_mutex(x) (0) -#define ap_release_mutex(x) (0) -#define ap_acquire_mutex(x) (0) - -/* These macros allow correct support of 8-bit characters on systems which - * support 8-bit characters. Pretty dumb how the cast is required, but - * that's legacy libc for ya. These new macros do not support EOF like - * the standard macros do. Tough. - */ -#define ap_isalnum(c) (isalnum(((unsigned char)(c)))) -#define ap_isalpha(c) (isalpha(((unsigned char)(c)))) -#define ap_iscntrl(c) (iscntrl(((unsigned char)(c)))) -#define ap_isdigit(c) (isdigit(((unsigned char)(c)))) -#define ap_isgraph(c) (isgraph(((unsigned char)(c)))) -#define ap_islower(c) (islower(((unsigned char)(c)))) -#define ap_isprint(c) (isprint(((unsigned char)(c)))) -#define ap_ispunct(c) (ispunct(((unsigned char)(c)))) -#define ap_isspace(c) (isspace(((unsigned char)(c)))) -#define ap_isupper(c) (isupper(((unsigned char)(c)))) -#define ap_isxdigit(c) (isxdigit(((unsigned char)(c)))) -#define ap_tolower(c) (tolower(((unsigned char)(c)))) -#define ap_toupper(c) (toupper(((unsigned char)(c)))) - +APR_DECLARE(const char *) apr_filepath_name_get(const char *pathname); - - -/* +/** + * apr_killpg * Small utility macros to make things easier to read. Not usually a * goal, to be sure.. */ #ifdef WIN32 -#define ap_killpg(x, y) +#define apr_killpg(x, y) #else /* WIN32 */ #ifdef NO_KILLPG -#define ap_killpg(x, y) (kill (-(x), (y))) +#define apr_killpg(x, y) (kill (-(x), (y))) #else /* NO_KILLPG */ -#define ap_killpg(x, y) (killpg ((x), (y))) +#define apr_killpg(x, y) (killpg ((x), (y))) #endif /* NO_KILLPG */ #endif /* WIN32 */ -/* - * ap_vformatter() is a generic printf-style formatting routine - * with some extensions. The extensions are: - * - * %pA takes a struct in_addr *, and prints it as a.b.c.d - * %pI takes a struct sockaddr_in * and prints it as a.b.c.d:port - * %pp takes a void * and outputs it in hex - * - * The %p hacks are to force gcc's printf warning code to skip +/** + * apr_vformatter() is a generic printf-style formatting routine + * with some extensions. + * @param flush_func The function to call when the buffer is full + * @param c The buffer to write to + * @param fmt The format string + * @param ap The arguments to use to fill out the format string. + * + * @remark + * <PRE> + * The extensions are: + * + * - %%pA takes a struct in_addr *, and prints it as a.b.c.d + * - %%pI takes an apr_sockaddr_t * and prints it as a.b.c.d:port or + * \[ipv6-address\]:port + * - %%pT takes an apr_os_thread_t * and prints it in decimal + * ('0' is printed if !APR_HAS_THREADS) + * - %%pt takes an apr_os_thread_t * and prints it in hexadecimal + * ('0' is printed if !APR_HAS_THREADS) + * - %%pm takes an apr_status_t * and prints the appropriate error + * string (from apr_strerror) corresponding to that error code. + * - %%pp takes a void * and outputs it in hex + * - %%pB takes a apr_uint32_t * as bytes and outputs it's apr_strfsize + * - %%pF same as above, but takes a apr_off_t * + * - %%pS same as above, but takes a apr_size_t * + * + * %%pA, %%pI, %%pT, %%pp are available from APR 1.0.0 onwards (and in 0.9.x). + * %%pt is only available from APR 1.2.0 onwards. + * %%pm, %%pB, %%pF and %%pS are only available from APR 1.3.0 onwards. + * + * The %%p hacks are to force gcc's printf warning code to skip * over a pointer argument without complaining. This does - * mean that the ANSI-style %p (output a void * in hex format) won't + * mean that the ANSI-style %%p (output a void * in hex format) won't * work as expected at all, but that seems to be a fair trade-off * for the increased robustness of having printf-warnings work. * - * Additionally, ap_vformatter allows for arbitrary output methods - * using the ap_vformatter_buff and flush_func. + * Additionally, apr_vformatter allows for arbitrary output methods + * using the apr_vformatter_buff and flush_func. * - * The ap_vformatter_buff has two elements curpos and endpos. - * curpos is where ap_vformatter will write the next byte of output. + * The apr_vformatter_buff has two elements curpos and endpos. + * curpos is where apr_vformatter will write the next byte of output. * It proceeds writing output to curpos, and updating curpos, until * either the end of output is reached, or curpos == endpos (i.e. the * buffer is full). * - * If the end of output is reached, ap_vformatter returns the + * If the end of output is reached, apr_vformatter returns the * number of bytes written. * * When the buffer is full, the flush_func is called. The flush_func * can return -1 to indicate that no further output should be attempted, - * and ap_vformatter will return immediately with -1. Otherwise + * and apr_vformatter will return immediately with -1. Otherwise * the flush_func should flush the buffer in whatever manner is - * appropriate, re ap_pool_t nitialize curpos and endpos, and return 0. + * appropriate, re apr_pool_t nitialize curpos and endpos, and return 0. * * Note that flush_func is only invoked as a result of attempting to * write another byte at curpos when curpos >= endpos. So for * example, it's possible when the output exactly matches the buffer * space available that curpos == endpos will be true when - * ap_vformatter returns. + * apr_vformatter returns. * - * ap_vformatter does not call out to any other code, it is entirely + * apr_vformatter does not call out to any other code, it is entirely * self-contained. This allows the callers to do things which are - * otherwise "unsafe". For example, ap_psprintf uses the "scratch" + * otherwise "unsafe". For example, apr_psprintf uses the "scratch" * space at the unallocated end of a block, and doesn't actually - * complete the allocation until ap_vformatter returns. ap_psprintf - * would be completely broken if ap_vformatter were to call anything - * that used a ap_pool_t. Similarly http_bprintf() uses the "scratch" + * complete the allocation until apr_vformatter returns. apr_psprintf + * would be completely broken if apr_vformatter were to call anything + * that used this same pool. Similarly http_bprintf() uses the "scratch" * space at the end of its output buffer, and doesn't actually note * that the space is in use until it either has to flush the buffer - * or until ap_vformatter returns. - */ - -API_EXPORT(int) ap_vformatter(int (*flush_func)(ap_vformatter_buff_t *b), - ap_vformatter_buff_t *c, const char *fmt, - va_list ap); - - -/* A small routine to validate a plain text password with a password - * that has been encrypted using any algorithm APR knows about. - */ -API_EXPORT(ap_status_t) ap_validate_password(const char *passwd, const char *hash); - - -/* - * These are snprintf implementations based on ap_vformatter(). - * - * Note that various standards and implementations disagree on the return - * value of snprintf, and side-effects due to %n in the formatting string. - * ap_snprintf behaves as follows: - * - * Process the format string until the entire string is exhausted, or - * the buffer fills. If the buffer fills then stop processing immediately - * (so no further %n arguments are processed), and return the buffer - * length. In all cases the buffer is NUL terminated. - * - * In no event does ap_snprintf return a negative number. It's not possible - * to distinguish between an output which was truncated, and an output which - * exactly filled the buffer. - */ -API_EXPORT(int) ap_snprintf(char *buf, size_t len, const char *format, ...) - __attribute__((format(printf,3,4))); -API_EXPORT(int) ap_vsnprintf(char *buf, size_t len, const char *format, - va_list ap); - -/* - * APR memory structure manipulators (pools, tables, and arrays). + * or until apr_vformatter returns. + * </PRE> */ -API_EXPORT(ap_pool_t *) ap_make_sub_pool(ap_pool_t *p, int (*apr_abort)(int retcode)); -API_EXPORT(void) ap_clear_pool(struct ap_pool_t *p); -API_EXPORT(void) ap_destroy_pool(struct ap_pool_t *p); -API_EXPORT(long) ap_bytes_in_pool(ap_pool_t *p); -API_EXPORT(long) ap_bytes_in_free_blocks(void); -API_EXPORT(ap_pool_t *) ap_find_pool(const void *ts); -API_EXPORT(int) ap_pool_is_ancestor(ap_pool_t *a, ap_pool_t *b); -API_EXPORT(void) ap_pool_join(ap_pool_t *p, ap_pool_t *sub); - -/* used to guarantee to the ap_pool_t debugging code that the sub ap_pool_t will not be - * destroyed before the parent pool +APR_DECLARE(int) apr_vformatter(int (*flush_func)(apr_vformatter_buff_t *b), + apr_vformatter_buff_t *c, const char *fmt, + va_list ap); + +/** + * Display a prompt and read in the password from stdin. + * @param prompt The prompt to display + * @param pwbuf Buffer to store the password + * @param bufsize The length of the password buffer. + * @remark If the password entered must be truncated to fit in + * the provided buffer, APR_ENAMETOOLONG will be returned. + * Note that the bufsize paramater is passed by reference for no + * reason; its value will never be modified by the apr_password_get() + * function. */ -#ifndef POOL_DEBUG -#ifdef ap_pool_join -#undef ap_pool_join -#endif /* ap_pool_join */ -#define ap_pool_join(a,b) -#endif /* POOL_DEBUG */ - - -API_EXPORT(void *) ap_palloc(struct ap_pool_t *c, int reqsize); -API_EXPORT(void *) ap_pcalloc(struct ap_pool_t *p, int size); -API_EXPORT(char *) ap_pstrdup(struct ap_pool_t *p, const char *s); -API_EXPORT(char *) ap_pstrndup(struct ap_pool_t *p, const char *s, int n); -API_EXPORT_NONSTD(char *) ap_pstrcat(struct ap_pool_t *p, ...); -API_EXPORT(char *) ap_pvsprintf(struct ap_pool_t *p, const char *fmt, va_list ap); -API_EXPORT_NONSTD(char *) ap_psprintf(struct ap_pool_t *p, const char *fmt, ...); -API_EXPORT(ap_array_header_t *) ap_make_array(struct ap_pool_t *p, int nelts, - int elt_size); -API_EXPORT(void *) ap_push_array(ap_array_header_t *arr); -API_EXPORT(void) ap_array_cat(ap_array_header_t *dst, - const ap_array_header_t *src); -API_EXPORT(ap_array_header_t *) ap_copy_array(struct ap_pool_t *p, - const ap_array_header_t *arr); -API_EXPORT(ap_array_header_t *) - ap_copy_array_hdr(struct ap_pool_t *p, - const ap_array_header_t *arr); -API_EXPORT(ap_array_header_t *) - ap_append_arrays(struct ap_pool_t *p, - const ap_array_header_t *first, - const ap_array_header_t *second); -API_EXPORT(char *) ap_array_pstrcat(struct ap_pool_t *p, - const ap_array_header_t *arr, - const char sep); -API_EXPORT(ap_table_t *) ap_make_table(struct ap_pool_t *p, int nelts); -API_EXPORT(ap_table_t *) ap_copy_table(struct ap_pool_t *p, const ap_table_t *t); -API_EXPORT(void) ap_clear_table(ap_table_t *t); -API_EXPORT(const char *) ap_table_get(const ap_table_t *t, const char *key); -API_EXPORT(void) ap_table_set(ap_table_t *t, const char *key, - const char *val); -API_EXPORT(void) ap_table_setn(ap_table_t *t, const char *key, - const char *val); -API_EXPORT(void) ap_table_unset(ap_table_t *t, const char *key); -API_EXPORT(void) ap_table_merge(ap_table_t *t, const char *key, - const char *val); -API_EXPORT(void) ap_table_mergen(ap_table_t *t, const char *key, - const char *val); -API_EXPORT(void) ap_table_add(ap_table_t *t, const char *key, - const char *val); -API_EXPORT(void) ap_table_addn(ap_table_t *t, const char *key, - const char *val); -API_EXPORT(ap_table_t *) ap_overlay_tables(struct ap_pool_t *p, - const ap_table_t *overlay, - const ap_table_t *base); -API_EXPORT(void) - ap_table_do(int (*comp) (void *, const char *, const char *), - void *rec, const ap_table_t *t, ...); -#define AP_OVERLAP_TABLES_SET (0) -#define AP_OVERLAP_TABLES_MERGE (1) -API_EXPORT(void) ap_overlap_tables(ap_table_t *a, const ap_table_t *b, - unsigned flags); -API_EXPORT(void) ap_register_cleanup(struct ap_pool_t *p, void *data, - ap_status_t (*plain_cleanup) (void *), - ap_status_t (*child_cleanup) (void *)); -API_EXPORT(void) ap_kill_cleanup(struct ap_pool_t *p, void *data, - ap_status_t (*cleanup) (void *)); -API_EXPORT(void) ap_run_cleanup(struct ap_pool_t *p, void *data, - ap_status_t (*cleanup) (void *)); -API_EXPORT(void) ap_cleanup_for_exec(void); -API_EXPORT(ap_status_t) ap_getpass(const char *prompt, char *pwbuf, size_t *bufsize); -API_EXPORT_NONSTD(ap_status_t) ap_null_cleanup(void *data); +APR_DECLARE(apr_status_t) apr_password_get(const char *prompt, char *pwbuf, + apr_size_t *bufsize); -API_EXPORT(void) ap_note_subprocess(struct ap_pool_t *a, ap_proc_t *pid, - enum kill_conditions how); -API_EXPORT(int) - ap_spawn_child(ap_pool_t *p, - int (*func) (void *a, ap_child_info_t *c), - void *data, enum kill_conditions kill_how, - FILE **pipe_in, FILE **pipe_out, - FILE **pipe_err); +/** @} */ -API_EXPORT(char *) ap_cpystrn(char *dst, const char *src, size_t dst_size); - -/* - * Routine definitions that only work on Windows. +/** + * @defgroup apr_ctype ctype functions + * These macros allow correct support of 8-bit characters on systems which + * support 8-bit characters. Pretty dumb how the cast is required, but + * that's legacy libc for ya. These new macros do not support EOF like + * the standard macros do. Tough. + * @{ */ - -/*#ifdef TPF*/ -#define ap_block_alarms() -#define ap_unblock_alarms() -/*#else -API_EXPORT(void) ap_block_alarms(void); -API_EXPORT(void) ap_unblock_alarms(void); -#endif */ +/** @see isalnum */ +#define apr_isalnum(c) (isalnum(((unsigned char)(c)))) +/** @see isalpha */ +#define apr_isalpha(c) (isalpha(((unsigned char)(c)))) +/** @see iscntrl */ +#define apr_iscntrl(c) (iscntrl(((unsigned char)(c)))) +/** @see isdigit */ +#define apr_isdigit(c) (isdigit(((unsigned char)(c)))) +/** @see isgraph */ +#define apr_isgraph(c) (isgraph(((unsigned char)(c)))) +/** @see islower*/ +#define apr_islower(c) (islower(((unsigned char)(c)))) +/** @see isascii */ +#if APR_CHARSET_EBCDIC || defined(isascii) +#define apr_isascii(c) (isascii(((unsigned char)(c)))) +#else +#define apr_isascii(c) (((c) & ~0x7f)==0) +#endif +/** @see isprint */ +#define apr_isprint(c) (isprint(((unsigned char)(c)))) +/** @see ispunct */ +#define apr_ispunct(c) (ispunct(((unsigned char)(c)))) +/** @see isspace */ +#define apr_isspace(c) (isspace(((unsigned char)(c)))) +/** @see isupper */ +#define apr_isupper(c) (isupper(((unsigned char)(c)))) +/** @see isxdigit */ +#define apr_isxdigit(c) (isxdigit(((unsigned char)(c)))) +/** @see tolower */ +#define apr_tolower(c) (tolower(((unsigned char)(c)))) +/** @see toupper */ +#define apr_toupper(c) (toupper(((unsigned char)(c)))) + +/** @} */ #ifdef __cplusplus } diff --git a/include/apr_lock.h b/include/apr_lock.h deleted file mode 100644 index b2ebc2382a8..00000000000 --- a/include/apr_lock.h +++ /dev/null @@ -1,197 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#ifndef APR_LOCKS_H -#define APR_LOCKS_H - -#include "apr_general.h" -#include "apr_errno.h" - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -typedef enum {APR_CROSS_PROCESS, APR_INTRAPROCESS, APR_LOCKALL} ap_lockscope_e; - -typedef enum {APR_MUTEX, APR_READWRITE} ap_locktype_e; - -typedef struct ap_lock_t ap_lock_t; - -/* Function definitions */ -/* - -=head1 ap_status_t ap_create_lock(ap_lock_t **lock, ap_locktype_e type, ap_lockscope_e scope, const char *fname, ap_pool_t *cont) - -B<Create a new instance of a lock structure.> - - arg 1) The newly created lock structure. - arg 2) The type of lock to create, one of: - APR_MUTEX - APR_READWRITE - arg 3) The scope of the lock to create, one of: - APR_CROSS_PROCESS -- lock processes from the protected area. - APR_INTRAPROCESS -- lock threads from the protected area. - APR_LOCKALL -- lock processes and threads from the - protected area. - arg 4) A file name to use if the lock mechanism requires one. This - argument should always be provided. The lock code itself will - determine if it should be used. - arg 5) The pool to operate on. - -B<NOTE>: APR_CROSS_PROCESS may lock both processes and threads, but it is - only guaranteed to lock processes. - -=cut - */ -ap_status_t ap_create_lock(ap_lock_t **lock, ap_locktype_e type, - ap_lockscope_e scope, const char *fname, - ap_pool_t *cont); - -/* - -=head1 ap_status_t ap_lock(ap_lock_t *lock) - -B<Lock a protected region.> - - arg 1) The lock to set. - -=cut - */ -ap_status_t ap_lock(ap_lock_t *lock); - -/* - -=head1 ap_status_t ap_unlock(ap_lock_t *lock) - -B<Unlock a protected region.> - - arg 1) The lock to reset. - -=cut - */ -ap_status_t ap_unlock(ap_lock_t *lock); - -/* - -=head1 ap_status_t ap_destroy_lock(ap_lock_t *lock) - -B<Free the memory associated with a lock.> - - arg 1) The lock to free. - -B<NOTE>: If the lock is currently active when it is destroyed, it - will be unlocked first. - -=cut - */ -ap_status_t ap_destroy_lock(ap_lock_t *lock); - -/* - -=head1 ap_status_t ap_child_init_lock(ap_lock_t **lock, const char *fname, ap_pool_t *cont) - -B<Re-open a lock in a child process.> - - arg 1) The newly re-opened lock structure. - arg 2) A file name to use if the lock mechanism requires one. This - argument should always be provided. The lock code itself will - determine if it should be used. This filename should be the same - one that was passed to ap_create_lock - arg 3) The pool to operate on. - -B<NOTE>: This function doesn't always do something, it depends on the - locking mechanism chosen for the platform, but it is a good - idea to call it regardless, because it makes the code more - portable. - -=cut - */ -ap_status_t ap_child_init_lock(ap_lock_t **lock, const char *fname, - ap_pool_t *cont); - -/* - -=head1 ap_status_t ap_get_lockdata(ap_lock_t *lock, char *key, void *data) - -B<Return the pool associated with the current lock.> - - arg 1) The currently open lock. - arg 2) The key to use when retreiving data associated with this lock - arg 3) The user data associated with the lock. - -=cut - */ -ap_status_t ap_get_lockdata(ap_lock_t *lock, char *key, void *data); - -/* - -=head1 ap_status_t ap_set_lockdata(ap_lock_t *lock, void *data, char *key, ap_status_t (*cleanup) (void *)) - -B<Return the pool associated with the current lock.> - - arg 1) The currently open lock. - arg 2) The user data to associate with the lock. - arg 3) The key to use when associating data with this lock - arg 4) The cleanup to use when the lock is destroyed. - -=cut - */ -ap_status_t ap_set_lockdata(ap_lock_t *lock, void *data, char *key, - ap_status_t (*cleanup) (void *)); - -#ifdef __cplusplus -} -#endif - -#endif /* ! APR_LOCKS_H */ diff --git a/include/apr_md4.h b/include/apr_md4.h new file mode 100644 index 00000000000..e1336d6686b --- /dev/null +++ b/include/apr_md4.h @@ -0,0 +1,135 @@ +/* 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. + */ +/* This is derived from material copyright RSA Data Security, Inc. + * Their notice is reproduced below in its entirety. + * + * Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All + * rights reserved. + * + * License to copy and use this software is granted provided that it + * is identified as the "RSA Data Security, Inc. MD4 Message-Digest + * Algorithm" in all material mentioning or referencing this software + * or this function. + * + * License is also granted to make and use derivative works provided + * that such works are identified as "derived from the RSA Data + * Security, Inc. MD4 Message-Digest Algorithm" in all material + * mentioning or referencing the derived work. + * + * RSA Data Security, Inc. makes no representations concerning either + * the merchantability of this software or the suitability of this + * software for any particular purpose. It is provided "as is" + * without express or implied warranty of any kind. + * + * These notices must be retained in any copies of any part of this + * documentation and/or software. + */ + +#ifndef APR_MD4_H +#define APR_MD4_H + +#include "apu.h" +#include "apr_xlate.h" +/** + * @file apr_md4.h + * @brief APR-UTIL MD4 Library + */ +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup APR_Util_MD4 MD4 Library + * @ingroup APR + * @{ + */ + +/** The digestsize for MD4 */ +#define APR_MD4_DIGESTSIZE 16 + +/** @see apr_md4_ctx_t */ +typedef struct apr_md4_ctx_t apr_md4_ctx_t; + +/** MD4 context. */ +struct apr_md4_ctx_t { + /** state (ABCD) */ + apr_uint32_t state[4]; + /** number of bits, modulo 2^64 (lsb first) */ + apr_uint32_t count[2]; + /** input buffer */ + unsigned char buffer[64]; +#if APR_HAS_XLATE + /** translation handle */ + apr_xlate_t *xlate; +#endif +}; + +/** + * MD4 Initialize. Begins an MD4 operation, writing a new context. + * @param context The MD4 context to initialize. + */ +APR_DECLARE(apr_status_t) apr_md4_init(apr_md4_ctx_t *context); + +#if APR_HAS_XLATE +/** + * MDr4 translation setup. Provides the APR translation handle to be used + * for translating the content before calculating the digest. + * @param context The MD4 content to set the translation for. + * @param xlate The translation handle to use for this MD4 context + */ +APR_DECLARE(apr_status_t) apr_md4_set_xlate(apr_md4_ctx_t *context, + apr_xlate_t *xlate); +#else +#define apr_md4_set_xlate(context, xlate) APR_ENOTIMPL +#endif + +/** + * MD4 block update operation. Continue an MD4 message-digest operation, + * processing another message block, and updating the context. + * @param context The MD4 content to update. + * @param input next message block to update + * @param inputLen The length of the next message block + */ +APR_DECLARE(apr_status_t) apr_md4_update(apr_md4_ctx_t *context, + const unsigned char *input, + apr_size_t inputLen); + +/** + * MD4 finalization. Ends an MD4 message-digest operation, writing the + * message digest and zeroing the context + * @param digest The final MD4 digest + * @param context The MD4 content we are finalizing. + */ +APR_DECLARE(apr_status_t) apr_md4_final( + unsigned char digest[APR_MD4_DIGESTSIZE], + apr_md4_ctx_t *context); + +/** + * MD4 digest computation + * @param digest The MD4 digest + * @param input message block to use + * @param inputLen The length of the message block + */ +APR_DECLARE(apr_status_t) apr_md4(unsigned char digest[APR_MD4_DIGESTSIZE], + const unsigned char *input, + apr_size_t inputLen); + +/** @} */ +#ifdef __cplusplus +} +#endif + +#endif /* !APR_MD4_H */ diff --git a/include/apr_md5.h b/include/apr_md5.h index 8f2506bc4bb..1e5ba359ec5 100644 --- a/include/apr_md5.h +++ b/include/apr_md5.h @@ -28,92 +28,149 @@ documentation and/or software. */ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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. */ -#ifndef APACHE_MD5_H -#define APACHE_MD5_H +#ifndef APR_MD5_H +#define APR_MD5_H -#include "apr_lib.h" +#include "apu.h" +#include "apr_xlate.h" #ifdef __cplusplus extern "C" { #endif +/** + * @file apr_md5.h + * @brief APR MD5 Routines + */ + +/** + * @defgroup APR_MD5 MD5 Routines + * @ingroup APR + * @{ + */ + +/** The MD5 digest size */ +#define APR_MD5_DIGESTSIZE 16 + +/** @see apr_md5_ctx_t */ +typedef struct apr_md5_ctx_t apr_md5_ctx_t; + +/** MD5 context. */ +struct apr_md5_ctx_t { + /** state (ABCD) */ + apr_uint32_t state[4]; + /** number of bits, modulo 2^64 (lsb first) */ + apr_uint32_t count[2]; + /** input buffer */ + unsigned char buffer[64]; + /** translation handle + * ignored if xlate is unsupported + */ + apr_xlate_t *xlate; +}; -#define MD5_DIGESTSIZE 16 +/** + * MD5 Initialize. Begins an MD5 operation, writing a new context. + * @param context The MD5 context to initialize. + */ +APR_DECLARE(apr_status_t) apr_md5_init(apr_md5_ctx_t *context); + +/** + * MD5 translation setup. Provides the APR translation handle to be used + * for translating the content before calculating the digest. + * @param context The MD5 content to set the translation for. + * @param xlate The translation handle to use for this MD5 context + */ +APR_DECLARE(apr_status_t) apr_md5_set_xlate(apr_md5_ctx_t *context, + apr_xlate_t *xlate); -/* UINT4 defines a four byte word */ -typedef unsigned int UINT4; +/** + * MD5 block update operation. Continue an MD5 message-digest operation, + * processing another message block, and updating the context. + * @param context The MD5 content to update. + * @param input next message block to update + * @param inputLen The length of the next message block + */ +APR_DECLARE(apr_status_t) apr_md5_update(apr_md5_ctx_t *context, + const void *input, + apr_size_t inputLen); -/* MD5 context. */ -typedef struct { - UINT4 state[4]; /* state (ABCD) */ - UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */ - unsigned char buffer[64]; /* input buffer */ -} ap_md5_ctx_t; +/** + * MD5 finalization. Ends an MD5 message-digest operation, writing the + * message digest and zeroing the context + * @param digest The final MD5 digest + * @param context The MD5 content we are finalizing. + */ +APR_DECLARE(apr_status_t) apr_md5_final(unsigned char digest[APR_MD5_DIGESTSIZE], + apr_md5_ctx_t *context); + +/** + * MD5 in one step + * @param digest The final MD5 digest + * @param input The message block to use + * @param inputLen The length of the message block + */ +APR_DECLARE(apr_status_t) apr_md5(unsigned char digest[APR_MD5_DIGESTSIZE], + const void *input, + apr_size_t inputLen); + +/** + * Encode a password using an MD5 algorithm + * @param pw The password to encode + * @param salt The salt string to use for the encoding + * @param result The string to store the encoded password in + * @param nbytes The size of the result buffer + */ +APR_DECLARE(apr_status_t) apr_md5_encode(const char *pw, const char *salt, + char *result, apr_size_t nbytes); + +/** + * Encode a password using the bcrypt algorithm + * @param pw The password to encode + * @param count The cost of the encoding, possible values are 4 to 31 + * @param salt Pointer to binary data to be used as salt for the encoding + * @param salt_len The size of the salt data (must be >= 16) + * @param out The string to store the encoded password in + * @param out_len The size of the result buffer (must be >= 61) + */ +APR_DECLARE(apr_status_t) apr_bcrypt_encode(const char *pw, + unsigned int count, + const unsigned char *salt, + apr_size_t salt_len, + char *out, apr_size_t out_len); + +/** + * Validate hashes created by APR-supported algorithms: md5, bcrypt, and sha1. + * hashes created by crypt are supported only on platforms that provide + * crypt(3), so don't rely on that function unless you know that your + * application will be run only on platforms that support it. On platforms + * that don't support crypt(3), this falls back to a clear text string + * comparison. + * @param passwd The password to validate + * @param hash The password to validate against + */ +APR_DECLARE(apr_status_t) apr_password_validate(const char *passwd, + const char *hash); -API_EXPORT(ap_status_t) ap_MD5Init(ap_md5_ctx_t *context); -API_EXPORT(ap_status_t) ap_MD5Update(ap_md5_ctx_t *context, - const unsigned char *input, - unsigned int inputLen); -API_EXPORT(ap_status_t) ap_MD5Final(unsigned char digest[MD5_DIGESTSIZE], - ap_md5_ctx_t *context); -API_EXPORT(ap_status_t) ap_MD5Encode(const char *password, const char *salt, - char *result, size_t nbytes); +/** @} */ #ifdef __cplusplus } #endif -#endif /* !APACHE_MD5_H */ +#endif /* !APR_MD5_H */ diff --git a/include/apr_memcache.h b/include/apr_memcache.h new file mode 100644 index 00000000000..2a3bcaab88b --- /dev/null +++ b/include/apr_memcache.h @@ -0,0 +1,444 @@ +/* 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. + */ + +#ifndef APR_MEMCACHE_H +#define APR_MEMCACHE_H + +/** + * @file apr_memcache.h + * @brief Client interface for memcached + * @remark To use this interface you must have a separate memcached + * server running. See the memcached website at http://www.danga.com/memcached/ + * for more information. + */ + +#include "apr.h" +#include "apr_pools.h" +#include "apr_time.h" +#include "apr_strings.h" +#include "apr_network_io.h" +#include "apr_buckets.h" +#include "apr_ring.h" +#include "apr_reslist.h" +#include "apr_hash.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup APR_Util_MC Memcached Client Routines + * @ingroup APR + * @{ + */ + +/** Specifies the status of a memcached server */ +typedef enum +{ + APR_MC_SERVER_LIVE, /**< Server is alive and responding to requests */ + APR_MC_SERVER_DEAD /**< Server is not responding to requests */ +} apr_memcache_server_status_t; + +/** Opaque memcache client connection object */ +typedef struct apr_memcache_conn_t apr_memcache_conn_t; + +/** Memcache Server Info Object */ +typedef struct apr_memcache_server_t apr_memcache_server_t; +struct apr_memcache_server_t +{ + const char *host; /**< Hostname of this Server */ + apr_port_t port; /**< Port of this Server */ + apr_memcache_server_status_t status; /**< @see apr_memcache_server_status_t */ +#if APR_HAS_THREADS || defined(DOXYGEN) + apr_reslist_t *conns; /**< Resource list of actual client connections */ +#else + apr_memcache_conn_t *conn; +#endif + apr_pool_t *p; /** Pool to use for private allocations */ +#if APR_HAS_THREADS + apr_thread_mutex_t *lock; +#endif + apr_time_t btime; +}; + +/* Custom hash callback function prototype, user for server selection. +* @param baton user selected baton +* @param data data to hash +* @param data_len length of data +*/ +typedef apr_uint32_t (*apr_memcache_hash_func)(void *baton, + const char *data, + const apr_size_t data_len); + +typedef struct apr_memcache_t apr_memcache_t; + +/* Custom Server Select callback function prototype. +* @param baton user selected baton +* @param mc memcache instance, use mc->live_servers to select a node +* @param hash hash of the selected key. +*/ +typedef apr_memcache_server_t* (*apr_memcache_server_func)(void *baton, + apr_memcache_t *mc, + const apr_uint32_t hash); + +/** Container for a set of memcached servers */ +struct apr_memcache_t +{ + apr_uint32_t flags; /**< Flags, Not currently used */ + apr_uint16_t nalloc; /**< Number of Servers Allocated */ + apr_uint16_t ntotal; /**< Number of Servers Added */ + apr_memcache_server_t **live_servers; /**< Array of Servers */ + apr_pool_t *p; /** Pool to use for allocations */ + void *hash_baton; + apr_memcache_hash_func hash_func; + void *server_baton; + apr_memcache_server_func server_func; +}; + +/** Returned Data from a multiple get */ +typedef struct +{ + apr_status_t status; + const char* key; + apr_size_t len; + char *data; + apr_uint16_t flags; +} apr_memcache_value_t; + +/** + * Creates a crc32 hash used to split keys between servers + * @param mc The memcache client object to use + * @param data Data to be hashed + * @param data_len Length of the data to use + * @return crc32 hash of data + * @remark The crc32 hash is not compatible with old memcached clients. + */ +APR_DECLARE(apr_uint32_t) apr_memcache_hash(apr_memcache_t *mc, + const char *data, + const apr_size_t data_len); + +/** + * Pure CRC32 Hash. Used by some clients. + */ +APR_DECLARE(apr_uint32_t) apr_memcache_hash_crc32(void *baton, + const char *data, + const apr_size_t data_len); + +/** + * hash compatible with the standard Perl Client. + */ +APR_DECLARE(apr_uint32_t) apr_memcache_hash_default(void *baton, + const char *data, + const apr_size_t data_len); + +/** + * Picks a server based on a hash + * @param mc The memcache client object to use + * @param hash Hashed value of a Key + * @return server that controls specified hash + * @see apr_memcache_hash + */ +APR_DECLARE(apr_memcache_server_t *) apr_memcache_find_server_hash(apr_memcache_t *mc, + const apr_uint32_t hash); + +/** + * server selection compatible with the standard Perl Client. + */ +APR_DECLARE(apr_memcache_server_t *) +apr_memcache_find_server_hash_default(void *baton, + apr_memcache_t *mc, + const apr_uint32_t hash); + +/** + * Adds a server to a client object + * @param mc The memcache client object to use + * @param server Server to add + * @remark Adding servers is not thread safe, and should be done once at startup. + * @warning Changing servers after startup may cause keys to go to + * different servers. + */ +APR_DECLARE(apr_status_t) apr_memcache_add_server(apr_memcache_t *mc, + apr_memcache_server_t *server); + + +/** + * Finds a Server object based on a hostname/port pair + * @param mc The memcache client object to use + * @param host Hostname of the server + * @param port Port of the server + * @return Server with matching Hostname and Port, or NULL if none was found. + */ +APR_DECLARE(apr_memcache_server_t *) apr_memcache_find_server(apr_memcache_t *mc, + const char *host, + apr_port_t port); + +/** + * Enables a Server for use again + * @param mc The memcache client object to use + * @param ms Server to Activate + */ +APR_DECLARE(apr_status_t) apr_memcache_enable_server(apr_memcache_t *mc, + apr_memcache_server_t *ms); + + +/** + * Disable a Server + * @param mc The memcache client object to use + * @param ms Server to Disable + */ +APR_DECLARE(apr_status_t) apr_memcache_disable_server(apr_memcache_t *mc, + apr_memcache_server_t *ms); + +/** + * Creates a new Server Object + * @param p Pool to use + * @param host hostname of the server + * @param port port of the server + * @param min minimum number of client sockets to open + * @param smax soft maximum number of client connections to open + * @param max hard maximum number of client connections + * @param ttl time to live in microseconds of a client connection + * @param ns location of the new server object + * @see apr_reslist_create + * @remark min, smax, and max are only used when APR_HAS_THREADS + */ +APR_DECLARE(apr_status_t) apr_memcache_server_create(apr_pool_t *p, + const char *host, + apr_port_t port, + apr_uint32_t min, + apr_uint32_t smax, + apr_uint32_t max, + apr_uint32_t ttl, + apr_memcache_server_t **ns); +/** + * Creates a new memcached client object + * @param p Pool to use + * @param max_servers maximum number of servers + * @param flags Not currently used + * @param mc location of the new memcache client object + */ +APR_DECLARE(apr_status_t) apr_memcache_create(apr_pool_t *p, + apr_uint16_t max_servers, + apr_uint32_t flags, + apr_memcache_t **mc); + +/** + * Gets a value from the server, allocating the value out of p + * @param mc client to use + * @param p Pool to use + * @param key null terminated string containing the key + * @param baton location of the allocated value + * @param len length of data at baton + * @param flags any flags set by the client for this key + * @return + */ +APR_DECLARE(apr_status_t) apr_memcache_getp(apr_memcache_t *mc, + apr_pool_t *p, + const char* key, + char **baton, + apr_size_t *len, + apr_uint16_t *flags); + + +/** + * Add a key to a hash for a multiget query + * if the hash (*value) is NULL it will be created + * @param data_pool pool from where the hash and their items are created from + * @param key null terminated string containing the key + * @param values hash of keys and values that this key will be added to + * @return + */ +APR_DECLARE(void) apr_memcache_add_multget_key(apr_pool_t *data_pool, + const char* key, + apr_hash_t **values); + +/** + * Gets multiple values from the server, allocating the values out of p + * @param mc client to use + * @param temp_pool Pool used for temporary allocations. May be cleared inside this + * call. + * @param data_pool Pool used to allocate data for the returned values. + * @param values hash of apr_memcache_value_t keyed by strings, contains the + * result of the multiget call. + * @return + */ +APR_DECLARE(apr_status_t) apr_memcache_multgetp(apr_memcache_t *mc, + apr_pool_t *temp_pool, + apr_pool_t *data_pool, + apr_hash_t *values); + +/** + * Sets a value by key on the server + * @param mc client to use + * @param key null terminated string containing the key + * @param baton data to store on the server + * @param data_size length of data at baton + * @param timeout time in seconds for the data to live on the server + * @param flags any flags set by the client for this key + */ +APR_DECLARE(apr_status_t) apr_memcache_set(apr_memcache_t *mc, + const char *key, + char *baton, + const apr_size_t data_size, + apr_uint32_t timeout, + apr_uint16_t flags); + +/** + * Adds value by key on the server + * @param mc client to use + * @param key null terminated string containing the key + * @param baton data to store on the server + * @param data_size length of data at baton + * @param timeout time for the data to live on the server + * @param flags any flags set by the client for this key + * @return APR_SUCCESS if the key was added, APR_EEXIST if the key + * already exists on the server. + */ +APR_DECLARE(apr_status_t) apr_memcache_add(apr_memcache_t *mc, + const char *key, + char *baton, + const apr_size_t data_size, + apr_uint32_t timeout, + apr_uint16_t flags); + +/** + * Replaces value by key on the server + * @param mc client to use + * @param key null terminated string containing the key + * @param baton data to store on the server + * @param data_size length of data at baton + * @param timeout time for the data to live on the server + * @param flags any flags set by the client for this key + * @return APR_SUCCESS if the key was added, APR_EEXIST if the key + * did not exist on the server. + */ +APR_DECLARE(apr_status_t) apr_memcache_replace(apr_memcache_t *mc, + const char *key, + char *baton, + const apr_size_t data_size, + apr_uint32_t timeout, + apr_uint16_t flags); +/** + * Deletes a key from a server + * @param mc client to use + * @param key null terminated string containing the key + * @param timeout time for the delete to stop other clients from adding + */ +APR_DECLARE(apr_status_t) apr_memcache_delete(apr_memcache_t *mc, + const char *key, + apr_uint32_t timeout); + +/** + * Increments a value + * @param mc client to use + * @param key null terminated string containing the key + * @param n number to increment by + * @param nv new value after incrementing + */ +APR_DECLARE(apr_status_t) apr_memcache_incr(apr_memcache_t *mc, + const char *key, + apr_int32_t n, + apr_uint32_t *nv); + +/** + * Decrements a value + * @param mc client to use + * @param key null terminated string containing the key + * @param n number to decrement by + * @param new_value new value after decrementing + */ +APR_DECLARE(apr_status_t) apr_memcache_decr(apr_memcache_t *mc, + const char *key, + apr_int32_t n, + apr_uint32_t *new_value); + +/** + * Query a server's version + * @param ms server to query + * @param p Pool to allocate answer from + * @param baton location to store server version string + */ +APR_DECLARE(apr_status_t) apr_memcache_version(apr_memcache_server_t *ms, + apr_pool_t *p, + char **baton); + +typedef struct +{ + /** Version string of this server */ + const char *version; + /** Process id of this server process */ + apr_uint32_t pid; + /** Number of seconds this server has been running */ + apr_uint32_t uptime; + /** current UNIX time according to the server */ + apr_time_t time; + /** The size of a pointer on the current machine */ + apr_uint32_t pointer_size; + /** Accumulated user time for this process */ + apr_time_t rusage_user; + /** Accumulated system time for this process */ + apr_time_t rusage_system; + /** Current number of items stored by the server */ + apr_uint32_t curr_items; + /** Total number of items stored by this server */ + apr_uint32_t total_items; + /** Current number of bytes used by this server to store items */ + apr_uint64_t bytes; + /** Number of open connections */ + apr_uint32_t curr_connections; + /** Total number of connections opened since the server started running */ + apr_uint32_t total_connections; + /** Number of connection structures allocated by the server */ + apr_uint32_t connection_structures; + /** Cumulative number of retrieval requests */ + apr_uint32_t cmd_get; + /** Cumulative number of storage requests */ + apr_uint32_t cmd_set; + /** Number of keys that have been requested and found present */ + apr_uint32_t get_hits; + /** Number of items that have been requested and not found */ + apr_uint32_t get_misses; + /** Number of items removed from cache because they passed their + expiration time */ + apr_uint64_t evictions; + /** Total number of bytes read by this server */ + apr_uint64_t bytes_read; + /** Total number of bytes sent by this server */ + apr_uint64_t bytes_written; + /** Number of bytes this server is allowed to use for storage. */ + apr_uint32_t limit_maxbytes; + /** Number of threads the server is running (if built with threading) */ + apr_uint32_t threads; +} apr_memcache_stats_t; + +/** + * Query a server for statistics + * @param ms server to query + * @param p Pool to allocate answer from + * @param stats location of the new statistics structure + */ +APR_DECLARE(apr_status_t) apr_memcache_stats(apr_memcache_server_t *ms, + apr_pool_t *p, + apr_memcache_stats_t **stats); + + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* APR_MEMCACHE_H */ diff --git a/include/apr_mmap.h b/include/apr_mmap.h index 598b0e3f964..c14de1928ae 100644 --- a/include/apr_mmap.h +++ b/include/apr_mmap.h @@ -1,121 +1,171 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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. */ #ifndef APR_MMAP_H #define APR_MMAP_H -#include "apr_general.h" +/** + * @file apr_mmap.h + * @brief APR MMAP routines + */ + +#include "apr.h" +#include "apr_pools.h" #include "apr_errno.h" -#include "apr_network_io.h" -#include "apr_portable.h" +#include "apr_ring.h" +#include "apr_file_io.h" /* for apr_file_t */ + +#ifdef BEOS +#include <kernel/OS.h> +#endif #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ - -typedef struct ap_mmap_t ap_mmap_t; - -/* Function definitions */ - -/* - -=head1 ap_status_t ap_mmap_create(ap_mmap_t **new, ap_file_t *file, ap_off_t offset) - -B<Create a new mmap'ed file out of an existing APR file.> - - arg 1) The newly created mmap'ed file. - arg 2) The file turn into an mmap. - arg 3) The offset into the file to start the data pointer at. - arg 4) The size of the file - arg 5) The pool to use when creating the mmap. - -=cut +/** + * @defgroup apr_mmap MMAP (Memory Map) Routines + * @ingroup APR + * @{ */ -ap_status_t ap_mmap_create(ap_mmap_t ** newmmap, ap_file_t *file, ap_off_t offset, - ap_size_t size, ap_pool_t *cntxt); -/* - -=head1 ap_status_t ap_mmap_delete(ap_mmap_t *mmap) +/** MMap opened for reading */ +#define APR_MMAP_READ 1 +/** MMap opened for writing */ +#define APR_MMAP_WRITE 2 + +/** @see apr_mmap_t */ +typedef struct apr_mmap_t apr_mmap_t; + +/** + * @remark + * As far as I can tell the only really sane way to store an MMAP is as a + * void * and a length. BeOS requires this area_id, but that's just a little + * something extra. I am exposing this type, because it doesn't make much + * sense to keep it private, and opening it up makes some stuff easier in + * Apache. + */ +/** The MMAP structure */ +struct apr_mmap_t { + /** The pool the mmap structure was allocated out of. */ + apr_pool_t *cntxt; +#ifdef BEOS + /** An area ID. Only valid on BeOS */ + area_id area; +#endif +#ifdef WIN32 + /** The handle of the file mapping */ + HANDLE mhandle; + /** The start of the real memory page area (mapped view) */ + void *mv; + /** The physical start, size and offset */ + apr_off_t pstart; + apr_size_t psize; + apr_off_t poffset; +#endif + /** The start of the memory mapped area */ + void *mm; + /** The amount of data in the mmap */ + apr_size_t size; + /** ring of apr_mmap_t's that reference the same + * mmap'ed region; acts in place of a reference count */ + APR_RING_ENTRY(apr_mmap_t) link; +}; + +#if APR_HAS_MMAP || defined(DOXYGEN) + +/** @def APR_MMAP_THRESHOLD + * Files have to be at least this big before they're mmap()d. This is to deal + * with systems where the expense of doing an mmap() and an munmap() outweighs + * the benefit for small files. It shouldn't be set lower than 1. + */ +#ifdef MMAP_THRESHOLD +# define APR_MMAP_THRESHOLD MMAP_THRESHOLD +#else +# ifdef SUNOS4 +# define APR_MMAP_THRESHOLD (8*1024) +# else +# define APR_MMAP_THRESHOLD 1 +# endif /* SUNOS4 */ +#endif /* MMAP_THRESHOLD */ + +/** @def APR_MMAP_LIMIT + * Maximum size of MMap region + */ +#ifdef MMAP_LIMIT +# define APR_MMAP_LIMIT MMAP_LIMIT +#else +# define APR_MMAP_LIMIT (4*1024*1024) +#endif /* MMAP_LIMIT */ -B<Remove a mmap'ed.> +/** Can this file be MMaped */ +#define APR_MMAP_CANDIDATE(filelength) \ + ((filelength >= APR_MMAP_THRESHOLD) && (filelength < APR_MMAP_LIMIT)) - arg 1) The mmap'ed file. +/* Function definitions */ -=cut +/** + * Create a new mmap'ed file out of an existing APR file. + * @param newmmap The newly created mmap'ed file. + * @param file The file to turn into an mmap. + * @param offset The offset into the file to start the data pointer at. + * @param size The size of the file + * @param flag bit-wise or of: + * <PRE> + * APR_MMAP_READ MMap opened for reading + * APR_MMAP_WRITE MMap opened for writing + * </PRE> + * @param cntxt The pool to use when creating the mmap. */ -ap_status_t ap_mmap_delete(ap_mmap_t *mmap); - -/* - -=head1 ap_status_t ap_mmap_offset(void **addr, ap_mmap_t *mmap, ap_offset_t offset) +APR_DECLARE(apr_status_t) apr_mmap_create(apr_mmap_t **newmmap, + apr_file_t *file, apr_off_t offset, + apr_size_t size, apr_int32_t flag, + apr_pool_t *cntxt); + +/** + * Duplicate the specified MMAP. + * @param new_mmap The structure to duplicate into. + * @param old_mmap The mmap to duplicate. + * @param p The pool to use for new_mmap. + */ +APR_DECLARE(apr_status_t) apr_mmap_dup(apr_mmap_t **new_mmap, + apr_mmap_t *old_mmap, + apr_pool_t *p); + +/** + * Remove a mmap'ed. + * @param mm The mmap'ed file. + */ +APR_DECLARE(apr_status_t) apr_mmap_delete(apr_mmap_t *mm); -B<Move the pointer into the mmap'ed file to the specified offset.> +/** + * Move the pointer into the mmap'ed file to the specified offset. + * @param addr The pointer to the offset specified. + * @param mm The mmap'ed file. + * @param offset The offset to move to. + */ +APR_DECLARE(apr_status_t) apr_mmap_offset(void **addr, apr_mmap_t *mm, + apr_off_t offset); - arg 1) The pointer to the offset specified. - arg 2) The mmap'ed file. - arg 3) The offset to move to. +#endif /* APR_HAS_MMAP */ -=cut - */ -ap_status_t ap_mmap_offset(void **addr, ap_mmap_t *mmap, ap_off_t offset); +/** @} */ #ifdef __cplusplus } #endif #endif /* ! APR_MMAP_H */ - - diff --git a/include/apr_network_io.h b/include/apr_network_io.h index 8646f939efc..733bf5a1791 100644 --- a/include/apr_network_io.h +++ b/include/apr_network_io.h @@ -1,718 +1,956 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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. */ #ifndef APR_NETWORK_IO_H #define APR_NETWORK_IO_H +/** + * @file apr_network_io.h + * @brief APR Network library + */ -#ifdef WIN32 -#include <winsock2.h> -#endif - -#include "apr_general.h" +#include "apr.h" +#include "apr_pools.h" #include "apr_file_io.h" #include "apr_errno.h" +#include "apr_inherit.h" +#include "apr_perms_set.h" + #if APR_HAVE_NETINET_IN_H #include <netinet/in.h> #endif +#if APR_HAVE_SYS_UN_H +#include <sys/un.h> +#endif #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ -#ifndef MAX_SECS_TO_LINGER -#define MAX_SECS_TO_LINGER 30 +/** + * @defgroup apr_network_io Network Routines + * @ingroup APR + * @{ + */ + +#ifndef APR_MAX_SECS_TO_LINGER +/** Maximum seconds to linger */ +#define APR_MAX_SECS_TO_LINGER 30 #endif #ifndef APRMAXHOSTLEN +/** Maximum hostname length */ #define APRMAXHOSTLEN 256 #endif #ifndef APR_ANYADDR +/** Default 'any' address */ #define APR_ANYADDR "0.0.0.0" #endif -/* Socket option definitions */ -#define APR_SO_LINGER 1 -#define APR_SO_KEEPALIVE 2 -#define APR_SO_DEBUG 4 -#define APR_SO_NONBLOCK 8 -#define APR_SO_REUSEADDR 16 -#define APR_SO_TIMEOUT 32 -#define APR_SO_SNDBUF 64 - -#define APR_POLLIN 0x001 -#define APR_POLLPRI 0x002 -#define APR_POLLOUT 0x004 -#define APR_POLLERR 0x010 -#define APR_POLLHUP 0x020 -#define APR_POLLNVAL 0x040 - -typedef enum {APR_SHUTDOWN_READ, APR_SHUTDOWN_WRITE, - APR_SHUTDOWN_READWRITE} ap_shutdown_how_e; - -/* We need to make sure we always have an in_addr type, so APR will just +/** + * @defgroup apr_sockopt Socket option definitions + * @{ + */ +#define APR_SO_LINGER 1 /**< Linger */ +#define APR_SO_KEEPALIVE 2 /**< Keepalive */ +#define APR_SO_DEBUG 4 /**< Debug */ +#define APR_SO_NONBLOCK 8 /**< Non-blocking IO */ +#define APR_SO_REUSEADDR 16 /**< Reuse addresses */ +#define APR_SO_SNDBUF 64 /**< Send buffer */ +#define APR_SO_RCVBUF 128 /**< Receive buffer */ +#define APR_SO_DISCONNECTED 256 /**< Disconnected */ +#define APR_TCP_NODELAY 512 /**< For SCTP sockets, this is mapped + * to STCP_NODELAY internally. + */ +#define APR_TCP_NOPUSH 1024 /**< No push */ +#define APR_RESET_NODELAY 2048 /**< This flag is ONLY set internally + * when we set APR_TCP_NOPUSH with + * APR_TCP_NODELAY set to tell us that + * APR_TCP_NODELAY should be turned on + * again when NOPUSH is turned off + */ +#define APR_INCOMPLETE_READ 4096 /**< Set on non-blocking sockets + * (timeout != 0) on which the + * previous read() did not fill a buffer + * completely. the next apr_socket_recv() + * will first call select()/poll() rather than + * going straight into read(). (Can also + * be set by an application to force a + * select()/poll() call before the next + * read, in cases where the app expects + * that an immediate read would fail.) + */ +#define APR_INCOMPLETE_WRITE 8192 /**< like APR_INCOMPLETE_READ, but for write + * @see APR_INCOMPLETE_READ + */ +#define APR_IPV6_V6ONLY 16384 /**< Don't accept IPv4 connections on an + * IPv6 listening socket. + */ +#define APR_TCP_DEFER_ACCEPT 32768 /**< Delay accepting of new connections + * until data is available. + * @see apr_socket_accept_filter + */ +#define APR_SO_BROADCAST 65536 /**< Allow broadcast + */ +#define APR_SO_FREEBIND 131072 /**< Allow binding to addresses not owned + * by any interface + */ + +/** @} */ + +/** Define what type of socket shutdown should occur. */ +typedef enum { + APR_SHUTDOWN_READ, /**< no longer allow read request */ + APR_SHUTDOWN_WRITE, /**< no longer allow write requests */ + APR_SHUTDOWN_READWRITE /**< no longer allow read or write requests */ +} apr_shutdown_how_e; + +#define APR_IPV4_ADDR_OK 0x01 /**< @see apr_sockaddr_info_get() */ +#define APR_IPV6_ADDR_OK 0x02 /**< @see apr_sockaddr_info_get() */ + +#if (!APR_HAVE_IN_ADDR) +/** + * We need to make sure we always have an in_addr type, so APR will just * define it ourselves, if the platform doesn't provide it. */ -#if !defined(APR_HAVE_IN_ADDR) struct in_addr { - ap_uint32_t s_addr; -} -#endif - -/* I guess not everybody uses inet_addr. This defines ap_inet_addr - * appropriately. - */ - -#if APR_HAVE_INET_ADDR -#define ap_inet_addr inet_addr -#elif APR_HAVE_INET_NETWORK /* only DGUX, as far as I know */ -#define ap_inet_addr inet_network -#endif - -typedef struct ap_socket_t ap_socket_t; -typedef struct ap_pollfd_t ap_pollfd_t; -typedef struct ap_hdtr_t ap_hdtr_t; -typedef struct in_addr ap_in_addr; - -#if APR_HAS_SENDFILE -/* A structure to encapsulate headers and trailers for ap_sendfile */ -struct ap_hdtr_t { - struct iovec* headers; - int numheaders; - struct iovec* trailers; - int numtrailers; + apr_uint32_t s_addr; /**< storage to hold the IP# */ }; #endif -/* function definitions */ - -/* - -=head1 ap_status_t ap_create_tcp_socket(ap_socket_t **new, ap_pool_t *cont) - -B<Create a socket for tcp communication.> - - arg 1) The new socket that has been setup. - arg 2) The pool to use - -=cut - */ -ap_status_t ap_create_tcp_socket(ap_socket_t **new, ap_pool_t *cont); - -/* - -=head1 ap_status_t ap_shutdown(ap_socket_t *thesocket, ap_shutdown_how_e how) - -B<Shutdown either reading, writing, or both sides of a tcp socket.> - - arg 1) The socket to close - arg 2) How to shutdown the socket. One of: - APR_SHUTDOWN_READ -- no longer allow read requests - APR_SHUTDOWN_WRITE -- no longer allow write requests - APR_SHUTDOWN_READWRITE -- no longer allow read or write requests - -B<NOTE>: This does not actually close the socket descriptor, it just - controls which calls are still valid on the socket. - -=cut - */ -ap_status_t ap_shutdown(ap_socket_t *ithesocket, ap_shutdown_how_e how); - -/* - -=head1 ap_status_t ap_close_socket(ap_socket_t *thesocket) - -B<Close a tcp socket.> - - arg 1) The socket to close - -=cut +/** @def APR_INADDR_NONE + * Not all platforms have a real INADDR_NONE. This macro replaces + * INADDR_NONE on all platforms. */ -ap_status_t ap_close_socket(ap_socket_t *thesocket); - -/* - -=head1 ap_status_t ap_bind(ap_socket_t *sock) - -B<Bind the socket to it's assocaited port> - - arg 1) The socket to bind - -B<NOTE>: This is where we will find out if there is any other process - using the selected port. - -=cut - */ -ap_status_t ap_bind(ap_socket_t *sock); - -/* - -=head1 ap_status_t ap_listen(ap_socket_t *sock, ap_int32_t backlog) - -B<Listen to a bound socketi for connections.> - - arg 1) The socket to listen on - arg 2) The number of outstanding connections allowed in the sockets - listen queue. If this value is less than zero, the listen - queue size is set to zero. - -=cut - */ -ap_status_t ap_listen(ap_socket_t *sock, ap_int32_t backlog); - -/* - -=head1 ap_status_t ap_accept(ap_socket_t **new, ap_socket_t *sock, ap_pool_t *connection_pool) - -B<Accept a new connection request> - - arg 1) A copy of the socket that is connected to the socket that - made the connection request. This is the socket which should - be used for all future communication. - arg 2) The socket we are listening on. - arg 3) The pool for the new socket. +#ifdef INADDR_NONE +#define APR_INADDR_NONE INADDR_NONE +#else +#define APR_INADDR_NONE ((unsigned int) 0xffffffff) +#endif -=cut +/** + * @def APR_INET + * Not all platforms have these defined, so we'll define them here + * The default values come from FreeBSD 4.1.1 */ -ap_status_t ap_accept(ap_socket_t **new, const ap_socket_t *sock, - ap_pool_t *connection_pool); - -/* - -=head1 ap_status_t ap_connect(ap_socket_t *sock, char *hostname) - -B<Issue a connection request to a socket either on the same machine or a different one.> - - arg 1) The socket we wish to use for our side of the connection - arg 2) The hostname of the machine we wish to connect to. If NULL, - APR assumes that the sockaddr_in in the apr_socket is completely - filled out. - -=cut +#define APR_INET AF_INET +/** @def APR_UNSPEC + * Let the system decide which address family to use */ -ap_status_t ap_connect(ap_socket_t *sock, char *hostname); - -/* - -=head1 ap_status_t ap_get_remote_hostname(char **name, ap_socket_t *sock) +#ifdef AF_UNSPEC +#define APR_UNSPEC AF_UNSPEC +#else +#define APR_UNSPEC 0 +#endif +#if APR_HAVE_IPV6 +/** @def APR_INET6 +* IPv6 Address Family. Not all platforms may have this defined. +*/ -B<Get name of the machine we are currently connected to.> +#define APR_INET6 AF_INET6 +#endif - arg 1) A buffer to store the hostname in. - arg 2) The socket to examine. +#if APR_HAVE_SOCKADDR_UN +#if defined (AF_UNIX) +#define APR_UNIX AF_UNIX +#elif defined(AF_LOCAL) +#define APR_UNIX AF_LOCAL +#else +#error "Neither AF_UNIX nor AF_LOCAL is defined" +#endif +#else /* !APR_HAVE_SOCKADDR_UN */ +#if defined (AF_UNIX) +#define APR_UNIX AF_UNIX +#elif defined(AF_LOCAL) +#define APR_UNIX AF_LOCAL +#else +/* TODO: Use a smarter way to detect unique APR_UNIX value */ +#define APR_UNIX 1234 +#endif +#endif -=cut +/** + * @defgroup IP_Proto IP Protocol Definitions for use when creating sockets + * @{ */ -ap_status_t ap_get_remote_hostname(char **name, ap_socket_t *sock); - -/* +#define APR_PROTO_TCP 6 /**< TCP */ +#define APR_PROTO_UDP 17 /**< UDP */ +#define APR_PROTO_SCTP 132 /**< SCTP */ +/** @} */ -=head1 ap_status_t ap_gethostname(char *buf, ap_int32_t len, ap_pool_t *cont) - -B<Get name of the current machine> - - arg 1) A buffer to store the hostname in. - arg 2) The maximum length of the hostname that can be stored in the - buffer provided. - arg 3) The pool to use. - -=cut +/** + * Enum used to denote either the local and remote endpoint of a + * connection. */ -ap_status_t ap_gethostname(char *buf, int len, ap_pool_t *cont); - -/* +typedef enum { + APR_LOCAL, /**< Socket information for local end of connection */ + APR_REMOTE /**< Socket information for remote end of connection */ +} apr_interface_e; -=head1 ap_status_t ap_get_socketdata(void **data, char *key, ap_socket_t *sock) - -B<Return the pool associated with the current socket.> - - arg 1) The currently open socket. - arg 2) The user data associated with the socket. - -=cut +/** + * The specific declaration of inet_addr's ... some platforms fall back + * inet_network (this is not good, but necessary) */ -ap_status_t ap_get_socketdata(void **data, char *key, ap_socket_t *sock); - -/* - -=head1 ap_status_t ap_set_socketdata(ap_socket_t *sock, void *data, char *key, ap_status_t (*cleanup) (void *)) - -B<Set the pool associated with the current socket.> - - arg 1) The currently open socket. - arg 2) The user data to associate with the socket. - arg 3) The key to associate with the data. - arg 4) The cleanup to call when the socket is destroyed. -=cut - */ -ap_status_t ap_set_socketdata(ap_socket_t *sock, void *data, char *key, - ap_status_t (*cleanup) (void*)); - -/* - -=head1 ap_status_t ap_send(ap_socket_t *sock, const char *buf, ap_ssize_t *len) - -B<Send data over a network.> - - arg 1) The socket to send the data over. - arg 2) The buffer which contains the data to be sent. - arg 3) On entry, the number of bytes to send; on exit, the number - of bytes sent. - -B<NOTE>: This functions acts like a blocking write by default. To change - this behavior, use ap_setsocketopt with the APR_SO_TIMEOUT option. - - It is possible for both bytes to be sent and an error to be returned. - - APR_EINTR is never returned. - -=cut - */ -ap_status_t ap_send(ap_socket_t *sock, const char *buf, ap_ssize_t *len); - -/* - -=head1 ap_status_t ap_sendv(ap_socket_t *sock, const struct iovec *vec, ap_int32_t nvec, ap_int32_t *len) - -B<Send multiple packets of data over a network.> - - arg 1) The socket to send the data over. - arg 2) The array of iovec structs containing the data to send - arg 3) The number of iovec structs in the array - arg 4) Receives the number of bytes actually written - -B<NOTE>: This functions acts like a blocking write by default. To change - this behavior, use ap_setsocketopt with the APR_SO_TIMEOUT option. - The number of bytes actually sent is stored in argument 3. - - It is possible for both bytes to be sent and an error to be returned. - - APR_EINTR is never returned. +#if APR_HAVE_INET_ADDR +#define apr_inet_addr inet_addr +#elif APR_HAVE_INET_NETWORK /* only DGUX, as far as I know */ +/** + * @warning + * not generally safe... inet_network() and inet_addr() perform + * different functions */ +#define apr_inet_addr inet_network +#endif -=cut - */ -ap_status_t ap_sendv(ap_socket_t *sock, const struct iovec *vec, - ap_int32_t nvec, ap_int32_t *len); +/** A structure to represent sockets */ +typedef struct apr_socket_t apr_socket_t; +/** + * A structure to encapsulate headers and trailers for apr_socket_sendfile + */ +typedef struct apr_hdtr_t apr_hdtr_t; +/** A structure to represent in_addr */ +typedef struct in_addr apr_in_addr_t; +/** A structure to represent an IP subnet */ +typedef struct apr_ipsubnet_t apr_ipsubnet_t; + +/** @remark use apr_uint16_t just in case some system has a short that isn't 16 bits... */ +typedef apr_uint16_t apr_port_t; + +/** @remark It's defined here as I think it should all be platform safe... + * @see apr_sockaddr_t + */ +typedef struct apr_sockaddr_t apr_sockaddr_t; +/** + * APRs socket address type, used to ensure protocol independence + */ +struct apr_sockaddr_t { + /** The pool to use... */ + apr_pool_t *pool; + /** The hostname */ + char *hostname; + /** Either a string of the port number or the service name for the port */ + char *servname; + /** The numeric port */ + apr_port_t port; + /** The family */ + apr_int32_t family; + /** How big is the sockaddr we're using? */ + apr_socklen_t salen; + /** How big is the ip address structure we're using? */ + int ipaddr_len; + /** How big should the address buffer be? 16 for v4 or 46 for v6 + * used in inet_ntop... */ + int addr_str_len; + /** This points to the IP address structure within the appropriate + * sockaddr structure. */ + void *ipaddr_ptr; + /** If multiple addresses were found by apr_sockaddr_info_get(), this + * points to a representation of the next address. */ + apr_sockaddr_t *next; + /** Union of either IPv4 or IPv6 sockaddr. */ + union { + /** IPv4 sockaddr structure */ + struct sockaddr_in sin; +#if APR_HAVE_IPV6 + /** IPv6 sockaddr structure */ + struct sockaddr_in6 sin6; +#endif +#if APR_HAVE_SA_STORAGE + /** Placeholder to ensure that the size of this union is not + * dependent on whether APR_HAVE_IPV6 is defined. */ + struct sockaddr_storage sas; +#endif +#if APR_HAVE_SOCKADDR_UN + /** Unix domain socket sockaddr structure */ + struct sockaddr_un unx; +#endif + } sa; +}; #if APR_HAS_SENDFILE -/* - -=head1 ap_status_t ap_sendfile(ap_socket_t *sock, ap_file_t *file, ap_hdtr_t *hdtr, ap_off_t *offset, ap_size_t *len, ap_int32_t flags) - -B<Send a file from an open file descriptor to a socket, along with optional headers and trailers> - - arg 1) The socket to which we're writing - arg 2) The open file from which to read - arg 3) A structure containing the headers and trailers to send - arg 4) Offset into the file where we should begin writing - arg 5) Number of bytes to send - arg 6) OS-specific flags to pass to sendfile() - -B<NOTE>: This functions acts like a blocking write by default. To change - this behavior, use ap_setsocketopt with the APR_SO_TIMEOUT option. - The number of bytes actually sent is stored in argument 5. - -=cut +/** + * Support reusing the socket on platforms which support it (from disconnect, + * specifically Win32. + * @remark Optional flag passed into apr_socket_sendfile() */ -ap_status_t ap_sendfile(ap_socket_t *sock, ap_file_t *file, ap_hdtr_t *hdtr, - ap_off_t *offset, ap_size_t *len, ap_int32_t flags); +#define APR_SENDFILE_DISCONNECT_SOCKET 1 #endif -/* - -=head1 ap_status_t ap_recv(ap_socket_t *sock, char *buf, ap_ssize_t *len) - -B<Read data from a network.> - - arg 1) The socket to read the data from. - arg 2) The buffer to store the data in. - arg 3) On entry, the number of bytes to receive; on exit, the number - of bytes received. - -B<NOTE>: This functions acts like a blocking read by default. To change - this behavior, use ap_setsocketopt with the APR_SO_TIMEOUT option. - The number of bytes actually sent is stored in argument 3. - - It is possible for both bytes to be received and an APR_EOF or - other error to be returned. - - APR_EINTR is never returned. - -=cut - */ -ap_status_t ap_recv(ap_socket_t *sock, char *buf, ap_ssize_t *len); - -/* - -=head1 ap_status_t ap_setsocketopt(ap_socket_t *sock, ap_int32_t opt, ap_int32_t on) - -B<Setup socket options for the specified socket> - - arg 1) The socket to set up. - arg 2) The option we would like to configure. One of: - APR_SO_DEBUG -- turn on debugging information - APR_SO_KEEPALIVE -- keep connections active - APR_SO_LINGER -- lingers on close if data is present - APR_SO_NONBLOCK -- Turns blocking on/off for socket - APR_SO_REUSEADDR -- The rules used in validating addresses - supplied to bind should allow reuse - of local addresses. - APR_SO_TIMEOUT -- Set the timeout value in microseconds. - values < 0 mean wait forever. 0 means - don't wait at all. - APR_SO_SNDBUF -- Set the SendBufferSize - arg 3) Are we turning the option on or off. - -=cut - */ -ap_status_t ap_setsocketopt(ap_socket_t *sock, ap_int32_t opt, ap_int32_t on); - -/* - -=head1 ap_status_t ap_set_local_port(ap_socket_t *sock, ap_uint32_t port) - Assocaite a local port with a socket. - - arg 1) The socket to set - arg 2) The local port this socket will be dealing with. - -B<NOTE>: This does not bind the two together, it is just telling apr - that this socket is going to use this port if possible. If - the port is already used, we won't find out about it here. - -=cut - */ -ap_status_t ap_set_local_port(ap_socket_t *sock, ap_uint32_t port); - -/* - -=head1 ap_status_t ap_set_remote_port(ap_socket_t *sock, ap_uint32_t port) - -B<Assocaite a remote port with a socket.> - - arg 1) The socket to enquire about. - arg 2) The local port this socket will be dealing with. - -B<NOTE>: This does not make a connection to the remote port, it is just - telling apr which port ap_connect() should attempt to connect to. - -=cut - */ -ap_status_t ap_set_remote_port(ap_socket_t *sock, ap_uint32_t port); - -/* - -=head1 ap_status_t ap_get_local_port(ap_uint32_t *port, ap_socket_t *sock) - -B<Return the local port with a socket.> - - arg 1) The local port this socket is associated with. - arg 2) The socket to enquire about. - -=cut - */ -ap_status_t ap_get_local_port(ap_uint32_t *port, ap_socket_t *sock); - -/* - -=head1 ap_status_t ap_get_remote_port(ap_uint32_t *port, ap_socket_t *sock) - -B<Return the remote port associated with a socket.> - - arg 1) The remote port this socket is associated with. - arg 2) The socket to enquire about. - -=cut - */ -ap_status_t ap_get_remote_port(ap_uint32_t *port, ap_socket_t *sock); - -/* - -=head1 ap_status_t ap_set_local_ipaddr(ap_socket_t *sock, cont char *addr) - -B<Assocaite a local socket addr with an apr socket.> - - arg 1) The socket to use - arg 2) The IP address to attach to the socket. - Use APR_ANYADDR to use any IP addr on the machine. - -B<NOTE>: This does not bind the two together, it is just telling apr - that this socket is going to use this address if possible. - -=cut - */ -ap_status_t ap_set_local_ipaddr(ap_socket_t *sock, const char *addr); - -/* - -=head1 ap_status_t ap_set_remote_ipaddr(ap_socket_t *sock, cont char *addr) - -B<Assocaite a remote socket addr with an apr socket.> - - arg 1) The socket to use - arg 2) The IP address to attach to the socket. - -B<NOTE>: This does not make a connection to the remote address, it is just - telling apr which address ap_connect() should attempt to connect to. - -=cut - */ -ap_status_t ap_set_remote_ipaddr(ap_socket_t *sock, const char *addr); - -/* - -=head1 ap_status_t ap_get_local_ipaddr(char **addr, const ap_socket_t *sock) - -B<Return the local IP address associated with an apr socket.> +/** A structure to encapsulate headers and trailers for apr_socket_sendfile */ +struct apr_hdtr_t { + /** An iovec to store the headers sent before the file. */ + struct iovec* headers; + /** number of headers in the iovec */ + int numheaders; + /** An iovec to store the trailers sent after the file. */ + struct iovec* trailers; + /** number of trailers in the iovec */ + int numtrailers; +}; - arg 1) The local IP address associated with the socket. - arg 2) The socket to use +/* function definitions */ -=cut +/** + * Create a socket. + * @param new_sock The new socket that has been set up. + * @param family The address family of the socket (e.g., APR_INET). + * @param type The type of the socket (e.g., SOCK_STREAM). + * @param protocol The protocol of the socket (e.g., APR_PROTO_TCP). + * @param cont The pool for the apr_socket_t and associated storage. + * @note The pool will be used by various functions that operate on the + * socket. The caller must ensure that it is not used by other threads + * at the same time. + */ +APR_DECLARE(apr_status_t) apr_socket_create(apr_socket_t **new_sock, + int family, int type, + int protocol, + apr_pool_t *cont); + +/** + * Shutdown either reading, writing, or both sides of a socket. + * @param thesocket The socket to close + * @param how How to shutdown the socket. One of: + * <PRE> + * APR_SHUTDOWN_READ no longer allow read requests + * APR_SHUTDOWN_WRITE no longer allow write requests + * APR_SHUTDOWN_READWRITE no longer allow read or write requests + * </PRE> + * @see apr_shutdown_how_e + * @remark This does not actually close the socket descriptor, it just + * controls which calls are still valid on the socket. + */ +APR_DECLARE(apr_status_t) apr_socket_shutdown(apr_socket_t *thesocket, + apr_shutdown_how_e how); + +/** + * Close a socket. + * @param thesocket The socket to close + */ +APR_DECLARE(apr_status_t) apr_socket_close(apr_socket_t *thesocket); + +/** + * Bind the socket to its associated port + * @param sock The socket to bind + * @param sa The socket address to bind to + * @remark This may be where we will find out if there is any other process + * using the selected port. + */ +APR_DECLARE(apr_status_t) apr_socket_bind(apr_socket_t *sock, + apr_sockaddr_t *sa); + +/** + * Listen to a bound socket for connections. + * @param sock The socket to listen on + * @param backlog The number of outstanding connections allowed in the sockets + * listen queue. If this value is less than zero, the listen + * queue size is set to zero. + */ +APR_DECLARE(apr_status_t) apr_socket_listen(apr_socket_t *sock, + apr_int32_t backlog); + +/** + * Accept a new connection request + * @param new_sock A copy of the socket that is connected to the socket that + * made the connection request. This is the socket which should + * be used for all future communication. + * @param sock The socket we are listening on. + * @param connection_pool The pool for the new socket. + * @note The pool will be used by various functions that operate on the + * socket. The caller must ensure that it is not used by other threads + * at the same time. + */ +APR_DECLARE(apr_status_t) apr_socket_accept(apr_socket_t **new_sock, + apr_socket_t *sock, + apr_pool_t *connection_pool); + +/** + * Issue a connection request to a socket either on the same machine + * or a different one. + * @param sock The socket we wish to use for our side of the connection + * @param sa The address of the machine we wish to connect to. + */ +APR_DECLARE(apr_status_t) apr_socket_connect(apr_socket_t *sock, + apr_sockaddr_t *sa); + +/** + * Determine whether the receive part of the socket has been closed by + * the peer (such that a subsequent call to apr_socket_read would + * return APR_EOF), if the socket's receive buffer is empty. This + * function does not block waiting for I/O. + * + * @param sock The socket to check + * @param atreadeof If APR_SUCCESS is returned, *atreadeof is set to + * non-zero if a subsequent read would return APR_EOF + * @return an error is returned if it was not possible to determine the + * status, in which case *atreadeof is not changed. + */ +APR_DECLARE(apr_status_t) apr_socket_atreadeof(apr_socket_t *sock, + int *atreadeof); + +/** + * Create apr_sockaddr_t from hostname, address family, and port. + * @param sa The new apr_sockaddr_t. + * @param hostname The hostname or numeric address string to resolve/parse, or + * NULL to build an address that corresponds to 0.0.0.0 or :: + * or in case of APR_UNIX family it is absolute socket filename. + * @param family The address family to use, or APR_UNSPEC if the system should + * decide. + * @param port The port number. + * @param flags Special processing flags: + * <PRE> + * APR_IPV4_ADDR_OK first query for IPv4 addresses; only look + * for IPv6 addresses if the first query failed; + * only valid if family is APR_UNSPEC and hostname + * isn't NULL; mutually exclusive with + * APR_IPV6_ADDR_OK + * APR_IPV6_ADDR_OK first query for IPv6 addresses; only look + * for IPv4 addresses if the first query failed; + * only valid if family is APR_UNSPEC and hostname + * isn't NULL and APR_HAVE_IPV6; mutually exclusive + * with APR_IPV4_ADDR_OK + * </PRE> + * @param p The pool for the apr_sockaddr_t and associated storage. + */ +APR_DECLARE(apr_status_t) apr_sockaddr_info_get(apr_sockaddr_t **sa, + const char *hostname, + apr_int32_t family, + apr_port_t port, + apr_int32_t flags, + apr_pool_t *p); + +/** + * Copy apr_sockaddr_t src to dst on pool p. + * @param dst The destination apr_sockaddr_t. + * @param src The source apr_sockaddr_t. + * @param p The pool for the apr_sockaddr_t and associated storage. + */ +APR_DECLARE(apr_status_t) apr_sockaddr_info_copy(apr_sockaddr_t **dst, + const apr_sockaddr_t *src, + apr_pool_t *p); + +/* Set the zone of an IPv6 link-local address object. + * @param sa Socket address object + * @param zone_id Zone ID (textual "eth0" or numeric "3"). + * @return Returns APR_EBADIP for non-IPv6 socket or an IPv6 address + * which isn't link-local. + */ +APR_DECLARE(apr_status_t) apr_sockaddr_zone_set(apr_sockaddr_t *sa, + const char *zone_id); + + +/* Retrieve the zone of an IPv6 link-local address object. + * @param sa Socket address object + * @param name If non-NULL, set to the textual representation of the zone id + * @param id If non-NULL, set to the integer zone id + * @param p Pool from which *name is allocated if used. + * @return Returns APR_EBADIP for non-IPv6 socket or socket without any zone id + * set, or other error if the interface could not be mapped to a name. + * @remark Both name and id may be NULL, neither are modified if + * non-NULL in error cases. + */ +APR_DECLARE(apr_status_t) apr_sockaddr_zone_get(const apr_sockaddr_t *sa, + const char **name, + apr_uint32_t *id, + apr_pool_t *p); + +/** + * Look up the host name from an apr_sockaddr_t. + * @param hostname The hostname. + * @param sa The apr_sockaddr_t. + * @param flags Special processing flags. + * @remark Results can vary significantly between platforms + * when processing wildcard socket addresses. + */ +APR_DECLARE(apr_status_t) apr_getnameinfo(char **hostname, + apr_sockaddr_t *sa, + apr_int32_t flags); + +/** + * Parse hostname/IP address with scope id and port. + * + * Any of the following strings are accepted: + * 8080 (just the port number) + * www.apache.org (just the hostname) + * www.apache.org:8080 (hostname and port number) + * [fe80::1]:80 (IPv6 numeric address string only) + * [fe80::1%eth0] (IPv6 numeric address string and scope id) + * + * Invalid strings: + * (empty string) + * [abc] (not valid IPv6 numeric address string) + * abc:65536 (invalid port number) + * + * @param addr The new buffer containing just the hostname. On output, *addr + * will be NULL if no hostname/IP address was specfied. + * @param scope_id The new buffer containing just the scope id. On output, + * *scope_id will be NULL if no scope id was specified. + * @param port The port number. On output, *port will be 0 if no port was + * specified. + * ### FIXME: 0 is a legal port (per RFC 1700). this should + * ### return something besides zero if the port is missing. + * @param str The input string to be parsed. + * @param p The pool from which *addr and *scope_id are allocated. + * @remark If scope id shouldn't be allowed, check for scope_id != NULL in + * addition to checking the return code. If addr/hostname should be + * required, check for addr == NULL in addition to checking the + * return code. + */ +APR_DECLARE(apr_status_t) apr_parse_addr_port(char **addr, + char **scope_id, + apr_port_t *port, + const char *str, + apr_pool_t *p); + +/** + * Get name of the current machine + * @param buf A buffer to store the hostname in. + * @param len The maximum length of the hostname that can be stored in the + * buffer provided. The suggested length is APRMAXHOSTLEN + 1. + * @param cont The pool to use. + * @remark If the buffer was not large enough, an error will be returned. + */ +APR_DECLARE(apr_status_t) apr_gethostname(char *buf, int len, apr_pool_t *cont); + +/** + * Return the data associated with the current socket + * @param data The user data associated with the socket. + * @param key The key to associate with the user data. + * @param sock The currently open socket. + */ +APR_DECLARE(apr_status_t) apr_socket_data_get(void **data, const char *key, + apr_socket_t *sock); + +/** + * Set the data associated with the current socket. + * @param sock The currently open socket. + * @param data The user data to associate with the socket. + * @param key The key to associate with the data. + * @param cleanup The cleanup to call when the socket is destroyed. + */ +APR_DECLARE(apr_status_t) apr_socket_data_set(apr_socket_t *sock, void *data, + const char *key, + apr_status_t (*cleanup)(void*)); + +/** + * Send data over a network. + * @param sock The socket to send the data over. + * @param buf The buffer which contains the data to be sent. + * @param len On entry, the number of bytes to send; on exit, the number + * of bytes sent. + * @remark + * <PRE> + * This functions acts like a blocking write by default. To change + * this behavior, use apr_socket_timeout_set() or the APR_SO_NONBLOCK + * socket option. + * + * It is possible for both bytes to be sent and an error to be returned. + * + * APR_EINTR is never returned. + * </PRE> + */ +APR_DECLARE(apr_status_t) apr_socket_send(apr_socket_t *sock, const char *buf, + apr_size_t *len); + +/** + * Send multiple buffers over a network. + * @param sock The socket to send the data over. + * @param vec The array of iovec structs containing the data to send + * @param nvec The number of iovec structs in the array + * @param len Receives the number of bytes actually written + * @remark + * <PRE> + * This functions acts like a blocking write by default. To change + * this behavior, use apr_socket_timeout_set() or the APR_SO_NONBLOCK + * socket option. + * The number of bytes actually sent is stored in argument 4. + * + * It is possible for both bytes to be sent and an error to be returned. + * + * APR_EINTR is never returned. + * </PRE> + */ +APR_DECLARE(apr_status_t) apr_socket_sendv(apr_socket_t *sock, + const struct iovec *vec, + apr_int32_t nvec, apr_size_t *len); + +/** + * @param sock The socket to send from + * @param where The apr_sockaddr_t describing where to send the data + * @param flags The flags to use + * @param buf The data to send + * @param len The length of the data to send + */ +APR_DECLARE(apr_status_t) apr_socket_sendto(apr_socket_t *sock, + apr_sockaddr_t *where, + apr_int32_t flags, const char *buf, + apr_size_t *len); + +/** + * Read data from a socket. On success, the address of the peer from + * which the data was sent is copied into the @a from parameter, and the + * @a len parameter is updated to give the number of bytes written to + * @a buf. + * + * @param from Updated with the address from which the data was received + * @param sock The socket to use + * @param flags The flags to use + * @param buf The buffer to use + * @param len The length of the available buffer + */ + +APR_DECLARE(apr_status_t) apr_socket_recvfrom(apr_sockaddr_t *from, + apr_socket_t *sock, + apr_int32_t flags, char *buf, + apr_size_t *len); + +#if APR_HAS_SENDFILE || defined(DOXYGEN) + +/** + * Send a file from an open file descriptor to a socket, along with + * optional headers and trailers + * @param sock The socket to which we're writing + * @param file The open file from which to read + * @param hdtr A structure containing the headers and trailers to send + * @param offset Offset into the file where we should begin writing + * @param len (input) - Number of bytes to send from the file + * (output) - Number of bytes actually sent, + * including headers, file, and trailers + * @param flags APR flags that are mapped to OS specific flags + * @remark This functions acts like a blocking write by default. To change + * this behavior, use apr_socket_timeout_set() or the + * APR_SO_NONBLOCK socket option. + * The number of bytes actually sent is stored in the len parameter. + * The offset parameter is passed by reference for no reason; its + * value will never be modified by the apr_socket_sendfile() function. + * It is possible for both bytes to be sent and an error to be returned. + */ +APR_DECLARE(apr_status_t) apr_socket_sendfile(apr_socket_t *sock, + apr_file_t *file, + apr_hdtr_t *hdtr, + apr_off_t *offset, + apr_size_t *len, + apr_int32_t flags); + +#endif /* APR_HAS_SENDFILE */ + +/** + * Read data from a network. + * @param sock The socket to read the data from. + * @param buf The buffer to store the data in. + * @param len On entry, the number of bytes to receive; on exit, the number + * of bytes received. + * @remark + * <PRE> + * This functions acts like a blocking read by default. To change + * this behavior, use apr_socket_timeout_set() or the APR_SO_NONBLOCK + * socket option. + * The number of bytes actually received is stored in argument 3. + * + * It is possible for both bytes to be received and an APR_EOF or + * other error to be returned. + * + * APR_EINTR is never returned. + * </PRE> + */ +APR_DECLARE(apr_status_t) apr_socket_recv(apr_socket_t *sock, + char *buf, apr_size_t *len); + +/** + * Wait for a socket to be ready for input or output + * @param sock the socket to wait on + * @param direction whether to wait for reading or writing to be ready + * @remark Will time out if socket has a time out set for it + * @remark direction can be either APR_WAIT_READ or APR_WAIT_WRITE + */ +APR_DECLARE(apr_status_t) apr_socket_wait(apr_socket_t *sock, + apr_wait_type_t direction); + +/** + * Setup socket options for the specified socket + * @param sock The socket to set up. + * @param opt The option we would like to configure. One of: + * <PRE> + * APR_SO_DEBUG -- turn on debugging information + * APR_SO_KEEPALIVE -- keep connections active + * APR_SO_LINGER -- lingers on close if data is present + * APR_SO_NONBLOCK -- Turns blocking on/off for socket + * When this option is enabled, use + * the APR_STATUS_IS_EAGAIN() macro to + * see if a send or receive function + * could not transfer data without + * blocking. + * APR_SO_REUSEADDR -- The rules used in validating addresses + * supplied to bind should allow reuse + * of local addresses. + * APR_SO_SNDBUF -- Set the SendBufferSize + * APR_SO_RCVBUF -- Set the ReceiveBufferSize + * APR_SO_FREEBIND -- Allow binding to non-local IP address. + * </PRE> + * @param on Value for the option. + */ +APR_DECLARE(apr_status_t) apr_socket_opt_set(apr_socket_t *sock, + apr_int32_t opt, apr_int32_t on); + +/** + * Setup socket timeout for the specified socket + * @param sock The socket to set up. + * @param t Value for the timeout. + * <PRE> + * t > 0 -- read and write calls return APR_TIMEUP if specified time + * elapsess with no data read or written + * t == 0 -- read and write calls never block + * t < 0 -- read and write calls block + * </PRE> + */ +APR_DECLARE(apr_status_t) apr_socket_timeout_set(apr_socket_t *sock, + apr_interval_time_t t); + +/** + * Query socket options for the specified socket + * @param sock The socket to query + * @param opt The option we would like to query. One of: + * <PRE> + * APR_SO_DEBUG -- turn on debugging information + * APR_SO_KEEPALIVE -- keep connections active + * APR_SO_LINGER -- lingers on close if data is present + * APR_SO_NONBLOCK -- Turns blocking on/off for socket + * APR_SO_REUSEADDR -- The rules used in validating addresses + * supplied to bind should allow reuse + * of local addresses. + * APR_SO_SNDBUF -- Set the SendBufferSize + * APR_SO_RCVBUF -- Set the ReceiveBufferSize + * APR_SO_DISCONNECTED -- Query the disconnected state of the socket. + * (Currently only used on Windows) + * </PRE> + * @param on Socket option returned on the call. + */ +APR_DECLARE(apr_status_t) apr_socket_opt_get(apr_socket_t *sock, + apr_int32_t opt, apr_int32_t *on); + +/** + * Query socket timeout for the specified socket + * @param sock The socket to query + * @param t Socket timeout returned from the query. + */ +APR_DECLARE(apr_status_t) apr_socket_timeout_get(apr_socket_t *sock, + apr_interval_time_t *t); + +/** + * Query the specified socket if at the OOB/Urgent data mark + * @param sock The socket to query + * @param atmark Is set to true if socket is at the OOB/urgent mark, + * otherwise is set to false. + */ +APR_DECLARE(apr_status_t) apr_socket_atmark(apr_socket_t *sock, + int *atmark); + +/** + * Return an address associated with a socket; either the address to + * which the socket is bound locally or the address of the peer + * to which the socket is connected. + * @param sa The returned apr_sockaddr_t. + * @param which Whether to retrieve the local or remote address + * @param sock The socket to use + */ +APR_DECLARE(apr_status_t) apr_socket_addr_get(apr_sockaddr_t **sa, + apr_interface_e which, + apr_socket_t *sock); + +/** + * Return the IP address (in numeric address string format) in + * an APR socket address. APR will allocate storage for the IP address + * string from the pool of the apr_sockaddr_t. + * @param addr The IP address. + * @param sockaddr The socket address to reference. + */ +APR_DECLARE(apr_status_t) apr_sockaddr_ip_get(char **addr, + apr_sockaddr_t *sockaddr); + +/** + * Write the IP address (in numeric address string format) of the APR + * socket address @a sockaddr into the buffer @a buf (of size @a buflen). + * @param sockaddr The socket address to reference. + */ +APR_DECLARE(apr_status_t) apr_sockaddr_ip_getbuf(char *buf, apr_size_t buflen, + apr_sockaddr_t *sockaddr); + +/** + * See if the IP addresses in two APR socket addresses are + * equivalent. Appropriate logic is present for comparing + * IPv4-mapped IPv6 addresses with IPv4 addresses. + * + * @param addr1 One of the APR socket addresses. + * @param addr2 The other APR socket address. + * @remark The return value will be non-zero if the addresses + * are equivalent. */ -ap_status_t ap_get_local_ipaddr(char **addr, const ap_socket_t *sock); - -/* - -=head1 ap_status_t ap_get_remote_ipaddr(char **addr, const ap_socket_t *sock) - -B<Return the remote IP address associated with an apr socket.> +APR_DECLARE(int) apr_sockaddr_equal(const apr_sockaddr_t *addr1, + const apr_sockaddr_t *addr2); - arg 1) The remote IP address associated with the socket. - arg 2) The socket to use +/** + * See if the IP address in an APR socket address refers to the wildcard + * address for the protocol family (e.g., INADDR_ANY for IPv4). + * + * @param addr The APR socket address to examine. + * @remark The return value will be non-zero if the address is + * initialized and is the wildcard address. + */ +APR_DECLARE(int) apr_sockaddr_is_wildcard(const apr_sockaddr_t *addr); + +/** +* Return the type of the socket. +* @param sock The socket to query. +* @param type The returned type (e.g., SOCK_STREAM). +*/ +APR_DECLARE(apr_status_t) apr_socket_type_get(apr_socket_t *sock, + int *type); + +/** + * Given an apr_sockaddr_t and a service name, set the port for the service + * @param sockaddr The apr_sockaddr_t that will have its port set + * @param servname The name of the service you wish to use + */ +APR_DECLARE(apr_status_t) apr_getservbyname(apr_sockaddr_t *sockaddr, + const char *servname); +/** + * Build an ip-subnet representation from an IP address and optional netmask or + * number-of-bits. + * @param ipsub The new ip-subnet representation + * @param ipstr The input IP address string + * @param mask_or_numbits The input netmask or number-of-bits string, or NULL + * @param p The pool to allocate from + */ +APR_DECLARE(apr_status_t) apr_ipsubnet_create(apr_ipsubnet_t **ipsub, + const char *ipstr, + const char *mask_or_numbits, + apr_pool_t *p); + +/** + * Test the IP address in an apr_sockaddr_t against a pre-built ip-subnet + * representation. + * @param ipsub The ip-subnet representation + * @param sa The socket address to test + * @return non-zero if the socket address is within the subnet, 0 otherwise + */ +APR_DECLARE(int) apr_ipsubnet_test(apr_ipsubnet_t *ipsub, apr_sockaddr_t *sa); + +#if APR_HAS_SO_ACCEPTFILTER || defined(DOXYGEN) +/** + * Set an OS level accept filter. + * @param sock The socket to put the accept filter on. + * @param name The accept filter + * @param args Any extra args to the accept filter. Passing NULL here removes + * the accept filter. + */ +apr_status_t apr_socket_accept_filter(apr_socket_t *sock, const char *name, + const char *args); +#endif -=cut +/** + * Return the protocol of the socket. + * @param sock The socket to query. + * @param protocol The returned protocol (e.g., APR_PROTO_TCP). */ -ap_status_t ap_get_remote_ipaddr(char **addr, const ap_socket_t *sock); - -/* +APR_DECLARE(apr_status_t) apr_socket_protocol_get(apr_socket_t *sock, + int *protocol); -=head1 ap_status_t ap_get_local_name(struct sockaddr_in **name, const ap_socket_t *sock) - -B<Return the local socket name as a BSD style struct sockaddr_in.> - - arg 1) The local name associated with the socket. - arg 2) The socket to use - -=cut +/** + * Get the pool used by the socket. */ -ap_status_t ap_get_local_name(struct sockaddr_in **name, const ap_socket_t *sock); - -/* +APR_POOL_DECLARE_ACCESSOR(socket); -=head1 ap_status_t ap_get_remote_name(struct sockaddr_in **name, const ap_socket_t *sock) - -B<Return the remote socket name as a BSD style struct sockaddr_in.> - - arg 1) The remote name associated with the socket. - arg 2) The socket to use - -=cut +/** + * Set a socket to be inherited by child processes. */ -ap_status_t ap_get_remote_name(struct sockaddr_in **name, const ap_socket_t *sock); - -/* +APR_DECLARE_INHERIT_SET(socket); -=head1 ap_status_t ap_setup_poll(ap_pollfd_t **new, ap_int32_t num, ap_pool_t *cont) - -B<Setup the memory required for poll to operate properly.> - - arg 1) The poll structure to be used. - arg 2) The number of socket descriptors to be polled. - arg 3) The pool to operate on. - -=cut +/** + * Unset a socket from being inherited by child processes. */ -ap_status_t ap_setup_poll(ap_pollfd_t **new, ap_int32_t num, - ap_pool_t *cont); - -/* - -=head1 ap_status_t ap_poll(ap_pollfd_t *aprset, ap_int32_t *nsds, ap_interval_time_t timeout) - -B<Poll the sockets in the poll structure.> - - arg 1) The poll structure we will be using. - arg 2) The number of sockets we are polling. - arg 3) The amount of time in microseconds to wait. This is a maximum, not - a minimum. If a socket is signalled, we will wake up before this - time. A negative number means wait until a socket is signalled. +APR_DECLARE_INHERIT_UNSET(socket); -B<NOTE>: The number of sockets signalled is returned in the second argument. - - This is a blocking call, and it will not return until either a - socket has been signalled, or the timeout has expired. - -=cut +/** + * Set socket permissions. */ -ap_status_t ap_poll(ap_pollfd_t *aprset, ap_int32_t *nsds, ap_interval_time_t timeout); - -/* - -=head1 ap_status_t ap_add_poll_socket(ap_pollfd_t *aprset, ap_socket_t *sock, ap_int16_t event) +APR_PERMS_SET_IMPLEMENT(socket); -B<Add a socket to the poll structure.> - - arg 1) The poll structure we will be using. - arg 2) The socket to add to the current poll structure. - arg 3) The events to look for when we do the poll. One of: - APR_POLLIN -- signal if read will not block - APR_POLLPRI -- signal if prioirty data is availble to be read - APR_POLLOUT -- signal if write will not block - -=cut +/** + * @defgroup apr_mcast IP Multicast + * @{ */ -ap_status_t ap_add_poll_socket(ap_pollfd_t *aprset, ap_socket_t *socket, - ap_int16_t event); - -/* - -=head1 ap_status_t ap_mask_poll_socket(ap_pollfd_t *aprset, ap_socket_t *sock, ap_int16_t events) -B<Modfify a socket in the poll structure with mask.> - - arg 1) The poll structure we will be using. - arg 2) The socket to modify in poll structure. - arg 3) The events to stop looking for during the poll. One of: - APR_POLLIN -- signal if read will not block - APR_POLLPRI -- signal if prioirty data is availble to be read - APR_POLLOUT -- signal if write will not block - -=cut +/** + * Join a Multicast Group + * @param sock The socket to join a multicast group + * @param join The address of the multicast group to join + * @param iface Address of the interface to use. If NULL is passed, the + * default multicast interface will be used. (OS Dependent) + * @param source Source Address to accept transmissions from (non-NULL + * implies Source-Specific Multicast) */ -ap_status_t ap_mask_poll_socket(ap_pollfd_t *aprset, ap_socket_t *sock, - ap_int16_t events); -/* - -=head1 ap_status_t ap_remove_poll_socket(ap_pollfd_t *aprset, ap_socket_t *sock) - -B<Remove a socket from the poll structure.> +APR_DECLARE(apr_status_t) apr_mcast_join(apr_socket_t *sock, + apr_sockaddr_t *join, + apr_sockaddr_t *iface, + apr_sockaddr_t *source); - arg 1) The poll structure we will be using. - arg 2) The socket to remove from the current poll structure. - -=cut +/** + * Leave a Multicast Group. All arguments must be the same as + * apr_mcast_join. + * @param sock The socket to leave a multicast group + * @param addr The address of the multicast group to leave + * @param iface Address of the interface to use. If NULL is passed, the + * default multicast interface will be used. (OS Dependent) + * @param source Source Address to accept transmissions from (non-NULL + * implies Source-Specific Multicast) */ -ap_status_t ap_remove_poll_socket(ap_pollfd_t *aprset, ap_socket_t *sock); - -/* - -=head1 ap_status_t ap_clear_poll_sockets(ap_pollfd_t *aprset, ap_int16_t events) +APR_DECLARE(apr_status_t) apr_mcast_leave(apr_socket_t *sock, + apr_sockaddr_t *addr, + apr_sockaddr_t *iface, + apr_sockaddr_t *source); -B<Remove all sockets from the poll structure.> - - arg 1) The poll structure we will be using. - arg 2) The events to clear from all sockets. One of: - APR_POLLIN -- signal if read will not block - APR_POLLPRI -- signal if prioirty data is availble to be read - APR_POLLOUT -- signal if write will not block - -=cut +/** + * Set the Multicast Time to Live (ttl) for a multicast transmission. + * @param sock The socket to set the multicast ttl + * @param ttl Time to live to Assign. 0-255, default=1 + * @remark If the TTL is 0, packets will only be seen by sockets on + * the local machine, and only when multicast loopback is enabled. */ -ap_status_t ap_clear_poll_sockets(ap_pollfd_t *aprset, ap_int16_t events); - -/* - -=head1 ap_status_t ap_get_revents(ap_int_16_t *event, ap_socket_t *sock, ap_pollfd_t *aprset) +APR_DECLARE(apr_status_t) apr_mcast_hops(apr_socket_t *sock, + apr_byte_t ttl); -B<Get the return events for the specified socket.> - - arg 1) The returned events for the socket. One of: - APR_POLLIN -- Data is available to be read - APR_POLLPRI -- Prioirty data is availble to be read - APR_POLLOUT -- Write will succeed - APR_POLLERR -- An error occurred on the socket - APR_POLLHUP -- The connection has been terminated - APR_POLLNVAL -- This is an invalid socket to poll on. - Socket not open. - arg 2) The socket we wish to get information about. - arg 3) The poll structure we will be using. - -=cut +/** + * Toggle IP Multicast Loopback + * @param sock The socket to set multicast loopback + * @param opt 0=disable, 1=enable */ -ap_status_t ap_get_revents(ap_int16_t *event, ap_socket_t *sock, - ap_pollfd_t *aprset); - -/* +APR_DECLARE(apr_status_t) apr_mcast_loopback(apr_socket_t *sock, + apr_byte_t opt); -=head1 ap_status_t ap_get_polldata(ap_pollfd_t *pollfd, char *key, void *data) -B<Return the pool associated with the current poll.> - - arg 1) The currently open pollfd. - arg 2) The key to use for retreiving data associated with a poll struct. - arg 3) The user data associated with the pollfd. - -=cut +/** + * Set the Interface to be used for outgoing Multicast Transmissions. + * @param sock The socket to set the multicast interface on + * @param iface Address of the interface to use for Multicast */ -ap_status_t ap_get_polldata(ap_pollfd_t *pollfd, char *key, void *data); - -/* - -=head1 ap_status_t ap_set_polldata(ap_pollfd_t *pollfd, void *data, char *key, ap_status_t (*cleanup) (void *)) +APR_DECLARE(apr_status_t) apr_mcast_interface(apr_socket_t *sock, + apr_sockaddr_t *iface); -B<Return the pool associated with the current poll.> - - arg 1) The currently open pollfd. - arg 2) The user data to associate with the pollfd. - -=cut - */ -ap_status_t ap_set_polldata(ap_pollfd_t *pollfd, void *data, char *key, - ap_status_t (*cleanup) (void *)); +/** @} */ -/* accessor functions */ +/** @} */ #ifdef __cplusplus } diff --git a/include/apr_optional.h b/include/apr_optional.h new file mode 100644 index 00000000000..e628fa0d35c --- /dev/null +++ b/include/apr_optional.h @@ -0,0 +1,92 @@ +/* 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. + */ + +#ifndef APR_OPTIONAL_H +#define APR_OPTIONAL_H + +#include "apu.h" +/** + * @file apr_optional.h + * @brief APR-UTIL registration of functions exported by modules + */ +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup APR_Util_Opt Optional Functions + * @ingroup APR + * + * Typesafe registration and retrieval of functions that may not be present + * (i.e. functions exported by optional modules) + * @{ + */ + +/** + * The type of an optional function. + * @param name The name of the function + */ +#define APR_OPTIONAL_FN_TYPE(name) apr_OFN_##name##_t + +/** + * Declare an optional function. + * @param ret The return type of the function + * @param name The name of the function + * @param args The function arguments (including brackets) + */ +#define APR_DECLARE_OPTIONAL_FN(ret,name,args) \ +typedef ret (APR_OPTIONAL_FN_TYPE(name)) args + +/** + * XXX: This doesn't belong here, then! + * Private function! DO NOT USE! + * @internal + */ + +typedef void (apr_opt_fn_t)(void); +/** @internal */ +APR_DECLARE_NONSTD(void) apr_dynamic_fn_register(const char *szName, + apr_opt_fn_t *pfn); + +/** + * Register an optional function. This can be later retrieved, type-safely, by + * name. Like all global functions, the name must be unique. Note that, + * confusingly but correctly, the function itself can be static! + * @param name The name of the function + */ +#define APR_REGISTER_OPTIONAL_FN(name) do { \ + APR_OPTIONAL_FN_TYPE(name) *apu__opt = name; \ + apr_dynamic_fn_register(#name,(apr_opt_fn_t *)apu__opt); \ +} while (0) + +/** @internal + * Private function! DO NOT USE! + */ +APR_DECLARE(apr_opt_fn_t *) apr_dynamic_fn_retrieve(const char *szName); + +/** + * Retrieve an optional function. Returns NULL if the function is not present. + * @param name The name of the function + */ +#define APR_RETRIEVE_OPTIONAL_FN(name) \ + (APR_OPTIONAL_FN_TYPE(name) *)apr_dynamic_fn_retrieve(#name) + +/** @} */ +#ifdef __cplusplus +} +#endif + +#endif /* APR_OPTIONAL_H */ diff --git a/include/apr_optional_hooks.h b/include/apr_optional_hooks.h new file mode 100644 index 00000000000..ac100a24893 --- /dev/null +++ b/include/apr_optional_hooks.h @@ -0,0 +1,117 @@ +/* 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. + */ +/** + * @file apr_optional_hooks.h + * @brief Apache optional hook functions + */ + + +#ifndef APR_OPTIONAL_HOOK_H +#define APR_OPTIONAL_HOOK_H + +#include "apr_tables.h" + +#ifdef __cplusplus +extern "C" { +#endif +/** + * @defgroup APR_Util_OPT_HOOK Optional Hook Functions + * @ingroup APR_Util_Hook + * @{ + */ +/** + * Function to implement the APR_OPTIONAL_HOOK Macro + * @internal + * @see APR_OPTIONAL_HOOK + * + * @param szName The name of the hook + * @param pfn A pointer to a function that will be called + * @param aszPre a NULL-terminated array of strings that name modules whose hooks should precede this one + * @param aszSucc a NULL-terminated array of strings that name modules whose hooks should succeed this one + * @param nOrder an integer determining order before honouring aszPre and aszSucc (for example HOOK_MIDDLE) + */ + + +APR_DECLARE(void) apr_optional_hook_add(const char *szName,void (*pfn)(void), + const char * const *aszPre, + const char * const *aszSucc, + int nOrder); + +/** + * Hook to an optional hook. + * + * @param ns The namespace prefix of the hook functions + * @param name The name of the hook + * @param pfn A pointer to a function that will be called + * @param aszPre a NULL-terminated array of strings that name modules whose hooks should precede this one + * @param aszSucc a NULL-terminated array of strings that name modules whose hooks should succeed this one + * @param nOrder an integer determining order before honouring aszPre and aszSucc (for example HOOK_MIDDLE) + */ + +#define APR_OPTIONAL_HOOK(ns,name,pfn,aszPre,aszSucc,nOrder) do { \ + ns##_HOOK_##name##_t *apu__hook = pfn; \ + apr_optional_hook_add(#name,(void (*)(void))apu__hook,aszPre, aszSucc, nOrder); \ +} while (0) + +/** + * @internal + * @param szName - the name of the function + * @return the hook structure for a given hook + */ +APR_DECLARE(apr_array_header_t *) apr_optional_hook_get(const char *szName); + +/** + * Implement an optional hook that runs until one of the functions + * returns something other than OK or DECLINE. + * + * @param ns The namespace prefix of the hook functions + * @param link The linkage declaration prefix of the hook + * @param ret The type of the return value of the hook + * @param ret The type of the return value of the hook + * @param name The name of the hook + * @param args_decl The declaration of the arguments for the hook + * @param args_use The names for the arguments for the hook + * @param ok Success value + * @param decline Decline value + */ +#define APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(ns,link,ret,name,args_decl,args_use,ok,decline) \ +link##_DECLARE(ret) ns##_run_##name args_decl \ + { \ + ns##_LINK_##name##_t *pHook; \ + int n; \ + ret rv; \ + apr_array_header_t *pHookArray=apr_optional_hook_get(#name); \ +\ + if(!pHookArray) \ + return ok; \ +\ + pHook=(ns##_LINK_##name##_t *)pHookArray->elts; \ + for(n=0 ; n < pHookArray->nelts ; ++n) \ + { \ + rv=(pHook[n].pFunc)args_use; \ +\ + if(rv != ok && rv != decline) \ + return rv; \ + } \ + return ok; \ + } + +/** @} */ +#ifdef __cplusplus +} +#endif + +#endif /* APR_OPTIONAL_HOOK_H */ diff --git a/include/apr_perms_set.h b/include/apr_perms_set.h new file mode 100644 index 00000000000..92a1362b8e5 --- /dev/null +++ b/include/apr_perms_set.h @@ -0,0 +1,65 @@ +/* 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. + */ + +#ifndef APR_PERMS_SET_H +#define APR_PERMS_SET_H + +/** + * @file apr_perms_set.h + * @brief APR Process Locking Routines + */ + +#include "apr.h" +#include "apr_pools.h" +#include "apr_errno.h" +#include "apr_user.h" +#include "apr_file_info.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup apr_perms_set Object permission set functions + * @ingroup APR + * @{ + */ + +/** Permission set callback function. */ +typedef apr_status_t (apr_perms_setfn_t)(void *object, apr_fileperms_t perms, + apr_uid_t uid, apr_gid_t gid); + +#define APR_PERMS_SET_IMPLEMENT(type) \ + APR_DECLARE(apr_status_t) apr_##type##_perms_set \ + (void *the##type, apr_fileperms_t perms, \ + apr_uid_t uid, apr_gid_t gid) + +#define APR_PERMS_SET_ENOTIMPL(type) \ + APR_DECLARE(apr_status_t) apr_##type##_perms_set \ + (void *the##type, apr_fileperms_t perms, \ + apr_uid_t uid, apr_gid_t gid) \ + { return APR_ENOTIMPL ; } + +#define APR_PERMS_SET_FN(type) apr_##type##_perms_set + + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* ! APR_PERMS_SET */ diff --git a/include/apr_poll.h b/include/apr_poll.h new file mode 100644 index 00000000000..482d6ee1db7 --- /dev/null +++ b/include/apr_poll.h @@ -0,0 +1,446 @@ +/* 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. + */ + +#ifndef APR_POLL_H +#define APR_POLL_H +/** + * @file apr_poll.h + * @brief APR Poll interface + */ +#include "apr.h" +#include "apr_pools.h" +#include "apr_errno.h" +#include "apr_inherit.h" +#include "apr_file_io.h" +#include "apr_network_io.h" + +#if APR_HAVE_NETINET_IN_H +#include <netinet/in.h> +#endif + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup apr_poll Poll Routines + * @ingroup APR + * @{ + */ + +/** + * @defgroup pollopts Poll options + * @ingroup apr_poll + * @{ + */ +#define APR_POLLIN 0x001 /**< Can read without blocking */ +#define APR_POLLPRI 0x002 /**< Priority data available */ +#define APR_POLLOUT 0x004 /**< Can write without blocking */ +#define APR_POLLERR 0x010 /**< Pending error */ +#define APR_POLLHUP 0x020 /**< Hangup occurred */ +#define APR_POLLNVAL 0x040 /**< Descriptor invalid */ +/** @} */ + +/** + * @defgroup pollflags Pollset Flags + * @ingroup apr_poll + * @{ + */ +#define APR_POLLSET_THREADSAFE 0x001 /**< Adding or removing a descriptor is + * thread-safe + */ +#define APR_POLLSET_NOCOPY 0x002 /**< Descriptors passed to apr_pollset_add() + * are not copied + */ +#define APR_POLLSET_WAKEABLE 0x004 /**< Poll operations are interruptable by + * apr_pollset_wakeup() or apr_pollcb_wakeup() + */ +#define APR_POLLSET_NODEFAULT 0x010 /**< Do not try to use the default method if + * the specified non-default method cannot be + * used + */ +/** @} */ + +/** + * Pollset Methods + */ +typedef enum { + APR_POLLSET_DEFAULT, /**< Platform default poll method */ + APR_POLLSET_SELECT, /**< Poll uses select method */ + APR_POLLSET_KQUEUE, /**< Poll uses kqueue method */ + APR_POLLSET_PORT, /**< Poll uses Solaris event port method */ + APR_POLLSET_EPOLL, /**< Poll uses epoll method */ + APR_POLLSET_POLL, /**< Poll uses poll method */ + APR_POLLSET_AIO_MSGQ /**< Poll uses z/OS asio method */ +} apr_pollset_method_e; + +/** Used in apr_pollfd_t to determine what the apr_descriptor is */ +typedef enum { + APR_NO_DESC, /**< nothing here */ + APR_POLL_SOCKET, /**< descriptor refers to a socket */ + APR_POLL_FILE, /**< descriptor refers to a file */ + APR_POLL_LASTDESC /**< @deprecated descriptor is the last one in the list */ +} apr_datatype_e ; + +/** Union of either an APR file or socket. */ +typedef union { + apr_file_t *f; /**< file */ + apr_socket_t *s; /**< socket */ +} apr_descriptor; + +/** @see apr_pollfd_t */ +typedef struct apr_pollfd_t apr_pollfd_t; + +/** Poll descriptor set. */ +struct apr_pollfd_t { + apr_pool_t *p; /**< associated pool */ + apr_datatype_e desc_type; /**< descriptor type */ + apr_int16_t reqevents; /**< requested events */ + apr_int16_t rtnevents; /**< returned events */ + apr_descriptor desc; /**< @see apr_descriptor */ + void *client_data; /**< allows app to associate context */ +}; + + +/* General-purpose poll API for arbitrarily large numbers of + * file descriptors + */ + +/** Opaque structure used for pollset API */ +typedef struct apr_pollset_t apr_pollset_t; + +/** + * Set up a pollset object + * @param pollset The pointer in which to return the newly created object + * @param size The maximum number of descriptors that this pollset can hold + * @param p The pool from which to allocate the pollset + * @param flags Optional flags to modify the operation of the pollset. + * + * @remark If flags contains APR_POLLSET_THREADSAFE, then a pollset is + * created on which it is safe to make concurrent calls to + * apr_pollset_add(), apr_pollset_remove() and apr_pollset_poll() + * from separate threads. This feature is only supported on some + * platforms; the apr_pollset_create() call will fail with + * APR_ENOTIMPL on platforms where it is not supported. + * @remark If flags contains APR_POLLSET_WAKEABLE, then a pollset is + * created with an additional internal pipe object used for the + * apr_pollset_wakeup() call. The actual size of pollset is + * in that case @a size + 1. This feature is only supported on some + * platforms; the apr_pollset_create() call will fail with + * APR_ENOTIMPL on platforms where it is not supported. + * @remark If flags contains APR_POLLSET_NOCOPY, then the apr_pollfd_t + * structures passed to apr_pollset_add() are not copied and + * must have a lifetime at least as long as the pollset. + * @remark Some poll methods (including APR_POLLSET_KQUEUE, + * APR_POLLSET_PORT, and APR_POLLSET_EPOLL) do not have a + * fixed limit on the size of the pollset. For these methods, + * the size parameter controls the maximum number of + * descriptors that will be returned by a single call to + * apr_pollset_poll(). + */ +APR_DECLARE(apr_status_t) apr_pollset_create(apr_pollset_t **pollset, + apr_uint32_t size, + apr_pool_t *p, + apr_uint32_t flags); + +/** + * Set up a pollset object + * @param pollset The pointer in which to return the newly created object + * @param size The maximum number of descriptors that this pollset can hold + * @param p The pool from which to allocate the pollset + * @param flags Optional flags to modify the operation of the pollset. + * @param method Poll method to use. See #apr_pollset_method_e. If this + * method cannot be used, the default method will be used unless the + * APR_POLLSET_NODEFAULT flag has been specified. + * + * @remark If flags contains APR_POLLSET_THREADSAFE, then a pollset is + * created on which it is safe to make concurrent calls to + * apr_pollset_add(), apr_pollset_remove() and apr_pollset_poll() + * from separate threads. This feature is only supported on some + * platforms; the apr_pollset_create_ex() call will fail with + * APR_ENOTIMPL on platforms where it is not supported. + * @remark If flags contains APR_POLLSET_WAKEABLE, then a pollset is + * created with additional internal pipe object used for the + * apr_pollset_wakeup() call. The actual size of pollset is + * in that case size + 1. This feature is only supported on some + * platforms; the apr_pollset_create_ex() call will fail with + * APR_ENOTIMPL on platforms where it is not supported. + * @remark If flags contains APR_POLLSET_NOCOPY, then the apr_pollfd_t + * structures passed to apr_pollset_add() are not copied and + * must have a lifetime at least as long as the pollset. + * @remark Some poll methods (including APR_POLLSET_KQUEUE, + * APR_POLLSET_PORT, and APR_POLLSET_EPOLL) do not have a + * fixed limit on the size of the pollset. For these methods, + * the size parameter controls the maximum number of + * descriptors that will be returned by a single call to + * apr_pollset_poll(). + */ +APR_DECLARE(apr_status_t) apr_pollset_create_ex(apr_pollset_t **pollset, + apr_uint32_t size, + apr_pool_t *p, + apr_uint32_t flags, + apr_pollset_method_e method); + +/** + * Destroy a pollset object + * @param pollset The pollset to destroy + */ +APR_DECLARE(apr_status_t) apr_pollset_destroy(apr_pollset_t *pollset); + +/** + * Add a socket or file descriptor to a pollset + * @param pollset The pollset to which to add the descriptor + * @param descriptor The descriptor to add + * @remark If you set client_data in the descriptor, that value + * will be returned in the client_data field whenever this + * descriptor is signalled in apr_pollset_poll(). + * @remark If the pollset has been created with APR_POLLSET_THREADSAFE + * and thread T1 is blocked in a call to apr_pollset_poll() for + * this same pollset that is being modified via apr_pollset_add() + * in thread T2, the currently executing apr_pollset_poll() call in + * T1 will either: (1) automatically include the newly added descriptor + * in the set of descriptors it is watching or (2) return immediately + * with APR_EINTR. Option (1) is recommended, but option (2) is + * allowed for implementations where option (1) is impossible + * or impractical. + * @remark If the pollset has been created with APR_POLLSET_NOCOPY, the + * apr_pollfd_t structure referenced by descriptor will not be copied + * and must have a lifetime at least as long as the pollset. + * @remark Do not add the same socket or file descriptor to the same pollset + * multiple times, even if the requested events differ for the + * different calls to apr_pollset_add(). If the events of interest + * for a descriptor change, you must first remove the descriptor + * from the pollset with apr_pollset_remove(), then add it again + * specifying all requested events. + */ +APR_DECLARE(apr_status_t) apr_pollset_add(apr_pollset_t *pollset, + const apr_pollfd_t *descriptor); + +/** + * Remove a descriptor from a pollset + * @param pollset The pollset from which to remove the descriptor + * @param descriptor The descriptor to remove + * @remark If the descriptor is not found, APR_NOTFOUND is returned. + * @remark If the pollset has been created with APR_POLLSET_THREADSAFE + * and thread T1 is blocked in a call to apr_pollset_poll() for + * this same pollset that is being modified via apr_pollset_remove() + * in thread T2, the currently executing apr_pollset_poll() call in + * T1 will either: (1) automatically exclude the newly added descriptor + * in the set of descriptors it is watching or (2) return immediately + * with APR_EINTR. Option (1) is recommended, but option (2) is + * allowed for implementations where option (1) is impossible + * or impractical. + * @remark apr_pollset_remove() cannot be used to remove a subset of requested + * events for a descriptor. The reqevents field in the apr_pollfd_t + * parameter must contain the same value when removing as when adding. + */ +APR_DECLARE(apr_status_t) apr_pollset_remove(apr_pollset_t *pollset, + const apr_pollfd_t *descriptor); + +/** + * Block for activity on the descriptor(s) in a pollset + * @param pollset The pollset to use + * @param timeout The amount of time in microseconds to wait. This is a + * maximum, not a minimum. If a descriptor is signalled, the + * function will return before this time. If timeout is + * negative, the function will block until a descriptor is + * signalled or until apr_pollset_wakeup() has been called. + * @param num Number of signalled descriptors (output parameter) + * @param descriptors Array of signalled descriptors (output parameter) + * @remark APR_EINTR will be returned if the pollset has been created with + * APR_POLLSET_WAKEABLE, apr_pollset_wakeup() has been called while + * waiting for activity, and there were no signalled descriptors at the + * time of the wakeup call. + * @remark Multiple signalled conditions for the same descriptor may be reported + * in one or more returned apr_pollfd_t structures, depending on the + * implementation. + */ +APR_DECLARE(apr_status_t) apr_pollset_poll(apr_pollset_t *pollset, + apr_interval_time_t timeout, + apr_int32_t *num, + const apr_pollfd_t **descriptors); + +/** + * Interrupt the blocked apr_pollset_poll() call. + * @param pollset The pollset to use + * @remark If the pollset was not created with APR_POLLSET_WAKEABLE the + * return value is APR_EINIT. + */ +APR_DECLARE(apr_status_t) apr_pollset_wakeup(apr_pollset_t *pollset); + +/** + * Poll the descriptors in the poll structure + * @param aprset The poll structure we will be using. + * @param numsock The number of descriptors we are polling + * @param nsds The number of descriptors signalled (output parameter) + * @param timeout The amount of time in microseconds to wait. This is a + * maximum, not a minimum. If a descriptor is signalled, the + * function will return before this time. If timeout is + * negative, the function will block until a descriptor is + * signalled or until apr_pollset_wakeup() has been called. + * @remark The number of descriptors signalled is returned in the third argument. + * This is a blocking call, and it will not return until either a + * descriptor has been signalled or the timeout has expired. + * @remark The rtnevents field in the apr_pollfd_t array will only be filled- + * in if the return value is APR_SUCCESS. + */ +APR_DECLARE(apr_status_t) apr_poll(apr_pollfd_t *aprset, apr_int32_t numsock, + apr_int32_t *nsds, + apr_interval_time_t timeout); + +/** + * Return a printable representation of the pollset method. + * @param pollset The pollset to use + */ +APR_DECLARE(const char *) apr_pollset_method_name(apr_pollset_t *pollset); + +/** + * Return a printable representation of the default pollset method + * (APR_POLLSET_DEFAULT). + */ +APR_DECLARE(const char *) apr_poll_method_defname(void); + +/** Opaque structure used for pollcb API */ +typedef struct apr_pollcb_t apr_pollcb_t; + +/** + * Set up a pollcb object + * @param pollcb The pointer in which to return the newly created object + * @param size The maximum number of descriptors that a single _poll can return. + * @param p The pool from which to allocate the pollcb + * @param flags Optional flags to modify the operation of the pollcb. + * + * @remark If flags contains APR_POLLSET_WAKEABLE, then a pollcb is + * created with an additional internal pipe object used for the + * apr_pollcb_wakeup() call. The actual size of pollcb is + * in that case @a size + 1. + * @remark Pollcb is only supported on some platforms; the apr_pollcb_create() + * call will fail with APR_ENOTIMPL on platforms where it is not supported. + */ +APR_DECLARE(apr_status_t) apr_pollcb_create(apr_pollcb_t **pollcb, + apr_uint32_t size, + apr_pool_t *p, + apr_uint32_t flags); + +/** + * Set up a pollcb object + * @param pollcb The pointer in which to return the newly created object + * @param size The maximum number of descriptors that a single _poll can return. + * @param p The pool from which to allocate the pollcb + * @param flags Optional flags to modify the operation of the pollcb. + * @param method Poll method to use. See #apr_pollset_method_e. If this + * method cannot be used, the default method will be used unless the + * APR_POLLSET_NODEFAULT flag has been specified. + * + * @remark If flags contains APR_POLLSET_WAKEABLE, then a pollcb is + * created with an additional internal pipe object used for the + * apr_pollcb_wakeup() call. The actual size of pollcb is + * in that case @a size + 1. + * @remark Pollcb is only supported on some platforms; the apr_pollcb_create_ex() + * call will fail with APR_ENOTIMPL on platforms where it is not supported. + */ +APR_DECLARE(apr_status_t) apr_pollcb_create_ex(apr_pollcb_t **pollcb, + apr_uint32_t size, + apr_pool_t *p, + apr_uint32_t flags, + apr_pollset_method_e method); + +/** + * Add a socket or file descriptor to a pollcb + * @param pollcb The pollcb to which to add the descriptor + * @param descriptor The descriptor to add + * @remark If you set client_data in the descriptor, that value will be + * returned in the client_data field whenever this descriptor is + * signalled in apr_pollcb_poll(). + * @remark Unlike the apr_pollset API, the descriptor is not copied, and users + * must retain the memory used by descriptor, as the same pointer will + * be returned to them from apr_pollcb_poll. + * @remark Do not add the same socket or file descriptor to the same pollcb + * multiple times, even if the requested events differ for the + * different calls to apr_pollcb_add(). If the events of interest + * for a descriptor change, you must first remove the descriptor + * from the pollcb with apr_pollcb_remove(), then add it again + * specifying all requested events. + */ +APR_DECLARE(apr_status_t) apr_pollcb_add(apr_pollcb_t *pollcb, + apr_pollfd_t *descriptor); +/** + * Remove a descriptor from a pollcb + * @param pollcb The pollcb from which to remove the descriptor + * @param descriptor The descriptor to remove + * @remark If the descriptor is not found, APR_NOTFOUND is returned. + * @remark apr_pollcb_remove() cannot be used to remove a subset of requested + * events for a descriptor. The reqevents field in the apr_pollfd_t + * parameter must contain the same value when removing as when adding. + */ +APR_DECLARE(apr_status_t) apr_pollcb_remove(apr_pollcb_t *pollcb, + apr_pollfd_t *descriptor); + +/** + * Function prototype for pollcb handlers + * @param baton Opaque baton passed into apr_pollcb_poll() + * @param descriptor Contains the notification for an active descriptor. + * The @a rtnevents member describes which events were triggered + * for this descriptor. + * @remark If the pollcb handler does not return APR_SUCCESS, the apr_pollcb_poll() + * call returns with the handler's return value. + */ +typedef apr_status_t (*apr_pollcb_cb_t)(void *baton, apr_pollfd_t *descriptor); + +/** + * Block for activity on the descriptor(s) in a pollcb + * @param pollcb The pollcb to use + * @param timeout The amount of time in microseconds to wait. This is a + * maximum, not a minimum. If a descriptor is signalled, the + * function will return before this time. If timeout is + * negative, the function will block until a descriptor is + * signalled or until apr_pollcb_wakeup() has been called. + * @param func Callback function to call for each active descriptor. + * @param baton Opaque baton passed to the callback function. + * @remark Multiple signalled conditions for the same descriptor may be reported + * in one or more calls to the callback function, depending on the + * implementation. + * @remark APR_EINTR will be returned if the pollset has been created with + * APR_POLLSET_WAKEABLE and apr_pollcb_wakeup() has been called while + * waiting for activity. + */ +APR_DECLARE(apr_status_t) apr_pollcb_poll(apr_pollcb_t *pollcb, + apr_interval_time_t timeout, + apr_pollcb_cb_t func, + void *baton); + +/** + * Interrupt the blocked apr_pollcb_poll() call. + * @param pollcb The pollcb to use + * @remark If the pollcb was not created with APR_POLLSET_WAKEABLE the + * return value is APR_EINIT. + */ +APR_DECLARE(apr_status_t) apr_pollcb_wakeup(apr_pollcb_t *pollcb); + +/** + * Return a printable representation of the pollcb method. + * @param pollcb The pollcb to use + */ +APR_DECLARE(const char *) apr_pollcb_method_name(apr_pollcb_t *pollcb); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* ! APR_POLL_H */ + diff --git a/include/apr_pools.h b/include/apr_pools.h index c485464e2d4..f87b90b98e6 100644 --- a/include/apr_pools.h +++ b/include/apr_pools.h @@ -1,65 +1,26 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#ifndef ap_POOLS_H -#define ap_POOLS_H +/* 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. + */ -#ifdef __cplusplus -extern "C" { -#endif +#ifndef APR_POOLS_H +#define APR_POOLS_H -/* +/** + * @file apr_pools.h + * @brief APR memory allocation + * * Resource allocation routines... * * designed so that we don't have to keep track of EVERYTHING so that @@ -67,178 +28,783 @@ extern "C" { * particularly in the presence of die()). * * Instead, we maintain pools, and allocate items (both memory and I/O - * handlers) from the pools --- currently there are two, one for per - * transaction info, and one for config info. When a transaction is over, - * we can delete everything in the per-transaction ap_pool_t without fear, and - * without thinking too hard about it either. + * handlers) from the pools --- currently there are two, one for + * per-transaction info, and one for config info. When a transaction is + * over, we can delete everything in the per-transaction apr_pool_t without + * fear, and without thinking too hard about it either. * - * rst + * Note that most operations on pools are not thread-safe: a single pool + * should only be accessed by a single thread at any given time. The one + * exception to this rule is creating a subpool of a given pool: one or more + * threads can safely create subpools at the same time that another thread + * accesses the parent pool. */ -/* Arenas for configuration info and transaction info - * --- actual layout of the ap_pool_t structure is private to - * alloc.c. +#include "apr.h" +#include "apr_errno.h" +#include "apr_general.h" /* for APR_STRINGIFY */ +#define APR_WANT_MEMFUNC /**< for no good reason? */ +#include "apr_want.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup apr_pools Memory Pool Functions + * @ingroup APR + * @{ */ -#include "apr_lib.h" +/** The fundamental pool type */ +typedef struct apr_pool_t apr_pool_t; -#if APR_HAVE_SYS_TYPES_H -#include <sys/types.h> -#endif -struct process_chain { - ap_proc_t *pid; - enum kill_conditions kill_how; - struct process_chain *next; -}; +/** + * Declaration helper macro to construct apr_foo_pool_get()s. + * + * This standardized macro is used by opaque (APR) data types to return + * the apr_pool_t that is associated with the data type. + * + * APR_POOL_DECLARE_ACCESSOR() is used in a header file to declare the + * accessor function. A typical usage and result would be: + * <pre> + * APR_POOL_DECLARE_ACCESSOR(file); + * becomes: + * APR_DECLARE(apr_pool_t *) apr_file_pool_get(const apr_file_t *thefile); + * </pre> + * @remark Doxygen unwraps this macro (via doxygen.conf) to provide + * actual help for each specific occurrence of apr_foo_pool_get. + * @remark the linkage is specified for APR. It would be possible to expand + * the macros to support other linkages. + */ +#define APR_POOL_DECLARE_ACCESSOR(type) \ + APR_DECLARE(apr_pool_t *) apr_##type##_pool_get \ + (const apr_##type##_t *the##type) + +/** + * Implementation helper macro to provide apr_foo_pool_get()s. + * + * In the implementation, the APR_POOL_IMPLEMENT_ACCESSOR() is used to + * actually define the function. It assumes the field is named "pool". + */ +#define APR_POOL_IMPLEMENT_ACCESSOR(type) \ + APR_DECLARE(apr_pool_t *) apr_##type##_pool_get \ + (const apr_##type##_t *the##type) \ + { return the##type->pool; } -struct ap_table_t { - /* This has to be first to promote backwards compatibility with - * older modules which cast a ap_table_t * to an ap_array_header_t *... - * they should use the table_elts() function for most of the - * cases they do this for. - */ - ap_array_header_t a; -#ifdef MAKE_TABLE_PROFILE - void *creator; -#endif -}; -/* - * Tables. Implemented alist style, for now, though we try to keep - * it so that imposing a hash table structure on top in the future - * wouldn't be *too* hard... +/** + * Pool debug levels + * + * <pre> + * | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | + * --------------------------------- + * | | | | | | | | x | General debug code enabled (useful in + * combination with --with-efence). + * + * | | | | | | | x | | Verbose output on stderr (report + * CREATE, CLEAR, DESTROY). + * + * | | | | x | | | | | Verbose output on stderr (report + * PALLOC, PCALLOC). + * + * | | | | | | x | | | Lifetime checking. On each use of a + * pool, check its lifetime. If the pool + * is out of scope, abort(). + * In combination with the verbose flag + * above, it will output LIFE in such an + * event prior to aborting. * - * Note that key comparisons for these are case-insensitive, largely - * because that's what's appropriate and convenient everywhere they're - * currently being used... + * | | | | | x | | | | Pool owner checking. On each use of a + * pool, check if the current thread is the + * pool's owner. If not, abort(). In + * combination with the verbose flag above, + * it will output OWNER in such an event + * prior to aborting. Use the debug + * function apr_pool_owner_set() to switch + * a pool's ownership. + * + * When no debug level was specified, assume general debug mode. + * If level 0 was specified, debugging is switched off. + * </pre> */ +#if defined(APR_POOL_DEBUG) +/* If APR_POOL_DEBUG is blank, we get 1; if it is a number, we get -1. */ +#if (APR_POOL_DEBUG - APR_POOL_DEBUG -1 == 1) +#undef APR_POOL_DEBUG +#define APR_POOL_DEBUG 1 +#endif +#else +#define APR_POOL_DEBUG 0 +#endif -ap_status_t ap_init_alloc(void); /* Set up everything */ -void ap_term_alloc(void); /* Tear down everything */ +/** the place in the code where the particular function was called */ +#define APR_POOL__FILE_LINE__ __FILE__ ":" APR_STRINGIFY(__LINE__) -/* used to guarantee to the pool debugging code that the sub pool will not be - * destroyed before the parent pool + + +/** A function that is called when allocation fails. */ +typedef int (*apr_abortfunc_t)(int retcode); + +/* + * APR memory structure manipulators (pools, tables, and arrays). */ -#ifndef POOL_DEBUG -#ifdef ap_pool_join -#undef ap_pool_join -#endif /* ap_pool_join */ -#define ap_pool_join(a,b) -#endif /* POOL_DEBUG */ -/* Clearing out EVERYTHING in an pool... destroys any sub-pools */ +/* + * Initialization + */ -/* Preparing for exec() --- close files, etc., but *don't* flush I/O - * buffers, *don't* wait for subprocesses, and *don't* free any memory. +/** + * Setup all of the internal structures required to use pools + * @remark Programs do NOT need to call this directly. APR will call this + * automatically from apr_initialize. + * @internal */ +APR_DECLARE(apr_status_t) apr_pool_initialize(void); -/* routines to allocate memory from an pool... */ +/** + * Tear down all of the internal structures required to use pools + * @remark Programs do NOT need to call this directly. APR will call this + * automatically from apr_terminate. + * @internal + */ +APR_DECLARE(void) apr_pool_terminate(void); -API_EXPORT_NONSTD(char *) ap_psprintf(struct ap_pool_t *, const char *fmt, ...) - __attribute__((format(printf,2,3))); +/* + * Pool creation/destruction + */ -/* array and alist management... keeping lists of things. - * Common enough to want common support code ... +#include "apr_allocator.h" + +/** + * Create a new pool. + * @param newpool The pool we have just created. + * @param parent The parent pool. If this is NULL, the new pool is a root + * pool. If it is non-NULL, the new pool will inherit all + * of its parent pool's attributes, except the apr_pool_t will + * be a sub-pool. + * @param abort_fn A function to use if the pool cannot allocate more memory. + * @param allocator The allocator to use with the new pool. If NULL the + * allocator of the parent pool will be used. + * @remark This function is thread-safe, in the sense that multiple threads + * can safely create subpools of the same parent pool concurrently. + * Similarly, a subpool can be created by one thread at the same + * time that another thread accesses the parent pool. */ +APR_DECLARE(apr_status_t) apr_pool_create_ex(apr_pool_t **newpool, + apr_pool_t *parent, + apr_abortfunc_t abort_fn, + apr_allocator_t *allocator) + __attribute__((nonnull(1))); + +/** + * Create a new unmanaged pool. + * @param newpool The pool we have just created. + * @param abort_fn A function to use if the pool cannot allocate more memory. + * @param allocator The allocator to use with the new pool. If NULL a + * new allocator will be created with the new pool as owner. + * @remark An unmanaged pool is a special pool without a parent; it will + * NOT be destroyed upon apr_terminate. It must be explicitly + * destroyed by calling apr_pool_destroy, to prevent memory leaks. + * Use of this function is discouraged, think twice about whether + * you really really need it. + * @warning Any child cleanups registered against the new pool, or + * against sub-pools thereof, will not be executed during an + * invocation of apr_proc_create(), so resources created in an + * "unmanaged" pool hierarchy will leak to child processes. + */ +APR_DECLARE(apr_status_t) apr_pool_create_unmanaged_ex(apr_pool_t **newpool, + apr_abortfunc_t abort_fn, + apr_allocator_t *allocator) + __attribute__((nonnull(1))); + +/** + * Debug version of apr_pool_create_ex. + * @param newpool @see apr_pool_create. + * @param parent @see apr_pool_create. + * @param abort_fn @see apr_pool_create. + * @param allocator @see apr_pool_create. + * @param file_line Where the function is called from. + * This is usually APR_POOL__FILE_LINE__. + * @remark Only available when APR_POOL_DEBUG is defined. + * Call this directly if you have your apr_pool_create_ex + * calls in a wrapper function and wish to override + * the file_line argument to reflect the caller of + * your wrapper function. If you do not have + * apr_pool_create_ex in a wrapper, trust the macro + * and don't call apr_pool_create_ex_debug directly. + */ +APR_DECLARE(apr_status_t) apr_pool_create_ex_debug(apr_pool_t **newpool, + apr_pool_t *parent, + apr_abortfunc_t abort_fn, + apr_allocator_t *allocator, + const char *file_line) + __attribute__((nonnull(1))); + +#if APR_POOL_DEBUG +#define apr_pool_create_ex(newpool, parent, abort_fn, allocator) \ + apr_pool_create_ex_debug(newpool, parent, abort_fn, allocator, \ + APR_POOL__FILE_LINE__) +#endif -/* ap_array_pstrcat generates a new string from the ap_pool_t containing - * the concatenated sequence of substrings referenced as elements within - * the array. The string will be empty if all substrings are empty or null, - * or if there are no elements in the array. - * If sep is non-NUL, it will be inserted between elements as a separator. + /** + * Debug version of apr_pool_create_unmanaged_ex. + * @param newpool @see apr_pool_create_unmanaged. + * @param abort_fn @see apr_pool_create_unmanaged. + * @param allocator @see apr_pool_create_unmanaged. + * @param file_line Where the function is called from. + * This is usually APR_POOL__FILE_LINE__. + * @remark Only available when APR_POOL_DEBUG is defined. + * Call this directly if you have your apr_pool_create_unmanaged_ex + * calls in a wrapper function and wish to override + * the file_line argument to reflect the caller of + * your wrapper function. If you do not have + * apr_pool_create_unmanaged_ex in a wrapper, trust the macro + * and don't call apr_pool_create_unmanaged_ex_debug directly. */ +APR_DECLARE(apr_status_t) apr_pool_create_unmanaged_ex_debug(apr_pool_t **newpool, + apr_abortfunc_t abort_fn, + apr_allocator_t *allocator, + const char *file_line) + __attribute__((nonnull(1))); + +#if APR_POOL_DEBUG +#define apr_pool_create_unmanaged_ex(newpool, abort_fn, allocator) \ + apr_pool_create_unmanaged_ex_debug(newpool, abort_fn, allocator, \ + APR_POOL__FILE_LINE__) -/* copy_array copies the *entire* array. copy_array_hdr just copies - * the header, and arranges for the elements to be copied if (and only - * if) the code subsequently does a push or arraycat. +#endif + +/** + * Create a new pool. + * @param newpool The pool we have just created. + * @param parent The parent pool. If this is NULL, the new pool is a root + * pool. If it is non-NULL, the new pool will inherit all + * of its parent pool's attributes, except the apr_pool_t will + * be a sub-pool. + * @remark This function is thread-safe, in the sense that multiple threads + * can safely create subpools of the same parent pool concurrently. + * Similarly, a subpool can be created by one thread at the same + * time that another thread accesses the parent pool. */ +#if defined(DOXYGEN) +APR_DECLARE(apr_status_t) apr_pool_create(apr_pool_t **newpool, + apr_pool_t *parent); +#else +#if APR_POOL_DEBUG +#define apr_pool_create(newpool, parent) \ + apr_pool_create_ex_debug(newpool, parent, NULL, NULL, \ + APR_POOL__FILE_LINE__) +#else +#define apr_pool_create(newpool, parent) \ + apr_pool_create_ex(newpool, parent, NULL, NULL) +#endif +#endif +/** + * Create a new unmanaged pool. + * @param newpool The pool we have just created. + */ +#if defined(DOXYGEN) +APR_DECLARE(apr_status_t) apr_pool_create_unmanaged(apr_pool_t **newpool); +#else +#if APR_POOL_DEBUG +#define apr_pool_create_unmanaged(newpool) \ + apr_pool_create_unmanaged_ex_debug(newpool, NULL, NULL, \ + APR_POOL__FILE_LINE__) +#else +#define apr_pool_create_unmanaged(newpool) \ + apr_pool_create_unmanaged_ex(newpool, NULL, NULL) +#endif +#endif +/** + * Find the pool's allocator + * @param pool The pool to get the allocator from. + */ +APR_DECLARE(apr_allocator_t *) apr_pool_allocator_get(apr_pool_t *pool) + __attribute__((nonnull(1))); + +/** + * Clear all memory in the pool and run all the cleanups. This also destroys all + * subpools. + * @param p The pool to clear + * @remark This does not actually free the memory, it just allows the pool + * to re-use this memory for the next allocation. + * @see apr_pool_destroy() + */ +APR_DECLARE(void) apr_pool_clear(apr_pool_t *p) __attribute__((nonnull(1))); + +/** + * Debug version of apr_pool_clear. + * @param p See: apr_pool_clear. + * @param file_line Where the function is called from. + * This is usually APR_POOL__FILE_LINE__. + * @remark Only available when APR_POOL_DEBUG is defined. + * Call this directly if you have your apr_pool_clear + * calls in a wrapper function and wish to override + * the file_line argument to reflect the caller of + * your wrapper function. If you do not have + * apr_pool_clear in a wrapper, trust the macro + * and don't call apr_pool_destroy_clear directly. + */ +APR_DECLARE(void) apr_pool_clear_debug(apr_pool_t *p, + const char *file_line) + __attribute__((nonnull(1))); -/* Conceptually, ap_overlap_tables does this: +#if APR_POOL_DEBUG +#define apr_pool_clear(p) \ + apr_pool_clear_debug(p, APR_POOL__FILE_LINE__) +#endif - ap_array_header_t *barr = ap_table_elts(b); - ap_table_entry_t *belt = (ap_table_entry_t *)barr->elts; - int i; +/** + * Destroy the pool. This takes similar action as apr_pool_clear() and then + * frees all the memory. + * @param p The pool to destroy + * @remark This will actually free the memory + */ +APR_DECLARE(void) apr_pool_destroy(apr_pool_t *p) __attribute__((nonnull(1))); + +/** + * Debug version of apr_pool_destroy. + * @param p See: apr_pool_destroy. + * @param file_line Where the function is called from. + * This is usually APR_POOL__FILE_LINE__. + * @remark Only available when APR_POOL_DEBUG is defined. + * Call this directly if you have your apr_pool_destroy + * calls in a wrapper function and wish to override + * the file_line argument to reflect the caller of + * your wrapper function. If you do not have + * apr_pool_destroy in a wrapper, trust the macro + * and don't call apr_pool_destroy_debug directly. + */ +APR_DECLARE(void) apr_pool_destroy_debug(apr_pool_t *p, + const char *file_line) + __attribute__((nonnull(1))); - for (i = 0; i < barr->nelts; ++i) { - if (flags & ap_OVERLAP_TABLES_MERGE) { - ap_table_mergen(a, belt[i].key, belt[i].val); - } - else { - ap_table_setn(a, belt[i].key, belt[i].val); - } - } +#if APR_POOL_DEBUG +#define apr_pool_destroy(p) \ + apr_pool_destroy_debug(p, APR_POOL__FILE_LINE__) +#endif - Except that it is more efficient (less space and cpu-time) especially - when b has many elements. - Notice the assumptions on the keys and values in b -- they must be - in an ancestor of a's pool. In practice b and a are usually from - the same pool. -*/ -#define ap_OVERLAP_TABLES_SET (0) -#define ap_OVERLAP_TABLES_MERGE (1) +/* + * Memory allocation + */ -/* A set of flags which indicate places where the server should raise(SIGSTOP). - * This is useful for debugging, because you can then attach to that process - * with gdb and continue. This is important in cases where one_process - * debugging isn't possible. +/** + * Allocate a block of memory from a pool + * @param p The pool to allocate from + * @param size The amount of memory to allocate + * @return The allocated memory + */ +APR_DECLARE(void *) apr_palloc(apr_pool_t *p, apr_size_t size) +#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4)) + __attribute__((alloc_size(2))) +#endif + __attribute__((nonnull(1))); + +/** + * Debug version of apr_palloc + * @param p See: apr_palloc + * @param size See: apr_palloc + * @param file_line Where the function is called from. + * This is usually APR_POOL__FILE_LINE__. + * @return See: apr_palloc */ -#define SIGSTOP_DETACH 1 -#define SIGSTOP_MAKE_CHILD 2 #define SIGSTOP_SPAWN_CHILD 4 -#define SIGSTOP_PIPED_LOG_SPAWN 8 -#define SIGSTOP_CGI_CHILD 16 +APR_DECLARE(void *) apr_palloc_debug(apr_pool_t *p, apr_size_t size, + const char *file_line) +#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4)) + __attribute__((alloc_size(2))) +#endif + __attribute__((nonnull(1))); -#ifdef DEBUG_SIGSTOP -extern int raise_sigstop_flags; -#define RAISE_SIGSTOP(x) do { \ - if (raise_sigstop_flags & SIGSTOP_##x) raise(SIGSTOP);\ - } while (0) -#else -#define RAISE_SIGSTOP(x) +#if APR_POOL_DEBUG +#define apr_palloc(p, size) \ + apr_palloc_debug(p, size, APR_POOL__FILE_LINE__) #endif -#ifdef ULTRIX_BRAIN_DEATH -#define ap_fdopen(d,m) fdopen((d), (char *)(m)) -#else -#define ap_fdopen(d,m) fdopen((d), (m)) +/** + * Allocate a block of memory from a pool and set all of the memory to 0 + * @param p The pool to allocate from + * @param size The amount of memory to allocate + * @return The allocated memory + */ +#if defined(DOXYGEN) +APR_DECLARE(void *) apr_pcalloc(apr_pool_t *p, apr_size_t size); +#elif !APR_POOL_DEBUG +#define apr_pcalloc(p, size) memset(apr_palloc(p, size), 0, size) #endif -/* XXX - the socket functions for pools should (and will) use APR sockets. - * This is temporary. */ -#ifndef BEOS /* this really screws up BeOS R4.5 !! */ -#define closesocket(s) close(s) +/** + * Debug version of apr_pcalloc + * @param p See: apr_pcalloc + * @param size See: apr_pcalloc + * @param file_line Where the function is called from. + * This is usually APR_POOL__FILE_LINE__. + * @return See: apr_pcalloc + */ +APR_DECLARE(void *) apr_pcalloc_debug(apr_pool_t *p, apr_size_t size, + const char *file_line) + __attribute__((nonnull(1))); + +#if APR_POOL_DEBUG +#define apr_pcalloc(p, size) \ + apr_pcalloc_debug(p, size, APR_POOL__FILE_LINE__) #endif +/* + * Pool Properties + */ + +/** + * Set the function to be called when an allocation failure occurs. + * @remark If the program wants APR to exit on a memory allocation error, + * then this function can be called to set the callback to use (for + * performing cleanup and then exiting). If this function is not called, + * then APR will return an error and expect the calling program to + * deal with the error accordingly. + */ +APR_DECLARE(void) apr_pool_abort_set(apr_abortfunc_t abortfunc, + apr_pool_t *pool) + __attribute__((nonnull(2))); + +/** + * Get the abort function associated with the specified pool. + * @param pool The pool for retrieving the abort function. + * @return The abort function for the given pool. + */ +APR_DECLARE(apr_abortfunc_t) apr_pool_abort_get(apr_pool_t *pool) + __attribute__((nonnull(1))); + +/** + * Get the parent pool of the specified pool. + * @param pool The pool for retrieving the parent pool. + * @return The parent of the given pool. + */ +APR_DECLARE(apr_pool_t *) apr_pool_parent_get(apr_pool_t *pool) + __attribute__((nonnull(1))); + +/** + * Determine if pool a is an ancestor of pool b. + * @param a The pool to search + * @param b The pool to search for + * @return True if a is an ancestor of b, NULL is considered an ancestor + * of all pools. + * @remark if compiled with APR_POOL_DEBUG, this function will also + * return true if A is a pool which has been guaranteed by the caller + * (using apr_pool_join) to have a lifetime at least as long as some + * ancestor of pool B. + */ +APR_DECLARE(int) apr_pool_is_ancestor(apr_pool_t *a, apr_pool_t *b); + +/** + * Tag a pool (give it a name) + * @param pool The pool to tag + * @param tag The tag + */ +APR_DECLARE(void) apr_pool_tag(apr_pool_t *pool, const char *tag) + __attribute__((nonnull(1))); + +/** + * Retrieve the tag name. + * @param pool The pool + * @return Tag name, or NULL if no name is set. + */ +APR_DECLARE(const char *) apr_pool_get_tag(apr_pool_t *pool) + __attribute__((nonnull(1))); + +/* + * User data management + */ -/* XXX: these know about the definition of struct ap_table_t in alloc.c. That - * definition is not here because it is supposed to be private, and by not - * placing it here we are able to get compile-time diagnostics from modules - * written which assume that a ap_table_t is the same as an ap_array_header_t. -djg +/** + * Set the data associated with the current pool + * @param data The user data associated with the pool. + * @param key The key to use for association + * @param cleanup The cleanup program to use to cleanup the data (NULL if none) + * @param pool The current pool + * @warning The data to be attached to the pool should have a life span + * at least as long as the pool it is being attached to. + * + * Users of APR must take EXTREME care when choosing a key to + * use for their data. It is possible to accidentally overwrite + * data by choosing a key that another part of the program is using. + * Therefore it is advised that steps are taken to ensure that unique + * keys are used for all of the userdata objects in a particular pool + * (the same key in two different pools or a pool and one of its + * subpools is okay) at all times. Careful namespace prefixing of + * key names is a typical way to help ensure this uniqueness. + * + */ +APR_DECLARE(apr_status_t) apr_pool_userdata_set(const void *data, + const char *key, + apr_status_t (*cleanup)(void *), + apr_pool_t *pool) + __attribute__((nonnull(2,4))); + +/** + * Set the data associated with the current pool + * @param data The user data associated with the pool. + * @param key The key to use for association + * @param cleanup The cleanup program to use to cleanup the data (NULL if none) + * @param pool The current pool + * @note same as apr_pool_userdata_set(), except that this version doesn't + * make a copy of the key (this function is useful, for example, when + * the key is a string literal) + * @warning This should NOT be used if the key could change addresses by + * any means between the apr_pool_userdata_setn() call and a + * subsequent apr_pool_userdata_get() on that key, such as if a + * static string is used as a userdata key in a DSO and the DSO could + * be unloaded and reloaded between the _setn() and the _get(). You + * MUST use apr_pool_userdata_set() in such cases. + * @warning More generally, the key and the data to be attached to the + * pool should have a life span at least as long as the pool itself. + * */ -#define ap_table_elts(t) ((ap_array_header_t *)(t)) -#define ap_is_empty_table(t) (((t) == NULL)||(((ap_array_header_t *)(t))->nelts == 0)) +APR_DECLARE(apr_status_t) apr_pool_userdata_setn( + const void *data, const char *key, + apr_status_t (*cleanup)(void *), + apr_pool_t *pool) + __attribute__((nonnull(2,4))); + +/** + * Return the data associated with the current pool. + * @param data The user data associated with the pool. + * @param key The key for the data to retrieve + * @param pool The current pool. + */ +APR_DECLARE(apr_status_t) apr_pool_userdata_get(void **data, const char *key, + apr_pool_t *pool) + __attribute__((nonnull(1,2,3))); -/* magic numbers --- min free bytes to consider a free ap_pool_t block useable, - * and the min amount to allocate if we have to go to malloc() */ -#ifndef BLOCK_MINFREE -#define BLOCK_MINFREE 4096 +/** + * @defgroup PoolCleanup Pool Cleanup Functions + * + * Cleanups are performed in the reverse order they were registered. That is: + * Last In, First Out. A cleanup function can safely allocate memory from + * the pool that is being cleaned up. It can also safely register additional + * cleanups which will be run LIFO, directly after the current cleanup + * terminates. Cleanups have to take caution in calling functions that + * create subpools. Subpools, created during cleanup will NOT automatically + * be cleaned up. In other words, cleanups are to clean up after themselves. + * + * @{ + */ + +/** + * Register a function to be called when a pool is cleared or destroyed + * @param p The pool to register the cleanup with + * @param data The data to pass to the cleanup function. + * @param plain_cleanup The function to call when the pool is cleared + * or destroyed + * @param child_cleanup The function to call when a child process is about + * to exec - this function is called in the child, obviously! + */ +APR_DECLARE(void) apr_pool_cleanup_register( + apr_pool_t *p, const void *data, + apr_status_t (*plain_cleanup)(void *), + apr_status_t (*child_cleanup)(void *)) + __attribute__((nonnull(3,4))); + +/** + * Register a function to be called when a pool is cleared or destroyed. + * + * Unlike apr_pool_cleanup_register which registers a cleanup + * that is called AFTER all subpools are destroyed, this function registers + * a function that will be called before any of the subpools are destroyed. + * + * @param p The pool to register the cleanup with + * @param data The data to pass to the cleanup function. + * @param plain_cleanup The function to call when the pool is cleared + * or destroyed + */ +APR_DECLARE(void) apr_pool_pre_cleanup_register( + apr_pool_t *p, const void *data, + apr_status_t (*plain_cleanup)(void *)) + __attribute__((nonnull(3))); + +/** + * Remove a previously registered cleanup function. + * + * The cleanup most recently registered with @a p having the same values of + * @a data and @a cleanup will be removed. + * + * @param p The pool to remove the cleanup from + * @param data The data of the registered cleanup + * @param cleanup The function to remove from cleanup + * @remarks For some strange reason only the plain_cleanup is handled by this + * function + */ +APR_DECLARE(void) apr_pool_cleanup_kill(apr_pool_t *p, const void *data, + apr_status_t (*cleanup)(void *)) + __attribute__((nonnull(3))); + +/** + * Replace the child cleanup function of a previously registered cleanup. + * + * The cleanup most recently registered with @a p having the same values of + * @a data and @a plain_cleanup will have the registered child cleanup + * function replaced with @a child_cleanup. + * + * @param p The pool of the registered cleanup + * @param data The data of the registered cleanup + * @param plain_cleanup The plain cleanup function of the registered cleanup + * @param child_cleanup The function to register as the child cleanup + */ +APR_DECLARE(void) apr_pool_child_cleanup_set( + apr_pool_t *p, const void *data, + apr_status_t (*plain_cleanup)(void *), + apr_status_t (*child_cleanup)(void *)) + __attribute__((nonnull(3,4))); + +/** + * Run the specified cleanup function immediately and unregister it. + * + * The cleanup most recently registered with @a p having the same values of + * @a data and @a cleanup will be removed and @a cleanup will be called + * with @a data as the argument. + * + * @param p The pool to remove the cleanup from + * @param data The data to remove from cleanup + * @param cleanup The function to remove from cleanup + */ +APR_DECLARE(apr_status_t) apr_pool_cleanup_run(apr_pool_t *p, void *data, + apr_status_t (*cleanup)(void *)) + __attribute__((nonnull(3))); + +/** + * An empty cleanup function. + * + * Passed to apr_pool_cleanup_register() when no cleanup is required. + * + * @param data The data to cleanup, will not be used by this function. + */ +APR_DECLARE_NONSTD(apr_status_t) apr_pool_cleanup_null(void *data); + +/** + * Run all registered child cleanups, in preparation for an exec() + * call in a forked child -- close files, etc., but *don't* flush I/O + * buffers, *don't* wait for subprocesses, and *don't* free any + * memory. + */ +APR_DECLARE(void) apr_pool_cleanup_for_exec(void); + +/** @} */ + +/** + * @defgroup PoolDebug Pool Debugging functions. + * + * pools have nested lifetimes -- sub_pools are destroyed when the + * parent pool is cleared. We allow certain liberties with operations + * on things such as tables (and on other structures in a more general + * sense) where we allow the caller to insert values into a table which + * were not allocated from the table's pool. The table's data will + * remain valid as long as all the pools from which its values are + * allocated remain valid. + * + * For example, if B is a sub pool of A, and you build a table T in + * pool B, then it's safe to insert data allocated in A or B into T + * (because B lives at most as long as A does, and T is destroyed when + * B is cleared/destroyed). On the other hand, if S is a table in + * pool A, it is safe to insert data allocated in A into S, but it + * is *not safe* to insert data allocated from B into S... because + * B can be cleared/destroyed before A is (which would leave dangling + * pointers in T's data structures). + * + * In general we say that it is safe to insert data into a table T + * if the data is allocated in any ancestor of T's pool. This is the + * basis on which the APR_POOL_DEBUG code works -- it tests these ancestor + * relationships for all data inserted into tables. APR_POOL_DEBUG also + * provides tools (apr_pool_find, and apr_pool_is_ancestor) for other + * folks to implement similar restrictions for their own data + * structures. + * + * However, sometimes this ancestor requirement is inconvenient -- + * sometimes it's necessary to create a sub pool where the sub pool is + * guaranteed to have the same lifetime as the parent pool. This is a + * guarantee implemented by the *caller*, not by the pool code. That + * is, the caller guarantees they won't destroy the sub pool + * individually prior to destroying the parent pool. + * + * In this case the caller must call apr_pool_join() to indicate this + * guarantee to the APR_POOL_DEBUG code. + * + * These functions are only implemented when #APR_POOL_DEBUG is set. + * + * @{ + */ +#if APR_POOL_DEBUG || defined(DOXYGEN) +/** + * Guarantee that a subpool has the same lifetime as the parent. + * @param p The parent pool + * @param sub The subpool + */ +APR_DECLARE(void) apr_pool_join(apr_pool_t *p, apr_pool_t *sub) + __attribute__((nonnull(2))); + +/** + * Guarantee that a pool is only used by the current thread. + * This should be used when a pool is created by a different thread than + * the thread it is using, or if there is some locking in use to ensure + * that only one thread uses the pool at the same time. + * + * @param pool The pool + * @param flags Flags, currently unused + */ +APR_DECLARE(void) apr_pool_owner_set(apr_pool_t *pool, apr_uint32_t flags); + +/** + * Find a pool from something allocated in it. + * @param mem The thing allocated in the pool + * @return The pool it is allocated in + */ +APR_DECLARE(apr_pool_t *) apr_pool_find(const void *mem); + +/** + * Report the number of bytes currently in the pool + * @param p The pool to inspect + * @param recurse Recurse/include the subpools' sizes + * @return The number of bytes + */ +APR_DECLARE(apr_size_t) apr_pool_num_bytes(apr_pool_t *p, int recurse) + __attribute__((nonnull(1))); + +/** + * Lock a pool + * @param pool The pool to lock + * @param flag The flag + */ +APR_DECLARE(void) apr_pool_lock(apr_pool_t *pool, int flag); + +/* @} */ + +#else /* APR_POOL_DEBUG or DOXYGEN */ + +#ifdef apr_pool_join +#undef apr_pool_join +#endif +#define apr_pool_join(a,b) + +#ifdef apr_pool_owner_set +#undef apr_pool_owner_set #endif -#ifndef BLOCK_MINALLOC -#define BLOCK_MINALLOC 8192 +#define apr_pool_owner_set(a,b) + +#ifdef apr_pool_lock +#undef apr_pool_lock #endif +#define apr_pool_lock(pool, lock) -/* Finally, some accounting */ +#endif /* APR_POOL_DEBUG or DOXYGEN */ -API_EXPORT(long) ap_bytes_in_pool(ap_pool_t *p); -API_EXPORT(long) ap_bytes_in_free_blocks(void); +/** @} */ #ifdef __cplusplus } #endif -#endif /* !ap_POOLS_H */ +#endif /* !APR_POOLS_H */ diff --git a/include/apr_portable.h b/include/apr_portable.h index dca3d43dd25..7bb7a3568e2 100644 --- a/include/apr_portable.h +++ b/include/apr_portable.h @@ -1,75 +1,41 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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. */ /* This header file is where you should put ANY platform specific information. * This should be the only header file that programs need to include that - * actually has platform dependant code which refers to the . + * actually has platform dependent code which refers to the . */ #ifndef APR_PORTABLE_H #define APR_PORTABLE_H +/** + * @file apr_portable.h + * @brief APR Portability Routines + */ -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -#include "apr_general.h" +#include "apr.h" +#include "apr_pools.h" #include "apr_thread_proc.h" #include "apr_file_io.h" #include "apr_network_io.h" #include "apr_errno.h" -#include "apr_lock.h" +#include "apr_global_mutex.h" +#include "apr_proc_mutex.h" #include "apr_time.h" +#include "apr_dso.h" +#include "apr_shm.h" #if APR_HAVE_DIRENT_H #include <dirent.h> @@ -80,362 +46,494 @@ extern "C" { #if APR_HAVE_PTHREAD_H #include <pthread.h> #endif -#if APR_HAVE_UNION_SEMUN -#include <sys/sem.h> +#if APR_HAVE_SEMAPHORE_H +#include <semaphore.h> #endif +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup apr_portabile Portability Routines + * @ingroup APR + * @{ + */ + #ifdef WIN32 /* The primitives for Windows types */ -typedef HANDLE ap_os_file_t; -typedef HANDLE ap_os_dir_t; -typedef SOCKET ap_os_sock_t; -typedef HANDLE ap_os_lock_t; -typedef HANDLE ap_os_thread_t; -typedef PROCESS_INFORMATION ap_os_proc_t; -typedef DWORD ap_os_threadkey_t; -typedef FILETIME ap_os_imp_time_t; -typedef SYSTEMTIME ap_os_exp_time_t; +typedef HANDLE apr_os_file_t; +typedef HANDLE apr_os_dir_t; +typedef SOCKET apr_os_sock_t; +typedef HANDLE apr_os_proc_mutex_t; +typedef HANDLE apr_os_thread_t; +typedef HANDLE apr_os_proc_t; +typedef DWORD apr_os_threadkey_t; +typedef FILETIME apr_os_imp_time_t; +typedef SYSTEMTIME apr_os_exp_time_t; +typedef HANDLE apr_os_dso_handle_t; +typedef HANDLE apr_os_shm_t; #elif defined(OS2) -#define INCL_DOS -#include <os2.h> -typedef HFILE ap_os_file_t; -typedef HDIR ap_os_dir_t; -typedef int ap_os_sock_t; -typedef HMTX ap_os_lock_t; -typedef TID ap_os_thread_t; -typedef PID ap_os_proc_t; -typedef PULONG ap_os_threadkey_t; -typedef struct timeval ap_os_imp_time_t; -typedef struct tm ap_os_exp_time_t; - -#elif defined(BEOS) +typedef HFILE apr_os_file_t; +typedef HDIR apr_os_dir_t; +typedef int apr_os_sock_t; +typedef HMTX apr_os_proc_mutex_t; +typedef TID apr_os_thread_t; +typedef PID apr_os_proc_t; +typedef PULONG apr_os_threadkey_t; +typedef struct timeval apr_os_imp_time_t; +typedef struct tm apr_os_exp_time_t; +typedef HMODULE apr_os_dso_handle_t; +typedef void* apr_os_shm_t; + +#elif defined(__BEOS__) #include <kernel/OS.h> +#include <kernel/image.h> -struct ap_os_lock_t { - /* Inter proc */ - sem_id sem_interproc; - int32 ben_interproc; - /* Intra Proc */ - sem_id sem_intraproc; - int32 ben_intraproc; +struct apr_os_proc_mutex_t { + sem_id sem; + int32 ben; }; -typedef int ap_os_file_t; -typedef DIR ap_os_dir_t; -typedef int ap_os_sock_t; -typedef struct ap_os_lock_t ap_os_lock_t; -typedef thread_id ap_os_thread_t; -typedef thread_id ap_os_proc_t; -typedef int ap_os_threadkey_t; -typedef struct timeval ap_os_imp_time_t; -typedef struct tm ap_os_exp_time_t; +typedef int apr_os_file_t; +typedef DIR apr_os_dir_t; +typedef int apr_os_sock_t; +typedef struct apr_os_proc_mutex_t apr_os_proc_mutex_t; +typedef thread_id apr_os_thread_t; +typedef thread_id apr_os_proc_t; +typedef int apr_os_threadkey_t; +typedef struct timeval apr_os_imp_time_t; +typedef struct tm apr_os_exp_time_t; +typedef image_id apr_os_dso_handle_t; +typedef void* apr_os_shm_t; + +#elif defined(NETWARE) +typedef int apr_os_file_t; +typedef DIR apr_os_dir_t; +typedef int apr_os_sock_t; +typedef NXMutex_t * apr_os_proc_mutex_t; +typedef NXThreadId_t apr_os_thread_t; +typedef long apr_os_proc_t; +typedef NXKey_t apr_os_threadkey_t; +typedef struct timeval apr_os_imp_time_t; +typedef struct tm apr_os_exp_time_t; +typedef void * apr_os_dso_handle_t; +typedef void* apr_os_shm_t; #else /* Any other OS should go above this one. This is the lowest common * denominator typedefs for all UNIX-like systems. :) */ -#ifdef NEED_UNION_SEMUN -/* it makes no sense, but this isn't defined on solaris */ -union semun { - long val; - struct semid_ds *buf; - ushort *array; -}; -#endif - -struct ap_os_lock_t { -#if APR_USE_SYSVSEM_SERIALIZE - int crossproc; -#elif APR_USE_FCNTL_SERIALIZE +/** Basic OS process mutex structure. */ +struct apr_os_proc_mutex_t { +#if APR_HAS_SYSVSEM_SERIALIZE || APR_HAS_FCNTL_SERIALIZE || APR_HAS_FLOCK_SERIALIZE + /** Value used for SYS V Semaphore, FCNTL and FLOCK serialization */ int crossproc; -#elif APR_USE_PROC_PTHREAD_SERIALIZE - pthread_mutex_t *crossproc; -#elif APR_USE_FLOCK_SERIALIZE - int crossproc; -#else - /* No Interprocess serialization, too bad. */ #endif -#if APR_HAS_THREADS - /* If no threads, no need for thread locks */ -#if APR_USE_PTHREAD_SERIALIZE - pthread_mutex_t *intraproc; +#if APR_HAS_PROC_PTHREAD_SERIALIZE + /** Value used for PTHREAD serialization */ + pthread_mutex_t *pthread_interproc; #endif +#if APR_HAS_POSIXSEM_SERIALIZE + /** Value used for POSIX semaphores serialization */ + sem_t *psem_interproc; #endif }; -typedef int ap_os_file_t; -typedef DIR ap_os_dir_t; -typedef int ap_os_sock_t; -typedef struct ap_os_lock_t ap_os_lock_t; +typedef int apr_os_file_t; /**< native file */ +typedef DIR apr_os_dir_t; /**< native dir */ +typedef int apr_os_sock_t; /**< native dir */ +typedef struct apr_os_proc_mutex_t apr_os_proc_mutex_t; /**< native process + * mutex + */ #if APR_HAS_THREADS && APR_HAVE_PTHREAD_H -typedef pthread_t ap_os_thread_t; -typedef pthread_key_t ap_os_threadkey_t; +typedef pthread_t apr_os_thread_t; /**< native thread */ +typedef pthread_key_t apr_os_threadkey_t; /**< native thread address + * space */ #endif -typedef pid_t ap_os_proc_t; -typedef struct timeval ap_os_imp_time_t; -typedef struct tm ap_os_exp_time_t; +typedef pid_t apr_os_proc_t; /**< native pid */ +typedef struct timeval apr_os_imp_time_t; /**< native timeval */ +typedef struct tm apr_os_exp_time_t; /**< native tm */ +/** @var apr_os_dso_handle_t + * native dso types + */ +#if defined(HPUX) || defined(HPUX10) || defined(HPUX11) +#include <dl.h> +typedef shl_t apr_os_dso_handle_t; +#elif defined(DARWIN) +#include <mach-o/dyld.h> +typedef NSModule apr_os_dso_handle_t; +#else +typedef void * apr_os_dso_handle_t; #endif +typedef void* apr_os_shm_t; /**< native SHM */ -/* - -=head1 ap_status_t ap_get_os_file(ap_os_file_t *thefile, ap_file_t *file) - -B<convert the file from apr type to os specific type.> - - arg 1) The os specific file we are converting to - arg 2) The apr file to convert. - -B<NOTE>: On Unix, it is only possible to get a file descriptor from - an apr file type. +#endif -=cut +/** + * @typedef apr_os_sock_info_t + * @brief alias for local OS socket */ -ap_status_t ap_get_os_file(ap_os_file_t *thefile, ap_file_t *file); - -/* - -=head1 ap_status_t ap_get_os_dir(ap_os_dir_t **thedir, ap_dir_t *dir) - -B<convert the dir from apr type to os specific type.> - - arg 1) The os specific dir we are converting to - arg 2) The apr dir to convert. - -=cut - */ -ap_status_t ap_get_os_dir(ap_os_dir_t **thedir, ap_dir_t *dir); - -/* - -=head1 ap_status_t ap_get_os_sock(ap_os_sock_t *thesock, ap_socket_t *sock) - -B<Convert the socket from an apr type to an OS specific socket> - - arg 1) The socket to convert. - arg 2) The os specifc equivelant of the apr socket.. - -=cut +/** + * everything APR needs to know about an active socket to construct + * an APR socket from it; currently, this is platform-independent */ -ap_status_t ap_get_os_sock(ap_os_sock_t *thesock, ap_socket_t *sock); +struct apr_os_sock_info_t { + apr_os_sock_t *os_sock; /**< always required */ + struct sockaddr *local; /**< NULL if not yet bound */ + struct sockaddr *remote; /**< NULL if not connected */ + int family; /**< always required (APR_INET, APR_INET6, etc.) */ + int type; /**< always required (SOCK_STREAM, SOCK_DGRAM, etc.) */ + int protocol; /**< 0 or actual protocol (APR_PROTO_SCTP, APR_PROTO_TCP, etc.) */ +}; -/* +typedef struct apr_os_sock_info_t apr_os_sock_info_t; -=head1 ap_status_t ap_get_os_lock(ap_os_lock_t *oslock, ap_lock_t *lock) +#if APR_PROC_MUTEX_IS_GLOBAL || defined(DOXYGEN) +/** Opaque global mutex type */ +#define apr_os_global_mutex_t apr_os_proc_mutex_t +/** @return apr_os_global_mutex */ +#define apr_os_global_mutex_get apr_os_proc_mutex_get +#else + /** Thread and process mutex for those platforms where process mutexes + * are not held in threads. + */ + struct apr_os_global_mutex_t { + apr_pool_t *pool; + apr_proc_mutex_t *proc_mutex; +#if APR_HAS_THREADS + apr_thread_mutex_t *thread_mutex; +#endif /* APR_HAS_THREADS */ + }; + typedef struct apr_os_global_mutex_t apr_os_global_mutex_t; -B<Convert the lock from os specific type to apr type> +APR_DECLARE(apr_status_t) apr_os_global_mutex_get(apr_os_global_mutex_t *ospmutex, + apr_global_mutex_t *pmutex); +#endif - arg 1) The os specific lock we are converting to. - arg 2) The apr lock to convert. -=cut +/** + * convert the file from apr type to os specific type. + * @param thefile The os specific file we are converting to + * @param file The apr file to convert. + * @remark On Unix, it is only possible to get a file descriptor from + * an apr file type. */ -ap_status_t ap_get_os_lock(ap_os_lock_t *oslock, ap_lock_t *lock); +APR_DECLARE(apr_status_t) apr_os_file_get(apr_os_file_t *thefile, + apr_file_t *file); -/* - -=head1 ap_status_t ap_get_os_proc(ap_os_proc_t *theproc, ap_proc_t *proc) - -B<convert the proc from os specific type to apr type.> - - arg 1) The os specific proc we are converting to - arg 2) The apr proc we are converting +/** + * convert the dir from apr type to os specific type. + * @param thedir The os specific dir we are converting to + * @param dir The apr dir to convert. + */ +APR_DECLARE(apr_status_t) apr_os_dir_get(apr_os_dir_t **thedir, + apr_dir_t *dir); -=cut +/** + * Convert the socket from an apr type to an OS specific socket + * @param thesock The socket to convert. + * @param sock The os specific equivalent of the apr socket.. */ -ap_status_t ap_get_os_proc(ap_os_proc_t *theproc, ap_proc_t *proc); - -/* - -=head1 ap_status_t ap_get_os_exp_time(ap_os_exp_time_t **ostime, ap_exploded_time_t *aprtime) - -B<Get the exploded time in the platforms native format.> - - arg 1) the native time format - arg 2) the time to convert +APR_DECLARE(apr_status_t) apr_os_sock_get(apr_os_sock_t *thesock, + apr_socket_t *sock); -=cut +/** + * Convert the proc mutex from apr type to os specific type + * @param ospmutex The os specific proc mutex we are converting to. + * @param pmutex The apr proc mutex to convert. */ -ap_status_t ap_get_os_exp_time(ap_os_exp_time_t **, ap_exploded_time_t *); - -/* - -=head1 ap_status_t ap_get_os_imp_time(ap_os_imp_time_t **ostime, ap_time_t *aprtime) - -B<Get the imploded time in the platforms native format.> - - arg 1) the native time format - arg 2) the time to convert - -=cut +APR_DECLARE(apr_status_t) apr_os_proc_mutex_get(apr_os_proc_mutex_t *ospmutex, + apr_proc_mutex_t *pmutex); + +/** + * Convert the proc mutex from apr type to os specific type, also + * providing the mechanism used by the apr mutex. + * @param ospmutex The os specific proc mutex we are converting to. + * @param pmutex The apr proc mutex to convert. + * @param mech The mechanism used by the apr proc mutex (if not NULL). + * @remark Allows for disambiguation for platforms with multiple mechanisms + * available. */ -ap_status_t ap_get_os_imp_time(ap_os_imp_time_t **, ap_time_t *); -#if APR_HAS_THREADS -/* - -=head1 ap_status_t ap_get_os_thread(ap_thread_t *thethd, ap_os_thread_t *thd) - -B<convert the thread to os specific type from apr type.> - - arg 1) The apr thread to convert - arg 2) The os specific thread we are converting to - -=cut +APR_DECLARE(apr_status_t) apr_os_proc_mutex_get_ex(apr_os_proc_mutex_t *ospmutex, + apr_proc_mutex_t *pmutex, + apr_lockmech_e *mech); + +/** + * Get the exploded time in the platforms native format. + * @param ostime the native time format + * @param aprtime the time to convert */ -ap_status_t ap_get_os_thread(ap_os_thread_t *thethd, ap_thread_t *thd); - -/* +APR_DECLARE(apr_status_t) apr_os_exp_time_get(apr_os_exp_time_t **ostime, + apr_time_exp_t *aprtime); -=head1 ap_status_t ap_get_os_threadkey(ap_threadkey_t *thekey, ap_os_threadkey_t *key) - -B<convert the thread private memory key to os specific type from an apr type.> - - arg 1) The apr handle we are converting from. - arg 2) The os specific handle we are converting to. - -=cut +/** + * Get the imploded time in the platforms native format. + * @param ostime the native time format + * @param aprtime the time to convert */ -ap_status_t ap_get_os_threadkey(ap_os_threadkey_t *thekey, ap_threadkey_t *key); -#endif +APR_DECLARE(apr_status_t) apr_os_imp_time_get(apr_os_imp_time_t **ostime, + apr_time_t *aprtime); -/* - -=head1 ap_status_t ap_put_os_file(ap_file_t **file, ap_os_file_t *thefile, ap_pool_t *cont) - -B<convert the file from os specific type to apr type.> - - arg 1) The apr file we are converting to. - arg 2) The os specific file to convert - arg 3) The pool to use if it is needed. - -B<NOTE>: On Unix, it is only possible to put a file descriptor into - an apr file type. +/** + * convert the shm from apr type to os specific type. + * @param osshm The os specific shm representation + * @param shm The apr shm to convert. + */ +APR_DECLARE(apr_status_t) apr_os_shm_get(apr_os_shm_t *osshm, + apr_shm_t *shm); -=cut +#if APR_HAS_THREADS || defined(DOXYGEN) +/** + * @defgroup apr_os_thread Thread portability Routines + * @{ */ -ap_status_t ap_put_os_file(ap_file_t **file, ap_os_file_t *thefile, - ap_pool_t *cont); - -/* - -=head1 ap_status_t ap_put_os_dir(ap_dir_t **dir, ap_os_dir_t *thedir, ap_pool_t *cont) - -B<convert the dir from os specific type to apr type.> - - arg 1) The apr dir we are converting to. - arg 2) The os specific dir to convert - arg 3) The pool to use when creating to apr directory. - -=cut +/** + * convert the thread to os specific type from apr type. + * @param thethd The apr thread to convert + * @param thd The os specific thread we are converting to */ -ap_status_t ap_put_os_dir(ap_dir_t **dir, ap_os_dir_t *thedir, - ap_pool_t *cont); - -/* - -=head1 ap_status_t ap_put_os_sock(ap_socket_t **sock, ap_os_socket_t *thesock, ap_pool_t *cont) +APR_DECLARE(apr_status_t) apr_os_thread_get(apr_os_thread_t **thethd, + apr_thread_t *thd); -B<Convert a socket from the os specific type to the apr type> - - arg 1) The pool to use. - arg 2) The socket to convert to. - arg 3) The socket we are converting to an apr type. - -=cut +/** + * convert the thread private memory key to os specific type from an apr type. + * @param thekey The apr handle we are converting from. + * @param key The os specific handle we are converting to. */ -ap_status_t ap_put_os_sock(ap_socket_t **sock, ap_os_sock_t *thesock, - ap_pool_t *cont); - -/* - -=head1 ap_status_t ap_put_os_lock(ap_lock_t **lock, ap_os_lock_t *, ap_pool_t *cont) - -B<Convert the lock from os specific type to apr type> - - arg 1) The apr lock we are converting to. - arg 2) The os specific lock to convert. - arg 3) The pool to use if it is needed. - -=cut +APR_DECLARE(apr_status_t) apr_os_threadkey_get(apr_os_threadkey_t *thekey, + apr_threadkey_t *key); + +/** + * convert the thread from os specific type to apr type. + * @param thd The apr thread we are converting to. + * @param thethd The os specific thread to convert + * @param cont The pool to use if it is needed. */ -ap_status_t ap_put_os_lock(ap_lock_t **lock, ap_os_lock_t *thelock, - ap_pool_t *cont); - -/* - -=head1 ap_status_t ap_put_os_proc(ap_proc_t *proc, ap_os_proc_t *theproc, ap_pool_t *cont) - -B<convert the proc from os specific type to apr type.> - - arg 1) The apr proc we are converting to. - arg 2) The os specific proc to convert - arg 3) The pool to use if it is needed. - -=cut +APR_DECLARE(apr_status_t) apr_os_thread_put(apr_thread_t **thd, + apr_os_thread_t *thethd, + apr_pool_t *cont); + +/** + * convert the thread private memory key from os specific type to apr type. + * @param key The apr handle we are converting to. + * @param thekey The os specific handle to convert + * @param cont The pool to use if it is needed. */ -ap_status_t ap_put_os_proc(ap_proc_t **proc, ap_os_proc_t *theproc, - ap_pool_t *cont); - -/* - -=head1 ap_status_t ap_put_os_imp_time(ap_time_t *aprtime, ap_os_imp_time_t **ostime, ap_pool_t, *cont) - -B<Put the imploded time in the APR format.> - - arg 1) the APR time format - arg 2) the time to convert - arg 3) the pool to use if necessary - -=cut +APR_DECLARE(apr_status_t) apr_os_threadkey_put(apr_threadkey_t **key, + apr_os_threadkey_t *thekey, + apr_pool_t *cont); +/** + * Get the thread ID */ -ap_status_t ap_put_os_imp_time(ap_time_t *, ap_os_imp_time_t **, ap_pool_t *); - -/* - -=head1 ap_status_t ap_put_os_exp_time(ap_exploded_time_t *aprtime, ap_os_exp_time_t **ostime, ap_pool_t, *cont) - -B<Put the exploded time in the APR format.> - - arg 1) the APR time format - arg 2) the time to convert - arg 3) the pool to use if necessary - -=cut +APR_DECLARE(apr_os_thread_t) apr_os_thread_current(void); + +/** + * Compare two thread id's + * @param tid1 1st Thread ID to compare + * @param tid2 2nd Thread ID to compare + * @return non-zero if the two threads are equal, zero otherwise + */ +APR_DECLARE(int) apr_os_thread_equal(apr_os_thread_t tid1, + apr_os_thread_t tid2); + +/** @} */ +#endif /* APR_HAS_THREADS */ + +/** + * convert the file from os specific type to apr type. + * @param file The apr file we are converting to. + * @param thefile The os specific file to convert + * @param flags The flags that were used to open this file. + * @param cont The pool to use if it is needed. + * @remark On Unix, it is only possible to put a file descriptor into + * an apr file type. + */ +APR_DECLARE(apr_status_t) apr_os_file_put(apr_file_t **file, + apr_os_file_t *thefile, + apr_int32_t flags, apr_pool_t *cont); + +/** + * convert the file from os specific type to apr type. + * @param file The apr file we are converting to. + * @param thefile The os specific pipe to convert + * @param cont The pool to use if it is needed. + * @remark On Unix, it is only possible to put a file descriptor into + * an apr file type. + */ +APR_DECLARE(apr_status_t) apr_os_pipe_put(apr_file_t **file, + apr_os_file_t *thefile, + apr_pool_t *cont); + +/** + * convert the file from os specific type to apr type. + * @param file The apr file we are converting to. + * @param thefile The os specific pipe to convert + * @param register_cleanup A cleanup will be registered on the apr_file_t + * to issue apr_file_close(). + * @param cont The pool to use if it is needed. + * @remark On Unix, it is only possible to put a file descriptor into + * an apr file type. + */ +APR_DECLARE(apr_status_t) apr_os_pipe_put_ex(apr_file_t **file, + apr_os_file_t *thefile, + int register_cleanup, + apr_pool_t *cont); + +/** + * convert the dir from os specific type to apr type. + * @param dir The apr dir we are converting to. + * @param thedir The os specific dir to convert + * @param cont The pool to use when creating to apr directory. + */ +APR_DECLARE(apr_status_t) apr_os_dir_put(apr_dir_t **dir, + apr_os_dir_t *thedir, + apr_pool_t *cont); + +/** + * Convert a socket from the os specific type to the APR type. If + * sock points to NULL, a socket will be created from the pool + * provided. If **sock does not point to NULL, the structure pointed + * to by sock will be reused and updated with the given socket. + * @param sock The pool to use. + * @param thesock The socket to convert to. + * @param cont The socket we are converting to an apr type. + * @remark If it is a true socket, it is best to call apr_os_sock_make() + * and provide APR with more information about the socket. */ -ap_status_t ap_put_os_exp_time(ap_exploded_time_t *, ap_os_exp_time_t **, ap_pool_t *); +APR_DECLARE(apr_status_t) apr_os_sock_put(apr_socket_t **sock, + apr_os_sock_t *thesock, + apr_pool_t *cont); + +/** + * Create a socket from an existing descriptor and local and remote + * socket addresses. + * @param apr_sock The new socket that has been set up + * @param os_sock_info The os representation of the socket handle and + * other characteristics of the socket + * @param cont The pool to use + * @remark If you only know the descriptor/handle or if it isn't really + * a true socket, use apr_os_sock_put() instead. + */ +APR_DECLARE(apr_status_t) apr_os_sock_make(apr_socket_t **apr_sock, + apr_os_sock_info_t *os_sock_info, + apr_pool_t *cont); + +/** + * Convert the proc mutex from os specific type to apr type + * @param pmutex The apr proc mutex we are converting to. + * @param ospmutex The os specific proc mutex to convert. + * @param cont The pool to use if it is needed. + */ +APR_DECLARE(apr_status_t) apr_os_proc_mutex_put(apr_proc_mutex_t **pmutex, + apr_os_proc_mutex_t *ospmutex, + apr_pool_t *cont); + +/** + * Convert the proc mutex from os specific type to apr type, using the + * specified mechanism. + * @param pmutex The apr proc mutex we are converting to. + * @param ospmutex The os specific proc mutex to convert. + * @param mech The apr mutex locking mechanism + * @param register_cleanup Whether to destroy the os mutex with the apr + * one (either on explicit destroy or pool cleanup). + * @param cont The pool to use if it is needed. + * @remark Allows for disambiguation for platforms with multiple mechanisms + * available. + */ +APR_DECLARE(apr_status_t) apr_os_proc_mutex_put_ex(apr_proc_mutex_t **pmutex, + apr_os_proc_mutex_t *ospmutex, + apr_lockmech_e mech, + int register_cleanup, + apr_pool_t *cont); + +/** + * Put the imploded time in the APR format. + * @param aprtime the APR time format + * @param ostime the time to convert + * @param cont the pool to use if necessary + */ +APR_DECLARE(apr_status_t) apr_os_imp_time_put(apr_time_t *aprtime, + apr_os_imp_time_t **ostime, + apr_pool_t *cont); + +/** + * Put the exploded time in the APR format. + * @param aprtime the APR time format + * @param ostime the time to convert + * @param cont the pool to use if necessary + */ +APR_DECLARE(apr_status_t) apr_os_exp_time_put(apr_time_exp_t *aprtime, + apr_os_exp_time_t **ostime, + apr_pool_t *cont); + +/** + * convert the shared memory from os specific type to apr type. + * @param shm The apr shm representation of osshm + * @param osshm The os specific shm identity + * @param cont The pool to use if it is needed. + * @remark On fork()ed architectures, this is typically nothing more than + * the memory block mapped. On non-fork architectures, this is typically + * some internal handle to pass the mapping from process to process. + */ +APR_DECLARE(apr_status_t) apr_os_shm_put(apr_shm_t **shm, + apr_os_shm_t *osshm, + apr_pool_t *cont); -#if APR_HAS_THREADS -/* -=head1 ap_status_t ap_put_os_thread(ap_thread_t *thd, ap_os_thread_t *thethd, ap_pool_t *cont) +#if APR_HAS_DSO || defined(DOXYGEN) +/** + * @defgroup apr_os_dso DSO (Dynamic Loading) Portability Routines + * @{ + */ +/** + * convert the dso handle from os specific to apr + * @param dso The apr handle we are converting to + * @param thedso the os specific handle to convert + * @param pool the pool to use if it is needed + */ +APR_DECLARE(apr_status_t) apr_os_dso_handle_put(apr_dso_handle_t **dso, + apr_os_dso_handle_t thedso, + apr_pool_t *pool); + +/** + * convert the apr dso handle into an os specific one + * @param aprdso The apr dso handle to convert + * @param dso The os specific dso to return + */ +APR_DECLARE(apr_status_t) apr_os_dso_handle_get(apr_os_dso_handle_t *dso, + apr_dso_handle_t *aprdso); -B<convert the thread from os specific type to apr type.> +/** @} */ +#endif /* APR_HAS_DSO */ - arg 1) The apr thread we are converting to. - arg 2) The os specific thread to convert - arg 3) The pool to use if it is needed. -=cut +#if APR_HAS_OS_UUID +/** + * Private: apr-util's apr_uuid module when supported by the platform */ -ap_status_t ap_put_os_thread(ap_thread_t **thd, ap_os_thread_t *thethd, - ap_pool_t *cont); - -/* +APR_DECLARE(apr_status_t) apr_os_uuid_get(unsigned char *uuid_data); +#endif -=head1 ap_status_t ap_put_os_threadkey(ap_threadkey_t *key, ap_os_threadkey_t *thekey, ap_pool_t *cont) -B<convert the thread private memory key from os specific type to apr type.> +/** + * Get the name of the system default character set. + * @param pool the pool to allocate the name from, if needed + */ +APR_DECLARE(const char*) apr_os_default_encoding(apr_pool_t *pool); - arg 1) The apr handle we are converting to. - arg 2) The os specific handle to convert - arg 3) The pool to use if it is needed. -=cut +/** + * Get the name of the current locale character set. + * @param pool the pool to allocate the name from, if needed + * @remark Defers to apr_os_default_encoding if the current locale's + * data can't be retrieved on this system. */ -ap_status_t ap_put_os_threadkey(ap_threadkey_t **key, ap_os_threadkey_t *thekey, - ap_pool_t *cont); -#endif +APR_DECLARE(const char*) apr_os_locale_encoding(apr_pool_t *pool); + +/** @} */ #ifdef __cplusplus } diff --git a/include/apr_private.hw b/include/apr_private.hw deleted file mode 100644 index d3015e35862..00000000000 --- a/include/apr_private.hw +++ /dev/null @@ -1,158 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -/* - * Note: - * This is the windows specific autoconf like config file - * which is used to generate apr_private.h at build time. - * Do not put any code into this file which depends on - * APR include files. - */ - -#ifdef WIN32 - -#ifndef APR_CONFIG_H -#define APR_CONFIG_H - -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif -#ifndef _WIN32_WINNT -/* - * Compile the server including all the Windows NT 4.0 header files by - * default. - */ -#define _WIN32_WINNT 0x0400 -#endif -#include <windows.h> -#include <winsock2.h> -#include <mswsock.h> -#include <sys/types.h> -#include <stddef.h> -#include <stdio.h> -#include <time.h> - -#define HAVE_SENDFILE 1 - -/* Use this section to define all of the HAVE_FOO_H - * that are required to build properly. - */ -#define HAVE_CONIO_H 1 -#define HAVE_MALLOC_H 1 -#define HAVE_STDLIB_H 1 -#define HAVE_LIMITS_H 1 -#define HAVE_SIGNAL_H 1 - -#define SIGHUP 1 -/* 2 is used for SIGINT on windows */ -#define SIGQUIT 3 -/* 4 is used for SIGILL on windows */ -#define SIGTRAP 5 -#define SIGIOT 6 -#define SIGBUS 7 -/* 8 is used for SIGFPE on windows */ -#define SIGKILL 9 -#define SIGUSR1 10 -/* 11 is used for SIGSEGV on windows */ -#define SIGUSR2 12 -#define SIGPIPE 13 -#define SIGALRM 14 -/* 15 is used for SIGTERM on windows */ -#define SIGSTKFLT 16 -#define SIGCHLD 17 -#define SIGCONT 18 -#define SIGSTOP 19 -#define SIGTSTP 20 -/* 21 is used for SIGBREAK on windows */ -/* 22 is used for SIGABRT on windows */ -#define SIGTTIN 23 -#define SIGTTOU 24 -#define SIGURG 25 -#define SIGXCPU 26 -#define SIGXFSZ 27 -#define SIGVTALRM 28 -#define SIGPROF 29 -#define SIGWINCH 30 -#define SIGIO 31 - -#define __attribute__(__x) - -/* APR COMPATABILITY FUNCTIONS - * This section should be used to define functions and - * macros which are need to make Windows features look - * like POSIX features. - */ -typedef void (Sigfunc)(int); - -#define strcasecmp(s1, s2) stricmp(s1, s2) -#define sleep(t) Sleep(t * 1000) - - -/* APR FEATURE MACROS. - * This section should be used to define feature macros - * that the windows port needs. - */ -#define APR_HAS_THREADS 1 - -#define SIZEOF_SHORT 2 -#define SIZEOF_INT 4 -#define SIZEOF_LONGLONG 8 -#define SIZEOF_CHAR 1 -#define SIZEOF_SSIZE_T SIZEOF_INT - -unsigned __stdcall SignalHandling(void *); -int thread_ready(void); - -#endif /*APR_CONFIG_H*/ -#endif /*WIN32*/ diff --git a/include/apr_proc_mutex.h b/include/apr_proc_mutex.h new file mode 100644 index 00000000000..418c95048a7 --- /dev/null +++ b/include/apr_proc_mutex.h @@ -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. + */ + +#ifndef APR_PROC_MUTEX_H +#define APR_PROC_MUTEX_H + +/** + * @file apr_proc_mutex.h + * @brief APR Process Locking Routines + */ + +#include "apr.h" +#include "apr_pools.h" +#include "apr_errno.h" +#include "apr_perms_set.h" +#include "apr_time.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup apr_proc_mutex Process Locking Routines + * @ingroup APR + * @{ + */ + +/** + * Enumerated potential types for APR process locking methods + * @warning Check APR_HAS_foo_SERIALIZE defines to see if the platform supports + * APR_LOCK_foo. Only APR_LOCK_DEFAULT is portable. + */ +typedef enum { + APR_LOCK_FCNTL, /**< fcntl() */ + APR_LOCK_FLOCK, /**< flock() */ + APR_LOCK_SYSVSEM, /**< System V Semaphores */ + APR_LOCK_PROC_PTHREAD, /**< POSIX pthread process-based locking */ + APR_LOCK_POSIXSEM, /**< POSIX semaphore process-based locking */ + APR_LOCK_DEFAULT, /**< Use the default process lock */ + APR_LOCK_DEFAULT_TIMED /**< Use the default process timed lock */ +} apr_lockmech_e; + +/** Opaque structure representing a process mutex. */ +typedef struct apr_proc_mutex_t apr_proc_mutex_t; + +/* Function definitions */ + +/** + * Create and initialize a mutex that can be used to synchronize processes. + * @param mutex the memory address where the newly created mutex will be + * stored. + * @param fname A file name to use if the lock mechanism requires one. This + * argument should always be provided. The lock code itself will + * determine if it should be used. + * @param mech The mechanism to use for the interprocess lock, if any; one of + * <PRE> + * APR_LOCK_FCNTL + * APR_LOCK_FLOCK + * APR_LOCK_SYSVSEM + * APR_LOCK_POSIXSEM + * APR_LOCK_PROC_PTHREAD + * APR_LOCK_DEFAULT pick the default mechanism for the platform + * </PRE> + * @param pool the pool from which to allocate the mutex. + * @see apr_lockmech_e + * @warning Check APR_HAS_foo_SERIALIZE defines to see if the platform supports + * APR_LOCK_foo. Only APR_LOCK_DEFAULT is portable. + */ +APR_DECLARE(apr_status_t) apr_proc_mutex_create(apr_proc_mutex_t **mutex, + const char *fname, + apr_lockmech_e mech, + apr_pool_t *pool); + +/** + * Re-open a mutex in a child process. + * @param mutex The newly re-opened mutex structure. + * @param fname A file name to use if the mutex mechanism requires one. This + * argument should always be provided. The mutex code itself will + * determine if it should be used. This filename should be the + * same one that was passed to apr_proc_mutex_create(). + * @param pool The pool to operate on. + * @remark This function must be called to maintain portability, even + * if the underlying lock mechanism does not require it. + */ +APR_DECLARE(apr_status_t) apr_proc_mutex_child_init(apr_proc_mutex_t **mutex, + const char *fname, + apr_pool_t *pool); + +/** + * Acquire the lock for the given mutex. If the mutex is already locked, + * the current thread will be put to sleep until the lock becomes available. + * @param mutex the mutex on which to acquire the lock. + */ +APR_DECLARE(apr_status_t) apr_proc_mutex_lock(apr_proc_mutex_t *mutex); + +/** + * Attempt to acquire the lock for the given mutex. If the mutex has already + * been acquired, the call returns immediately with APR_EBUSY. Note: it + * is important that the APR_STATUS_IS_EBUSY(s) macro be used to determine + * if the return value was APR_EBUSY, for portability reasons. + * @param mutex the mutex on which to attempt the lock acquiring. + */ +APR_DECLARE(apr_status_t) apr_proc_mutex_trylock(apr_proc_mutex_t *mutex); + +/** + * Attempt to acquire the lock for the given mutex until timeout expires. + * If the acquisition time outs, the call returns with APR_TIMEUP. + * @param mutex the mutex on which to attempt the lock acquiring. + * @param timeout the relative timeout (microseconds). + * @note A negative or nul timeout means immediate attempt, returning + * APR_TIMEUP without blocking if it the lock is already acquired. + */ +APR_DECLARE(apr_status_t) apr_proc_mutex_timedlock(apr_proc_mutex_t *mutex, + apr_interval_time_t timeout); + +/** + * Release the lock for the given mutex. + * @param mutex the mutex from which to release the lock. + */ +APR_DECLARE(apr_status_t) apr_proc_mutex_unlock(apr_proc_mutex_t *mutex); + +/** + * Destroy the mutex and free the memory associated with the lock. + * @param mutex the mutex to destroy. + */ +APR_DECLARE(apr_status_t) apr_proc_mutex_destroy(apr_proc_mutex_t *mutex); + +/** + * Destroy the mutex and free the memory associated with the lock. + * @param mutex the mutex to destroy. + * @note This function is generally used to kill a cleanup on an already + * created mutex + */ +APR_DECLARE(apr_status_t) apr_proc_mutex_cleanup(void *mutex); + +/** + * Return the name of the lockfile for the mutex, or NULL + * if the mutex doesn't use a lock file + */ + +APR_DECLARE(const char *) apr_proc_mutex_lockfile(apr_proc_mutex_t *mutex); + +/** + * Get the mechanism of the mutex, as it relates to the actual method + * used for the underlying apr_proc_mutex_t. + * @param mutex the mutex to get the mechanism from. + */ +APR_DECLARE(apr_lockmech_e) apr_proc_mutex_mech(apr_proc_mutex_t *mutex); + +/** + * Get the mechanism's name of the mutex, as it relates to the actual method + * used for the underlying apr_proc_mutex_t. + * @param mutex the mutex to get the mechanism's name from. + */ +APR_DECLARE(const char *) apr_proc_mutex_name(apr_proc_mutex_t *mutex); + +/** + * Display the name of the default mutex: APR_LOCK_DEFAULT + */ +APR_DECLARE(const char *) apr_proc_mutex_defname(void); + +/** + * Set mutex permissions. + */ +APR_PERMS_SET_IMPLEMENT(proc_mutex); + +/** + * Get the pool used by this proc_mutex. + * @return apr_pool_t the pool + */ +APR_POOL_DECLARE_ACCESSOR(proc_mutex); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* ! APR_PROC_MUTEX_H */ diff --git a/include/apr_queue.h b/include/apr_queue.h new file mode 100644 index 00000000000..e345da5d453 --- /dev/null +++ b/include/apr_queue.h @@ -0,0 +1,171 @@ +/* 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. + */ + +#ifndef APR_QUEUE_H +#define APR_QUEUE_H + +/** + * @file apr_queue.h + * @brief Thread Safe FIFO bounded queue + * @note Since most implementations of the queue are backed by a condition + * variable implementation, it isn't available on systems without threads. + * Although condition variables are sometimes available without threads. + */ + +#include "apu.h" +#include "apr_errno.h" +#include "apr_pools.h" +#include "apr_time.h" + +#if APR_HAS_THREADS + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup APR_Util_FIFO Thread Safe FIFO bounded queue + * @ingroup APR + * @{ + */ + +/** + * opaque structure + */ +typedef struct apr_queue_t apr_queue_t; + +/** + * create a FIFO queue + * @param queue The new queue + * @param queue_capacity maximum size of the queue + * @param a pool to allocate queue from + */ +APR_DECLARE(apr_status_t) apr_queue_create(apr_queue_t **queue, + unsigned int queue_capacity, + apr_pool_t *a); + +/** + * push/add an object to the queue, blocking if the queue is already full + * + * @param queue the queue + * @param data the data + * @returns APR_EINTR the blocking was interrupted (try again) + * @returns APR_EOF the queue has been terminated + * @returns APR_SUCCESS on a successful push + */ +APR_DECLARE(apr_status_t) apr_queue_push(apr_queue_t *queue, void *data); + +/** + * pop/get an object from the queue, blocking if the queue is already empty + * + * @param queue the queue + * @param data the data + * @returns APR_EINTR the blocking was interrupted (try again) + * @returns APR_EOF if the queue has been terminated + * @returns APR_SUCCESS on a successful pop + */ +APR_DECLARE(apr_status_t) apr_queue_pop(apr_queue_t *queue, void **data); + +/** + * push/add an object to the queue, returning immediately if the queue is full + * + * @param queue the queue + * @param data the data + * @returns APR_EINTR the blocking operation was interrupted (try again) + * @returns APR_EAGAIN the queue is full + * @returns APR_EOF the queue has been terminated + * @returns APR_SUCCESS on a successful push + */ +APR_DECLARE(apr_status_t) apr_queue_trypush(apr_queue_t *queue, void *data); + +/** + * pop/get an object from the queue, returning immediately if the queue is empty + * + * @param queue the queue + * @param data the data + * @returns APR_EINTR the blocking operation was interrupted (try again) + * @returns APR_EAGAIN the queue is empty + * @returns APR_EOF the queue has been terminated + * @returns APR_SUCCESS on a successful pop + */ +APR_DECLARE(apr_status_t) apr_queue_trypop(apr_queue_t *queue, void **data); + +/** + * push/add an object to the queue, waiting a maximum of timeout microseconds + * before returning if the queue is empty + * + * @param queue the queue + * @param data the data + * @param timeout the timeout + * @returns APR_EINTR the blocking operation was interrupted (try again) + * @returns APR_EAGAIN the queue is empty and timeout is 0 + * @returns APR_TIMEUP the queue is empty and the timeout expired + * @returns APR_EOF the queue has been terminated + * @returns APR_SUCCESS on a successful pop + */ +APR_DECLARE(apr_status_t) apr_queue_timedpush(apr_queue_t *queue, void *data, + apr_interval_time_t timeout); + +/** + * pop/get an object from the queue, waiting a maximum of timeout microseconds + * before returning if the queue is empty + * + * @param queue the queue + * @param data the data + * @param timeout the timeout + * @returns APR_EINTR the blocking operation was interrupted (try again) + * @returns APR_EAGAIN the queue is empty and timeout is 0 + * @returns APR_TIMEUP the queue is empty and the timeout expired + * @returns APR_EOF the queue has been terminated + * @returns APR_SUCCESS on a successful pop + */ +APR_DECLARE(apr_status_t) apr_queue_timedpop(apr_queue_t *queue, void **data, + apr_interval_time_t timeout); + +/** + * returns the size of the queue. + * + * @warning this is not threadsafe, and is intended for reporting/monitoring + * of the queue. + * @param queue the queue + * @returns the size of the queue + */ +APR_DECLARE(unsigned int) apr_queue_size(apr_queue_t *queue); + +/** + * interrupt all the threads blocking on this queue. + * + * @param queue the queue + */ +APR_DECLARE(apr_status_t) apr_queue_interrupt_all(apr_queue_t *queue); + +/** + * terminate the queue, sending an interrupt to all the + * blocking threads + * + * @param queue the queue + */ +APR_DECLARE(apr_status_t) apr_queue_term(apr_queue_t *queue); + +#ifdef __cplusplus +} +#endif + +/** @} */ + +#endif /* APR_HAS_THREADS */ + +#endif /* APRQUEUE_H */ diff --git a/include/apr_random.h b/include/apr_random.h new file mode 100644 index 00000000000..29154358dbf --- /dev/null +++ b/include/apr_random.h @@ -0,0 +1,153 @@ +/* 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. + */ + +#ifndef APR_RANDOM_H +#define APR_RANDOM_H + +/** + * @file apr_random.h + * @brief APR PRNG routines + */ + +#include "apr_pools.h" +#include "apr_thread_proc.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup apr_random PRNG Routines + * @ingroup APR + * @{ + */ + +typedef struct apr_crypto_hash_t apr_crypto_hash_t; + +typedef void apr_crypto_hash_init_t(apr_crypto_hash_t *hash); +typedef void apr_crypto_hash_add_t(apr_crypto_hash_t *hash, const void *data, + apr_size_t bytes); +typedef void apr_crypto_hash_finish_t(apr_crypto_hash_t *hash, + unsigned char *result); + + +/* FIXME: make this opaque */ +struct apr_crypto_hash_t { + apr_crypto_hash_init_t *init; + apr_crypto_hash_add_t *add; + apr_crypto_hash_finish_t *finish; + apr_size_t size; + void *data; +}; + +/** + * Allocate and initialize the SHA-256 context + * @param p The pool to allocate from + */ +APR_DECLARE(apr_crypto_hash_t *) apr_crypto_sha256_new(apr_pool_t *p); + +/** Opaque PRNG structure. */ +typedef struct apr_random_t apr_random_t; + +/** + * Initialize a PRNG state + * @param g The PRNG state + * @param p The pool to allocate from + * @param pool_hash Pool hash functions + * @param key_hash Key hash functions + * @param prng_hash PRNG hash functions + */ +APR_DECLARE(void) apr_random_init(apr_random_t *g, apr_pool_t *p, + apr_crypto_hash_t *pool_hash, + apr_crypto_hash_t *key_hash, + apr_crypto_hash_t *prng_hash); +/** + * Allocate and initialize (apr_crypto_sha256_new) a new PRNG state. + * @param p The pool to allocate from + */ +APR_DECLARE(apr_random_t *) apr_random_standard_new(apr_pool_t *p); + +/** + * Mix the randomness pools. + * @param g The PRNG state + * @param entropy_ Entropy buffer + * @param bytes Length of entropy_ in bytes + */ +APR_DECLARE(void) apr_random_add_entropy(apr_random_t *g, + const void *entropy_, + apr_size_t bytes); +/** + * Generate cryptographically insecure random bytes. + * @param g The RNG state + * @param random Buffer to fill with random bytes + * @param bytes Length of buffer in bytes + */ +APR_DECLARE(apr_status_t) apr_random_insecure_bytes(apr_random_t *g, + void *random, + apr_size_t bytes); + +/** + * Generate cryptographically secure random bytes. + * @param g The RNG state + * @param random Buffer to fill with random bytes + * @param bytes Length of buffer in bytes + */ +APR_DECLARE(apr_status_t) apr_random_secure_bytes(apr_random_t *g, + void *random, + apr_size_t bytes); +/** + * Ensures that E bits of conditional entropy are mixed into the PRNG + * before any further randomness is extracted. + * @param g The RNG state + */ +APR_DECLARE(void) apr_random_barrier(apr_random_t *g); + +/** + * Return APR_SUCCESS if the cryptographic PRNG has been seeded with + * enough data, APR_ENOTENOUGHENTROPY otherwise. + * @param r The RNG state + */ +APR_DECLARE(apr_status_t) apr_random_secure_ready(apr_random_t *r); + +/** + * Return APR_SUCCESS if the PRNG has been seeded with enough data, + * APR_ENOTENOUGHENTROPY otherwise. + * @param r The PRNG state + */ +APR_DECLARE(apr_status_t) apr_random_insecure_ready(apr_random_t *r); + +/** + * Mix the randomness pools after forking. + * @param proc The resulting process handle from apr_proc_fork() + * @remark Call this in the child after forking to mix the randomness + * pools. Note that its generally a bad idea to fork a process with a + * real PRNG in it - better to have the PRNG externally and get the + * randomness from there. However, if you really must do it, then you + * should supply all your entropy to all the PRNGs - don't worry, they + * won't produce the same output. + * @remark Note that apr_proc_fork() calls this for you, so only weird + * applications need ever call it themselves. + * @internal + */ +APR_DECLARE(void) apr_random_after_fork(apr_proc_t *proc); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* !APR_RANDOM_H */ diff --git a/include/apr_redis.h b/include/apr_redis.h new file mode 100644 index 00000000000..6333ae0e6be --- /dev/null +++ b/include/apr_redis.h @@ -0,0 +1,459 @@ +/* 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. + */ + +/** + * @file apr_redis.h + * @brief Client interface for redis + * @remark To use this interface you must have a separate redis + * for more information. + */ + +#ifndef APR_REDIS_H +#define APR_REDIS_H + +#include "apr.h" +#include "apr_pools.h" +#include "apr_time.h" +#include "apr_strings.h" +#include "apr_network_io.h" +#include "apr_ring.h" +#include "apr_buckets.h" +#include "apr_reslist.h" +#include "apr_hash.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#ifndef RC_DEFAULT_SERVER_PORT +#define RC_DEFAULT_SERVER_PORT 6379 +#endif + +#ifndef RC_DEFAULT_SERVER_MIN +#define RC_DEFAULT_SERVER_MIN 0 +#endif + +#ifndef RC_DEFAULT_SERVER_SMAX +#define RC_DEFAULT_SERVER_SMAX 1 +#endif + +#ifndef RC_DEFAULT_SERVER_TTL +#define RC_DEFAULT_SERVER_TTL 600 +#endif + +/** + * @defgroup APR_Util_RC Redis Client Routines + * @ingroup APR_Util + * @{ + */ + +/** Specifies the status of a redis server */ +typedef enum +{ + APR_RC_SERVER_LIVE, /**< Server is alive and responding to requests */ + APR_RC_SERVER_DEAD /**< Server is not responding to requests */ +} apr_redis_server_status_t; + +/** Opaque redis client connection object */ +typedef struct apr_redis_conn_t apr_redis_conn_t; + +/** Redis Server Info Object */ +typedef struct apr_redis_server_t apr_redis_server_t; +struct apr_redis_server_t +{ + const char *host; /**< Hostname of this Server */ + apr_port_t port; /**< Port of this Server */ + apr_redis_server_status_t status; /**< @see apr_redis_server_status_t */ +#if APR_HAS_THREADS || defined(DOXYGEN) + apr_reslist_t *conns; /**< Resource list of actual client connections */ +#else + apr_redis_conn_t *conn; +#endif + apr_pool_t *p; /** Pool to use for private allocations */ +#if APR_HAS_THREADS + apr_thread_mutex_t *lock; +#endif + apr_time_t btime; + apr_uint32_t rwto; + struct + { + int major; + int minor; + int patch; + char *number; + } version; +}; + +typedef struct apr_redis_t apr_redis_t; + +/* Custom hash callback function prototype, user for server selection. +* @param baton user selected baton +* @param data data to hash +* @param data_len length of data +*/ +typedef apr_uint32_t (*apr_redis_hash_func)(void *baton, + const char *data, + const apr_size_t data_len); +/* Custom Server Select callback function prototype. +* @param baton user selected baton +* @param rc redis instance, use rc->live_servers to select a node +* @param hash hash of the selected key. +*/ +typedef apr_redis_server_t* (*apr_redis_server_func)(void *baton, + apr_redis_t *rc, + const apr_uint32_t hash); + +/** Container for a set of redis servers */ +struct apr_redis_t +{ + apr_uint32_t flags; /**< Flags, Not currently used */ + apr_uint16_t nalloc; /**< Number of Servers Allocated */ + apr_uint16_t ntotal; /**< Number of Servers Added */ + apr_redis_server_t **live_servers; /**< Array of Servers */ + apr_pool_t *p; /** Pool to use for allocations */ + void *hash_baton; + apr_redis_hash_func hash_func; + void *server_baton; + apr_redis_server_func server_func; +}; + +/** + * Creates a crc32 hash used to split keys between servers + * @param rc The redis client object to use + * @param data Data to be hashed + * @param data_len Length of the data to use + * @return crc32 hash of data + * @remark The crc32 hash is not compatible with old redisd clients. + */ +APR_DECLARE(apr_uint32_t) apr_redis_hash(apr_redis_t *rc, + const char *data, + const apr_size_t data_len); + +/** + * Pure CRC32 Hash. Used by some clients. + */ +APR_DECLARE(apr_uint32_t) apr_redis_hash_crc32(void *baton, + const char *data, + const apr_size_t data_len); + +/** + * hash compatible with the standard Perl Client. + */ +APR_DECLARE(apr_uint32_t) apr_redis_hash_default(void *baton, + const char *data, + const apr_size_t data_len); + +/** + * Picks a server based on a hash + * @param rc The redis client object to use + * @param hash Hashed value of a Key + * @return server that controls specified hash + * @see apr_redis_hash + */ +APR_DECLARE(apr_redis_server_t *) apr_redis_find_server_hash(apr_redis_t *rc, + const apr_uint32_t hash); + +/** + * server selection compatible with the standard Perl Client. + */ +APR_DECLARE(apr_redis_server_t *) apr_redis_find_server_hash_default(void *baton, + apr_redis_t *rc, + const apr_uint32_t hash); + +/** + * Adds a server to a client object + * @param rc The redis client object to use + * @param server Server to add + * @remark Adding servers is not thread safe, and should be done once at startup. + * @warning Changing servers after startup may cause keys to go to + * different servers. + */ +APR_DECLARE(apr_status_t) apr_redis_add_server(apr_redis_t *rc, + apr_redis_server_t *server); + + +/** + * Finds a Server object based on a hostname/port pair + * @param rc The redis client object to use + * @param host Hostname of the server + * @param port Port of the server + * @return Server with matching Hostname and Port, or NULL if none was found. + */ +APR_DECLARE(apr_redis_server_t *) apr_redis_find_server(apr_redis_t *rc, + const char *host, + apr_port_t port); + +/** + * Enables a Server for use again + * @param rc The redis client object to use + * @param rs Server to Activate + */ +APR_DECLARE(apr_status_t) apr_redis_enable_server(apr_redis_t *rc, + apr_redis_server_t *rs); + + +/** + * Disable a Server + * @param rc The redis client object to use + * @param rs Server to Disable + */ +APR_DECLARE(apr_status_t) apr_redis_disable_server(apr_redis_t *rc, + apr_redis_server_t *rs); + +/** + * Creates a new Server Object + * @param p Pool to use + * @param host hostname of the server + * @param port port of the server + * @param min minimum number of client sockets to open + * @param smax soft maximum number of client connections to open + * @param max hard maximum number of client connections + * @param ttl time to live in microseconds of a client connection + * @param rwto r/w timeout value in seconds of a client connection + * @param ns location of the new server object + * @see apr_reslist_create + * @remark min, smax, and max are only used when APR_HAS_THREADS + */ +APR_DECLARE(apr_status_t) apr_redis_server_create(apr_pool_t *p, + const char *host, + apr_port_t port, + apr_uint32_t min, + apr_uint32_t smax, + apr_uint32_t max, + apr_uint32_t ttl, + apr_uint32_t rwto, + apr_redis_server_t **ns); +/** + * Creates a new redisd client object + * @param p Pool to use + * @param max_servers maximum number of servers + * @param flags Not currently used + * @param rc location of the new redis client object + */ +APR_DECLARE(apr_status_t) apr_redis_create(apr_pool_t *p, + apr_uint16_t max_servers, + apr_uint32_t flags, + apr_redis_t **rc); + +/** + * Gets a value from the server, allocating the value out of p + * @param rc client to use + * @param p Pool to use + * @param key null terminated string containing the key + * @param baton location of the allocated value + * @param len length of data at baton + * @param flags any flags set by the client for this key + * @return + */ +APR_DECLARE(apr_status_t) apr_redis_getp(apr_redis_t *rc, + apr_pool_t *p, + const char* key, + char **baton, + apr_size_t *len, + apr_uint16_t *flags); + +/** + * Sets a value by key on the server + * @param rc client to use + * @param key null terminated string containing the key + * @param baton data to store on the server + * @param data_size length of data at baton + * @param flags any flags set by the client for this key + */ +APR_DECLARE(apr_status_t) apr_redis_set(apr_redis_t *rc, + const char *key, + char *baton, + const apr_size_t data_size, + apr_uint16_t flags); + +/** + * Sets a value by key on the server + * @param rc client to use + * @param key null terminated string containing the key + * @param baton data to store on the server + * @param data_size length of data at baton + * @param timeout time in seconds for the data to live on the server + * @param flags any flags set by the client for this key + */ +APR_DECLARE(apr_status_t) apr_redis_setex(apr_redis_t *rc, + const char *key, + char *baton, + const apr_size_t data_size, + apr_uint32_t timeout, + apr_uint16_t flags); + +/** + * Deletes a key from a server + * @param rc client to use + * @param key null terminated string containing the key + * @param timeout time for the delete to stop other clients from adding + */ +APR_DECLARE(apr_status_t) apr_redis_delete(apr_redis_t *rc, + const char *key, + apr_uint32_t timeout); + +/** + * Query a server's version + * @param rs server to query + * @param p Pool to allocate answer from + * @param baton location to store server version string + */ +APR_DECLARE(apr_status_t) apr_redis_version(apr_redis_server_t *rs, + apr_pool_t *p, + char **baton); + +/** + * Query a server's INFO + * @param rs server to query + * @param p Pool to allocate answer from + * @param baton location to store server INFO response string + */ +APR_DECLARE(apr_status_t) apr_redis_info(apr_redis_server_t *rs, + apr_pool_t *p, + char **baton); + +/** + * Increments a value + * @param rc client to use + * @param key null terminated string containing the key + * @param inc number to increment by + * @param new_value new value after incrementing + */ +APR_DECLARE(apr_status_t) apr_redis_incr(apr_redis_t *rc, + const char *key, + apr_int32_t inc, + apr_uint32_t *new_value); +/** + * Decrements a value + * @param rc client to use + * @param key null terminated string containing the key + * @param inc number to decrement by + * @param new_value new value after decrementing + */ +APR_DECLARE(apr_status_t) apr_redis_decr(apr_redis_t *rc, + const char *key, + apr_int32_t inc, + apr_uint32_t *new_value); + + +/** + * Pings the server + * @param rs Server to ping + */ +APR_DECLARE(apr_status_t) apr_redis_ping(apr_redis_server_t *rs); + +/** + * Gets multiple values from the server, allocating the values out of p + * @param rc client to use + * @param temp_pool Pool used for temporary allocations. May be cleared inside this + * call. + * @param data_pool Pool used to allocate data for the returned values. + * @param values hash of apr_redis_value_t keyed by strings, contains the + * result of the multiget call. + * @return + */ +APR_DECLARE(apr_status_t) apr_redis_multgetp(apr_redis_t *rc, + apr_pool_t *temp_pool, + apr_pool_t *data_pool, + apr_hash_t *values); + +typedef enum +{ + APR_RS_SERVER_MASTER, /**< Server is a master */ + APR_RS_SERVER_SLAVE, /**< Server is a slave */ + APR_RS_SERVER_UNKNOWN /**< Server role is unknown */ +} apr_redis_server_role_t; + +typedef struct +{ +/* # Server */ + /** Major version number of this server */ + apr_uint32_t major; + /** Minor version number of this server */ + apr_uint32_t minor; + /** Patch version number of this server */ + apr_uint32_t patch; + /** Process id of this server process */ + apr_uint32_t process_id; + /** Number of seconds this server has been running */ + apr_uint32_t uptime_in_seconds; + /** Bitsize of the arch on the current machine */ + apr_uint32_t arch_bits; + +/* # Clients */ + /** Number of connected clients */ + apr_uint32_t connected_clients; + /** Number of blocked clients */ + apr_uint32_t blocked_clients; + +/* # Memory */ + /** Max memory of this server */ + apr_uint64_t maxmemory; + /** Amount of used memory */ + apr_uint64_t used_memory; + /** Total memory available on this server */ + apr_uint64_t total_system_memory; + +/* # Stats */ + /** Total connections received */ + apr_uint64_t total_connections_received; + /** Total commands processed */ + apr_uint64_t total_commands_processed; + /** Total commands rejected */ + apr_uint64_t rejected_connections; + /** Total net input bytes */ + apr_uint64_t total_net_input_bytes; + /** Total net output bytes */ + apr_uint64_t total_net_output_bytes; + /** Keyspace hits */ + apr_uint64_t keyspace_hits; + /** Keyspace misses */ + apr_uint64_t keyspace_misses; + +/* # Replication */ + /** Role */ + apr_redis_server_role_t role; + /** Number of connected slave */ + apr_uint32_t connected_slaves; + +/* # CPU */ + /** Accumulated CPU user time for this process */ + apr_uint32_t used_cpu_sys; + /** Accumulated CPU system time for this process */ + apr_uint32_t used_cpu_user; + +/* # Cluster */ + /** Is cluster enabled */ + apr_uint32_t cluster_enabled; +} apr_redis_stats_t; + +/** + * Query a server for statistics + * @param rs server to query + * @param p Pool to allocate answer from + * @param stats location of the new statistics structure + */ +APR_DECLARE(apr_status_t) apr_redis_stats(apr_redis_server_t *rs, + apr_pool_t *p, + apr_redis_stats_t **stats); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* APR_REDIS_H */ diff --git a/include/apr_reslist.h b/include/apr_reslist.h new file mode 100644 index 00000000000..4e09e12aacb --- /dev/null +++ b/include/apr_reslist.h @@ -0,0 +1,183 @@ +/* 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. + */ + +#ifndef APR_RESLIST_H +#define APR_RESLIST_H + +/** + * @file apr_reslist.h + * @brief APR-UTIL Resource List Routines + */ + +#include "apr.h" +#include "apu.h" +#include "apr_pools.h" +#include "apr_errno.h" +#include "apr_time.h" + +/** + * @defgroup APR_Util_RL Resource List Routines + * @ingroup APR + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** Opaque resource list object */ +typedef struct apr_reslist_t apr_reslist_t; + +/* Generic constructor called by resource list when it needs to create a + * resource. + * @param resource opaque resource + * @param params flags + * @param pool Pool + */ +typedef apr_status_t (*apr_reslist_constructor)(void **resource, void *params, + apr_pool_t *pool); + +/* Generic destructor called by resource list when it needs to destroy a + * resource. + * @param resource opaque resource + * @param params flags + * @param pool Pool + */ +typedef apr_status_t (*apr_reslist_destructor)(void *resource, void *params, + apr_pool_t *pool); + +/* Cleanup order modes */ +#define APR_RESLIST_CLEANUP_DEFAULT 0 /**< default pool cleanup */ +#define APR_RESLIST_CLEANUP_FIRST 1 /**< use pool pre cleanup */ + +/** + * Create a new resource list with the following parameters: + * @param reslist An address where the pointer to the new resource + * list will be stored. + * @param min Allowed minimum number of available resources. Zero + * creates new resources only when needed. + * @param smax Resources will be destroyed during reslist maintenance to + * meet this maximum restriction as they expire (reach their ttl). + * @param hmax Absolute maximum limit on the number of total resources. + * @param ttl If non-zero, sets the maximum amount of time in microseconds an + * unused resource is valid. Any resource which has exceeded this + * time will be destroyed, either when encountered by + * apr_reslist_acquire() or during reslist maintenance. + * @param con Constructor routine that is called to create a new resource. + * @param de Destructor routine that is called to destroy an expired resource. + * @param params Passed to constructor and deconstructor + * @param pool The pool from which to create this resource list. Also the + * same pool that is passed to the constructor and destructor + * routines. + * @remark If APR has been compiled without thread support, hmax will be + * automatically set to 1 and values of min and smax will be forced to + * 1 for any non-zero value. + */ +APR_DECLARE(apr_status_t) apr_reslist_create(apr_reslist_t **reslist, + int min, int smax, int hmax, + apr_interval_time_t ttl, + apr_reslist_constructor con, + apr_reslist_destructor de, + void *params, + apr_pool_t *pool); + +/** + * Destroy the given resource list and all resources controlled by + * this list. + * FIXME: Should this block until all resources become available, + * or maybe just destroy all the free ones, or maybe destroy + * them even though they might be in use by something else? + * Currently it will abort if there are resources that haven't + * been released, so there is an assumption that all resources + * have been released to the list before calling this function. + * @param reslist The reslist to destroy + */ +APR_DECLARE(apr_status_t) apr_reslist_destroy(apr_reslist_t *reslist); + +/** + * Retrieve a resource from the list, creating a new one if necessary. + * If we have met our maximum number of resources, we will block + * until one becomes available. + * @param reslist The resource list. + * @param resource An address where the pointer to the resource + * will be stored. + */ +APR_DECLARE(apr_status_t) apr_reslist_acquire(apr_reslist_t *reslist, + void **resource); + +/** + * Return a resource back to the list of available resources. + * @param reslist The resource list. + * @param resource The resource to return to the list. + */ +APR_DECLARE(apr_status_t) apr_reslist_release(apr_reslist_t *reslist, + void *resource); + +/** + * Set the timeout the acquire will wait for a free resource + * when the maximum number of resources is exceeded. + * @param reslist The resource list. + * @param timeout Timeout to wait. The zero waits forever. + */ +APR_DECLARE(void) apr_reslist_timeout_set(apr_reslist_t *reslist, + apr_interval_time_t timeout); + +/** + * Return the number of outstanding resources. + * @param reslist The resource list. + */ +APR_DECLARE(apr_uint32_t) apr_reslist_acquired_count(apr_reslist_t *reslist); + +/** + * Invalidate a resource in the pool - e.g. a database connection + * that returns a "lost connection" error and can't be restored. + * Use this instead of apr_reslist_release if the resource is bad. + * @param reslist The resource list. + * @param resource The resource to invalidate. + */ +APR_DECLARE(apr_status_t) apr_reslist_invalidate(apr_reslist_t *reslist, + void *resource); + +/** + * Perform routine maintenance on the resource list. This call + * may instantiate new resources or expire old resources. + * @param reslist The resource list. + */ +APR_DECLARE(apr_status_t) apr_reslist_maintain(apr_reslist_t *reslist); + +/** + * Set reslist cleanup order. + * @param reslist The resource list. + * @param mode Cleanup order mode + * <PRE> + * APR_RESLIST_CLEANUP_DEFAULT default pool cleanup order + * APR_RESLIST_CLEANUP_FIRST use pool pre cleanup + * </PRE> + * @remark If APR_RESLIST_CLEANUP_FIRST is used the destructors will + * be called before child pools of the pool used to create the reslist + * are destroyed. This allows to explicitly destroy the child pools + * inside reslist destructors. + */ +APR_DECLARE(void) apr_reslist_cleanup_order_set(apr_reslist_t *reslist, + apr_uint32_t mode); + +#ifdef __cplusplus +} +#endif + +/** @} */ + +#endif /* ! APR_RESLIST_H */ diff --git a/include/apr_ring.h b/include/apr_ring.h new file mode 100644 index 00000000000..eec735fcf58 --- /dev/null +++ b/include/apr_ring.h @@ -0,0 +1,513 @@ +/* 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. + */ + +/* + * This code draws heavily from the 4.4BSD <sys/queue.h> macros + * and Dean Gaudet's "splim/ring.h". + * <http://www.freebsd.org/cgi/cvsweb.cgi/src/sys/sys/queue.h> + * <http://www.arctic.org/~dean/splim/> + * + * We'd use Dean's code directly if we could guarantee the + * availability of inline functions. + */ + +#ifndef APR_RING_H +#define APR_RING_H + +/** + * @file apr_ring.h + * @brief APR Rings + */ + +/* + * for offsetof() + */ +#include "apr_general.h" + +/** + * @defgroup apr_ring Ring Macro Implementations + * @ingroup APR + * A ring is a kind of doubly-linked list that can be manipulated + * without knowing where its head is. + * @{ + */ + +/** + * The Ring Element + * + * A ring element struct is linked to the other elements in the ring + * through its ring entry field, e.g. + * <pre> + * struct my_element_t { + * APR_RING_ENTRY(my_element_t) link; + * int foo; + * char *bar; + * }; + * </pre> + * + * An element struct may be put on more than one ring if it has more + * than one APR_RING_ENTRY field. Each APR_RING_ENTRY has a corresponding + * APR_RING_HEAD declaration. + * + * @warning For strict C standards compliance you should put the APR_RING_ENTRY + * first in the element struct unless the head is always part of a larger + * object with enough earlier fields to accommodate the offsetof() used + * to compute the ring sentinel below. You can usually ignore this caveat. + */ +#define APR_RING_ENTRY(elem) \ + struct { \ + struct elem * volatile next; \ + struct elem * volatile prev; \ + } + +/** + * The Ring Head + * + * Each ring is managed via its head, which is a struct declared like this: + * <pre> + * APR_RING_HEAD(my_ring_t, my_element_t); + * struct my_ring_t ring, *ringp; + * </pre> + * + * This struct looks just like the element link struct so that we can + * be sure that the typecasting games will work as expected. + * + * The first element in the ring is next after the head, and the last + * element is just before the head. + */ +#define APR_RING_HEAD(head, elem) \ + struct head { \ + struct elem * volatile next; \ + struct elem * volatile prev; \ + } + +/** + * The Ring Sentinel + * + * This is the magic pointer value that occurs before the first and + * after the last elements in the ring, computed from the address of + * the ring's head. The head itself isn't an element, but in order to + * get rid of all the special cases when dealing with the ends of the + * ring, we play typecasting games to make it look like one. + * + * Here is a diagram to illustrate the arrangements of the next and + * prev pointers of each element in a single ring. Note that they point + * to the start of each element, not to the APR_RING_ENTRY structure. + * + * <pre> + * +->+------+<-+ +->+------+<-+ +->+------+<-+ + * | |struct| | | |struct| | | |struct| | + * / | elem | \/ | elem | \/ | elem | \ + * ... | | /\ | | /\ | | ... + * +------+ | | +------+ | | +------+ + * ...--|prev | | +--|ring | | +--|prev | + * | next|--+ | entry|--+ | next|--... + * +------+ +------+ +------+ + * | etc. | | etc. | | etc. | + * : : : : : : + * </pre> + * + * The APR_RING_HEAD is nothing but a bare APR_RING_ENTRY. The prev + * and next pointers in the first and last elements don't actually + * point to the head, they point to a phantom place called the + * sentinel. Its value is such that last->next->next == first because + * the offset from the sentinel to the head's next pointer is the same + * as the offset from the start of an element to its next pointer. + * This also works in the opposite direction. + * + * <pre> + * last first + * +->+------+<-+ +->sentinel<-+ +->+------+<-+ + * | |struct| | | | | |struct| | + * / | elem | \/ \/ | elem | \ + * ... | | /\ /\ | | ... + * +------+ | | +------+ | | +------+ + * ...--|prev | | +--|ring | | +--|prev | + * | next|--+ | head|--+ | next|--... + * +------+ +------+ +------+ + * | etc. | | etc. | + * : : : : + * </pre> + * + * Note that the offset mentioned above is different for each kind of + * ring that the element may be on, and each kind of ring has a unique + * name for its APR_RING_ENTRY in each element, and has its own type + * for its APR_RING_HEAD. + * + * Note also that if the offset is non-zero (which is required if an + * element has more than one APR_RING_ENTRY), the unreality of the + * sentinel may have bad implications on very perverse implementations + * of C -- see the warning in APR_RING_ENTRY. + * + * @param hp The head of the ring + * @param elem The name of the element struct + * @param link The name of the APR_RING_ENTRY in the element struct + */ +#define APR_RING_SENTINEL(hp, elem, link) \ + (struct elem *)((char *)(&(hp)->next) - APR_OFFSETOF(struct elem, link)) + +/** + * The first element of the ring + * @param hp The head of the ring + */ +#define APR_RING_FIRST(hp) (hp)->next +/** + * The last element of the ring + * @param hp The head of the ring + */ +#define APR_RING_LAST(hp) (hp)->prev +/** + * The next element in the ring + * @param ep The current element + * @param link The name of the APR_RING_ENTRY in the element struct + */ +#define APR_RING_NEXT(ep, link) (ep)->link.next +/** + * The previous element in the ring + * @param ep The current element + * @param link The name of the APR_RING_ENTRY in the element struct + */ +#define APR_RING_PREV(ep, link) (ep)->link.prev + + +/** + * Initialize a ring + * @param hp The head of the ring + * @param elem The name of the element struct + * @param link The name of the APR_RING_ENTRY in the element struct + */ +#define APR_RING_INIT(hp, elem, link) do { \ + APR_RING_FIRST((hp)) = APR_RING_SENTINEL((hp), elem, link); \ + APR_RING_LAST((hp)) = APR_RING_SENTINEL((hp), elem, link); \ + } while (0) + +/** + * Determine if a ring is empty + * @param hp The head of the ring + * @param elem The name of the element struct + * @param link The name of the APR_RING_ENTRY in the element struct + * @return true or false + */ +#define APR_RING_EMPTY(hp, elem, link) \ + (APR_RING_FIRST((hp)) == APR_RING_SENTINEL((hp), elem, link)) + +/** + * Initialize a singleton element + * @param ep The element + * @param link The name of the APR_RING_ENTRY in the element struct + */ +#define APR_RING_ELEM_INIT(ep, link) do { \ + APR_RING_NEXT((ep), link) = (ep); \ + APR_RING_PREV((ep), link) = (ep); \ + } while (0) + + +/** + * Splice the sequence ep1..epN into the ring before element lep + * (..lep.. becomes ..ep1..epN..lep..) + * @warning This doesn't work for splicing before the first element or on + * empty rings... see APR_RING_SPLICE_HEAD for one that does + * @param lep Element in the ring to splice before + * @param ep1 First element in the sequence to splice in + * @param epN Last element in the sequence to splice in + * @param link The name of the APR_RING_ENTRY in the element struct + */ +#define APR_RING_SPLICE_BEFORE(lep, ep1, epN, link) do { \ + APR_RING_NEXT((epN), link) = (lep); \ + APR_RING_PREV((ep1), link) = APR_RING_PREV((lep), link); \ + APR_RING_NEXT(APR_RING_PREV((lep), link), link) = (ep1); \ + APR_RING_PREV((lep), link) = (epN); \ + } while (0) + +/** + * Splice the sequence ep1..epN into the ring after element lep + * (..lep.. becomes ..lep..ep1..epN..) + * @warning This doesn't work for splicing after the last element or on + * empty rings... see APR_RING_SPLICE_TAIL for one that does + * @param lep Element in the ring to splice after + * @param ep1 First element in the sequence to splice in + * @param epN Last element in the sequence to splice in + * @param link The name of the APR_RING_ENTRY in the element struct + */ +#define APR_RING_SPLICE_AFTER(lep, ep1, epN, link) do { \ + APR_RING_PREV((ep1), link) = (lep); \ + APR_RING_NEXT((epN), link) = APR_RING_NEXT((lep), link); \ + APR_RING_PREV(APR_RING_NEXT((lep), link), link) = (epN); \ + APR_RING_NEXT((lep), link) = (ep1); \ + } while (0) + +/** + * Insert the element nep into the ring before element lep + * (..lep.. becomes ..nep..lep..) + * @warning This doesn't work for inserting before the first element or on + * empty rings... see APR_RING_INSERT_HEAD for one that does + * @param lep Element in the ring to insert before + * @param nep Element to insert + * @param link The name of the APR_RING_ENTRY in the element struct + */ +#define APR_RING_INSERT_BEFORE(lep, nep, link) \ + APR_RING_SPLICE_BEFORE((lep), (nep), (nep), link) + +/** + * Insert the element nep into the ring after element lep + * (..lep.. becomes ..lep..nep..) + * @warning This doesn't work for inserting after the last element or on + * empty rings... see APR_RING_INSERT_TAIL for one that does + * @param lep Element in the ring to insert after + * @param nep Element to insert + * @param link The name of the APR_RING_ENTRY in the element struct + */ +#define APR_RING_INSERT_AFTER(lep, nep, link) \ + APR_RING_SPLICE_AFTER((lep), (nep), (nep), link) + + +/** + * Splice the sequence ep1..epN into the ring before the first element + * (..hp.. becomes ..hp..ep1..epN..) + * @param hp Head of the ring + * @param ep1 First element in the sequence to splice in + * @param epN Last element in the sequence to splice in + * @param elem The name of the element struct + * @param link The name of the APR_RING_ENTRY in the element struct + */ +#define APR_RING_SPLICE_HEAD(hp, ep1, epN, elem, link) \ + APR_RING_SPLICE_AFTER(APR_RING_SENTINEL((hp), elem, link), \ + (ep1), (epN), link) + +/** + * Splice the sequence ep1..epN into the ring after the last element + * (..hp.. becomes ..ep1..epN..hp..) + * @param hp Head of the ring + * @param ep1 First element in the sequence to splice in + * @param epN Last element in the sequence to splice in + * @param elem The name of the element struct + * @param link The name of the APR_RING_ENTRY in the element struct + */ +#define APR_RING_SPLICE_TAIL(hp, ep1, epN, elem, link) \ + APR_RING_SPLICE_BEFORE(APR_RING_SENTINEL((hp), elem, link), \ + (ep1), (epN), link) + +/** + * Insert the element nep into the ring before the first element + * (..hp.. becomes ..hp..nep..) + * @param hp Head of the ring + * @param nep Element to insert + * @param elem The name of the element struct + * @param link The name of the APR_RING_ENTRY in the element struct + */ +#define APR_RING_INSERT_HEAD(hp, nep, elem, link) \ + APR_RING_SPLICE_HEAD((hp), (nep), (nep), elem, link) + +/** + * Insert the element nep into the ring after the last element + * (..hp.. becomes ..nep..hp..) + * @param hp Head of the ring + * @param nep Element to insert + * @param elem The name of the element struct + * @param link The name of the APR_RING_ENTRY in the element struct + */ +#define APR_RING_INSERT_TAIL(hp, nep, elem, link) \ + APR_RING_SPLICE_TAIL((hp), (nep), (nep), elem, link) + +/** + * Concatenate ring h2 onto the end of ring h1, leaving h2 empty. + * @param h1 Head of the ring to concatenate onto + * @param h2 Head of the ring to concatenate + * @param elem The name of the element struct + * @param link The name of the APR_RING_ENTRY in the element struct + */ +#define APR_RING_CONCAT(h1, h2, elem, link) do { \ + if (!APR_RING_EMPTY((h2), elem, link)) { \ + APR_RING_SPLICE_BEFORE(APR_RING_SENTINEL((h1), elem, link), \ + APR_RING_FIRST((h2)), \ + APR_RING_LAST((h2)), link); \ + APR_RING_INIT((h2), elem, link); \ + } \ + } while (0) + +/** + * Prepend ring h2 onto the beginning of ring h1, leaving h2 empty. + * @param h1 Head of the ring to prepend onto + * @param h2 Head of the ring to prepend + * @param elem The name of the element struct + * @param link The name of the APR_RING_ENTRY in the element struct + */ +#define APR_RING_PREPEND(h1, h2, elem, link) do { \ + if (!APR_RING_EMPTY((h2), elem, link)) { \ + APR_RING_SPLICE_AFTER(APR_RING_SENTINEL((h1), elem, link), \ + APR_RING_FIRST((h2)), \ + APR_RING_LAST((h2)), link); \ + APR_RING_INIT((h2), elem, link); \ + } \ + } while (0) + +/** + * Unsplice a sequence of elements from a ring + * @warning The unspliced sequence is left with dangling pointers at either end + * @param ep1 First element in the sequence to unsplice + * @param epN Last element in the sequence to unsplice + * @param link The name of the APR_RING_ENTRY in the element struct + */ +#define APR_RING_UNSPLICE(ep1, epN, link) do { \ + APR_RING_NEXT(APR_RING_PREV((ep1), link), link) = \ + APR_RING_NEXT((epN), link); \ + APR_RING_PREV(APR_RING_NEXT((epN), link), link) = \ + APR_RING_PREV((ep1), link); \ + } while (0) + +/** + * Remove a single element from a ring + * @warning The unspliced element is left with dangling pointers at either end + * @param ep Element to remove + * @param link The name of the APR_RING_ENTRY in the element struct + */ +#define APR_RING_REMOVE(ep, link) \ + APR_RING_UNSPLICE((ep), (ep), link) + +/** + * Iterate over a ring + * @param ep The current element + * @param head The head of the ring + * @param elem The name of the element struct + * @param link The name of the APR_RING_ENTRY in the element struct + */ +#define APR_RING_FOREACH(ep, head, elem, link) \ + for (ep = APR_RING_FIRST(head); \ + ep != APR_RING_SENTINEL(head, elem, link); \ + ep = APR_RING_NEXT(ep, link)) + +/** + * Iterate over a ring safe against removal of the current element + * @param ep1 The current element + * @param ep2 Iteration cursor + * @param head The head of the ring + * @param elem The name of the element struct + * @param link The name of the APR_RING_ENTRY in the element struct + */ +#define APR_RING_FOREACH_SAFE(ep1, ep2, head, elem, link) \ + for (ep1 = APR_RING_FIRST(head), ep2 = APR_RING_NEXT(ep1, link); \ + ep1 != APR_RING_SENTINEL(head, elem, link); \ + ep1 = ep2, ep2 = APR_RING_NEXT(ep1, link)) + +/* Debugging tools: */ + +#ifdef APR_RING_DEBUG +#include <stdio.h> +#include <assert.h> + +#define APR_RING_CHECK_ONE(msg, ptr) \ + fprintf(stderr, "*** %s %p\n", msg, ptr) + +#define APR_RING_CHECK(hp, elem, link, msg) \ + APR_RING_CHECK_ELEM(APR_RING_SENTINEL(hp, elem, link), elem, link, msg) + +#define APR_RING_CHECK_ELEM(ep, elem, link, msg) do { \ + struct elem *start = (ep); \ + struct elem *here = start; \ + fprintf(stderr, "*** ring check start -- %s\n", msg); \ + do { \ + fprintf(stderr, "\telem %p\n", here); \ + fprintf(stderr, "\telem->next %p\n", \ + APR_RING_NEXT(here, link)); \ + fprintf(stderr, "\telem->prev %p\n", \ + APR_RING_PREV(here, link)); \ + fprintf(stderr, "\telem->next->prev %p\n", \ + APR_RING_PREV(APR_RING_NEXT(here, link), link)); \ + fprintf(stderr, "\telem->prev->next %p\n", \ + APR_RING_NEXT(APR_RING_PREV(here, link), link)); \ + if (APR_RING_PREV(APR_RING_NEXT(here, link), link) != here) { \ + fprintf(stderr, "\t*** elem->next->prev != elem\n"); \ + break; \ + } \ + if (APR_RING_NEXT(APR_RING_PREV(here, link), link) != here) { \ + fprintf(stderr, "\t*** elem->prev->next != elem\n"); \ + break; \ + } \ + here = APR_RING_NEXT(here, link); \ + } while (here != start); \ + fprintf(stderr, "*** ring check end\n"); \ + } while (0) + +#define APR_RING_CHECK_CONSISTENCY(hp, elem, link) \ + APR_RING_CHECK_ELEM_CONSISTENCY(APR_RING_SENTINEL(hp, elem, link),\ + elem, link) + +#define APR_RING_CHECK_ELEM_CONSISTENCY(ep, elem, link) do { \ + struct elem *start = (ep); \ + struct elem *here = start; \ + do { \ + assert(APR_RING_PREV(APR_RING_NEXT(here, link), link) == here); \ + assert(APR_RING_NEXT(APR_RING_PREV(here, link), link) == here); \ + here = APR_RING_NEXT(here, link); \ + } while (here != start); \ + } while (0) + +#else +/** + * Print a single pointer value to STDERR + * (This is a no-op unless APR_RING_DEBUG is defined.) + * @param msg Descriptive message + * @param ptr Pointer value to print + */ +#define APR_RING_CHECK_ONE(msg, ptr) +/** + * Dump all ring pointers to STDERR, starting with the head and looping all + * the way around the ring back to the head. Aborts if an inconsistency + * is found. + * (This is a no-op unless APR_RING_DEBUG is defined.) + * @param hp Head of the ring + * @param elem The name of the element struct + * @param link The name of the APR_RING_ENTRY in the element struct + * @param msg Descriptive message + */ +#define APR_RING_CHECK(hp, elem, link, msg) +/** + * Loops around a ring and checks all the pointers for consistency. Pops + * an assertion if any inconsistency is found. Same idea as APR_RING_CHECK() + * except that it's silent if all is well. + * (This is a no-op unless APR_RING_DEBUG is defined.) + * @param hp Head of the ring + * @param elem The name of the element struct + * @param link The name of the APR_RING_ENTRY in the element struct + */ +#define APR_RING_CHECK_CONSISTENCY(hp, elem, link) +/** + * Dump all ring pointers to STDERR, starting with the given element and + * looping all the way around the ring back to that element. Aborts if + * an inconsistency is found. + * (This is a no-op unless APR_RING_DEBUG is defined.) + * @param ep The element + * @param elem The name of the element struct + * @param link The name of the APR_RING_ENTRY in the element struct + * @param msg Descriptive message + */ +#define APR_RING_CHECK_ELEM(ep, elem, link, msg) +/** + * Loops around a ring, starting with the given element, and checks all + * the pointers for consistency. Pops an assertion if any inconsistency + * is found. Same idea as APR_RING_CHECK_ELEM() except that it's silent + * if all is well. + * (This is a no-op unless APR_RING_DEBUG is defined.) + * @param ep The element + * @param elem The name of the element struct + * @param link The name of the APR_RING_ENTRY in the element struct + */ +#define APR_RING_CHECK_ELEM_CONSISTENCY(ep, elem, link) +#endif + +/** @} */ + +#endif /* !APR_RING_H */ diff --git a/include/apr_rmm.h b/include/apr_rmm.h new file mode 100644 index 00000000000..cdb7e39d73f --- /dev/null +++ b/include/apr_rmm.h @@ -0,0 +1,137 @@ +/* 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. + */ + +#ifndef APR_RMM_H +#define APR_RMM_H +/** + * @file apr_rmm.h + * @brief APR-UTIL Relocatable Memory Management Routines + */ +/** + * @defgroup APR_Util_RMM Relocatable Memory Management Routines + * @ingroup APR + * @{ + */ + +#include "apr.h" +#include "apr_pools.h" +#include "apr_errno.h" +#include "apu.h" +#include "apr_anylock.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** Structure to access Relocatable, Managed Memory */ +typedef struct apr_rmm_t apr_rmm_t; + +/** Fundamental allocation unit, within a specific apr_rmm_t */ +typedef apr_size_t apr_rmm_off_t; + +/** + * Initialize a relocatable memory block to be managed by the apr_rmm API. + * @param rmm The relocatable memory block + * @param lock An apr_anylock_t of the appropriate type of lock, or NULL + * if no locking is required. + * @param membuf The block of relocatable memory to be managed + * @param memsize The size of relocatable memory block to be managed + * @param cont The pool to use for local storage and management + * @remark Both @param membuf and @param memsize must be aligned + * (for instance using APR_ALIGN_DEFAULT). + */ +APR_DECLARE(apr_status_t) apr_rmm_init(apr_rmm_t **rmm, apr_anylock_t *lock, + void *membuf, apr_size_t memsize, + apr_pool_t *cont); + +/** + * Destroy a managed memory block. + * @param rmm The relocatable memory block to destroy + */ +APR_DECLARE(apr_status_t) apr_rmm_destroy(apr_rmm_t *rmm); + +/** + * Attach to a relocatable memory block already managed by the apr_rmm API. + * @param rmm The relocatable memory block + * @param lock An apr_anylock_t of the appropriate type of lock + * @param membuf The block of relocatable memory already under management + * @param cont The pool to use for local storage and management + */ +APR_DECLARE(apr_status_t) apr_rmm_attach(apr_rmm_t **rmm, apr_anylock_t *lock, + void *membuf, apr_pool_t *cont); + +/** + * Detach from the managed block of memory. + * @param rmm The relocatable memory block to detach from + */ +APR_DECLARE(apr_status_t) apr_rmm_detach(apr_rmm_t *rmm); + +/** + * Allocate memory from the block of relocatable memory. + * @param rmm The relocatable memory block + * @param reqsize How much memory to allocate + */ +APR_DECLARE(apr_rmm_off_t) apr_rmm_malloc(apr_rmm_t *rmm, apr_size_t reqsize); + +/** + * Realloc memory from the block of relocatable memory. + * @param rmm The relocatable memory block + * @param entity The memory allocation to realloc + * @param reqsize The new size + */ +APR_DECLARE(apr_rmm_off_t) apr_rmm_realloc(apr_rmm_t *rmm, void *entity, apr_size_t reqsize); + +/** + * Allocate memory from the block of relocatable memory and initialize it to zero. + * @param rmm The relocatable memory block + * @param reqsize How much memory to allocate + */ +APR_DECLARE(apr_rmm_off_t) apr_rmm_calloc(apr_rmm_t *rmm, apr_size_t reqsize); + +/** + * Free allocation returned by apr_rmm_malloc or apr_rmm_calloc. + * @param rmm The relocatable memory block + * @param entity The memory allocation to free + */ +APR_DECLARE(apr_status_t) apr_rmm_free(apr_rmm_t *rmm, apr_rmm_off_t entity); + +/** + * Retrieve the physical address of a relocatable allocation of memory + * @param rmm The relocatable memory block + * @param entity The memory allocation to free + * @return address The address, aligned with APR_ALIGN_DEFAULT. + */ +APR_DECLARE(void *) apr_rmm_addr_get(apr_rmm_t *rmm, apr_rmm_off_t entity); + +/** + * Compute the offset of a relocatable allocation of memory + * @param rmm The relocatable memory block + * @param entity The physical address to convert to an offset + */ +APR_DECLARE(apr_rmm_off_t) apr_rmm_offset_get(apr_rmm_t *rmm, void *entity); + +/** + * Compute the required overallocation of memory needed to fit n allocs + * @param n The number of alloc/calloc regions desired + */ +APR_DECLARE(apr_size_t) apr_rmm_overhead_get(int n); + +#ifdef __cplusplus +} +#endif +/** @} */ +#endif /* ! APR_RMM_H */ + diff --git a/include/apr_sdbm.h b/include/apr_sdbm.h new file mode 100644 index 00000000000..632ee2386c3 --- /dev/null +++ b/include/apr_sdbm.h @@ -0,0 +1,177 @@ +/* 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. + */ + +/* + * sdbm - ndbm work-alike hashed database library + * based on Per-Ake Larson's Dynamic Hashing algorithms. BIT 18 (1978). + * author: oz@nexus.yorku.ca + * status: ex-public domain + */ + +#ifndef APR_SDBM_H +#define APR_SDBM_H + +#include "apu.h" +#include "apr_errno.h" +#include "apr_file_io.h" /* for apr_fileperms_t */ + +/** + * @file apr_sdbm.h + * @brief apr-util SDBM library + */ +/** + * @defgroup APR_Util_DBM_SDBM SDBM library + * @ingroup APR_Util_DBM + * @{ + */ + +/** + * Structure for referencing an sdbm + */ +typedef struct apr_sdbm_t apr_sdbm_t; + +/** + * Structure for referencing the datum record within an sdbm + */ +typedef struct { + /** pointer to the data stored/retrieved */ + char *dptr; + /** size of data */ + /* apr_ssize_t for release 2.0??? */ + int dsize; +} apr_sdbm_datum_t; + +/* The extensions used for the database files */ +/** SDBM Directory file extension */ +#define APR_SDBM_DIRFEXT ".dir" +/** SDBM page file extension */ +#define APR_SDBM_PAGFEXT ".pag" + +/* flags to sdbm_store */ +#define APR_SDBM_INSERT 0 /**< Insert */ +#define APR_SDBM_REPLACE 1 /**< Replace */ +#define APR_SDBM_INSERTDUP 2 /**< Insert with duplicates */ + +/** + * Open an sdbm database by file name + * @param db The newly opened database + * @param name The sdbm file to open + * @param mode The flag values (APR_FOPEN_READ and APR_FOPEN_BINARY flags are + * implicit) + * <PRE> + * APR_FOPEN_WRITE open for read-write access + * APR_FOPEN_CREATE create the sdbm if it does not exist + * APR_FOPEN_TRUNCATE empty the contents of the sdbm + * APR_FOPEN_EXCL fail for APR_FOPEN_CREATE if the file exists + * APR_FOPEN_DELONCLOSE delete the sdbm when closed + * APR_FOPEN_SHARELOCK support locking across process/machines + * </PRE> + * @param perms Permissions to apply to if created + * @param p The pool to use when creating the sdbm + * @remark The sdbm name is not a true file name, as sdbm appends suffixes + * for seperate data and index files. + */ +APR_DECLARE(apr_status_t) apr_sdbm_open(apr_sdbm_t **db, const char *name, + apr_int32_t mode, + apr_fileperms_t perms, apr_pool_t *p); + +/** + * Close an sdbm file previously opened by apr_sdbm_open + * @param db The database to close + */ +APR_DECLARE(apr_status_t) apr_sdbm_close(apr_sdbm_t *db); + +/** + * Lock an sdbm database for concurency of multiple operations + * @param db The database to lock + * @param type The lock type + * <PRE> + * APR_FLOCK_SHARED + * APR_FLOCK_EXCLUSIVE + * </PRE> + * @remark Calls to apr_sdbm_lock may be nested. All apr_sdbm functions + * perform implicit locking. Since an APR_FLOCK_SHARED lock cannot be + * portably promoted to an APR_FLOCK_EXCLUSIVE lock, apr_sdbm_store and + * apr_sdbm_delete calls will fail if an APR_FLOCK_SHARED lock is held. + * The apr_sdbm_lock call requires the database to be opened with the + * APR_FOPEN_SHARELOCK mode value. + */ +APR_DECLARE(apr_status_t) apr_sdbm_lock(apr_sdbm_t *db, int type); + +/** + * Release an sdbm lock previously aquired by apr_sdbm_lock + * @param db The database to unlock + */ +APR_DECLARE(apr_status_t) apr_sdbm_unlock(apr_sdbm_t *db); + +/** + * Fetch an sdbm record value by key + * @param db The database + * @param value The value datum retrieved for this record + * @param key The key datum to find this record + */ +APR_DECLARE(apr_status_t) apr_sdbm_fetch(apr_sdbm_t *db, + apr_sdbm_datum_t *value, + apr_sdbm_datum_t key); + +/** + * Store an sdbm record value by key + * @param db The database + * @param key The key datum to store this record by + * @param value The value datum to store in this record + * @param opt The method used to store the record + * <PRE> + * APR_SDBM_INSERT return an error if the record exists + * APR_SDBM_REPLACE overwrite any existing record for key + * </PRE> + */ +APR_DECLARE(apr_status_t) apr_sdbm_store(apr_sdbm_t *db, apr_sdbm_datum_t key, + apr_sdbm_datum_t value, int opt); + +/** + * Delete an sdbm record value by key + * @param db The database + * @param key The key datum of the record to delete + * @remark It is not an error to delete a non-existent record. + */ +APR_DECLARE(apr_status_t) apr_sdbm_delete(apr_sdbm_t *db, + const apr_sdbm_datum_t key); + +/** + * Retrieve the first record key from a dbm + * @param db The database + * @param key The key datum of the first record + * @remark The keys returned are not ordered. To traverse the list of keys + * for an sdbm opened with APR_FOPEN_SHARELOCK, the caller must use apr_sdbm_lock + * prior to retrieving the first record, and hold the lock until after the + * last call to apr_sdbm_nextkey. + */ +APR_DECLARE(apr_status_t) apr_sdbm_firstkey(apr_sdbm_t *db, apr_sdbm_datum_t *key); + +/** + * Retrieve the next record key from an sdbm + * @param db The database + * @param key The key datum of the next record + */ +APR_DECLARE(apr_status_t) apr_sdbm_nextkey(apr_sdbm_t *db, apr_sdbm_datum_t *key); + +/** + * Returns true if the sdbm database opened for read-only access + * @param db The database to test + */ +APR_DECLARE(int) apr_sdbm_rdonly(apr_sdbm_t *db); +/** @} */ +#endif /* APR_SDBM_H */ diff --git a/include/apr_sha1.h b/include/apr_sha1.h new file mode 100644 index 00000000000..c7ba3cf3cbf --- /dev/null +++ b/include/apr_sha1.h @@ -0,0 +1,121 @@ +/* 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. + */ +/* NIST Secure Hash Algorithm + * heavily modified by Uwe Hollerbach uh@alumni.caltech edu + * from Peter C. Gutmann's implementation as found in + * Applied Cryptography by Bruce Schneier + * This code is hereby placed in the public domain + */ + +#ifndef APR_SHA1_H +#define APR_SHA1_H + +#include "apu.h" +#include "apr_general.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @file apr_sha1.h + * @brief APR-UTIL SHA1 library + */ + +/** size of the SHA1 DIGEST */ +#define APR_SHA1_DIGESTSIZE 20 + +/** + * Define the Magic String prefix that identifies a password as being + * hashed using our algorithm. + */ +#define APR_SHA1PW_ID "{SHA}" + +/** length of the SHA Password */ +#define APR_SHA1PW_IDLEN 5 + +/** @see apr_sha1_ctx_t */ +typedef struct apr_sha1_ctx_t apr_sha1_ctx_t; + +/** + * SHA1 context structure + */ +struct apr_sha1_ctx_t { + /** message digest */ + apr_uint32_t digest[5]; + /** 64-bit bit counts */ + apr_uint32_t count_lo, count_hi; + /** SHA data buffer */ + apr_uint32_t data[16]; + /** unprocessed amount in data */ + int local; +}; + +/** + * Provide a means to SHA1 crypt/encode a plaintext password in a way which + * makes password file compatible with those commonly use in netscape web + * and ldap installations. + * @param clear The plaintext password + * @param len The length of the plaintext password + * @param out The encrypted/encoded password + * @note SHA1 support is useful for migration purposes, but is less + * secure than Apache's password format, since Apache's (MD5) + * password format uses a random eight character salt to generate + * one of many possible hashes for the same password. Netscape + * uses plain SHA1 without a salt, so the same password + * will always generate the same hash, making it easier + * to break since the search space is smaller. + */ +APR_DECLARE(void) apr_sha1_base64(const char *clear, int len, char *out); + +/** + * Initialize the SHA digest + * @param context The SHA context to initialize + */ +APR_DECLARE(void) apr_sha1_init(apr_sha1_ctx_t *context); + +/** + * Update the SHA digest + * @param context The SHA1 context to update + * @param input The buffer to add to the SHA digest + * @param inputLen The length of the input buffer + */ +APR_DECLARE(void) apr_sha1_update(apr_sha1_ctx_t *context, const char *input, + unsigned int inputLen); + +/** + * Update the SHA digest with binary data + * @param context The SHA1 context to update + * @param input The buffer to add to the SHA digest + * @param inputLen The length of the input buffer + */ +APR_DECLARE(void) apr_sha1_update_binary(apr_sha1_ctx_t *context, + const unsigned char *input, + unsigned int inputLen); + +/** + * Finish computing the SHA digest + * @param digest the output buffer in which to store the digest + * @param context The context to finalize + */ +APR_DECLARE(void) apr_sha1_final(unsigned char digest[APR_SHA1_DIGESTSIZE], + apr_sha1_ctx_t *context); + +#ifdef __cplusplus +} +#endif + +#endif /* APR_SHA1_H */ diff --git a/include/apr_shm.h b/include/apr_shm.h new file mode 100644 index 00000000000..635c654b17f --- /dev/null +++ b/include/apr_shm.h @@ -0,0 +1,229 @@ +/* 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. + */ + +#ifndef APR_SHM_H +#define APR_SHM_H + +/** + * @file apr_shm.h + * @brief APR Shared Memory Routines + */ + +#include "apr.h" +#include "apr_pools.h" +#include "apr_errno.h" +#include "apr_perms_set.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup apr_shm Shared Memory Routines + * @ingroup APR + * @{ + */ + +/** + * Private, platform-specific data struture representing a shared memory + * segment. + */ +typedef struct apr_shm_t apr_shm_t; + +/** + * Create and make accessible a shared memory segment with default + * properties. + * @param m The shared memory structure to create. + * @param reqsize The desired size of the segment. + * @param filename The file to use for shared memory on platforms that + * require it. + * @param pool the pool from which to allocate the shared memory + * structure. + * @remark A note about Anonymous vs. Named shared memory segments: + * Not all plaforms support anonymous shared memory segments, but in + * some cases it is prefered over other types of shared memory + * implementations. Passing a NULL 'file' parameter to this function + * will cause the subsystem to use anonymous shared memory segments. + * If such a system is not available, APR_ENOTIMPL is returned. + * @remark A note about allocation sizes: + * On some platforms it is necessary to store some metainformation + * about the segment within the actual segment. In order to supply + * the caller with the requested size it may be necessary for the + * implementation to request a slightly greater segment length + * from the subsystem. In all cases, the apr_shm_baseaddr_get() + * function will return the first usable byte of memory. + * + */ +APR_DECLARE(apr_status_t) apr_shm_create(apr_shm_t **m, + apr_size_t reqsize, + const char *filename, + apr_pool_t *pool); + +/** + * Special processing flags for apr_shm_create_ex() and apr_shm_attach_ex(). + */ +#define APR_SHM_NS_LOCAL 1 /* Create or attach to named shared memory + * segment in the "Local" namespace on + * Windows. (Ignored on other platforms.) + * By default, the "Global" namespace is + * used for privileged processes and the + * "Local" namespace is used otherwise. + */ +#define APR_SHM_NS_GLOBAL 2 /* Create or attach to named shared memory + * segment in the "Global" namespace on + * Windows. (Ignored on other platforms.) + */ + +/** + * Create and make accessible a shared memory segment with platform- + * specific processing. + * @param m The shared memory structure to create. + * @param reqsize The desired size of the segment. + * @param filename The file to use for shared memory on platforms that + * require it. + * @param pool the pool from which to allocate the shared memory + * structure. + * @param flags mask of APR_SHM_* (defined above) + * @remark A note about Anonymous vs. Named shared memory segments: + * Not all plaforms support anonymous shared memory segments, but in + * some cases it is prefered over other types of shared memory + * implementations. Passing a NULL 'file' parameter to this function + * will cause the subsystem to use anonymous shared memory segments. + * If such a system is not available, APR_ENOTIMPL is returned. + * @remark A note about allocation sizes: + * On some platforms it is necessary to store some metainformation + * about the segment within the actual segment. In order to supply + * the caller with the requested size it may be necessary for the + * implementation to request a slightly greater segment length + * from the subsystem. In all cases, the apr_shm_baseaddr_get() + * function will return the first usable byte of memory. + * + */ +APR_DECLARE(apr_status_t) apr_shm_create_ex(apr_shm_t **m, + apr_size_t reqsize, + const char *filename, + apr_pool_t *pool, + apr_int32_t flags); + +/** + * Remove named resource associated with a shared memory segment, + * preventing attachments to the resource, but not destroying it. + * @param filename The filename associated with shared-memory segment which + * needs to be removed + * @param pool The pool used for file operations + * @remark This function is only supported on platforms which support + * name-based shared memory segments, and will return APR_ENOTIMPL on + * platforms without such support. Removing the file while the shm + * is in use is not entirely portable, caller may use this to enhance + * obscurity of the resource, but be prepared for the call to fail, + * and for concurrent attempts to create a resource of the same name + * to also fail. The pool cleanup of apr_shm_create (apr_shm_destroy) + * also removes the named resource. + */ +APR_DECLARE(apr_status_t) apr_shm_remove(const char *filename, + apr_pool_t *pool); + +/** + * Delete named resource associated with a shared memory segment, + * preventing attachments to the resource. + * @param m The shared memory segment structure to delete. + * @remark This function is only supported on platforms which support + * name-based shared memory segments, and will return APR_ENOTIMPL on + * platforms without such support. Removing the file while the shm + * is in use is not entirely portable, caller may use this to enhance + * obscurity of the resource, but be prepared for the call to fail, + * and for concurrent attempts to create a resource of the same name + * to also fail. The pool cleanup of apr_shm_create (apr_shm_destroy) + * also removes the named resource. + */ +APR_DECLARE(apr_status_t) apr_shm_delete(apr_shm_t *m); + +/** + * Destroy a shared memory segment and associated memory. + * @param m The shared memory segment structure to destroy. + */ +APR_DECLARE(apr_status_t) apr_shm_destroy(apr_shm_t *m); + +/** + * Attach to a shared memory segment that was created + * by another process. + * @param m The shared memory structure to create. + * @param filename The file used to create the original segment. + * (This MUST match the original filename.) + * @param pool the pool from which to allocate the shared memory + * structure for this process. + */ +APR_DECLARE(apr_status_t) apr_shm_attach(apr_shm_t **m, + const char *filename, + apr_pool_t *pool); + +/** + * Attach to a shared memory segment that was created + * by another process, with platform-specific processing. + * @param m The shared memory structure to create. + * @param filename The file used to create the original segment. + * (This MUST match the original filename.) + * @param pool the pool from which to allocate the shared memory + * structure for this process. + * @param flags mask of APR_SHM_* (defined above) + */ +APR_DECLARE(apr_status_t) apr_shm_attach_ex(apr_shm_t **m, + const char *filename, + apr_pool_t *pool, + apr_int32_t flags); + +/** + * Detach from a shared memory segment without destroying it. + * @param m The shared memory structure representing the segment + * to detach from. + */ +APR_DECLARE(apr_status_t) apr_shm_detach(apr_shm_t *m); + +/** + * Retrieve the base address of the shared memory segment. + * NOTE: This address is only usable within the callers address + * space, since this API does not guarantee that other attaching + * processes will maintain the same address mapping. + * @param m The shared memory segment from which to retrieve + * the base address. + * @return address, aligned by APR_ALIGN_DEFAULT. + */ +APR_DECLARE(void *) apr_shm_baseaddr_get(const apr_shm_t *m); + +/** + * Retrieve the length of a shared memory segment in bytes. + * @param m The shared memory segment from which to retrieve + * the segment length. + */ +APR_DECLARE(apr_size_t) apr_shm_size_get(const apr_shm_t *m); + +/** + * Set shared memory permissions. + */ +APR_PERMS_SET_IMPLEMENT(shm); + +/** + * Get the pool used by this shared memory segment. + */ +APR_POOL_DECLARE_ACCESSOR(shm); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* APR_SHM_T */ diff --git a/include/apr_shmem.h b/include/apr_shmem.h deleted file mode 100644 index 47cf5944fe4..00000000000 --- a/include/apr_shmem.h +++ /dev/null @@ -1,213 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#ifndef APR_SHMEM_H -#define APR_SHMEM_H - -#include "apr.h" -#include "apr_general.h" -#include "apr_errno.h" - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -#if APR_USES_ANONYMOUS_SHM -typedef void ap_shm_name_t; -#elif APR_USES_FILEBASED_SHM -typedef char * ap_shm_name_t; -#elif APR_USES_KEYBASED_SHM -typedef key_t ap_shm_name_t; -#endif - -typedef struct shmem_t ap_shmem_t; - -/* - -=head1 ap_status_t ap_shm_init(ap_shmem_t *m, ap_size_t reqsize, char *file) - -B<Create a pool of shared memory for use later.> - - arg 1) The shared memory block. - arg 2) The size of the shared memory pool. - arg 3) The file to use for the shared memory on platforms that - require it. - arg 4) The pool to use - -=cut - */ -ap_status_t ap_shm_init(ap_shmem_t **m, ap_size_t reqsize, const char *file, ap_pool_t *cont); - -/* - -=head1 ap_status_t ap_shm_destroy(ap_shmem_t *m) - -B<Destroy the shared memory block.> - - arg 1) The shared memory block to destroy. - -=cut - */ -ap_status_t ap_shm_destroy(ap_shmem_t *m); - -/* - -=head1 ap_status_t ap_shm_malloc(ap_shmem_t *c, ap_size_t reqsize) - -B<allocate memory from the block of shared memory.> - - arg 1) The shared memory block to destroy. - arg 2) How much memory to allocate - -=cut - */ -void *ap_shm_malloc(ap_shmem_t *c, ap_size_t reqsize); - -/* - -=head1 void *ap_shm_calloc(ap_shmem_t *shared, ap_size_t size) - -B<allocate memory from the block of shared memory and initialize it to zero.> - - arg 1) The shared memory block to destroy. - arg 2) How much memory to allocate - -=cut - */ -void *ap_shm_calloc(ap_shmem_t *shared, ap_size_t size); - -/* - -=head1 ap_status_t ap_shm_free(ap_shmem_t *shared, void *entity) - -B<free shared memory previously allocated.> - - arg 1) The shared memory block to destroy. - -=cut - */ -ap_status_t ap_shm_free(ap_shmem_t *shared, void *free); - -/* - -=head1 ap_status_t ap_get_shm_name(ap_shmem_t *c, ap_shm_name_t **name) - -B<Get the name of the shared memory segment if not using anonymous shared memory.> - - arg 1) The shared memory block to destroy. - arg 2) The name of the shared memory block, NULL if anonymous - shared memory. - return) APR_USES_ANONYMOUS_SHM if we are using anonymous shared - memory. APR_USES_FILEBASED_SHM if our shared memory is - based on file access. APR_USES_KEYBASED_SHM if shared - memory is based on a key value such as shmctl. If the - shared memory is anonymous, the name is NULL. - -=cut - */ -ap_status_t ap_get_shm_name(ap_shmem_t *c, ap_shm_name_t **name); - -/* - -=head1 ap_status_t ap_set_shm_name(ap_shmem_t *c, ap_shm_name_t *name) - -B<Set the name of the shared memory segment if not using -anonymous shared memory.> This is to allow processes to open -shared memory created by another process. - - arg 1) The shared memory block to destroy. - arg 2) The name of the shared memory block, NULL if anonymous - shared memory. - return) APR_USES_ANONYMOUS_SHM if we are using anonymous shared - memory. APR_SUCCESS if we are using named shared memory - and we were able to assign the name correctly. - -=cut - */ -ap_status_t ap_set_shm_name(ap_shmem_t *c, ap_shm_name_t *name); - -/* - -=head1 ap_status_t ap_open_shmem(ap_shmem_t *c) - -B<Open the shared memory block in a child process.> - - arg 1) The shared memory block to open in the child. - return) This should be called after ap_set_shm_name. The ap_shmem_t - variable must refer to the memory segment to open. - -=cut - */ -ap_status_t ap_open_shmem(ap_shmem_t *c); - -/* - -=head1 ap_status_t ap_shm_avail(ap_shmem_t *c, ap_size_t *size) - -B<Determine how much memory is available in the specified shared memory block> - - arg 1) The shared memory block to open in the child. - arg 2) The amount of space available in the shared memory block. - -=cut - */ -ap_status_t ap_shm_avail(ap_shmem_t *c, ap_size_t *avail); - -#ifdef __cplusplus -} -#endif - -#endif /* ! APR_FILE_IO_H */ - - diff --git a/include/apr_signal.h b/include/apr_signal.h index 34f02ce3737..20631333023 100644 --- a/include/apr_signal.h +++ b/include/apr_signal.h @@ -1,73 +1,109 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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. */ #ifndef APR_SIGNAL_H #define APR_SIGNAL_H -#include "apr_general.h" -#include "apr_errno.h" +/** + * @file apr_signal.h + * @brief APR Signal Handling + */ + +#include "apr.h" +#include "apr_pools.h" + +#if APR_HAVE_SIGNAL_H +#include <signal.h> +#endif #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ -typedef int ap_signum_t; +/** + * @defgroup apr_signal Signal Handling + * @ingroup APR + * @{ + */ -#ifdef __cplusplus -} +#if APR_HAVE_SIGACTION || defined(DOXYGEN) + +#if defined(DARWIN) && !defined(__cplusplus) && !defined(_ANSI_SOURCE) +/* work around Darwin header file bugs + * http://www.opensource.apple.com/bugs/X/BSD%20Kernel/2657228.html + */ +#undef SIG_DFL +#undef SIG_IGN +#undef SIG_ERR +#define SIG_DFL (void (*)(int))0 +#define SIG_IGN (void (*)(int))1 +#define SIG_ERR (void (*)(int))-1 #endif -#endif /* ! APR_SIGNAL_H */ +/** Function prototype for signal handlers */ +typedef void apr_sigfunc_t(int); + +/** + * Set the signal handler function for a given signal + * @param signo The signal (eg... SIGWINCH) + * @param func the function to get called + */ +APR_DECLARE(apr_sigfunc_t *) apr_signal(int signo, apr_sigfunc_t * func); +#if defined(SIG_IGN) && !defined(SIG_ERR) +#define SIG_ERR ((apr_sigfunc_t *) -1) +#endif + +#else /* !APR_HAVE_SIGACTION */ +#define apr_signal(a, b) signal(a, b) +#endif + + +/** + * Get the description for a specific signal number + * @param signum The signal number + * @return The description of the signal + */ +APR_DECLARE(const char *) apr_signal_description_get(int signum); + +/** + * APR-private function for initializing the signal package + * @internal + * @param pglobal The internal, global pool + */ +void apr_signal_init(apr_pool_t *pglobal); + +/** + * Block the delivery of a particular signal + * @param signum The signal number + * @return status + */ +APR_DECLARE(apr_status_t) apr_signal_block(int signum); + +/** + * Enable the delivery of a particular signal + * @param signum The signal number + * @return status + */ +APR_DECLARE(apr_status_t) apr_signal_unblock(int signum); + +/** @} */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* APR_SIGNAL_H */ diff --git a/include/apr_siphash.h b/include/apr_siphash.h new file mode 100644 index 00000000000..d25498bfaf0 --- /dev/null +++ b/include/apr_siphash.h @@ -0,0 +1,147 @@ +/* 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. + */ +/* + SipHash reference C implementation + Copyright (c) 2012-2014 Jean-Philippe Aumasson + <jeanphilippe.aumasson@gmail.com> + Copyright (c) 2012-2014 Daniel J. Bernstein <djb@cr.yp.to> + To the extent possible under law, the author(s) have dedicated all copyright + and related and neighboring rights to this software to the public domain + worldwide. This software is distributed without any warranty. + You should have received a copy of the CC0 Public Domain Dedication along + with this software. If not, see + <http://creativecommons.org/publicdomain/zero/1.0/>. + */ + +#ifndef APR_SIPHASH_H +#define APR_SIPHASH_H + +#include "apr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @file apr_siphash.h + * @brief APR-UTIL siphash library + * "SipHash-c-d is a family of pseudorandom functions (a.k.a. keyed + * hash functions) optimized for speed on short messages", designed by + * Jean-Philippe Aumasson and Daniel J. Bernstein. It generates a 64bit + * hash (or MAC) from the message and a 128bit key. + * See http://cr.yp.to/siphash/siphash-20120620.pdf for the details, + * c is the number of compression rounds, d the number of finalization + * rounds; we also define fast implementations for c = 2 with d = 4 (aka + * siphash-2-4), and c = 4 with d = 8 (aka siphash-4-8), as recommended + * parameters per the authors. + */ + +/** size of the siphash digest */ +#define APR_SIPHASH_DSIZE 8 + +/** size of the siphash key */ +#define APR_SIPHASH_KSIZE 16 + + +/** + * @brief Computes SipHash-c-d, producing a 64bit (APR_SIPHASH_DSIZE) hash + * from a message and a 128bit (APR_SIPHASH_KSIZE) secret key. + * @param src The message + * @param len The length of the message + * @param key The secret key + * @param c The number of compression rounds + * @param d The number of finalization rounds + * @return The hash value as a 64bit unsigned integer + */ +APR_DECLARE(apr_uint64_t) apr_siphash(const void *src, apr_size_t len, + const unsigned char key[APR_SIPHASH_KSIZE], + unsigned int c, unsigned int d); + +/** + * @brief Computes SipHash-c-d, producing a 64bit (APR_SIPHASH_DSIZE) hash + * from a message and a 128bit (APR_SIPHASH_KSIZE) secret key, into a possibly + * unaligned buffer (using the little endian representation as defined by the + * authors for interoperabilty) usable as a MAC. + * @param out The output buffer (or MAC) + * @param src The message + * @param len The length of the message + * @param key The secret key + * @param c The number of compression rounds + * @param d The number of finalization rounds + * @return The hash value as a 64bit unsigned integer + */ +APR_DECLARE(void) apr_siphash_auth(unsigned char out[APR_SIPHASH_DSIZE], + const void *src, apr_size_t len, + const unsigned char key[APR_SIPHASH_KSIZE], + unsigned int c, unsigned int d); + +/** + * @brief Computes SipHash-2-4, producing a 64bit (APR_SIPHASH_DSIZE) hash + * from a message and a 128bit (APR_SIPHASH_KSIZE) secret key. + * @param src The message to hash + * @param len The length of the message + * @param key The secret key + * @return The hash value as a 64bit unsigned integer + */ +APR_DECLARE(apr_uint64_t) apr_siphash24(const void *src, apr_size_t len, + const unsigned char key[APR_SIPHASH_KSIZE]); + +/** + * @brief Computes SipHash-2-4, producing a 64bit (APR_SIPHASH_DSIZE) hash + * from a message and a 128bit (APR_SIPHASH_KSIZE) secret key, into a possibly + * unaligned buffer (using the little endian representation as defined by the + * authors for interoperabilty) usable as a MAC. + * @param out The output buffer (or MAC) + * @param src The message + * @param len The length of the message + * @param key The secret key + * @return The hash value as a 64bit unsigned integer + */ +APR_DECLARE(void) apr_siphash24_auth(unsigned char out[APR_SIPHASH_DSIZE], + const void *src, apr_size_t len, + const unsigned char key[APR_SIPHASH_KSIZE]); + +/** + * @brief Computes SipHash-4-8, producing a 64bit (APR_SIPHASH_DSIZE) hash + * from a message and a 128bit (APR_SIPHASH_KSIZE) secret key. + * @param src The message + * @param len The length of the message + * @param key The secret key + * @return The hash value as a 64bit unsigned integer + */ +APR_DECLARE(apr_uint64_t) apr_siphash48(const void *src, apr_size_t len, + const unsigned char key[APR_SIPHASH_KSIZE]); + +/** + * @brief Computes SipHash-4-8, producing a 64bit (APR_SIPHASH_DSIZE) hash + * from a message and a 128bit (APR_SIPHASH_KSIZE) secret key, into a possibly + * unaligned buffer (using the little endian representation as defined by the + * authors for interoperabilty) usable as a MAC. + * @param out The output buffer (or MAC) + * @param src The message + * @param len The length of the message + * @param key The secret key + * @return The hash value as a 64bit unsigned integer + */ +APR_DECLARE(void) apr_siphash48_auth(unsigned char out[APR_SIPHASH_DSIZE], + const void *src, apr_size_t len, + const unsigned char key[APR_SIPHASH_KSIZE]); + +#ifdef __cplusplus +} +#endif + +#endif /* APR_SIPHASH_H */ diff --git a/include/apr_skiplist.h b/include/apr_skiplist.h new file mode 100644 index 00000000000..1e7ab258c44 --- /dev/null +++ b/include/apr_skiplist.h @@ -0,0 +1,381 @@ +/* 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. + */ + +#ifndef APR_SKIPLIST_H +#define APR_SKIPLIST_H +/** + * @file apr_skiplist.h + * @brief APR skip list implementation + */ + +#include "apr.h" +#include "apr_portable.h" +#include <stdlib.h> + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup apr_skiplist Skip list implementation + * Refer to http://en.wikipedia.org/wiki/Skip_list for information + * about the purpose of and ideas behind skip lists. + * @ingroup APR + * @{ + */ + +/** + * apr_skiplist_compare is the function type that must be implemented + * per object type that is used in a skip list for comparisons to maintain + * order + * */ +typedef int (*apr_skiplist_compare) (void *, void *); + +/** + * apr_skiplist_freefunc is the function type that must be implemented + * to handle elements as they are removed from a skip list. + */ +typedef void (*apr_skiplist_freefunc) (void *); + +/** Opaque structure used to represent the skip list */ +struct apr_skiplist; +/** Opaque structure used to represent the skip list */ +typedef struct apr_skiplist apr_skiplist; + +/** + * Opaque structure used to represent abstract nodes in the skip list + * (an abstraction above the raw elements which are collected in the + * skip list). + */ +struct apr_skiplistnode; +/** Opaque structure */ +typedef struct apr_skiplistnode apr_skiplistnode; + +/** + * Allocate memory using the same mechanism as the skip list. + * @param sl The skip list + * @param size The amount to allocate + * @remark If a pool was provided to apr_skiplist_init(), memory will + * be allocated from the pool or from a free list maintained with + * the skip list. Otherwise, memory will be allocated using the + * C standard library heap functions. + */ +APR_DECLARE(void *) apr_skiplist_alloc(apr_skiplist *sl, size_t size); + +/** + * Free memory using the same mechanism as the skip list. + * @param sl The skip list + * @param mem The object to free + * @remark If a pool was provided to apr_skiplist_init(), memory will + * be added to a free list maintained with the skip list and be available + * to operations on the skip list or to other calls to apr_skiplist_alloc(). + * Otherwise, memory will be freed using the C standard library heap + * functions. + */ +APR_DECLARE(void) apr_skiplist_free(apr_skiplist *sl, void *mem); + +/** + * Allocate a new skip list + * @param sl The pointer in which to return the newly created skip list + * @param p The pool from which to allocate the skip list (optional). + * @remark Unlike most APR functions, a pool is optional. If no pool + * is provided, the C standard library heap functions will be used instead. + */ +APR_DECLARE(apr_status_t) apr_skiplist_init(apr_skiplist **sl, apr_pool_t *p); + +/** + * Set the comparison functions to be used for searching the skip list. + * @param sl The skip list + * @param XXX1 FIXME + * @param XXX2 FIXME + * + * @remark If existing comparison functions are being replaced, the index + * will be replaced during this call. That is a potentially expensive + * operation. + */ +APR_DECLARE(void) apr_skiplist_set_compare(apr_skiplist *sl, apr_skiplist_compare XXX1, + apr_skiplist_compare XXX2); + +/** + * Set the indexing functions to the specified comparison functions and + * rebuild the index. + * @param sl The skip list + * @param XXX1 FIXME + * @param XXX2 FIXME + * + * @remark If an index already exists, it will not be replaced and the + * comparison functions will not be changed. + */ +APR_DECLARE(void) apr_skiplist_add_index(apr_skiplist *sl, apr_skiplist_compare XXX1, + apr_skiplist_compare XXX2); + +/** + * Return the list maintained by the skip list abstraction. + * @param sl The skip list + */ +APR_DECLARE(apr_skiplistnode *) apr_skiplist_getlist(apr_skiplist *sl); + +/** + * Return the next matching element in the skip list using the specified + * comparison function. + * @param sl The skip list + * @param data The value to search for + * @param iter A pointer to the returned skip list node representing the element + * found + * @param func The comparison function to use + */ +APR_DECLARE(void *) apr_skiplist_find_compare(apr_skiplist *sl, + void *data, + apr_skiplistnode **iter, + apr_skiplist_compare func); + +/** + * Return the next matching element in the skip list using the current comparison + * function. + * @param sl The skip list + * @param data The value to search for + * @param iter A pointer to the returned skip list node representing the element + * found + */ +APR_DECLARE(void *) apr_skiplist_find(apr_skiplist *sl, void *data, apr_skiplistnode **iter); + +/** + * Return the last matching element in the skip list using the specified + * comparison function. + * @param sl The skip list + * @param data The value to search for + * @param iter A pointer to the returned skip list node representing the element + * found + * @param func The comparison function to use + */ +APR_DECLARE(void *) apr_skiplist_last_compare(apr_skiplist *sli, void *data, + apr_skiplistnode **iter, + apr_skiplist_compare comp); + +/** + * Return the last matching element in the skip list using the current comparison + * function. + * @param sl The skip list + * @param data The value to search for + * @param iter A pointer to the returned skip list node representing the element + * found + */ +APR_DECLARE(void *) apr_skiplist_last(apr_skiplist *sl, void *data, + apr_skiplistnode **iter); + +/** + * Return the next element in the skip list. + * @param sl The skip list + * @param iter On entry, a pointer to the skip list node to start with; on return, + * a pointer to the skip list node representing the element returned + * @remark If iter points to a NULL value on entry, NULL will be returned. + */ +APR_DECLARE(void *) apr_skiplist_next(apr_skiplist *sl, apr_skiplistnode **iter); + +/** + * Return the previous element in the skip list. + * @param sl The skip list + * @param iter On entry, a pointer to the skip list node to start with; on return, + * a pointer to the skip list node representing the element returned + * @remark If iter points to a NULL value on entry, NULL will be returned. + */ +APR_DECLARE(void *) apr_skiplist_previous(apr_skiplist *sl, apr_skiplistnode **iter); + +/** + * Return the element of the skip list node + * @param iter The skip list node + */ +APR_DECLARE(void *) apr_skiplist_element(apr_skiplistnode *iter); + +/** + * Insert an element into the skip list using the specified comparison function + * if it does not already exist. + * @param sl The skip list + * @param data The element to insert + * @param comp The comparison function to use for placement into the skip list + */ +APR_DECLARE(apr_skiplistnode *) apr_skiplist_insert_compare(apr_skiplist *sl, + void *data, apr_skiplist_compare comp); + +/** + * Insert an element into the skip list using the existing comparison function + * if it does not already exist. + * @param sl The skip list + * @param data The element to insert + * @remark If no comparison function has been set for the skip list, the element + * will not be inserted and NULL will be returned. + */ +APR_DECLARE(apr_skiplistnode *) apr_skiplist_insert(apr_skiplist* sl, void *data); + +/** + * Add an element into the skip list using the specified comparison function + * allowing for duplicates. + * @param sl The skip list + * @param data The element to add + * @param comp The comparison function to use for placement into the skip list + */ +APR_DECLARE(apr_skiplistnode *) apr_skiplist_add_compare(apr_skiplist *sl, + void *data, apr_skiplist_compare comp); + +/** + * Add an element into the skip list using the existing comparison function + * allowing for duplicates. + * @param sl The skip list + * @param data The element to insert + * @remark If no comparison function has been set for the skip list, the element + * will not be inserted and NULL will be returned. + */ +APR_DECLARE(apr_skiplistnode *) apr_skiplist_add(apr_skiplist* sl, void *data); + +/** + * Add an element into the skip list using the specified comparison function + * removing the existing duplicates. + * @param sl The skip list + * @param data The element to insert + * @param comp The comparison function to use for placement into the skip list + * @param myfree A function to be called for each removed duplicate + * @remark If no comparison function has been set for the skip list, the element + * will not be inserted, none will be replaced, and NULL will be returned. + */ +APR_DECLARE(apr_skiplistnode *) apr_skiplist_replace_compare(apr_skiplist *sl, + void *data, apr_skiplist_freefunc myfree, + apr_skiplist_compare comp); + +/** + * Add an element into the skip list using the existing comparison function + * removing the existing duplicates. + * @param sl The skip list + * @param data The element to insert + * @param myfree A function to be called for each removed duplicate + * @remark If no comparison function has been set for the skip list, the element + * will not be inserted, none will be replaced, and NULL will be returned. + */ +APR_DECLARE(apr_skiplistnode *) apr_skiplist_replace(apr_skiplist *sl, + void *data, apr_skiplist_freefunc myfree); + +/** + * Remove a node from the skip list. + * @param sl The skip list + * @param iter The skip list node to remove + * @param myfree A function to be called for the removed element + */ +APR_DECLARE(int) apr_skiplist_remove_node(apr_skiplist *sl, + apr_skiplistnode *iter, + apr_skiplist_freefunc myfree); + +/** + * Remove an element from the skip list using the specified comparison function for + * locating the element. In the case of duplicates, the 1st entry will be removed. + * @param sl The skip list + * @param data The element to remove + * @param myfree A function to be called for each removed element + * @param comp The comparison function to use for placement into the skip list + * @remark If the element is not found, 0 will be returned. Otherwise, the heightXXX + * will be returned. + */ +APR_DECLARE(int) apr_skiplist_remove_compare(apr_skiplist *sl, void *data, + apr_skiplist_freefunc myfree, apr_skiplist_compare comp); + +/** + * Remove an element from the skip list using the existing comparison function for + * locating the element. In the case of duplicates, the 1st entry will be removed. + * @param sl The skip list + * @param data The element to remove + * @param myfree A function to be called for each removed element + * @remark If the element is not found, 0 will be returned. Otherwise, the heightXXX + * will be returned. + * @remark If no comparison function has been set for the skip list, the element + * will not be removed and 0 will be returned. + */ +APR_DECLARE(int) apr_skiplist_remove(apr_skiplist *sl, void *data, apr_skiplist_freefunc myfree); + +/** + * Remove all elements from the skip list. + * @param sl The skip list + * @param myfree A function to be called for each removed element + */ +APR_DECLARE(void) apr_skiplist_remove_all(apr_skiplist *sl, apr_skiplist_freefunc myfree); + +/** + * Remove each element from the skip list. + * @param sl The skip list + * @param myfree A function to be called for each removed element + */ +APR_DECLARE(void) apr_skiplist_destroy(apr_skiplist *sl, apr_skiplist_freefunc myfree); + +/** + * Return the first element in the skip list, removing the element from the skip list. + * @param sl The skip list + * @param myfree A function to be called for the removed element + * @remark NULL will be returned if there are no elements + */ +APR_DECLARE(void *) apr_skiplist_pop(apr_skiplist *sl, apr_skiplist_freefunc myfree); + +/** + * Return the first element in the skip list, leaving the element in the skip list. + * @param sl The skip list + * @remark NULL will be returned if there are no elements + */ +APR_DECLARE(void *) apr_skiplist_peek(apr_skiplist *sl); + +/** + * Return the size of the list (number of elements), in O(1). + * @param sl The skip list + */ +APR_DECLARE(size_t) apr_skiplist_size(const apr_skiplist *sl); + +/** + * Return the height of the list (number of skip paths), in O(1). + * @param sl The skip list + */ +APR_DECLARE(int) apr_skiplist_height(const apr_skiplist *sl); + +/** + * Return the predefined maximum height of the skip list. + * @param sl The skip list + */ +APR_DECLARE(int) apr_skiplist_preheight(const apr_skiplist *sl); + +/** + * Set a predefined maximum height for the skip list. + * @param sl The skip list + * @param to The preheight to set, or a nul/negative value to disable. + * @remark When a preheight is used, the height of each inserted element is + * computed randomly up to this preheight instead of the current skip list's + * height plus one used by the default implementation. Using a preheight can + * probably ensure more fairness with long living elements (since with an + * adaptative height, former elements may have been created with a low height, + * hence a longest path to reach them while the skip list grows). On the other + * hand, the default behaviour (preheight <= 0) with a growing and decreasing + * maximum height is more adaptative/suitable for short living values. + * @note Should be called before any insertion/add. + */ +APR_DECLARE(void) apr_skiplist_set_preheight(apr_skiplist *sl, int to); + +/** + * Merge two skip lists. XXX SEMANTICS + * @param sl1 One of two skip lists to be merged + * @param sl2 The other of two skip lists to be merged + */ +APR_DECLARE(apr_skiplist *) apr_skiplist_merge(apr_skiplist *sl1, apr_skiplist *sl2); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* ! APR_SKIPLIST_H */ diff --git a/include/apr_strings.h b/include/apr_strings.h new file mode 100644 index 00000000000..c0642adb211 --- /dev/null +++ b/include/apr_strings.h @@ -0,0 +1,380 @@ +/* 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. + */ + +/* Portions of this file are covered by */ +/* -*- mode: c; c-file-style: "k&r" -*- + + strnatcmp.c -- Perform 'natural order' comparisons of strings in C. + Copyright (C) 2000 by Martin Pool <mbp@humbug.org.au> + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef APR_STRINGS_H +#define APR_STRINGS_H + +/** + * @file apr_strings.h + * @brief APR Strings library + */ + +#include "apr.h" +#include "apr_errno.h" +#include "apr_pools.h" +#define APR_WANT_IOVEC +#include "apr_want.h" + +#if APR_HAVE_STDARG_H +#include <stdarg.h> +#endif + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup apr_strings String routines + * @ingroup APR + * @{ + */ + +/** + * Do a natural order comparison of two strings. + * @param a The first string to compare + * @param b The second string to compare + * @return Either <0, 0, or >0. If the first string is less than the second + * this returns <0, if they are equivalent it returns 0, and if the + * first string is greater than second string it retuns >0. + */ +APR_DECLARE(int) apr_strnatcmp(char const *a, char const *b); + +/** + * Do a natural order comparison of two strings ignoring the case of the + * strings. + * @param a The first string to compare + * @param b The second string to compare + * @return Either <0, 0, or >0. If the first string is less than the second + * this returns <0, if they are equivalent it returns 0, and if the + * first string is greater than second string it retuns >0. + */ +APR_DECLARE(int) apr_strnatcasecmp(char const *a, char const *b); + +/** + * duplicate a string into memory allocated out of a pool + * @param p The pool to allocate out of + * @param s The string to duplicate + * @return The new string or NULL if s == NULL + */ +APR_DECLARE(char *) apr_pstrdup(apr_pool_t *p, const char *s); + +/** + * Create a null-terminated string by making a copy of a sequence + * of characters and appending a null byte + * @param p The pool to allocate out of + * @param s The block of characters to duplicate + * @param n The number of characters to duplicate + * @return The new string or NULL if s == NULL + * @remark This is a faster alternative to apr_pstrndup, for use + * when you know that the string being duplicated really + * has 'n' or more characters. If the string might contain + * fewer characters, use apr_pstrndup. + */ +APR_DECLARE(char *) apr_pstrmemdup(apr_pool_t *p, const char *s, apr_size_t n) +#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4)) + __attribute__((alloc_size(3))) +#endif + ; + +/** + * Duplicate at most n characters of a string into memory allocated + * out of a pool; the new string will be NUL-terminated + * @param p The pool to allocate out of + * @param s The string to duplicate + * @param n The maximum number of characters to duplicate + * @return The new string or NULL if s == NULL + * @remark The amount of memory allocated from the pool is the length + * of the returned string including the NUL terminator + */ +APR_DECLARE(char *) apr_pstrndup(apr_pool_t *p, const char *s, apr_size_t n); + +/** + * Duplicate a block of memory. + * + * @param p The pool to allocate from + * @param m The memory to duplicate + * @param n The number of bytes to duplicate + * @return The new block of memory or NULL if m == NULL + */ +APR_DECLARE(void *) apr_pmemdup(apr_pool_t *p, const void *m, apr_size_t n) +#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4)) + __attribute__((alloc_size(3))) +#endif + ; + +/** + * Concatenate multiple strings, allocating memory out a pool + * @param p The pool to allocate out of + * @param ... The strings to concatenate. The final string must be NULL + * @return The new string + */ +APR_DECLARE_NONSTD(char *) apr_pstrcat(apr_pool_t *p, ...) +#if defined(__GNUC__) && __GNUC__ >= 4 + __attribute__((sentinel)) +#endif + ; + +/** + * Concatenate multiple strings specified in a writev-style vector + * @param p The pool from which to allocate + * @param vec The strings to concatenate + * @param nvec The number of strings to concatenate + * @param nbytes (output) strlen of new string (pass in NULL to omit) + * @return The new string + */ +APR_DECLARE(char *) apr_pstrcatv(apr_pool_t *p, const struct iovec *vec, + apr_size_t nvec, apr_size_t *nbytes); + +/** + * printf-style style printing routine. The data is output to a string + * allocated from a pool + * @param p The pool to allocate out of + * @param fmt The format of the string + * @param ap The arguments to use while printing the data + * @return The new string + */ +APR_DECLARE(char *) apr_pvsprintf(apr_pool_t *p, const char *fmt, va_list ap); + +/** + * printf-style style printing routine. The data is output to a string + * allocated from a pool + * @param p The pool to allocate out of + * @param fmt The format of the string + * @param ... The arguments to use while printing the data + * @return The new string + */ +APR_DECLARE_NONSTD(char *) apr_psprintf(apr_pool_t *p, const char *fmt, ...) + __attribute__((format(printf,2,3))); + +/** + * Copy up to dst_size characters from src to dst; does not copy + * past a NUL terminator in src, but always terminates dst with a NUL + * regardless. + * @param dst The destination string + * @param src The source string + * @param dst_size The space available in dst; dst always receives + * NUL termination, so if src is longer than + * dst_size, the actual number of characters copied is + * dst_size - 1. + * @return Pointer to the NUL terminator of the destination string, dst + * @remark + * <PRE> + * Note the differences between this function and strncpy(): + * 1) strncpy() doesn't always NUL terminate; apr_cpystrn() does. + * 2) strncpy() pads the destination string with NULs, which is often + * unnecessary; apr_cpystrn() does not. + * 3) strncpy() returns a pointer to the beginning of the dst string; + * apr_cpystrn() returns a pointer to the NUL terminator of dst, + * to allow a check for truncation. + * </PRE> + */ +APR_DECLARE(char *) apr_cpystrn(char *dst, const char *src, + apr_size_t dst_size); + +/** + * Remove all whitespace from a string + * @param dest The destination string. It is okay to modify the string + * in place. Namely dest == src + * @param src The string to rid the spaces from. + * @return A pointer to the destination string's null terminator. + */ +APR_DECLARE(char *) apr_collapse_spaces(char *dest, const char *src); + +/** + * Convert the arguments to a program from one string to an array of + * strings terminated by a NULL pointer + * @param arg_str The arguments to convert + * @param argv_out Output location. This is a pointer to an array of strings. + * @param token_context Pool to use. + */ +APR_DECLARE(apr_status_t) apr_tokenize_to_argv(const char *arg_str, + char ***argv_out, + apr_pool_t *token_context); + +/** + * Split a string into separate null-terminated tokens. The tokens are + * delimited in the string by one or more characters from the sep + * argument. + * @param str The string to separate; this should be specified on the + * first call to apr_strtok() for a given string, and NULL + * on subsequent calls. + * @param sep The set of delimiters + * @param last State saved by apr_strtok() between calls. + * @return The next token from the string + * @note the 'last' state points to the trailing NUL char of the final + * token, otherwise it points to the character following the current + * token (all successive or empty occurances of sep are skiped on the + * subsequent call to apr_strtok). Therefore it is possible to avoid + * a strlen() determination, with the following logic; + * toklen = last - retval; if (*last) --toklen; + */ +APR_DECLARE(char *) apr_strtok(char *str, const char *sep, char **last); + +/** + * @defgroup APR_Strings_Snprintf snprintf implementations + * @warning + * These are snprintf implementations based on apr_vformatter(). + * + * Note that various standards and implementations disagree on the return + * value of snprintf, and side-effects due to %n in the formatting string. + * apr_snprintf (and apr_vsnprintf) behaves as follows: + * + * Process the format string until the entire string is exhausted, or + * the buffer fills. If the buffer fills then stop processing immediately + * (so no further %n arguments are processed), and return the buffer + * length. In all cases the buffer is NUL terminated. It will return the + * number of characters inserted into the buffer, not including the + * terminating NUL. As a special case, if len is 0, apr_snprintf will + * return the number of characters that would have been inserted if + * the buffer had been infinite (in this case, *buffer can be NULL) + * + * In no event does apr_snprintf return a negative number. + * @{ + */ + +/** + * snprintf routine based on apr_vformatter. This means it understands the + * same extensions. + * @param buf The buffer to write to + * @param len The size of the buffer + * @param format The format string + * @param ... The arguments to use to fill out the format string. + */ +APR_DECLARE_NONSTD(int) apr_snprintf(char *buf, apr_size_t len, + const char *format, ...) + __attribute__((format(printf,3,4))); + +/** + * vsnprintf routine based on apr_vformatter. This means it understands the + * same extensions. + * @param buf The buffer to write to + * @param len The size of the buffer + * @param format The format string + * @param ap The arguments to use to fill out the format string. + */ +APR_DECLARE(int) apr_vsnprintf(char *buf, apr_size_t len, const char *format, + va_list ap); +/** @} */ + +/** + * create a string representation of an int, allocated from a pool + * @param p The pool from which to allocate + * @param n The number to format + * @return The string representation of the number + */ +APR_DECLARE(char *) apr_itoa(apr_pool_t *p, int n); + +/** + * create a string representation of a long, allocated from a pool + * @param p The pool from which to allocate + * @param n The number to format + * @return The string representation of the number + */ +APR_DECLARE(char *) apr_ltoa(apr_pool_t *p, long n); + +/** + * create a string representation of an apr_off_t, allocated from a pool + * @param p The pool from which to allocate + * @param n The number to format + * @return The string representation of the number + */ +APR_DECLARE(char *) apr_off_t_toa(apr_pool_t *p, apr_off_t n); + +/** + * Convert a numeric string into an apr_off_t numeric value. + * @param offset The value of the parsed string. + * @param buf The string to parse. It may contain optional whitespace, + * followed by an optional '+' (positive, default) or '-' (negative) + * character, followed by an optional '0x' prefix if base is 0 or 16, + * followed by numeric digits appropriate for base. + * @param end A pointer to the end of the valid character in buf. If + * not NULL, it is set to the first invalid character in buf. + * @param base A numeric base in the range between 2 and 36 inclusive, + * or 0. If base is zero, buf will be treated as base ten unless its + * digits are prefixed with '0x', in which case it will be treated as + * base 16. + * @bug *end breaks type safety; where *buf is const, *end needs to be + * declared as const in APR 2.0 + */ +APR_DECLARE(apr_status_t) apr_strtoff(apr_off_t *offset, const char *buf, + char **end, int base); + +/** + * parse a numeric string into a 64-bit numeric value + * @param buf The string to parse. It may contain optional whitespace, + * followed by an optional '+' (positive, default) or '-' (negative) + * character, followed by an optional '0x' prefix if base is 0 or 16, + * followed by numeric digits appropriate for base. + * @param end A pointer to the end of the valid character in buf. If + * not NULL, it is set to the first invalid character in buf. + * @param base A numeric base in the range between 2 and 36 inclusive, + * or 0. If base is zero, buf will be treated as base ten unless its + * digits are prefixed with '0x', in which case it will be treated as + * base 16. + * @return The numeric value of the string. On overflow, errno is set + * to ERANGE. On success, errno is set to 0. + */ +APR_DECLARE(apr_int64_t) apr_strtoi64(const char *buf, char **end, int base); + +/** + * parse a base-10 numeric string into a 64-bit numeric value. + * Equivalent to apr_strtoi64(buf, (char**)NULL, 10). + * @param buf The string to parse + * @return The numeric value of the string. On overflow, errno is set + * to ERANGE. On success, errno is set to 0. + */ +APR_DECLARE(apr_int64_t) apr_atoi64(const char *buf); + +/** + * Format a binary size (magnitiudes are 2^10 rather than 10^3) from an apr_off_t, + * as bytes, K, M, T, etc, to a four character compacted human readable string. + * @param size The size to format + * @param buf The 5 byte text buffer (counting the trailing null) + * @return The buf passed to apr_strfsize() + * @remark All negative sizes report ' - ', apr_strfsize only formats positive values. + */ +APR_DECLARE(char *) apr_strfsize(apr_off_t size, char *buf); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* !APR_STRINGS_H */ diff --git a/include/apr_strmatch.h b/include/apr_strmatch.h new file mode 100644 index 00000000000..713970c9081 --- /dev/null +++ b/include/apr_strmatch.h @@ -0,0 +1,81 @@ +/* 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. + */ + +#ifndef APR_STRMATCH_H +#define APR_STRMATCH_H +/** + * @file apr_strmatch.h + * @brief APR-UTIL string matching routines + */ + +#include "apu.h" +#include "apr_pools.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup APR_Util_StrMatch String matching routines + * @ingroup APR + * @{ + */ + +/** @see apr_strmatch_pattern */ +typedef struct apr_strmatch_pattern apr_strmatch_pattern; + +/** + * Precompiled search pattern + */ +struct apr_strmatch_pattern { + /** Function called to compare */ + const char *(*compare)(const apr_strmatch_pattern *this_pattern, + const char *s, apr_size_t slen); + const char *pattern; /**< Current pattern */ + apr_size_t length; /**< Current length */ + void *context; /**< hook to add precomputed metadata */ +}; + +#if defined(DOXYGEN) +/** + * Search for a precompiled pattern within a string + * @param pattern The pattern + * @param s The string in which to search for the pattern + * @param slen The length of s (excluding null terminator) + * @return A pointer to the first instance of the pattern in s, or + * NULL if not found + */ +APR_DECLARE(const char *) apr_strmatch(const apr_strmatch_pattern *pattern, + const char *s, apr_size_t slen); +#else +#define apr_strmatch(pattern, s, slen) (*((pattern)->compare))((pattern), (s), (slen)) +#endif + +/** + * Precompile a pattern for matching using the Boyer-Moore-Horspool algorithm + * @param p The pool from which to allocate the pattern + * @param s The pattern string + * @param case_sensitive Whether the matching should be case-sensitive + * @return a pointer to the compiled pattern, or NULL if compilation fails + */ +APR_DECLARE(const apr_strmatch_pattern *) apr_strmatch_precompile(apr_pool_t *p, const char *s, int case_sensitive); + +/** @} */ +#ifdef __cplusplus +} +#endif + +#endif /* !APR_STRMATCH_H */ diff --git a/include/apr_strnatcmp.h b/include/apr_strnatcmp.h deleted file mode 100644 index c65f6dfb6d5..00000000000 --- a/include/apr_strnatcmp.h +++ /dev/null @@ -1,37 +0,0 @@ -/* -*- mode: c; c-file-style: "k&r" -*- - - strnatcmp.c -- Perform 'natural order' comparisons of strings in C. - Copyright (C) 2000 by Martin Pool <mbp@humbug.org.au> - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. -*/ - -#ifndef APR_STRNATCMP_H -#define APR_STRNATCMP_H - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -int ap_strnatcmp(char const *a, char const *b); -int ap_strnatcasecmp(char const *a, char const *b); - -#ifdef __cplusplus -} -#endif - -#endif /* !APR_STRNATCMP_H */ diff --git a/include/apr_tables.h b/include/apr_tables.h new file mode 100644 index 00000000000..fe3084bd646 --- /dev/null +++ b/include/apr_tables.h @@ -0,0 +1,507 @@ +/* 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. + */ + +#ifndef APR_TABLES_H +#define APR_TABLES_H + +/** + * @file apr_tables.h + * @brief APR Table library + */ + +#include "apr.h" +#include "apr_pools.h" + +#if APR_HAVE_STDARG_H +#include <stdarg.h> /* for va_list */ +#endif + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup apr_tables Table and Array Functions + * @ingroup APR + * Arrays are used to store data which is referenced sequentially or + * as a stack. Functions are provided to push and pop individual + * elements as well as to operate on the entire array. + * + * Tables are used to store data which can be referenced by key. + * Limited capabilities are provided for tables with multiple elements + * which share a key; while key lookup will return only a single + * element, iteration is available. Additionally, a table can be + * compressed to resolve duplicates. + * + * Both arrays and tables may store string or binary data; some features, + * such as concatenation or merging of elements, work only for string + * data. + * @{ + */ + +/** the table abstract data type */ +typedef struct apr_table_t apr_table_t; + +/** @see apr_array_header_t */ +typedef struct apr_array_header_t apr_array_header_t; + +/** An opaque array type */ +struct apr_array_header_t { + /** The pool the array is allocated out of */ + apr_pool_t *pool; + /** The amount of memory allocated for each element of the array */ + int elt_size; + /** The number of active elements in the array */ + int nelts; + /** The number of elements allocated in the array */ + int nalloc; + /** The elements in the array */ + char *elts; +}; + +/** + * The (opaque) structure for string-content tables. + */ +typedef struct apr_table_entry_t apr_table_entry_t; + +/** The type for each entry in a string-content table */ +struct apr_table_entry_t { + /** The key for the current table entry */ + char *key; /* maybe NULL in future; + * check when iterating thru table_elts + */ + /** The value for the current table entry */ + char *val; + + /** A checksum for the key, for use by the apr_table internals */ + apr_uint32_t key_checksum; +}; + +/** + * Get the elements from a table. + * @param t The table + * @return An array containing the contents of the table + */ +APR_DECLARE(const apr_array_header_t *) apr_table_elts(const apr_table_t *t); + +/** + * Determine if the table is empty (either NULL or having no elements). + * @param t The table to check + * @return True if empty, False otherwise + */ +APR_DECLARE(int) apr_is_empty_table(const apr_table_t *t); + +/** + * Determine if the array is empty (either NULL or having no elements). + * @param a The array to check + * @return True if empty, False otherwise + */ +APR_DECLARE(int) apr_is_empty_array(const apr_array_header_t *a); + +/** + * Create an array. + * @param p The pool to allocate the memory out of + * @param nelts the number of elements in the initial array + * @param elt_size The size of each element in the array. + * @return The new array + */ +APR_DECLARE(apr_array_header_t *) apr_array_make(apr_pool_t *p, + int nelts, int elt_size); + +/** + * Add a new element to an array (as a first-in, last-out stack). + * @param arr The array to add an element to. + * @return Location for the new element in the array. + * @remark If there are no free spots in the array, then this function will + * allocate new space for the new element. + */ +APR_DECLARE(void *) apr_array_push(apr_array_header_t *arr); + +/** A helper macro for accessing a member of an APR array. + * + * @param ary the array + * @param i the index into the array to return + * @param type the type of the objects stored in the array + * + * @return the item at index i + */ +#define APR_ARRAY_IDX(ary,i,type) (((type *)(ary)->elts)[i]) + +/** A helper macro for pushing elements into an APR array. + * + * @param ary the array + * @param type the type of the objects stored in the array + * + * @return the location where the new object should be placed + */ +#define APR_ARRAY_PUSH(ary,type) (*((type *)apr_array_push(ary))) + +/** + * Remove an element from an array (as a first-in, last-out stack). + * @param arr The array to remove an element from. + * @return Location of the element in the array. + * @remark If there are no elements in the array, NULL is returned. + */ +APR_DECLARE(void *) apr_array_pop(apr_array_header_t *arr); + +/** + * Remove all elements from an array. + * @param arr The array to remove all elements from. + * @remark As the underlying storage is allocated from a pool, no + * memory is freed by this operation, but is available for reuse. + */ +APR_DECLARE(void) apr_array_clear(apr_array_header_t *arr); + +/** + * Concatenate two arrays together. + * @param dst The destination array, and the one to go first in the combined + * array + * @param src The source array to add to the destination array + */ +APR_DECLARE(void) apr_array_cat(apr_array_header_t *dst, + const apr_array_header_t *src); + +/** + * Copy the entire array. + * @param p The pool to allocate the copy of the array out of + * @param arr The array to copy + * @return An exact copy of the array passed in + * @remark The alternate apr_array_copy_hdr copies only the header, and arranges + * for the elements to be copied if (and only if) the code subsequently + * does a push or arraycat. + */ +APR_DECLARE(apr_array_header_t *) apr_array_copy(apr_pool_t *p, + const apr_array_header_t *arr); +/** + * Copy the headers of the array, and arrange for the elements to be copied if + * and only if the code subsequently does a push or arraycat. + * @param p The pool to allocate the copy of the array out of + * @param arr The array to copy + * @return An exact copy of the array passed in + * @remark The alternate apr_array_copy copies the *entire* array. + */ +APR_DECLARE(apr_array_header_t *) apr_array_copy_hdr(apr_pool_t *p, + const apr_array_header_t *arr); + +/** + * Append one array to the end of another, creating a new array in the process. + * @param p The pool to allocate the new array out of + * @param first The array to put first in the new array. + * @param second The array to put second in the new array. + * @return A new array containing the data from the two arrays passed in. +*/ +APR_DECLARE(apr_array_header_t *) apr_array_append(apr_pool_t *p, + const apr_array_header_t *first, + const apr_array_header_t *second); + +/** + * Generate a new string from the apr_pool_t containing the concatenated + * sequence of substrings referenced as elements within the array. The string + * will be empty if all substrings are empty or null, or if there are no + * elements in the array. If sep is non-NUL, it will be inserted between + * elements as a separator. + * @param p The pool to allocate the string out of + * @param arr The array to generate the string from + * @param sep The separator to use + * @return A string containing all of the data in the array. + */ +APR_DECLARE(char *) apr_array_pstrcat(apr_pool_t *p, + const apr_array_header_t *arr, + const char sep); + +/** + * Make a new table. + * @param p The pool to allocate the pool out of + * @param nelts The number of elements in the initial table. + * @return The new table. + * @warning This table can only store text data + */ +APR_DECLARE(apr_table_t *) apr_table_make(apr_pool_t *p, int nelts); + +/** + * Create a new table and copy another table into it. + * @param p The pool to allocate the new table out of + * @param t The table to copy + * @return A copy of the table passed in + * @warning The table keys and respective values are not copied + */ +APR_DECLARE(apr_table_t *) apr_table_copy(apr_pool_t *p, + const apr_table_t *t); + +/** + * Create a new table whose contents are deep copied from the given + * table. A deep copy operation copies all fields, and makes copies + * of dynamically allocated memory pointed to by the fields. + * @param p The pool to allocate the new table out of + * @param t The table to clone + * @return A deep copy of the table passed in + */ +APR_DECLARE(apr_table_t *) apr_table_clone(apr_pool_t *p, + const apr_table_t *t); + +/** + * Delete all of the elements from a table. + * @param t The table to clear + */ +APR_DECLARE(void) apr_table_clear(apr_table_t *t); + +/** + * Get the value associated with a given key from the table. After this call, + * the data is still in the table. + * @param t The table to search for the key + * @param key The key to search for (case does not matter) + * @return The value associated with the key, or NULL if the key does not exist. + */ +APR_DECLARE(const char *) apr_table_get(const apr_table_t *t, const char *key); + +/** + * Get values associated with a given key from the table. If more than one + * value exists, return a comma separated list of values. After this call, the + * data is still in the table. + * @param p The pool to allocate the combined value from, if necessary + * @param t The table to search for the key + * @param key The key to search for (case does not matter) + * @return The value associated with the key, or NULL if the key does not exist. + */ +APR_DECLARE(const char *) apr_table_getm(apr_pool_t *p, const apr_table_t *t, + const char *key); + +/** + * Add a key/value pair to a table. If another element already exists with the + * same key, this will overwrite the old data. + * @param t The table to add the data to. + * @param key The key to use (case does not matter) + * @param val The value to add + * @remark When adding data, this function makes a copy of both the key and the + * value. + */ +APR_DECLARE(void) apr_table_set(apr_table_t *t, const char *key, + const char *val); + +/** + * Add a key/value pair to a table. If another element already exists with the + * same key, this will overwrite the old data. + * @param t The table to add the data to. + * @param key The key to use (case does not matter) + * @param val The value to add + * @warning When adding data, this function does not make a copy of the key or + * the value, so care should be taken to ensure that the values will + * not change after they have been added.. + */ +APR_DECLARE(void) apr_table_setn(apr_table_t *t, const char *key, + const char *val); + +/** + * Remove data from the table. + * @param t The table to remove data from + * @param key The key of the data being removed (case does not matter) + */ +APR_DECLARE(void) apr_table_unset(apr_table_t *t, const char *key); + +/** + * Add data to a table by merging the value with data that has already been + * stored. The merging is done by concatenating the two values, separated + * by the string ", ". + * @param t The table to search for the data + * @param key The key to merge data for (case does not matter) + * @param val The data to add + * @remark If the key is not found, then this function acts like apr_table_add + */ +APR_DECLARE(void) apr_table_merge(apr_table_t *t, const char *key, + const char *val); + +/** + * Add data to a table by merging the value with data that has already been + * stored. The merging is done by concatenating the two values, separated + * by the string ", ". + * @param t The table to search for the data + * @param key The key to merge data for (case does not matter) + * @param val The data to add + * @remark If the key is not found, then this function acts like apr_table_addn + */ +APR_DECLARE(void) apr_table_mergen(apr_table_t *t, const char *key, + const char *val); + +/** + * Add data to a table, regardless of whether there is another element with the + * same key. + * @param t The table to add to + * @param key The key to use + * @param val The value to add. + * @remark When adding data, this function makes a copy of both the key and the + * value. + */ +APR_DECLARE(void) apr_table_add(apr_table_t *t, const char *key, + const char *val); + +/** + * Add data to a table, regardless of whether there is another element with the + * same key. + * @param t The table to add to + * @param key The key to use + * @param val The value to add. + * @remark When adding data, this function does not make a copy of the key or the + * value, so care should be taken to ensure that the values will not + * change after they have been added. + */ +APR_DECLARE(void) apr_table_addn(apr_table_t *t, const char *key, + const char *val); + +/** + * Merge two tables into one new table. + * @param p The pool to use for the new table + * @param overlay The first table to put in the new table + * @param base The table to add at the end of the new table + * @return A new table containing all of the data from the two passed in + */ +APR_DECLARE(apr_table_t *) apr_table_overlay(apr_pool_t *p, + const apr_table_t *overlay, + const apr_table_t *base); + +/** + * Declaration prototype for the iterator callback function of apr_table_do() + * and apr_table_vdo(). + * @param rec The data passed as the first argument to apr_table_[v]do() + * @param key The key from this iteration of the table + * @param value The value from this iteration of the table + * @remark Iteration continues while this callback function returns non-zero. + * To export the callback function for apr_table_[v]do() it must be declared + * in the _NONSTD convention. + * @see apr_table_do @see apr_table_vdo + */ +typedef int (apr_table_do_callback_fn_t)(void *rec, const char *key, + const char *value); + +/** + * Iterate over a table running the provided function once for every + * element in the table. The varargs array must be a list of zero or + * more (char *) keys followed by a NULL pointer. If zero keys are + * given, the @param comp function will be invoked for every element + * in the table. Otherwise, the function is invoked only for those + * elements matching the keys specified. + * + * If an invocation of the comp function returns zero, + * iteration will continue using the next specified key, if any. + * + * @param comp The function to run + * @param rec The data to pass as the first argument to the function + * @param t The table to iterate over + * @param ... A varargs array of zero or more (char *) keys followed by NULL + * @return FALSE if one of the comp() iterations returned zero; TRUE if all + * iterations returned non-zero + * @see apr_table_do_callback_fn_t @see apr_table_vdo + */ +APR_DECLARE_NONSTD(int) apr_table_do(apr_table_do_callback_fn_t *comp, + void *rec, const apr_table_t *t, ...) +#if defined(__GNUC__) && __GNUC__ >= 4 + __attribute__((sentinel)) +#endif + ; + +/** + * Iterate over a table running the provided function once for every + * element in the table. The vp varargs parameter must be a + * list of zero or more (char *) keys followed by a NULL pointer. If + * zero keys are given, the @param comp function will be invoked for + * every element in the table. Otherwise, the function is invoked + * only for those elements matching the keys specified. + * + * If an invocation of the comp function returns zero, + * iteration will continue using the next specified key, if any. + * + * @param comp The function to run + * @param rec The data to pass as the first argument to the function + * @param t The table to iterate over + * @param vp List of zero or more (char *) keys followed by NULL + * @return FALSE if one of the comp() iterations returned zero; TRUE if all + * iterations returned non-zero + * @see apr_table_do_callback_fn_t @see apr_table_do + */ +APR_DECLARE(int) apr_table_vdo(apr_table_do_callback_fn_t *comp, + void *rec, const apr_table_t *t, va_list vp); + +/** flag for overlap to use apr_table_setn */ +#define APR_OVERLAP_TABLES_SET (0) +/** flag for overlap to use apr_table_mergen */ +#define APR_OVERLAP_TABLES_MERGE (1) +/** flag for overlap to use apr_table_addn */ +#define APR_OVERLAP_TABLES_ADD (2) +/** + * For each element in table b, either use setn or mergen to add the data + * to table a. Which method is used is determined by the flags passed in. + * @param a The table to add the data to. + * @param b The table to iterate over, adding its data to table a + * @param flags How to add the table to table a. One of: + * APR_OVERLAP_TABLES_SET Use apr_table_setn + * APR_OVERLAP_TABLES_MERGE Use apr_table_mergen + * APR_OVERLAP_TABLES_ADD Use apr_table_addn + * @remark When merging duplicates, the two values are concatenated, + * separated by the string ", ". + * @remark This function is highly optimized, and uses less memory and CPU cycles + * than a function that just loops through table b calling other functions. + */ +/** + * Conceptually, apr_table_overlap does this: + * + * <pre> + * apr_array_header_t *barr = apr_table_elts(b); + * apr_table_entry_t *belt = (apr_table_entry_t *)barr->elts; + * int i; + * + * for (i = 0; i < barr->nelts; ++i) { + * if (flags & APR_OVERLAP_TABLES_MERGE) { + * apr_table_mergen(a, belt[i].key, belt[i].val); + * } + * else if (flags & APR_OVERLAP_TABLES_ADD) { + * apr_table_addn(a, belt[i].key, belt[i].val); + * } + * else { + * apr_table_setn(a, belt[i].key, belt[i].val); + * } + * } + * </pre> + * + * Except that it is more efficient (less space and cpu-time) especially + * when b has many elements. + * + * Notice the assumptions on the keys and values in b -- they must be + * in an ancestor of a's pool. In practice b and a are usually from + * the same pool. + */ + +APR_DECLARE(void) apr_table_overlap(apr_table_t *a, const apr_table_t *b, + unsigned flags); + +/** + * Eliminate redundant entries in a table by either overwriting + * or merging duplicates. + * + * @param t Table. + * @param flags APR_OVERLAP_TABLES_MERGE to merge, or + * APR_OVERLAP_TABLES_SET to overwrite, or + * APR_OVERLAP_TABLES_ADD to add + * @remark When merging duplicates, the two values are concatenated, + * separated by the string ", ". + */ +APR_DECLARE(void) apr_table_compress(apr_table_t *t, unsigned flags); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* ! APR_TABLES_H */ diff --git a/include/apr_thread_cond.h b/include/apr_thread_cond.h new file mode 100644 index 00000000000..199f1dedc2a --- /dev/null +++ b/include/apr_thread_cond.h @@ -0,0 +1,139 @@ +/* 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. + */ + +#ifndef APR_THREAD_COND_H +#define APR_THREAD_COND_H + +/** + * @file apr_thread_cond.h + * @brief APR Condition Variable Routines + */ + +#include "apr.h" +#include "apr_pools.h" +#include "apr_errno.h" +#include "apr_time.h" +#include "apr_thread_mutex.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#if APR_HAS_THREADS || defined(DOXYGEN) + +/** + * @defgroup apr_thread_cond Condition Variable Routines + * @ingroup APR + * @{ + */ + +/** Opaque structure for thread condition variables */ +typedef struct apr_thread_cond_t apr_thread_cond_t; + +/** + * Note: destroying a condition variable (or likewise, destroying or + * clearing the pool from which a condition variable was allocated) if + * any threads are blocked waiting on it gives undefined results. + */ + +/** + * Create and initialize a condition variable that can be used to signal + * and schedule threads in a single process. + * @param cond the memory address where the newly created condition variable + * will be stored. + * @param pool the pool from which to allocate the condition. + */ +APR_DECLARE(apr_status_t) apr_thread_cond_create(apr_thread_cond_t **cond, + apr_pool_t *pool); + +/** + * Put the active calling thread to sleep until signaled to wake up. Each + * condition variable must be associated with a mutex, and that mutex must + * be locked before calling this function, or the behavior will be + * undefined. As the calling thread is put to sleep, the given mutex + * will be simultaneously released; and as this thread wakes up the lock + * is again simultaneously acquired. + * @param cond the condition variable on which to block. + * @param mutex the mutex that must be locked upon entering this function, + * is released while the thread is asleep, and is again acquired before + * returning from this function. + * @remark Spurious wakeups may occur. Before and after every call to wait on + * a condition variable, the caller should test whether the condition is already + * met. + */ +APR_DECLARE(apr_status_t) apr_thread_cond_wait(apr_thread_cond_t *cond, + apr_thread_mutex_t *mutex); + +/** + * Put the active calling thread to sleep until signaled to wake up or + * the timeout is reached. Each condition variable must be associated + * with a mutex, and that mutex must be locked before calling this + * function, or the behavior will be undefined. As the calling thread + * is put to sleep, the given mutex will be simultaneously released; + * and as this thread wakes up the lock is again simultaneously acquired. + * @param cond the condition variable on which to block. + * @param mutex the mutex that must be locked upon entering this function, + * is released while the thread is asleep, and is again acquired before + * returning from this function. + * @param timeout The amount of time in microseconds to wait. This is + * a maximum, not a minimum. If the condition is signaled, we + * will wake up before this time, otherwise the error APR_TIMEUP + * is returned. + */ +APR_DECLARE(apr_status_t) apr_thread_cond_timedwait(apr_thread_cond_t *cond, + apr_thread_mutex_t *mutex, + apr_interval_time_t timeout); + +/** + * Signals a single thread, if one exists, that is blocking on the given + * condition variable. That thread is then scheduled to wake up and acquire + * the associated mutex. Although it is not required, if predictable scheduling + * is desired, that mutex must be locked while calling this function. + * @param cond the condition variable on which to produce the signal. + * @remark If no threads are waiting on the condition variable, nothing happens. + */ +APR_DECLARE(apr_status_t) apr_thread_cond_signal(apr_thread_cond_t *cond); + +/** + * Signals all threads blocking on the given condition variable. + * Each thread that was signaled is then scheduled to wake up and acquire + * the associated mutex. This will happen in a serialized manner. + * @param cond the condition variable on which to produce the broadcast. + * @remark If no threads are waiting on the condition variable, nothing happens. + */ +APR_DECLARE(apr_status_t) apr_thread_cond_broadcast(apr_thread_cond_t *cond); + +/** + * Destroy the condition variable and free the associated memory. + * @param cond the condition variable to destroy. + */ +APR_DECLARE(apr_status_t) apr_thread_cond_destroy(apr_thread_cond_t *cond); + +/** + * Get the pool used by this thread_cond. + * @return apr_pool_t the pool + */ +APR_POOL_DECLARE_ACCESSOR(thread_cond); + +#endif /* APR_HAS_THREADS */ + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* ! APR_THREAD_COND_H */ diff --git a/include/apr_thread_mutex.h b/include/apr_thread_mutex.h new file mode 100644 index 00000000000..8eb617291b8 --- /dev/null +++ b/include/apr_thread_mutex.h @@ -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. + */ + +#ifndef APR_THREAD_MUTEX_H +#define APR_THREAD_MUTEX_H + +/** + * @file apr_thread_mutex.h + * @brief APR Thread Mutex Routines + */ + +#include "apr.h" +#include "apr_errno.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#if APR_HAS_THREADS || defined(DOXYGEN) + +/** + * @defgroup apr_thread_mutex Thread Mutex Routines + * @ingroup APR + * @{ + */ + +/** Opaque thread-local mutex structure */ +typedef struct apr_thread_mutex_t apr_thread_mutex_t; + +#define APR_THREAD_MUTEX_DEFAULT 0x0 /**< platform-optimal lock behavior */ +#define APR_THREAD_MUTEX_NESTED 0x1 /**< enable nested (recursive) locks */ +#define APR_THREAD_MUTEX_UNNESTED 0x2 /**< disable nested locks */ +#define APR_THREAD_MUTEX_TIMED 0x4 /**< enable timed locks */ + +/* Delayed the include to avoid a circular reference */ +#include "apr_pools.h" +#include "apr_time.h" + +/** + * Create and initialize a mutex that can be used to synchronize threads. + * @param mutex the memory address where the newly created mutex will be + * stored. + * @param flags Or'ed value of: + * <PRE> + * APR_THREAD_MUTEX_DEFAULT platform-optimal lock behavior. + * APR_THREAD_MUTEX_NESTED enable nested (recursive) locks. + * APR_THREAD_MUTEX_UNNESTED disable nested locks (non-recursive). + * </PRE> + * @param pool the pool from which to allocate the mutex. + * @warning Be cautious in using APR_THREAD_MUTEX_DEFAULT. While this is the + * most optimal mutex based on a given platform's performance characteristics, + * it will behave as either a nested or an unnested lock. + */ +APR_DECLARE(apr_status_t) apr_thread_mutex_create(apr_thread_mutex_t **mutex, + unsigned int flags, + apr_pool_t *pool); +/** + * Acquire the lock for the given mutex. If the mutex is already locked, + * the current thread will be put to sleep until the lock becomes available. + * @param mutex the mutex on which to acquire the lock. + */ +APR_DECLARE(apr_status_t) apr_thread_mutex_lock(apr_thread_mutex_t *mutex); + +/** + * Attempt to acquire the lock for the given mutex. If the mutex has already + * been acquired, the call returns immediately with APR_EBUSY. Note: it + * is important that the APR_STATUS_IS_EBUSY(s) macro be used to determine + * if the return value was APR_EBUSY, for portability reasons. + * @param mutex the mutex on which to attempt the lock acquiring. + */ +APR_DECLARE(apr_status_t) apr_thread_mutex_trylock(apr_thread_mutex_t *mutex); + +/** + * Attempt to acquire the lock for the given mutex until timeout expires. + * If the acquisition time outs, the call returns with APR_TIMEUP. + * @param mutex the mutex on which to attempt the lock acquiring. + * @param timeout the relative timeout (microseconds). + * @note A timeout negative or nul means immediate attempt, returning + * APR_TIMEUP without blocking if it the lock is already acquired. + */ +APR_DECLARE(apr_status_t) apr_thread_mutex_timedlock(apr_thread_mutex_t *mutex, + apr_interval_time_t timeout); + +/** + * Release the lock for the given mutex. + * @param mutex the mutex from which to release the lock. + */ +APR_DECLARE(apr_status_t) apr_thread_mutex_unlock(apr_thread_mutex_t *mutex); + +/** + * Destroy the mutex and free the memory associated with the lock. + * @param mutex the mutex to destroy. + */ +APR_DECLARE(apr_status_t) apr_thread_mutex_destroy(apr_thread_mutex_t *mutex); + +/** + * Get the pool used by this thread_mutex. + * @return apr_pool_t the pool + */ +APR_POOL_DECLARE_ACCESSOR(thread_mutex); + +#endif /* APR_HAS_THREADS */ + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* ! APR_THREAD_MUTEX_H */ diff --git a/include/apr_thread_pool.h b/include/apr_thread_pool.h new file mode 100644 index 00000000000..84abd661e87 --- /dev/null +++ b/include/apr_thread_pool.h @@ -0,0 +1,299 @@ +/* + * 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. + */ + +#ifndef APU_THREAD_POOL_H +#define APU_THREAD_POOL_H + +#include "apu.h" +#include "apr_thread_proc.h" + +/** + * @file apr_thread_pool.h + * @brief APR Thread Pool Library + + * @remarks This library implements a thread pool using apr_thread_t. A thread + * pool is a set of threads that can be created in advance or on demand until a + * maximum number. When a task is scheduled, the thread pool will find an idle + * thread to handle the task. In case all existing threads are busy and the + * number of tasks in the queue is higher than the adjustable threshold, the + * pool will try to create a new thread to serve the task if the maximum number + * has not been reached. Otherwise, the task will be put into a queue based on + * priority, which can be valued from 0 to 255, with higher values being served + * first. If there are tasks with the same priority, the new task might be put at + * the top or at the bottom - it depends on which function is used to put the task. + * + * @remarks There may be the case where the thread pool can use up to the maximum + * number of threads at peak load, but having those threads idle afterwards. A + * maximum number of idle threads can be set so that the extra idling threads will + * be terminated to save system resources. + */ +#if APR_HAS_THREADS + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup APR_Util_TP Thread Pool routines + * @ingroup APR + * @{ + */ + +/** Opaque Thread Pool structure. */ +typedef struct apr_thread_pool apr_thread_pool_t; + +#define APR_THREAD_TASK_PRIORITY_LOWEST 0 +#define APR_THREAD_TASK_PRIORITY_LOW 63 +#define APR_THREAD_TASK_PRIORITY_NORMAL 127 +#define APR_THREAD_TASK_PRIORITY_HIGH 191 +#define APR_THREAD_TASK_PRIORITY_HIGHEST 255 + +/** + * Create a thread pool + * @param me The pointer in which to return the newly created apr_thread_pool + * object, or NULL if thread pool creation fails. + * @param init_threads The number of threads to be created initially, this number + * will also be used as the initial value for the maximum number of idle threads. + * @param max_threads The maximum number of threads that can be created + * @param pool The pool to use + * @return APR_SUCCESS if the thread pool was created successfully. Otherwise, + * the error code. + */ +APR_DECLARE(apr_status_t) apr_thread_pool_create(apr_thread_pool_t **me, + apr_size_t init_threads, + apr_size_t max_threads, + apr_pool_t *pool); + +/** + * Destroy the thread pool and stop all the threads + * @return APR_SUCCESS if all threads are stopped. + */ +APR_DECLARE(apr_status_t) apr_thread_pool_destroy(apr_thread_pool_t *me); + +/** + * Schedule a task to the bottom of the tasks of same priority. + * @param me The thread pool + * @param func The task function + * @param param The parameter for the task function + * @param priority The priority of the task. + * @param owner Owner of this task. + * @return APR_SUCCESS if the task had been scheduled successfully + */ +APR_DECLARE(apr_status_t) apr_thread_pool_push(apr_thread_pool_t *me, + apr_thread_start_t func, + void *param, + apr_byte_t priority, + void *owner); +/** + * Schedule a task to be run after a delay + * @param me The thread pool + * @param func The task function + * @param param The parameter for the task function + * @param time Time in microseconds + * @param owner Owner of this task. + * @return APR_SUCCESS if the task had been scheduled successfully + */ +APR_DECLARE(apr_status_t) apr_thread_pool_schedule(apr_thread_pool_t *me, + apr_thread_start_t func, + void *param, + apr_interval_time_t time, + void *owner); + +/** + * Schedule a task to the top of the tasks of same priority. + * @param me The thread pool + * @param func The task function + * @param param The parameter for the task function + * @param priority The priority of the task. + * @param owner Owner of this task. + * @return APR_SUCCESS if the task had been scheduled successfully + */ +APR_DECLARE(apr_status_t) apr_thread_pool_top(apr_thread_pool_t *me, + apr_thread_start_t func, + void *param, + apr_byte_t priority, + void *owner); + +/** + * Cancel tasks submitted by the owner. If there is any task from the owner that + * is currently running, the function will spin until the task finished. + * @param me The thread pool + * @param owner Owner of the task + * @return APR_SUCCESS if the task has been cancelled successfully + * @note The task function should not be calling cancel, otherwise the function + * may get stuck forever. The function assert if it detect such a case. + */ +APR_DECLARE(apr_status_t) apr_thread_pool_tasks_cancel(apr_thread_pool_t *me, + void *owner); + +/** + * Get the current number of tasks waiting in the queue + * @param me The thread pool + * @return Number of tasks in the queue + */ +APR_DECLARE(apr_size_t) apr_thread_pool_tasks_count(apr_thread_pool_t *me); + +/** + * Get the current number of scheduled tasks waiting in the queue + * @param me The thread pool + * @return Number of scheduled tasks in the queue + */ +APR_DECLARE(apr_size_t) apr_thread_pool_scheduled_tasks_count(apr_thread_pool_t *me); + +/** + * Get the current number of threads + * @param me The thread pool + * @return Total number of threads + */ +APR_DECLARE(apr_size_t) apr_thread_pool_threads_count(apr_thread_pool_t *me); + +/** + * Get the current number of busy threads + * @param me The thread pool + * @return Number of busy threads + */ +APR_DECLARE(apr_size_t) apr_thread_pool_busy_count(apr_thread_pool_t *me); + +/** + * Get the current number of idle threads + * @param me The thread pool + * @return Number of idle threads + */ +APR_DECLARE(apr_size_t) apr_thread_pool_idle_count(apr_thread_pool_t *me); + +/** + * Access function for the maximum number of idle threads. Number of current + * idle threads will be reduced to the new limit. + * @param me The thread pool + * @param cnt The number + * @return The number of threads that were stopped. + */ +APR_DECLARE(apr_size_t) apr_thread_pool_idle_max_set(apr_thread_pool_t *me, + apr_size_t cnt); + +/** + * Get number of tasks that have run + * @param me The thread pool + * @return Number of tasks that have run + */ +APR_DECLARE(apr_size_t) + apr_thread_pool_tasks_run_count(apr_thread_pool_t * me); + +/** + * Get high water mark of the number of tasks waiting to run + * @param me The thread pool + * @return High water mark of tasks waiting to run + */ +APR_DECLARE(apr_size_t) + apr_thread_pool_tasks_high_count(apr_thread_pool_t * me); + +/** + * Get high water mark of the number of threads + * @param me The thread pool + * @return High water mark of threads in thread pool + */ +APR_DECLARE(apr_size_t) + apr_thread_pool_threads_high_count(apr_thread_pool_t * me); + +/** + * Get the number of idle threads that were destroyed after timing out + * @param me The thread pool + * @return Number of idle threads that timed out + */ +APR_DECLARE(apr_size_t) + apr_thread_pool_threads_idle_timeout_count(apr_thread_pool_t * me); + +/** + * Access function for the maximum number of idle threads + * @param me The thread pool + * @return The current maximum number + */ +APR_DECLARE(apr_size_t) apr_thread_pool_idle_max_get(apr_thread_pool_t *me); + +/** + * Access function for the maximum number of threads. + * @param me The thread pool + * @param cnt Number of threads + * @return The original maximum number of threads + */ +APR_DECLARE(apr_size_t) apr_thread_pool_thread_max_set(apr_thread_pool_t *me, + apr_size_t cnt); + +/** + * Access function for the maximum wait time (in microseconds) of an + * idling thread that exceeds the maximum number of idling threads. + * A non-zero value allows for the reaping of idling threads to shrink + * over time. Which helps reduce thrashing. + * @param me The thread pool + * @param timeout The number of microseconds an idle thread should wait + * till it reaps itself + * @return The original maximum wait time + */ +APR_DECLARE(apr_interval_time_t) + apr_thread_pool_idle_wait_set(apr_thread_pool_t * me, + apr_interval_time_t timeout); + +/** + * Access function for the maximum wait time (in microseconds) of an + * idling thread that exceeds the maximum number of idling threads + * @param me The thread pool + * @return The current maximum wait time + */ +APR_DECLARE(apr_interval_time_t) + apr_thread_pool_idle_wait_get(apr_thread_pool_t * me); + +/** + * Access function for the maximum number of threads + * @param me The thread pool + * @return The current maximum number + */ +APR_DECLARE(apr_size_t) apr_thread_pool_thread_max_get(apr_thread_pool_t *me); + +/** + * Access function for the threshold of tasks in queue to trigger a new thread. + * @param me The thread pool + * @param val The new threshold + * @return The original threshold + */ +APR_DECLARE(apr_size_t) apr_thread_pool_threshold_set(apr_thread_pool_t *me, + apr_size_t val); + +/** + * Access function for the threshold of tasks in queue to trigger a new thread. + * @param me The thread pool + * @return The current threshold + */ +APR_DECLARE(apr_size_t) apr_thread_pool_threshold_get(apr_thread_pool_t * me); + +/** + * Get owner of the task currently been executed by the thread. + * @param thd The thread is executing a task + * @param owner Pointer to receive owner of the task. + * @return APR_SUCCESS if the owner is retrieved successfully + */ +APR_DECLARE(apr_status_t) apr_thread_pool_task_owner_get(apr_thread_t *thd, + void **owner); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* APR_HAS_THREADS */ +#endif /* !APR_THREAD_POOL_H */ diff --git a/include/apr_thread_proc.h b/include/apr_thread_proc.h index b2625366c80..a09bdb0bf49 100644 --- a/include/apr_thread_proc.h +++ b/include/apr_thread_proc.h @@ -1,666 +1,834 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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. */ #ifndef APR_THREAD_PROC_H #define APR_THREAD_PROC_H +/** + * @file apr_thread_proc.h + * @brief APR Thread and Process Library + */ + +#include "apr.h" #include "apr_file_io.h" -#include "apr_general.h" +#include "apr_pools.h" #include "apr_errno.h" +#include "apr_perms_set.h" + +#if APR_HAVE_STRUCT_RLIMIT +#include <sys/time.h> +#include <sys/resource.h> +#endif #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ -typedef enum {APR_SHELLCMD, APR_PROGRAM} ap_cmdtype_e; -typedef enum {APR_WAIT, APR_NOWAIT} ap_wait_how_e; - +/** + * @defgroup apr_thread_proc Threads and Process Functions + * @ingroup APR + * @{ + */ + +typedef enum { + APR_SHELLCMD, /**< use the shell to invoke the program */ + APR_PROGRAM, /**< invoke the program directly, no copied env */ + APR_PROGRAM_ENV, /**< invoke the program, replicating our environment */ + APR_PROGRAM_PATH, /**< find program on PATH, use our environment */ + APR_SHELLCMD_ENV /**< use the shell to invoke the program, + * replicating our environment + */ +} apr_cmdtype_e; + +typedef enum { + APR_WAIT, /**< wait for the specified process to finish */ + APR_NOWAIT /**< do not wait -- just see if it has finished */ +} apr_wait_how_e; + +/* I am specifically calling out the values so that the macros below make + * more sense. Yes, I know I don't need to, but I am hoping this makes what + * I am doing more clear. If you want to add more reasons to exit, continue + * to use bitmasks. + */ +typedef enum { + APR_PROC_EXIT = 1, /**< process exited normally */ + APR_PROC_SIGNAL = 2, /**< process exited due to a signal */ + APR_PROC_SIGNAL_CORE = 4 /**< process exited and dumped a core file */ +} apr_exit_why_e; + +/** did we exit the process */ +#define APR_PROC_CHECK_EXIT(x) (x & APR_PROC_EXIT) +/** did we get a signal */ +#define APR_PROC_CHECK_SIGNALED(x) (x & APR_PROC_SIGNAL) +/** did we get core */ +#define APR_PROC_CHECK_CORE_DUMP(x) (x & APR_PROC_SIGNAL_CORE) + +/** @see apr_procattr_io_set */ #define APR_NO_PIPE 0 +/** @see apr_procattr_io_set and apr_file_pipe_create_ex */ #define APR_FULL_BLOCK 1 +/** @see apr_procattr_io_set and apr_file_pipe_create_ex */ #define APR_FULL_NONBLOCK 2 +/** @see apr_procattr_io_set */ #define APR_PARENT_BLOCK 3 +/** @see apr_procattr_io_set */ #define APR_CHILD_BLOCK 4 +/** @see apr_procattr_io_set */ +#define APR_NO_FILE 8 + +/** @see apr_file_pipe_create_ex */ +#define APR_READ_BLOCK 3 +/** @see apr_file_pipe_create_ex */ +#define APR_WRITE_BLOCK 4 + +/** @see apr_procattr_io_set + * @note Win32 only effective with version 1.2.12, portably introduced in 1.3.0 + */ +#define APR_NO_FILE 8 -#define APR_OC_REASON_DEATH 0 /* child has died, caller must call +/** @see apr_procattr_limit_set */ +#define APR_LIMIT_CPU 0 +/** @see apr_procattr_limit_set */ +#define APR_LIMIT_MEM 1 +/** @see apr_procattr_limit_set */ +#define APR_LIMIT_NPROC 2 +/** @see apr_procattr_limit_set */ +#define APR_LIMIT_NOFILE 3 + +/** + * @defgroup APR_OC Other Child Flags + * @{ + */ +#define APR_OC_REASON_DEATH 0 /**< child has died, caller must call * unregister still */ -#define APR_OC_REASON_UNWRITABLE 1 /* write_fd is unwritable */ -#define APR_OC_REASON_RESTART 2 /* a restart is occuring, perform +#define APR_OC_REASON_UNWRITABLE 1 /**< currently unused. */ +#define APR_OC_REASON_RESTART 2 /**< a restart is occurring, perform * any necessary cleanup (including * sending a special signal to child) */ -#define APR_OC_REASON_UNREGISTER 3 /* unregister has been called, do +#define APR_OC_REASON_UNREGISTER 3 /**< unregister has been called, do * whatever is necessary (including * kill the child) */ -#define APR_OC_REASON_LOST 4 /* somehow the child exited without +#define APR_OC_REASON_LOST 4 /**< somehow the child exited without * us knowing ... buggy os? */ +#define APR_OC_REASON_RUNNING 5 /**< a health check is occurring, + * for most maintainence functions + * this is a no-op. + */ +/** @} */ + +/** The APR process type */ +typedef struct apr_proc_t { + /** The process ID */ + pid_t pid; + /** Parent's side of pipe to child's stdin */ + apr_file_t *in; + /** Parent's side of pipe to child's stdout */ + apr_file_t *out; + /** Parent's side of pipe to child's stdouterr */ + apr_file_t *err; +#if APR_HAS_PROC_INVOKED || defined(DOXYGEN) + /** Diagnositics/debugging string of the command invoked for + * this process [only present if APR_HAS_PROC_INVOKED is true] + * @remark Only enabled on Win32 by default. + * @bug This should either always or never be present in release + * builds - since it breaks binary compatibility. We may enable + * it always in APR 1.0 yet leave it undefined in most cases. + */ + char *invoked; +#endif +#if defined(WIN32) || defined(DOXYGEN) + /** (Win32 only) Creator's handle granting access to the process + * @remark This handle is closed and reset to NULL in every case + * corresponding to a waitpid() on Unix which returns the exit status. + * Therefore Win32 correspond's to Unix's zombie reaping characteristics + * and avoids potential handle leaks. + */ + HANDLE hproc; +#endif +} apr_proc_t; -typedef struct ap_thread_t ap_thread_t; -typedef struct ap_threadattr_t ap_threadattr_t; -typedef struct ap_proc_t ap_proc_t; -typedef struct ap_procattr_t ap_procattr_t; - -typedef struct ap_threadkey_t ap_threadkey_t; -typedef struct ap_other_child_rec_t ap_other_child_rec_t; - -typedef void *(API_THREAD_FUNC *ap_thread_start_t)(void *); - -/* Thread Function definitions */ - -/* - -=head1 ap_status_t ap_create_threadattr(ap_threadattr_t **new, ap_pool_t *cont) - -B<Create and initialize a new threadattr variable> - - arg 1) The newly created threadattr. - arg 2) The pool to use - -=cut - */ -ap_status_t ap_create_threadattr(ap_threadattr_t **new, ap_pool_t *cont); - -/* - -=head1 ap_status_t ap_setthreadattr_detach(ap_threadattr_t *attr, ap_int32_t on) - -B<Set if newly created threads should be created in detach mode.> - - arg 1) The threadattr to affect - arg 2) Thread detach state on or off - -=cut - */ -ap_status_t ap_setthreadattr_detach(ap_threadattr_t *attr, ap_int32_t on); - -/* - -=head1 ap_status_t ap_getthreadattr_detach(ap_threadattr_t *attr) - -B<Get the detach mode for this threadattr.> - - arg 1) The threadattr to reference - -=cut - */ -ap_status_t ap_getthreadattr_detach(ap_threadattr_t *iattr); - -/* - -=head1 ap_status_t ap_create_thread(ap_thread_t **new, ap_threadattr_t *attr, ap_thread_start_t func, void *data, ap_pool_t *cont) - -B<Create a new thread of execution> - - arg 1) The newly created thread handle. - arg 2) The threadattr to use to determine how to create the thread - arg 3) The function to start the new thread in - arg 4) Any data to be passed to the starting function - arg 5) The pool to use - -=cut - */ -ap_status_t ap_create_thread(ap_thread_t **new, ap_threadattr_t *attr, - ap_thread_start_t func, void *data, - ap_pool_t *cont); - -/* - -=head1 ap_status_t ap_thread_exit(ap_thread_t *thd, ap_status_t *retval) - -B<stop the current thread> - - arg 1) The thread to stop - arg 2) The return value to pass back to any thread that cares - -=cut - */ -ap_status_t ap_thread_exit(ap_thread_t *thd, ap_status_t *retval); - -/* - -=head1 ap_status_t ap_thread_join(ap_status_t *retval, ap_thread_t *thd) - -B<block until the desired thread stops executing.> - - arg 1) The return value from the dead thread. - arg 2) The thread to join - -=cut - */ -ap_status_t ap_thread_join(ap_status_t *retval, ap_thread_t *thd); - -/* - -=head1 ap_status_t ap_thread_detach(ap_thread_t *thd) - -B<detach a thread> - - arg 1) The thread to detach - -=cut - */ -ap_status_t ap_thread_detach(ap_thread_t *thd); - -/* - -=head1 ap_status_t ap_get_threaddata(void **data, char *key, ap_thread_t *thread) - -B<Return the pool associated with the current thread.> - - arg 1) The user data associated with the thread. - arg 2) The key to associate with the data - arg 3) The currently open thread. - -=cut - */ -ap_status_t ap_get_threaddata(void **data, char *key, ap_thread_t *thread); - -/* - -=head1 ap_status_t ap_set_threaddata(void *data, char *key, ap_status_t (*cleanup) (void *), ap_thread_t *thread) - -B<Return the pool associated with the current thread.> - - arg 1) The user data to associate with the thread. - arg 2) The key to use for associating the data with the tread - arg 3) The cleanup routine to use when the thread is destroyed. - arg 4) The currently open thread. - -=cut - */ -ap_status_t ap_set_threaddata(void *data, char *key, - ap_status_t (*cleanup) (void *), - ap_thread_t *thread); - -/* - -=head1 ap_status_t ap_create_thread_private(ap_threadkey_t **key, void (*dest)(void *), ap_pool_t *cont) - -B<Create and initialize a new thread private address space> - - arg 1) The thread private handle. - arg 2) The destructor to use when freeing the private memory. - arg 3) The pool to use - -=cut - */ -ap_status_t ap_create_thread_private(ap_threadkey_t **key, void (*dest)(void *), - ap_pool_t *cont); - -/* - -=head1 ap_status_t ap_get_thread_private(void **new, ap_threadkey_t *key) - -B<Get a pointer to the thread private memory> - - arg 1) The data stored in private memory - arg 2) The handle for the desired thread private memory - -=cut - */ -ap_status_t ap_get_thread_private(void **new, ap_threadkey_t *key); - -/* - -=head1 ap_status_t ap_set_thread_private(void *priv, ap_threadkey_t *key) - -B<Set the data to be stored in thread private memory> - - arg 1) The data to be stored in private memory - arg 2) The handle for the desired thread private memory - -=cut - */ -ap_status_t ap_set_thread_private(void *priv, ap_threadkey_t *key); - -/* - -=head1 ap_status_t ap_delete_thread_private(ap_threadkey_t *key) - -B<Free the thread private memory> - - arg 1) The handle for the desired thread private memory - -=cut - */ -ap_status_t ap_delete_thread_private(ap_threadkey_t *key); - -/* - -=head1 ap_status_t ap_get_threadkeydata(void **data, char *key, ap_threadkey_t *threadkey) - -B<Return the pool associated with the current threadkey.> - - arg 1) The user data associated with the threadkey. - arg 2) The key associated with the data - arg 3) The currently open threadkey. - -=cut - */ -ap_status_t ap_get_threadkeydata(void **data, char *key, ap_threadkey_t *threadkey); - -/* - -=head1 ap_status_t ap_set_threadkeydata(void *data, char *key, ap_status_t (*cleanup) (void *), ap_threadkey_t *threadkey) - -B<Return the pool associated with the current threadkey.> - - arg 1) The data to set. - arg 2) The key to associate with the data. - arg 3) The cleanup routine to use when the file is destroyed. - arg 4) The currently open threadkey. - -=cut - */ -ap_status_t ap_set_threadkeydata(void *data, char *key, - ap_status_t (*cleanup) (void *), - ap_threadkey_t *threadkey); - -/* Process Function definitions */ -/* - -=head1 ap_status_t ap_createprocattr_init(ap_procattr_t **new, ap_pool_t *cont) - -B<Create and initialize a new procattr variable> - - arg 1) The newly created procattr. - arg 2) The pool to use - -=cut - */ -ap_status_t ap_createprocattr_init(ap_procattr_t **new, ap_pool_t *cont); - -/* - -=head1 ap_status_t ap_setprocattr_io(ap_procattr_t *attr, ap_int32_t in, ap_int32_t *out, ap_int32_t err) - -B<Determine if any of stdin, stdout, or stderr should be linked to pipes when starting a child process.> - - arg 1) The procattr we care about. - arg 2) Should stdin be a pipe back to the parent? - arg 3) Should stdout be a pipe back to the parent? - arg 4) Should stderr be a pipe back to the parent? - -=cut - */ -ap_status_t ap_setprocattr_io(ap_procattr_t *attr, ap_int32_t in, - ap_int32_t out, ap_int32_t err); - -/* - -=head1 ap_status_t ap_setprocattr_childin(ap_procattr_t *attr, ap_file_t *child_in, ap_file_t *parent_in) - -B<Set the child_in and/or parent_in values to existing ap_file_t values.> - - arg 1) The procattr we care about. - arg 2) ap_file_t value to use as child_in. Must be a valid file. - arg 3) ap_file_t value to use as parent_in. Must be a valid file. - -B<NOTE>: This is NOT a required initializer function. This is - useful if you have already opened a pipe (or multiple files) - that you wish to use, perhaps persistently across mutiple - process invocations - such as a log file. You can save some - extra function calls by not creating your own pipe since this - creates one in the process space for you. - -=cut - */ -ap_status_t ap_setprocattr_childin(struct ap_procattr_t *attr, ap_file_t *child_in, - ap_file_t *parent_in); - -/* - -=head1 ap_status_t ap_setprocattr_childout(ap_procattr_t *attr, ap_file_t *child_out, ap_file_t *parent_out) - -B<Set the child_out and parent_out values to existing ap_file_t values.> - - arg 1) The procattr we care about. - arg 2) ap_file_t value to use as child_out. Must be a valid file. - arg 3) ap_file_t value to use as parent_out. Must be a valid file. - -B<NOTE>: This is NOT a required initializer function. This is - useful if you have already opened a pipe (or multiple files) - that you wish to use, perhaps persistently across mutiple - process invocations - such as a log file. - -=cut - */ -ap_status_t ap_setprocattr_childout(struct ap_procattr_t *attr, - ap_file_t *child_out, - ap_file_t *parent_out); - -/* - -=head1 ap_status_t ap_setprocattr_childerr(ap_procattr_t *attr, ap_file_t *child_err, ap_file_t *parent_err) - -B<Set the child_err and parent_err values to existing ap_file_t values.> - - arg 1) The procattr we care about. - arg 2) ap_file_t value to use as child_err. Must be a valid file. - arg 3) ap_file_t value to use as parent_err. Must be a valid file. - -B<NOTE>: This is NOT a required initializer function. This is - useful if you have already opened a pipe (or multiple files) - that you wish to use, perhaps persistently across mutiple - process invocations - such as a log file. - -=cut - */ -ap_status_t ap_setprocattr_childerr(struct ap_procattr_t *attr, - ap_file_t *child_err, - ap_file_t *parent_err); - -/* - -=head1 ap_status_t ap_setprocattr_dir(ap_procattr_t *attr, constchar *dir) - -B<Set which directory the child process should start executing in.> - - arg 1) The procattr we care about. - arg 2) Which dir to start in. By default, this is the same dir as - the parent currently resides in, when the createprocess call - is made. - -=cut - */ -ap_status_t ap_setprocattr_dir(ap_procattr_t *attr, const char *dir); - -/* - -=head1 ap_status_t ap_setprocattr_cmdtype(ap_procattr_t *attr, ap_cmdtype_e cmd) - -B<Set what type of command the child process will call.> - - arg 1) The procattr we care about. - arg 2) The type of command. One of: - APR_SHELLCMD -- Shell script - APR_PROGRAM -- Executable program (default) - -=cut - */ -ap_status_t ap_setprocattr_cmdtype(ap_procattr_t *attr, ap_cmdtype_e cmd); - -/* - -=head1 ap_status_t ap_setprocattr_detach(ap_procattr_t *attr, ap_int32_t detach) - -B<Determine if the chlid should start in detached state.> - - arg 1) The procattr we care about. - arg 2) Should the child start in detached state? Default is no. - -=cut - */ -ap_status_t ap_setprocattr_detach(ap_procattr_t *attr, ap_int32_t detach); - -/* - -=head1 ap_status_t ap_get_procdata(char *key, void *data, ap_proc_t *proc) - -B<Return the pool associated with the current proc.> - - arg 1) The key associated with the data to retreive. - arg 2) The user data associated with the proc. - arg 3) The currently open proc. - -=cut +/** + * The prototype for APR child errfn functions. (See the description + * of apr_procattr_child_errfn_set() for more information.) + * It is passed the following parameters: + * @param pool Pool associated with the apr_proc_t. If your child + * error function needs user data, associate it with this + * pool. + * @param err APR error code describing the error + * @param description Text description of type of processing which failed */ -ap_status_t ap_get_procdata(char *key, void *data, ap_proc_t *proc); +typedef void (apr_child_errfn_t)(apr_pool_t *proc, apr_status_t err, + const char *description); -/* +/** Opaque Thread structure. */ +typedef struct apr_thread_t apr_thread_t; -=head1 ap_status_t ap_set_procdata(void *data, char *key, ap_status_t (*cleanup) (void *), ap_proc_t *proc) +/** Opaque Thread attributes structure. */ +typedef struct apr_threadattr_t apr_threadattr_t; -B<Return the pool associated with the current proc.> +/** Opaque Process attributes structure. */ +typedef struct apr_procattr_t apr_procattr_t; - arg 1) The user data to associate with the file. - arg 2) The key to use for assocaiteing data with the file. - arg 3) The cleanup routine to use when the file is destroyed. - arg 4) The current process. +/** Opaque control variable for one-time atomic variables. */ +typedef struct apr_thread_once_t apr_thread_once_t; -=cut - */ -ap_status_t ap_set_procdata(void *data, char *key, - ap_status_t (*cleanup) (void *), ap_proc_t *proc); - -/* - -=head1 ap_status_t ap_get_childin(ap_file_t **new, ap_proc_t *proc) - -B<Get the file handle that is assocaited with a child's stdin.> +/** Opaque thread private address space. */ +typedef struct apr_threadkey_t apr_threadkey_t; - arg 1) The returned file handle. - arg 2) The process handle that corresponds to the desired child process +/** Opaque record of child process. */ +typedef struct apr_other_child_rec_t apr_other_child_rec_t; -=cut +/** + * The prototype for any APR thread worker functions. */ -ap_status_t ap_get_childin(ap_file_t **new, ap_proc_t *proc); - -/* - -=head1 ap_status_t ap_get_childout(ap_file_t **new, ap_proc_t *proc) - -B<Get the file handle that is assocaited with a child's stdout.> +typedef void *(APR_THREAD_FUNC *apr_thread_start_t)(apr_thread_t*, void*); - arg 1) The returned file handle. - arg 2) The process handle that corresponds to the desired child process +typedef enum { + APR_KILL_NEVER, /**< process is never killed (i.e., never sent + * any signals), but it will be reaped if it exits + * before the pool is cleaned up */ + APR_KILL_ALWAYS, /**< process is sent SIGKILL on apr_pool_t cleanup */ + APR_KILL_AFTER_TIMEOUT, /**< SIGTERM, wait 3 seconds, SIGKILL */ + APR_JUST_WAIT, /**< wait forever for the process to complete */ + APR_KILL_ONLY_ONCE /**< send SIGTERM and then wait */ +} apr_kill_conditions_e; -=cut - */ -ap_status_t ap_get_childout(ap_file_t **new, ap_proc_t *proc); - -/* +/* Thread Function definitions */ -=head1 ap_status_t ap_get_childerr(ap_file_t **new, ap_proc_t *proc) +#if APR_HAS_THREADS + +/** + * Create and initialize a new threadattr variable + * @param new_attr The newly created threadattr. + * @param cont The pool to use + */ +APR_DECLARE(apr_status_t) apr_threadattr_create(apr_threadattr_t **new_attr, + apr_pool_t *cont); + +/** + * Set if newly created threads should be created in detached state. + * @param attr The threadattr to affect + * @param on Non-zero if detached threads should be created. + */ +APR_DECLARE(apr_status_t) apr_threadattr_detach_set(apr_threadattr_t *attr, + apr_int32_t on); + +/** + * Get the detach state for this threadattr. + * @param attr The threadattr to reference + * @return APR_DETACH if threads are to be detached, or APR_NOTDETACH + * if threads are to be joinable. + */ +APR_DECLARE(apr_status_t) apr_threadattr_detach_get(apr_threadattr_t *attr); + +/** + * Set the stack size of newly created threads. + * @param attr The threadattr to affect + * @param stacksize The stack size in bytes + */ +APR_DECLARE(apr_status_t) apr_threadattr_stacksize_set(apr_threadattr_t *attr, + apr_size_t stacksize); + +/** + * Set the stack guard area size of newly created threads. + * @param attr The threadattr to affect + * @param guardsize The stack guard area size in bytes + * @note Thread library implementations commonly use a "guard area" + * after each thread's stack which is not readable or writable such that + * stack overflows cause a segfault; this consumes e.g. 4K of memory + * and increases memory management overhead. Setting the guard area + * size to zero hence trades off reliable behaviour on stack overflow + * for performance. */ +APR_DECLARE(apr_status_t) apr_threadattr_guardsize_set(apr_threadattr_t *attr, + apr_size_t guardsize); + +/** + * Create a new thread of execution + * @param new_thread The newly created thread handle. + * @param attr The threadattr to use to determine how to create the thread + * @param func The function to start the new thread in + * @param data Any data to be passed to the starting function + * @param cont The pool to use + */ +APR_DECLARE(apr_status_t) apr_thread_create(apr_thread_t **new_thread, + apr_threadattr_t *attr, + apr_thread_start_t func, + void *data, apr_pool_t *cont); + +/** + * stop the current thread + * @param thd The thread to stop + * @param retval The return value to pass back to any thread that cares + */ +APR_DECLARE(apr_status_t) apr_thread_exit(apr_thread_t *thd, + apr_status_t retval); + +/** + * block until the desired thread stops executing. + * @param retval The return value from the dead thread. + * @param thd The thread to join + */ +APR_DECLARE(apr_status_t) apr_thread_join(apr_status_t *retval, + apr_thread_t *thd); + +/** + * force the current thread to yield the processor + */ +APR_DECLARE(void) apr_thread_yield(void); + +/** + * Initialize the control variable for apr_thread_once. If this isn't + * called, apr_initialize won't work. + * @param control The control variable to initialize + * @param p The pool to allocate data from. + */ +APR_DECLARE(apr_status_t) apr_thread_once_init(apr_thread_once_t **control, + apr_pool_t *p); + +/** + * Run the specified function one time, regardless of how many threads + * call it. + * @param control The control variable. The same variable should + * be passed in each time the function is tried to be + * called. This is how the underlying functions determine + * if the function has ever been called before. + * @param func The function to call. + */ +APR_DECLARE(apr_status_t) apr_thread_once(apr_thread_once_t *control, + void (*func)(void)); + +/** + * detach a thread + * @param thd The thread to detach + */ +APR_DECLARE(apr_status_t) apr_thread_detach(apr_thread_t *thd); + +/** + * Return user data associated with the current thread. + * @param data The user data associated with the thread. + * @param key The key to associate with the data + * @param thread The currently open thread. + */ +APR_DECLARE(apr_status_t) apr_thread_data_get(void **data, const char *key, + apr_thread_t *thread); + +/** + * Set user data associated with the current thread. + * @param data The user data to associate with the thread. + * @param key The key to use for associating the data with the thread + * @param cleanup The cleanup routine to use when the thread is destroyed. + * @param thread The currently open thread. + */ +APR_DECLARE(apr_status_t) apr_thread_data_set(void *data, const char *key, + apr_status_t (*cleanup) (void *), + apr_thread_t *thread); + +/** + * Create and initialize a new thread private address space + * @param key The thread private handle. + * @param dest The destructor to use when freeing the private memory. + * @param cont The pool to use + */ +APR_DECLARE(apr_status_t) apr_threadkey_private_create(apr_threadkey_t **key, + void (*dest)(void *), + apr_pool_t *cont); + +/** + * Get a pointer to the thread private memory + * @param new_mem The data stored in private memory + * @param key The handle for the desired thread private memory + */ +APR_DECLARE(apr_status_t) apr_threadkey_private_get(void **new_mem, + apr_threadkey_t *key); + +/** + * Set the data to be stored in thread private memory + * @param priv The data to be stored in private memory + * @param key The handle for the desired thread private memory + */ +APR_DECLARE(apr_status_t) apr_threadkey_private_set(void *priv, + apr_threadkey_t *key); + +/** + * Free the thread private memory + * @param key The handle for the desired thread private memory + */ +APR_DECLARE(apr_status_t) apr_threadkey_private_delete(apr_threadkey_t *key); + +/** + * Return the pool associated with the current threadkey. + * @param data The user data associated with the threadkey. + * @param key The key associated with the data + * @param threadkey The currently open threadkey. + */ +APR_DECLARE(apr_status_t) apr_threadkey_data_get(void **data, const char *key, + apr_threadkey_t *threadkey); + +/** + * Return the pool associated with the current threadkey. + * @param data The data to set. + * @param key The key to associate with the data. + * @param cleanup The cleanup routine to use when the file is destroyed. + * @param threadkey The currently open threadkey. + */ +APR_DECLARE(apr_status_t) apr_threadkey_data_set(void *data, const char *key, + apr_status_t (*cleanup) (void *), + apr_threadkey_t *threadkey); -B<Get the file handle that is assocaited with a child's stderr.> +#endif - arg 1) The returned file handle. - arg 2) The process handle that corresponds to the desired child process +/** + * Create and initialize a new procattr variable + * @param new_attr The newly created procattr. + * @param cont The pool to use + */ +APR_DECLARE(apr_status_t) apr_procattr_create(apr_procattr_t **new_attr, + apr_pool_t *cont); + +/** + * Determine if any of stdin, stdout, or stderr should be linked to pipes + * when starting a child process. + * @param attr The procattr we care about. + * @param in Should stdin be a pipe back to the parent? + * @param out Should stdout be a pipe back to the parent? + * @param err Should stderr be a pipe back to the parent? + * @note If APR_NO_PIPE, there will be no special channel, the child + * inherits the parent's corresponding stdio stream. If APR_NO_FILE is + * specified, that corresponding stream is closed in the child (and will + * be INVALID_HANDLE_VALUE when inspected on Win32). This can have ugly + * side effects, as the next file opened in the child on Unix will fall + * into the stdio stream fd slot! + */ +APR_DECLARE(apr_status_t) apr_procattr_io_set(apr_procattr_t *attr, + apr_int32_t in, apr_int32_t out, + apr_int32_t err); + +/** + * Set the child_in and/or parent_in values to existing apr_file_t values. + * @param attr The procattr we care about. + * @param child_in apr_file_t value to use as child_in. Must be a valid file. + * @param parent_in apr_file_t value to use as parent_in. Must be a valid file. + * @remark This is NOT a required initializer function. This is + * useful if you have already opened a pipe (or multiple files) + * that you wish to use, perhaps persistently across multiple + * process invocations - such as a log file. You can save some + * extra function calls by not creating your own pipe since this + * creates one in the process space for you. + * @bug Note that calling this function with two NULL files on some platforms + * creates an APR_FULL_BLOCK pipe, but this behavior is neither portable nor + * is it supported. @see apr_procattr_io_set instead for simple pipes. + */ +APR_DECLARE(apr_status_t) apr_procattr_child_in_set(struct apr_procattr_t *attr, + apr_file_t *child_in, + apr_file_t *parent_in); + +/** + * Set the child_out and parent_out values to existing apr_file_t values. + * @param attr The procattr we care about. + * @param child_out apr_file_t value to use as child_out. Must be a valid file. + * @param parent_out apr_file_t value to use as parent_out. Must be a valid file. + * @remark This is NOT a required initializer function. This is + * useful if you have already opened a pipe (or multiple files) + * that you wish to use, perhaps persistently across multiple + * process invocations - such as a log file. + * @bug Note that calling this function with two NULL files on some platforms + * creates an APR_FULL_BLOCK pipe, but this behavior is neither portable nor + * is it supported. @see apr_procattr_io_set instead for simple pipes. + */ +APR_DECLARE(apr_status_t) apr_procattr_child_out_set(struct apr_procattr_t *attr, + apr_file_t *child_out, + apr_file_t *parent_out); + +/** + * Set the child_err and parent_err values to existing apr_file_t values. + * @param attr The procattr we care about. + * @param child_err apr_file_t value to use as child_err. Must be a valid file. + * @param parent_err apr_file_t value to use as parent_err. Must be a valid file. + * @remark This is NOT a required initializer function. This is + * useful if you have already opened a pipe (or multiple files) + * that you wish to use, perhaps persistently across multiple + * process invocations - such as a log file. + * @bug Note that calling this function with two NULL files on some platforms + * creates an APR_FULL_BLOCK pipe, but this behavior is neither portable nor + * is it supported. @see apr_procattr_io_set instead for simple pipes. + */ +APR_DECLARE(apr_status_t) apr_procattr_child_err_set(struct apr_procattr_t *attr, + apr_file_t *child_err, + apr_file_t *parent_err); + +/** + * Set which directory the child process should start executing in. + * @param attr The procattr we care about. + * @param dir Which dir to start in. By default, this is the same dir as + * the parent currently resides in, when the createprocess call + * is made. + */ +APR_DECLARE(apr_status_t) apr_procattr_dir_set(apr_procattr_t *attr, + const char *dir); + +/** + * Set what type of command the child process will call. + * @param attr The procattr we care about. + * @param cmd The type of command. One of: + * <PRE> + * APR_SHELLCMD -- Anything that the shell can handle + * APR_PROGRAM -- Executable program (default) + * APR_PROGRAM_ENV -- Executable program, copy environment + * APR_PROGRAM_PATH -- Executable program on PATH, copy env + * </PRE> + */ +APR_DECLARE(apr_status_t) apr_procattr_cmdtype_set(apr_procattr_t *attr, + apr_cmdtype_e cmd); + +/** + * Determine if the child should start in detached state. + * @param attr The procattr we care about. + * @param detach Should the child start in detached state? Default is no. + */ +APR_DECLARE(apr_status_t) apr_procattr_detach_set(apr_procattr_t *attr, + apr_int32_t detach); + +#if APR_HAVE_STRUCT_RLIMIT +/** + * Set the Resource Utilization limits when starting a new process. + * @param attr The procattr we care about. + * @param what Which limit to set, one of: + * <PRE> + * APR_LIMIT_CPU + * APR_LIMIT_MEM + * APR_LIMIT_NPROC + * APR_LIMIT_NOFILE + * </PRE> + * @param limit Value to set the limit to. + */ +APR_DECLARE(apr_status_t) apr_procattr_limit_set(apr_procattr_t *attr, + apr_int32_t what, + struct rlimit *limit); +#endif -=cut - */ -ap_status_t ap_get_childerr(ap_file_t **new, ap_proc_t *proc); +/** + * Specify an error function to be called in the child process if APR + * encounters an error in the child prior to running the specified program. + * @param attr The procattr describing the child process to be created. + * @param errfn The function to call in the child process. + * @remark At the present time, it will only be called from apr_proc_create() + * on platforms where fork() is used. It will never be called on other + * platforms, on those platforms apr_proc_create() will return the error + * in the parent process rather than invoke the callback in the now-forked + * child process. + */ +APR_DECLARE(apr_status_t) apr_procattr_child_errfn_set(apr_procattr_t *attr, + apr_child_errfn_t *errfn); + +/** + * Specify that apr_proc_create() should do whatever it can to report + * failures to the caller of apr_proc_create(), rather than find out in + * the child. + * @param attr The procattr describing the child process to be created. + * @param chk Flag to indicate whether or not extra work should be done + * to try to report failures to the caller. + * @remark This flag only affects apr_proc_create() on platforms where + * fork() is used. This leads to extra overhead in the calling + * process, but that may help the application handle such + * errors more gracefully. + */ +APR_DECLARE(apr_status_t) apr_procattr_error_check_set(apr_procattr_t *attr, + apr_int32_t chk); + +/** + * Determine if the child should start in its own address space or using the + * current one from its parent + * @param attr The procattr we care about. + * @param addrspace Should the child start in its own address space? Default + * is no on NetWare and yes on other platforms. + */ +APR_DECLARE(apr_status_t) apr_procattr_addrspace_set(apr_procattr_t *attr, + apr_int32_t addrspace); + +/** + * Set the username used for running process + * @param attr The procattr we care about. + * @param username The username used + * @param password User password if needed. Password is needed on WIN32 + * or any other platform having + * APR_PROCATTR_USER_SET_REQUIRES_PASSWORD set. + */ +APR_DECLARE(apr_status_t) apr_procattr_user_set(apr_procattr_t *attr, + const char *username, + const char *password); + +/** + * Set the group used for running process + * @param attr The procattr we care about. + * @param groupname The group name used + */ +APR_DECLARE(apr_status_t) apr_procattr_group_set(apr_procattr_t *attr, + const char *groupname); + + +/** + * Register permission set function + * @param attr The procattr we care about. + * @param perms_set_fn Permission set callback + * @param data Data to pass to permission callback function + * @param perms Permissions to set + */ +APR_DECLARE(apr_status_t) apr_procattr_perms_set_register(apr_procattr_t *attr, + apr_perms_setfn_t *perms_set_fn, + void *data, + apr_fileperms_t perms); #if APR_HAS_FORK -/* - -=head1 ap_status_t ap_fork(ap_proc_t **proc, ap_pool_t *cont) - -B<This is currently the only non-portable call in APR. This executes a standard unix fork.> - - arg 1) The resulting process handle. - arg 2) The pool to use. - -=cut - */ -ap_status_t ap_fork(ap_proc_t **proc, ap_pool_t *cont); +/** + * This is currently the only non-portable call in APR. This executes + * a standard unix fork. + * @param proc The resulting process handle. + * @param cont The pool to use. + * @remark returns APR_INCHILD for the child, and APR_INPARENT for the parent + * or an error. + */ +APR_DECLARE(apr_status_t) apr_proc_fork(apr_proc_t *proc, apr_pool_t *cont); #endif -/* - -=head1 ap_status_t ap_create_process(ap_proc_t **new, const char *progname, char *const args[], char **env, ap_procattr_t *attr, ap_pool_t *cont) - -B<Create a new process and execute a new program within that process.> - - arg 1) The resulting process handle. - arg 2) The program to run - arg 3) the arguments to pass to the new program. The first one should - be the program name. - arg 4) The new environment ap_table_t for the new process. This should be a - list of NULL-terminated strings. - arg 5) the procattr we should use to determine how to create the new - process - arg 6) The pool to use. - -=cut - */ -ap_status_t ap_create_process(ap_proc_t **new, const char *progname, - char *const args[], char **env, - ap_procattr_t *attr, ap_pool_t *cont); - -/* - -=head1 ap_status_t ap_wait_proc(ap_proc_t *proc, ap_wait_how waithow) - -B<Wait for a child process to die> - - arg 1) The process handle that corresponds to the desired child process - arg 2) How should we wait. One of: - APR_WAIT -- block until the child process dies. - APR_NOWAIT -- return immediately regardless of if the - child is dead or not. - -B<NOTE>: The childs status is in the return code to this process. It is - one of: - APR_CHILD_DONE -- child is no longer running. - APR_CHILD_NOTDONE -- child is still running. - -=cut - */ -ap_status_t ap_wait_proc(ap_proc_t *proc, ap_wait_how_e waithow); - -/* - -=head1 ap_status_t ap_detach(ap_proc_t **new, ap_pool_t *cont) - -B<Detach the process from the controlling terminal.> - - arg 1) The new process handler - arg 2) The pool to use if it is needed. - -=cut - */ -ap_status_t ap_detach(ap_proc_t **new, ap_pool_t *cont); - -/* +/** + * Create a new process and execute a new program within that process. + * @param new_proc The resulting process handle. + * @param progname The program to run + * @param args the arguments to pass to the new program. The first + * one should be the program name. + * @param env The new environment table for the new process. This + * should be a list of NULL-terminated strings. This argument + * is ignored for APR_PROGRAM_ENV, APR_PROGRAM_PATH, and + * APR_SHELLCMD_ENV types of commands. + * @param attr the procattr we should use to determine how to create the new + * process + * @param pool The pool to use. + * @note This function returns without waiting for the new process to terminate; + * use apr_proc_wait for that. + */ +APR_DECLARE(apr_status_t) apr_proc_create(apr_proc_t *new_proc, + const char *progname, + const char * const *args, + const char * const *env, + apr_procattr_t *attr, + apr_pool_t *pool); + +/** + * Wait for a child process to die + * @param proc The process handle that corresponds to the desired child process + * @param exitcode The returned exit status of the child, if a child process + * dies, or the signal that caused the child to die. + * On platforms that don't support obtaining this information, + * the status parameter will be returned as APR_ENOTIMPL. + * @param exitwhy Why the child died, the bitwise or of: + * <PRE> + * APR_PROC_EXIT -- process terminated normally + * APR_PROC_SIGNAL -- process was killed by a signal + * APR_PROC_SIGNAL_CORE -- process was killed by a signal, and + * generated a core dump. + * </PRE> + * @param waithow How should we wait. One of: + * <PRE> + * APR_WAIT -- block until the child process dies. + * APR_NOWAIT -- return immediately regardless of if the + * child is dead or not. + * </PRE> + * @remark The child's status is in the return code to this process. It is one of: + * <PRE> + * APR_CHILD_DONE -- child is no longer running. + * APR_CHILD_NOTDONE -- child is still running. + * </PRE> + */ +APR_DECLARE(apr_status_t) apr_proc_wait(apr_proc_t *proc, + int *exitcode, apr_exit_why_e *exitwhy, + apr_wait_how_e waithow); + +/** + * Wait for any current child process to die and return information + * about that child. + * @param proc Pointer to NULL on entry, will be filled out with child's + * information + * @param exitcode The returned exit status of the child, if a child process + * dies, or the signal that caused the child to die. + * On platforms that don't support obtaining this information, + * the status parameter will be returned as APR_ENOTIMPL. + * @param exitwhy Why the child died, the bitwise or of: + * <PRE> + * APR_PROC_EXIT -- process terminated normally + * APR_PROC_SIGNAL -- process was killed by a signal + * APR_PROC_SIGNAL_CORE -- process was killed by a signal, and + * generated a core dump. + * </PRE> + * @param waithow How should we wait. One of: + * <PRE> + * APR_WAIT -- block until the child process dies. + * APR_NOWAIT -- return immediately regardless of if the + * child is dead or not. + * </PRE> + * @param p Pool to allocate child information out of. + * @bug Passing proc as a *proc rather than **proc was an odd choice + * for some platforms... this should be revisited in 1.0 + */ +APR_DECLARE(apr_status_t) apr_proc_wait_all_procs(apr_proc_t *proc, + int *exitcode, + apr_exit_why_e *exitwhy, + apr_wait_how_e waithow, + apr_pool_t *p); + +#define APR_PROC_DETACH_FOREGROUND 0 /**< Do not detach */ +#define APR_PROC_DETACH_DAEMONIZE 1 /**< Detach */ + +/** + * Detach the process from the controlling terminal. + * @param daemonize set to non-zero if the process should daemonize + * and become a background process, else it will + * stay in the foreground. + */ +APR_DECLARE(apr_status_t) apr_proc_detach(int daemonize); + +/** + * Register an other_child -- a child associated to its registered + * maintence callback. This callback is invoked when the process + * dies, is disconnected or disappears. + * @param proc The child process to register. + * @param maintenance maintenance is a function that is invoked with a + * reason and the data pointer passed here. + * @param data Opaque context data passed to the maintenance function. + * @param write_fd This argument is currently unused and should be passed + * as NULL. + * @param p The pool to use for allocating memory. + */ +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); + +/** + * Stop watching the specified other child. + * @param data The data to pass to the maintenance function. This is + * used to find the process to unregister. + * @warning Since this can be called by a maintenance function while we're + * scanning the other_children list, all scanners should protect + * themself by loading ocr->next before calling any maintenance + * function. + */ +APR_DECLARE(void) apr_proc_other_child_unregister(void *data); + +/** + * Notify the maintenance callback of a registered other child process + * that application has detected an event, such as death. + * @param proc The process to check + * @param reason The reason code to pass to the maintenance function + * @param status The status to pass to the maintenance function + * @remark An example of code using this behavior; + * <pre> + * rv = apr_proc_wait_all_procs(&proc, &exitcode, &status, APR_WAIT, p); + * if (APR_STATUS_IS_CHILD_DONE(rv)) { + * \#if APR_HAS_OTHER_CHILD + * if (apr_proc_other_child_alert(&proc, APR_OC_REASON_DEATH, status) + * == APR_SUCCESS) { + * ; (already handled) + * } + * else + * \#endif + * [... handling non-otherchild processes death ...] + * </pre> + */ +APR_DECLARE(apr_status_t) apr_proc_other_child_alert(apr_proc_t *proc, + int reason, + int status); + +/** + * Test one specific other child processes and invoke the maintenance callback + * with the appropriate reason code, if still running, or the appropriate reason + * code if the process is no longer healthy. + * @param ocr The registered other child + * @param reason The reason code (e.g. APR_OC_REASON_RESTART) if still running + */ +APR_DECLARE(void) apr_proc_other_child_refresh(apr_other_child_rec_t *ocr, + int reason); + +/** + * Test all registered other child processes and invoke the maintenance callback + * with the appropriate reason code, if still running, or the appropriate reason + * code if the process is no longer healthy. + * @param reason The reason code (e.g. APR_OC_REASON_RESTART) to running processes + */ +APR_DECLARE(void) apr_proc_other_child_refresh_all(int reason); + +/** + * Terminate a process. + * @param proc The process to terminate. + * @param sig How to kill the process. + */ +APR_DECLARE(apr_status_t) apr_proc_kill(apr_proc_t *proc, int sig); + +/** + * Register a process to be killed when a pool dies. + * @param a The pool to use to define the processes lifetime + * @param proc The process to register + * @param how How to kill the process, one of: + * <PRE> + * APR_KILL_NEVER -- process is never sent any signals + * APR_KILL_ALWAYS -- process is sent SIGKILL on apr_pool_t cleanup + * APR_KILL_AFTER_TIMEOUT -- SIGTERM, wait 3 seconds, SIGKILL + * APR_JUST_WAIT -- wait forever for the process to complete + * APR_KILL_ONLY_ONCE -- send SIGTERM and then wait + * </PRE> + */ +APR_DECLARE(void) apr_pool_note_subprocess(apr_pool_t *a, apr_proc_t *proc, + apr_kill_conditions_e how); + +#if APR_HAS_THREADS + +#if (APR_HAVE_SIGWAIT || APR_HAVE_SIGSUSPEND) && !defined(OS2) + +/** + * Setup the process for a single thread to be used for all signal handling. + * @warning This must be called before any threads are created + */ +APR_DECLARE(apr_status_t) apr_setup_signal_thread(void); + +/** + * Make the current thread listen for signals. This thread will loop + * forever, calling a provided function whenever it receives a signal. That + * functions should return 1 if the signal has been handled, 0 otherwise. + * @param signal_handler The function to call when a signal is received + * apr_status_t apr_signal_thread((int)(*signal_handler)(int signum)) + */ +APR_DECLARE(apr_status_t) apr_signal_thread(int(*signal_handler)(int signum)); + +#endif /* (APR_HAVE_SIGWAIT || APR_HAVE_SIGSUSPEND) && !defined(OS2) */ + +/** + * Get the child-pool used by the thread from the thread info. + * @return apr_pool_t the pool + */ +APR_POOL_DECLARE_ACCESSOR(thread); + +#endif /* APR_HAS_THREADS */ + +/** @} */ -=head1 void ap_register_other_child(ap_proc_t *pid, void (*maintenance) (int reason, void *data, int status), void *data, int write_fd, ap_pool_t *p) - -B<Register an other_child -- a child which must be kept track of so that the program knows when it has dies or disappeared.> - - arg 1) pid is the pid of the child. - arg 2) maintenance is a function that is invoked with a reason and the - data pointer passed here. - arg 3) The data to pass to the maintenance function. - arg 4) An fd that is probed for writing. If it is ever unwritable - then the maintenance is invoked with reason OC_REASON_UNWRITABLE. - arg 5) The pool to use for allocating memory. - -=cut - */ -/* XXX: it's not clear how write_fd can be made portable -- i think this - * needs to take an ap_file_t, expecting the write_fd to be a pipe. -dean - */ -void ap_register_other_child(ap_proc_t *pid, - void (*maintenance) (int reason, void *, int status), - void *data, int write_fd, ap_pool_t *p); - -/* - -=head1 void ap_unregister_other_child(void *data) - -B<Stop watching the specified process.> - - arg 1) The data to pass to the maintenance function. This is - used to find the process to unregister. - -B<NOTE>: Since this can be called by a maintenance function while we're - scanning the other_children list, all scanners should protect - themself by loading ocr->next before calling any maintenance - function. - -=cut - */ -void ap_unregister_other_children(void *data); - -/* - -=head1 ap_status_t ap_reap_other_child(ap_proc_t *pid, int status) - -B<Check on the specified process. If it is gone, call the maintenance function.> - - arg 1) The process to check. - -=cut - */ -ap_status_t ap_reap_other_child(ap_proc_t *pid, int status); - -/* - -=head1 void ap_check_other_child(void) - -B<Loop through all registered other_children and call the appropriate maintenance function when necessary.> - -=cut - */ -void ap_check_other_child(void); - -/* - -=head1 ap_status_t ap_kill(ap_proc_t *proc, int sig) - -B<Terminate a process.> - - arg 1) The process to terminate. - arg 2) How to kill the process. - -=cut - */ -ap_status_t ap_kill(ap_proc_t *proc, int sig); #ifdef __cplusplus } #endif -#endif /* ! APR_FILE_IO_H */ +#endif /* ! APR_THREAD_PROC_H */ diff --git a/include/apr_thread_rwlock.h b/include/apr_thread_rwlock.h new file mode 100644 index 00000000000..0bd958fbfa3 --- /dev/null +++ b/include/apr_thread_rwlock.h @@ -0,0 +1,129 @@ +/* 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. + */ + +#ifndef APR_THREAD_RWLOCK_H +#define APR_THREAD_RWLOCK_H + +/** + * @file apr_thread_rwlock.h + * @brief APR Reader/Writer Lock Routines + */ + +#include "apr.h" +#include "apr_pools.h" +#include "apr_errno.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#if APR_HAS_THREADS + +/** + * @defgroup apr_thread_rwlock Reader/Writer Lock Routines + * @ingroup APR + * @{ + */ + +/** Opaque read-write thread-safe lock. */ +typedef struct apr_thread_rwlock_t apr_thread_rwlock_t; + +/** + * Note: The following operations have undefined results: unlocking a + * read-write lock which is not locked in the calling thread; write + * locking a read-write lock which is already locked by the calling + * thread; destroying a read-write lock more than once; clearing or + * destroying the pool from which a <b>locked</b> read-write lock is + * allocated. + */ + +/** + * Create and initialize a read-write lock that can be used to synchronize + * threads. + * @param rwlock the memory address where the newly created readwrite lock + * will be stored. + * @param pool the pool from which to allocate the mutex. + */ +APR_DECLARE(apr_status_t) apr_thread_rwlock_create(apr_thread_rwlock_t **rwlock, + apr_pool_t *pool); +/** + * Acquire a shared-read lock on the given read-write lock. This will allow + * multiple threads to enter the same critical section while they have acquired + * the read lock. + * @param rwlock the read-write lock on which to acquire the shared read. + */ +APR_DECLARE(apr_status_t) apr_thread_rwlock_rdlock(apr_thread_rwlock_t *rwlock); + +/** + * Attempt to acquire the shared-read lock on the given read-write lock. This + * is the same as apr_thread_rwlock_rdlock(), only that the function fails + * if there is another thread holding the write lock, or if there are any + * write threads blocking on the lock. If the function fails for this case, + * APR_EBUSY will be returned. Note: it is important that the + * APR_STATUS_IS_EBUSY(s) macro be used to determine if the return value was + * APR_EBUSY, for portability reasons. + * @param rwlock the rwlock on which to attempt the shared read. + */ +APR_DECLARE(apr_status_t) apr_thread_rwlock_tryrdlock(apr_thread_rwlock_t *rwlock); + +/** + * Acquire an exclusive-write lock on the given read-write lock. This will + * allow only one single thread to enter the critical sections. If there + * are any threads currently holding the read-lock, this thread is put to + * sleep until it can have exclusive access to the lock. + * @param rwlock the read-write lock on which to acquire the exclusive write. + */ +APR_DECLARE(apr_status_t) apr_thread_rwlock_wrlock(apr_thread_rwlock_t *rwlock); + +/** + * Attempt to acquire the exclusive-write lock on the given read-write lock. + * This is the same as apr_thread_rwlock_wrlock(), only that the function fails + * if there is any other thread holding the lock (for reading or writing), + * in which case the function will return APR_EBUSY. Note: it is important + * that the APR_STATUS_IS_EBUSY(s) macro be used to determine if the return + * value was APR_EBUSY, for portability reasons. + * @param rwlock the rwlock on which to attempt the exclusive write. + */ +APR_DECLARE(apr_status_t) apr_thread_rwlock_trywrlock(apr_thread_rwlock_t *rwlock); + +/** + * Release either the read or write lock currently held by the calling thread + * associated with the given read-write lock. + * @param rwlock the read-write lock to be released (unlocked). + */ +APR_DECLARE(apr_status_t) apr_thread_rwlock_unlock(apr_thread_rwlock_t *rwlock); + +/** + * Destroy the read-write lock and free the associated memory. + * @param rwlock the rwlock to destroy. + */ +APR_DECLARE(apr_status_t) apr_thread_rwlock_destroy(apr_thread_rwlock_t *rwlock); + +/** + * Get the pool used by this thread_rwlock. + * @return apr_pool_t the pool + */ +APR_POOL_DECLARE_ACCESSOR(thread_rwlock); + +#endif /* APR_HAS_THREADS */ + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* ! APR_THREAD_RWLOCK_H */ diff --git a/include/apr_time.h b/include/apr_time.h index e38cdb84b75..b0efd791c98 100644 --- a/include/apr_time.h +++ b/include/apr_time.h @@ -1,183 +1,234 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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. */ #ifndef APR_TIME_H #define APR_TIME_H -#include "apr_general.h" +/** + * @file apr_time.h + * @brief APR Time Library + */ + +#include "apr.h" #include "apr_errno.h" #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ -API_VAR_IMPORT const char ap_month_snames[12][4]; -API_VAR_IMPORT const char ap_day_snames[7][4]; - -/* number of microseconds since 00:00:00 january 1, 1970 UTC */ -typedef ap_int64_t ap_time_t; - -/* intervals for I/O timeouts, in microseconds */ -typedef ap_int32_t ap_interval_time_t; - -#ifdef WIN32 -#define AP_USEC_PER_SEC ((LONGLONG) 1000000) -#else -/* XXX: this is wrong -- the LL is only required if int64 is implemented as - * a long long, it could be just a long on some platforms. the C99 - * correct way of doing this is to use INT64_C(1000000) which comes - * from stdint.h. we'd probably be doing a Good Thing to check for - * INT64_C in autoconf... or otherwise define an AP_INT64_C(). -dean - */ -#define AP_USEC_PER_SEC (1000000LL) -#endif - -/* - -=head1 ap_time_t ap_now(void) - -B<return the current time> - -=cut +/** + * @defgroup apr_time Time Routines + * @ingroup APR + * @{ */ -ap_time_t ap_now(void); -/* a structure similar to ANSI struct tm with the following differences: - - tm_usec isn't an ANSI field - - tm_gmtoff isn't an ANSI field (it's a bsdism) -*/ -typedef struct { - ap_int32_t tm_usec; /* microseconds past tm_sec */ - ap_int32_t tm_sec; /* (0-61) seconds past tm_min */ - ap_int32_t tm_min; /* (0-59) minutes past tm_hour */ - ap_int32_t tm_hour; /* (0-23) hours past midnight */ - ap_int32_t tm_mday; /* (1-31) day of the month */ - ap_int32_t tm_mon; /* (0-11) month of the year */ - ap_int32_t tm_year; /* year since 1900 */ - ap_int32_t tm_wday; /* (0-6) days since sunday */ - ap_int32_t tm_yday; /* (0-365) days since jan 1 */ - ap_int32_t tm_isdst; /* daylight saving time */ - ap_int32_t tm_gmtoff; /* seconds east of UTC */ -} ap_exploded_time_t; +/** month names */ +APR_DECLARE_DATA extern const char apr_month_snames[12][4]; +/** day names */ +APR_DECLARE_DATA extern const char apr_day_snames[7][4]; -/* -=head1 ap_status_t ap_ansi_time_to_ap_time(ap_time_t *result, time_t input) +/** number of microseconds since 00:00:00 January 1, 1970 UTC */ +typedef apr_int64_t apr_time_t; -B<convert an ansi time_t to an ap_time_t> - arg 1) the resulting ap_time_t - arg 2) the time_t to convert +/** mechanism to properly type apr_time_t literals */ +#define APR_TIME_C(val) APR_INT64_C(val) -=cut - */ -ap_status_t ap_ansi_time_to_ap_time(ap_time_t *result, time_t input); +/** mechanism to properly print apr_time_t values */ +#define APR_TIME_T_FMT APR_INT64_T_FMT -/* +/** intervals for I/O timeouts, in microseconds */ +typedef apr_int64_t apr_interval_time_t; +/** short interval for I/O timeouts, in microseconds */ +typedef apr_int32_t apr_short_interval_time_t; -=head1 ap_status_t ap_explode_gmt(ap_exploded_time_t *result, ap_time_t input) +/** number of microseconds per second */ +#define APR_USEC_PER_SEC APR_TIME_C(1000000) -B<convert a time to its human readable components in GMT timezone> +/** @return apr_time_t as a second */ +#define apr_time_sec(time) ((time) / APR_USEC_PER_SEC) - arg 1) the exploded time - arg 2) the time to explode +/** @return apr_time_t as a usec */ +#define apr_time_usec(time) ((time) % APR_USEC_PER_SEC) -=cut - */ -ap_status_t ap_explode_gmt(ap_exploded_time_t *result, ap_time_t input); +/** @return apr_time_t as a msec */ +#define apr_time_msec(time) (((time) / 1000) % 1000) -/* +/** @return apr_time_t as a msec */ +#define apr_time_as_msec(time) ((time) / 1000) -=head1 ap_status_t ap_explode_localtime(ap_exploded_time_t *result, ap_time_t input) +/** @return milliseconds as an apr_time_t */ +#define apr_time_from_msec(msec) ((apr_time_t)(msec) * 1000) -B<convert a time to its human readable components in local timezone> +/** @return seconds as an apr_time_t */ +#define apr_time_from_sec(sec) ((apr_time_t)(sec) * APR_USEC_PER_SEC) - arg 1) the exploded time - arg 2) the time to explode +/** @return a second and usec combination as an apr_time_t */ +#define apr_time_make(sec, usec) ((apr_time_t)(sec) * APR_USEC_PER_SEC \ + + (apr_time_t)(usec)) -=cut +/** + * @return the current time */ -ap_status_t ap_explode_localtime(ap_exploded_time_t *result, ap_time_t input); - -/* - -=head1 ap_status_t ap_implode_time(ap_time_t *t, ap_exploded_time_t *xt) +APR_DECLARE(apr_time_t) apr_time_now(void); -B<Convert time value from human readable format to number of seconds since epoch> +/** @see apr_time_exp_t */ +typedef struct apr_time_exp_t apr_time_exp_t; - arg 1) the resulting imploded time - arg 2) the input exploded time - -=cut +/** + * a structure similar to ANSI struct tm with the following differences: + * - tm_usec isn't an ANSI field + * - tm_gmtoff isn't an ANSI field (it's a BSDism) + */ +struct apr_time_exp_t { + /** microseconds past tm_sec */ + apr_int32_t tm_usec; + /** (0-61) seconds past tm_min */ + apr_int32_t tm_sec; + /** (0-59) minutes past tm_hour */ + apr_int32_t tm_min; + /** (0-23) hours past midnight */ + apr_int32_t tm_hour; + /** (1-31) day of the month */ + apr_int32_t tm_mday; + /** (0-11) month of the year */ + apr_int32_t tm_mon; + /** year since 1900 */ + apr_int32_t tm_year; + /** (0-6) days since Sunday */ + apr_int32_t tm_wday; + /** (0-365) days since January 1 */ + apr_int32_t tm_yday; + /** daylight saving time */ + apr_int32_t tm_isdst; + /** seconds east of UTC */ + apr_int32_t tm_gmtoff; +}; + +/* Delayed the include to avoid a circular reference */ +#include "apr_pools.h" + +/** + * Convert an ansi time_t to an apr_time_t + * @param result the resulting apr_time_t + * @param input the time_t to convert + */ +APR_DECLARE(apr_status_t) apr_time_ansi_put(apr_time_t *result, + time_t input); + +/** + * Convert a time to its human readable components using an offset + * from GMT. + * @param result the exploded time + * @param input the time to explode + * @param offs the number of seconds offset to apply + */ +APR_DECLARE(apr_status_t) apr_time_exp_tz(apr_time_exp_t *result, + apr_time_t input, + apr_int32_t offs); + +/** + * Convert a time to its human readable components (GMT). + * @param result the exploded time + * @param input the time to explode */ -ap_status_t ap_implode_time(ap_time_t *result, ap_exploded_time_t *input); +APR_DECLARE(apr_status_t) apr_time_exp_gmt(apr_time_exp_t *result, + apr_time_t input); -/* ap_rfc822_date formats dates in the RFC822 - format in an efficient manner. it is a fixed length - format and requires the indicated amount of storage - including trailing \0 */ -#define AP_RFC822_DATE_LEN (30) -ap_status_t ap_rfc822_date(char *date_str, ap_time_t t); +/** + * Convert a time to its human readable components in the local timezone. + * @param result the exploded time + * @param input the time to explode + */ +APR_DECLARE(apr_status_t) apr_time_exp_lt(apr_time_exp_t *result, + apr_time_t input); + +/** + * Convert time value from human readable format to a numeric apr_time_t + * (elapsed microseconds since the epoch). + * @param result the resulting imploded time + * @param input the input exploded time + */ +APR_DECLARE(apr_status_t) apr_time_exp_get(apr_time_t *result, + apr_time_exp_t *input); + +/** + * Convert time value from human readable format to a numeric apr_time_t that + * always represents GMT. + * @param result the resulting imploded time + * @param input the input exploded time + */ +APR_DECLARE(apr_status_t) apr_time_exp_gmt_get(apr_time_t *result, + apr_time_exp_t *input); -/* ap_ctime formats dates in the ctime() format - in an efficient manner. it is a fixed length format - and requires the indicated amount of storage - including trailing \0 */ -#define AP_CTIME_LEN (25) -ap_status_t ap_ctime(char *date_str, ap_time_t t); +/** + * Sleep for the specified number of micro-seconds. + * @param t desired amount of time to sleep. + * @warning May sleep for longer than the specified time. + */ +APR_DECLARE(void) apr_sleep(apr_interval_time_t t); + +/** length of a RFC822 Date */ +#define APR_RFC822_DATE_LEN (30) +/** + * apr_rfc822_date formats dates in the RFC822 + * format in an efficient manner. It is a fixed length + * format which requires APR_RFC822_DATA_LEN bytes of storage, + * including the trailing NUL terminator. + * @param date_str String to write to. + * @param t the time to convert + */ +APR_DECLARE(apr_status_t) apr_rfc822_date(char *date_str, apr_time_t t); + +/** length of a CTIME date */ +#define APR_CTIME_LEN (25) +/** + * apr_ctime formats dates in the ctime() format + * in an efficient manner. It is a fixed length format + * and requires APR_CTIME_LEN bytes of storage including + * the trailing NUL terminator. + * Unlike ANSI/ISO C ctime(), apr_ctime() does not include + * a \\n at the end of the string. + * @param date_str String to write to. + * @param t the time to convert + */ +APR_DECLARE(apr_status_t) apr_ctime(char *date_str, apr_time_t t); + +/** + * Formats the exploded time according to the format specified + * @param s string to write to + * @param retsize The length of the returned string + * @param max The maximum length of the string + * @param format The format for the time string + * @param tm The time to convert + */ +APR_DECLARE(apr_status_t) apr_strftime(char *s, apr_size_t *retsize, + apr_size_t max, const char *format, + apr_time_exp_t *tm); + +/** + * Improve the clock resolution for the lifetime of the given pool. + * Generally this is only desirable on benchmarking and other very + * time-sensitive applications, and has no impact on most platforms. + * @param p The pool to associate the finer clock resolution + */ +APR_DECLARE(void) apr_time_clock_hires(apr_pool_t *p); -ap_status_t ap_strftime(char *s, ap_size_t *retsize, ap_size_t max, const char *format, ap_exploded_time_t *tm); +/** @} */ #ifdef __cplusplus } diff --git a/include/apr_uri.h b/include/apr_uri.h new file mode 100644 index 00000000000..25ad8f281af --- /dev/null +++ b/include/apr_uri.h @@ -0,0 +1,178 @@ +/* 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. + */ + +/* + * apr_uri.h: External Interface of apr_uri.c + */ + +/** + * @file apr_uri.h + * @brief APR-UTIL URI Routines + */ + +#ifndef APR_URI_H +#define APR_URI_H + +#include "apu.h" + +#include "apr_network_io.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup APR_Util_URI URI + * @ingroup APR + * @{ + */ + +#define APR_URI_FTP_DEFAULT_PORT 21 /**< default FTP port */ +#define APR_URI_SSH_DEFAULT_PORT 22 /**< default SSH port */ +#define APR_URI_TELNET_DEFAULT_PORT 23 /**< default telnet port */ +#define APR_URI_GOPHER_DEFAULT_PORT 70 /**< default Gopher port */ +#define APR_URI_HTTP_DEFAULT_PORT 80 /**< default HTTP port */ +#define APR_URI_POP_DEFAULT_PORT 110 /**< default POP port */ +#define APR_URI_NNTP_DEFAULT_PORT 119 /**< default NNTP port */ +#define APR_URI_IMAP_DEFAULT_PORT 143 /**< default IMAP port */ +#define APR_URI_PROSPERO_DEFAULT_PORT 191 /**< default Prospero port */ +#define APR_URI_WAIS_DEFAULT_PORT 210 /**< default WAIS port */ +#define APR_URI_LDAP_DEFAULT_PORT 389 /**< default LDAP port */ +#define APR_URI_HTTPS_DEFAULT_PORT 443 /**< default HTTPS port */ +#define APR_URI_RTSP_DEFAULT_PORT 554 /**< default RTSP port */ +#define APR_URI_SNEWS_DEFAULT_PORT 563 /**< default SNEWS port */ +#define APR_URI_ACAP_DEFAULT_PORT 674 /**< default ACAP port */ +#define APR_URI_NFS_DEFAULT_PORT 2049 /**< default NFS port */ +#define APR_URI_TIP_DEFAULT_PORT 3372 /**< default TIP port */ +#define APR_URI_SIP_DEFAULT_PORT 5060 /**< default SIP port */ + +/** Flags passed to unparse_uri_components(): */ +/** suppress "scheme://user\@site:port" */ +#define APR_URI_UNP_OMITSITEPART (1U<<0) +/** Just omit user */ +#define APR_URI_UNP_OMITUSER (1U<<1) +/** Just omit password */ +#define APR_URI_UNP_OMITPASSWORD (1U<<2) +/** omit "user:password\@" part */ +#define APR_URI_UNP_OMITUSERINFO (APR_URI_UNP_OMITUSER | \ + APR_URI_UNP_OMITPASSWORD) +/** Show plain text password (default: show XXXXXXXX) */ +#define APR_URI_UNP_REVEALPASSWORD (1U<<3) +/** Show "scheme://user\@site:port" only */ +#define APR_URI_UNP_OMITPATHINFO (1U<<4) +/** Omit the "?queryarg" from the path */ +#define APR_URI_UNP_OMITQUERY (1U<<5) + +/** @see apr_uri_t */ +typedef struct apr_uri_t apr_uri_t; + +/** + * A structure to encompass all of the fields in a uri + */ +struct apr_uri_t { + /** scheme ("http"/"ftp"/...) */ + char *scheme; + /** combined [user[:password]\@]host[:port] */ + char *hostinfo; + /** user name, as in http://user:passwd\@host:port/ */ + char *user; + /** password, as in http://user:passwd\@host:port/ */ + char *password; + /** hostname from URI (or from Host: header) */ + char *hostname; + /** port string (integer representation is in "port") */ + char *port_str; + /** the request path (or NULL if only scheme://host was given) */ + char *path; + /** Everything after a '?' in the path, if present */ + char *query; + /** Trailing "#fragment" string, if present */ + char *fragment; + + /** structure returned from gethostbyname() */ + struct hostent *hostent; + + /** The port number, numeric, valid only if port_str != NULL */ + apr_port_t port; + + /** has the structure been initialized */ + unsigned is_initialized:1; + + /** has the DNS been looked up yet */ + unsigned dns_looked_up:1; + /** has the dns been resolved yet */ + unsigned dns_resolved:1; +}; + +/* apr_uri.c */ +/** + * Return the default port for a given scheme. The schemes recognized are + * http, ftp, https, gopher, wais, nntp, snews, and prospero + * @param scheme_str The string that contains the current scheme + * @return The default port for this scheme + */ +APR_DECLARE(apr_port_t) apr_uri_port_of_scheme(const char *scheme_str); + +/** + * Unparse a apr_uri_t structure to an URI string. Optionally + * suppress the password for security reasons. + * @param p The pool to allocate out of + * @param uptr All of the parts of the uri + * @param flags How to unparse the uri. One of: + * <PRE> + * APR_URI_UNP_OMITSITEPART Suppress "scheme://user\@site:port" + * APR_URI_UNP_OMITUSER Just omit user + * APR_URI_UNP_OMITPASSWORD Just omit password + * APR_URI_UNP_OMITUSERINFO Omit "user:password\@" part + * APR_URI_UNP_REVEALPASSWORD Show plain text password (default: show XXXXXXXX) + * APR_URI_UNP_OMITPATHINFO Show "scheme://user\@site:port" only + * APR_URI_UNP_OMITQUERY Omit "?queryarg" or "#fragment" + * </PRE> + * @return The uri as a string + */ +APR_DECLARE(char *) apr_uri_unparse(apr_pool_t *p, + const apr_uri_t *uptr, + unsigned flags); + +/** + * Parse a given URI, fill in all supplied fields of a apr_uri_t + * structure. This eliminates the necessity of extracting host, port, + * path, query info repeatedly in the modules. + * @param p The pool to allocate out of + * @param uri The uri to parse + * @param uptr The apr_uri_t to fill out + * @return APR_SUCCESS for success or error code + */ +APR_DECLARE(apr_status_t) apr_uri_parse(apr_pool_t *p, const char *uri, + apr_uri_t *uptr); + +/** + * Special case for CONNECT parsing: it comes with the hostinfo part only + * @param p The pool to allocate out of + * @param hostinfo The hostinfo string to parse + * @param uptr The apr_uri_t to fill out + * @return APR_SUCCESS for success or error code + */ +APR_DECLARE(apr_status_t) apr_uri_parse_hostinfo(apr_pool_t *p, + const char *hostinfo, + apr_uri_t *uptr); + +/** @} */ +#ifdef __cplusplus +} +#endif + +#endif /* APR_URI_H */ diff --git a/include/apr_user.h b/include/apr_user.h new file mode 100644 index 00000000000..0e0a3ac5ac5 --- /dev/null +++ b/include/apr_user.h @@ -0,0 +1,158 @@ +/* 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. + */ + +#ifndef APR_USER_H +#define APR_USER_H + +/** + * @file apr_user.h + * @brief APR User ID Services + */ + +#include "apr.h" +#include "apr_errno.h" +#include "apr_pools.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup apr_user User and Group ID Services + * @ingroup APR + * @{ + */ + +/** + * Structure for determining user ownership. + */ +#ifdef WIN32 +typedef PSID apr_uid_t; +#else +typedef uid_t apr_uid_t; +#endif + +/** + * Structure for determining group ownership. + */ +#ifdef WIN32 +typedef PSID apr_gid_t; +#else +typedef gid_t apr_gid_t; +#endif + +#if APR_HAS_USER + +/** + * Get the userid (and groupid) of the calling process + * @param userid Returns the user id + * @param groupid Returns the user's group id + * @param p The pool from which to allocate working space + * @remark This function is available only if APR_HAS_USER is defined. + */ +APR_DECLARE(apr_status_t) apr_uid_current(apr_uid_t *userid, + apr_gid_t *groupid, + apr_pool_t *p); + +/** + * Get the user name for a specified userid + * @param username Pointer to new string containing user name (on output) + * @param userid The userid + * @param p The pool from which to allocate the string + * @remark This function is available only if APR_HAS_USER is defined. + */ +APR_DECLARE(apr_status_t) apr_uid_name_get(char **username, apr_uid_t userid, + apr_pool_t *p); + +/** + * Get the userid (and groupid) for the specified username + * @param userid Returns the user id + * @param groupid Returns the user's group id + * @param username The username to look up + * @param p The pool from which to allocate working space + * @remark This function is available only if APR_HAS_USER is defined. + */ +APR_DECLARE(apr_status_t) apr_uid_get(apr_uid_t *userid, apr_gid_t *groupid, + const char *username, apr_pool_t *p); + +/** + * Get the home directory for the named user + * @param dirname Pointer to new string containing directory name (on output) + * @param username The named user + * @param p The pool from which to allocate the string + * @remark This function is available only if APR_HAS_USER is defined. + */ +APR_DECLARE(apr_status_t) apr_uid_homepath_get(char **dirname, + const char *username, + apr_pool_t *p); + +/** + * Compare two user identifiers for equality. + * @param left One uid to test + * @param right Another uid to test + * @return APR_SUCCESS if the apr_uid_t structures identify the same user, + * APR_EMISMATCH if not, APR_BADARG if an apr_uid_t is invalid. + * @remark This function is available only if APR_HAS_USER is defined. + */ +#if defined(WIN32) +APR_DECLARE(apr_status_t) apr_uid_compare(apr_uid_t left, apr_uid_t right); +#else +#define apr_uid_compare(left,right) (((left) == (right)) ? APR_SUCCESS : APR_EMISMATCH) +#endif + +/** + * Get the group name for a specified groupid + * @param groupname Pointer to new string containing group name (on output) + * @param groupid The groupid + * @param p The pool from which to allocate the string + * @remark This function is available only if APR_HAS_USER is defined. + */ +APR_DECLARE(apr_status_t) apr_gid_name_get(char **groupname, + apr_gid_t groupid, apr_pool_t *p); + +/** + * Get the groupid for a specified group name + * @param groupid Pointer to the group id (on output) + * @param groupname The group name to look up + * @param p The pool from which to allocate the string + * @remark This function is available only if APR_HAS_USER is defined. + */ +APR_DECLARE(apr_status_t) apr_gid_get(apr_gid_t *groupid, + const char *groupname, apr_pool_t *p); + +/** + * Compare two group identifiers for equality. + * @param left One gid to test + * @param right Another gid to test + * @return APR_SUCCESS if the apr_gid_t structures identify the same group, + * APR_EMISMATCH if not, APR_BADARG if an apr_gid_t is invalid. + * @remark This function is available only if APR_HAS_USER is defined. + */ +#if defined(WIN32) +APR_DECLARE(apr_status_t) apr_gid_compare(apr_gid_t left, apr_gid_t right); +#else +#define apr_gid_compare(left,right) (((left) == (right)) ? APR_SUCCESS : APR_EMISMATCH) +#endif + +#endif /* ! APR_HAS_USER */ + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* ! APR_USER_H */ diff --git a/include/apr_uuid.h b/include/apr_uuid.h new file mode 100644 index 00000000000..bb8841f1cda --- /dev/null +++ b/include/apr_uuid.h @@ -0,0 +1,76 @@ +/* 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. + */ + +/** + * @file apr_uuid.h + * @brief APR UUID library + */ +#ifndef APR_UUID_H +#define APR_UUID_H + +#include "apu.h" +#include "apr_errno.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup APR_UUID UUID Handling + * @ingroup APR + * @{ + */ + +/** + * we represent a UUID as a block of 16 bytes. + */ + +typedef struct { + unsigned char data[16]; /**< the actual UUID */ +} apr_uuid_t; + +/** UUIDs are formatted as: 00112233-4455-6677-8899-AABBCCDDEEFF */ +#define APR_UUID_FORMATTED_LENGTH 36 + + +/** + * Generate and return a (new) UUID + * @param uuid The resulting UUID + */ +APR_DECLARE(void) apr_uuid_get(apr_uuid_t *uuid); + +/** + * Format a UUID into a string, following the standard format + * @param buffer The buffer to place the formatted UUID string into. It must + * be at least APR_UUID_FORMATTED_LENGTH + 1 bytes long to hold + * the formatted UUID and a null terminator + * @param uuid The UUID to format + */ +APR_DECLARE(void) apr_uuid_format(char *buffer, const apr_uuid_t *uuid); + +/** + * Parse a standard-format string into a UUID + * @param uuid The resulting UUID + * @param uuid_str The formatted UUID + */ +APR_DECLARE(apr_status_t) apr_uuid_parse(apr_uuid_t *uuid, const char *uuid_str); + +/** @} */ +#ifdef __cplusplus +} +#endif + +#endif /* APR_UUID_H */ diff --git a/include/apr_version.h b/include/apr_version.h new file mode 100644 index 00000000000..c528be42d98 --- /dev/null +++ b/include/apr_version.h @@ -0,0 +1,164 @@ +/* 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. + */ + +#ifndef APR_VERSION_H +#define APR_VERSION_H + +/** + * @file apr_version.h + * @brief APR Versioning Interface + * + * APR's Version + * + * There are several different mechanisms for accessing the version. There + * is a string form, and a set of numbers; in addition, there are constants + * which can be compiled into your application, and you can query the library + * being used for its actual version. + * + * Note that it is possible for an application to detect that it has been + * compiled against a different version of APR by use of the compile-time + * constants and the use of the run-time query function. + * + * APR version numbering follows the guidelines specified in: + * + * http://apr.apache.org/versioning.html + */ + + +#define APR_COPYRIGHT "Copyright (c) 2000-2018 The Apache Software " \ + "Foundation or its licensors, as applicable." + +/* The numeric compile-time version constants. These constants are the + * authoritative version numbers for APR. + */ + +/** major version + * Major API changes that could cause compatibility problems for older + * programs such as structure size changes. No binary compatibility is + * possible across a change in the major version. + */ +#define APR_MAJOR_VERSION 2 + +/** minor version + * Minor API changes that do not cause binary compatibility problems. + * Reset to 0 when upgrading APR_MAJOR_VERSION + */ +#define APR_MINOR_VERSION 0 + +/** patch level + * The Patch Level never includes API changes, simply bug fixes. + * Reset to 0 when upgrading APR_MINOR_VERSION + */ +#define APR_PATCH_VERSION 0 + +/** + * The symbol APR_IS_DEV_VERSION is only defined for internal, + * "development" copies of APR. It is undefined for released versions + * of APR. + */ +#define APR_IS_DEV_VERSION + +/** + * Check at compile time if the APR version is at least a certain + * level. + * @param major The major version component of the version checked + * for (e.g., the "1" of "1.3.0"). + * @param minor The minor version component of the version checked + * for (e.g., the "3" of "1.3.0"). + * @param patch The patch level component of the version checked + * for (e.g., the "0" of "1.3.0"). + * @remark This macro is available with APR versions starting with + * 1.3.0. + */ +#define APR_VERSION_AT_LEAST(major,minor,patch) \ +(((major) < APR_MAJOR_VERSION) \ + || ((major) == APR_MAJOR_VERSION && (minor) < APR_MINOR_VERSION) \ + || ((major) == APR_MAJOR_VERSION && (minor) == APR_MINOR_VERSION && (patch) <= APR_PATCH_VERSION)) + +#if defined(APR_IS_DEV_VERSION) || defined(DOXYGEN) +/** Internal: string form of the "is dev" flag */ +#ifndef APR_IS_DEV_STRING +#define APR_IS_DEV_STRING "-dev" +#endif +#else +#define APR_IS_DEV_STRING "" +#endif + +/* APR_STRINGIFY is defined here, and also in apr_general.h, so wrap it */ +#ifndef APR_STRINGIFY +/** Properly quote a value as a string in the C preprocessor */ +#define APR_STRINGIFY(n) APR_STRINGIFY_HELPER(n) +/** Helper macro for APR_STRINGIFY */ +#define APR_STRINGIFY_HELPER(n) #n +#endif + +/** The formatted string of APR's version */ +#define APR_VERSION_STRING \ + APR_STRINGIFY(APR_MAJOR_VERSION) "." \ + APR_STRINGIFY(APR_MINOR_VERSION) "." \ + APR_STRINGIFY(APR_PATCH_VERSION) \ + APR_IS_DEV_STRING + +/** An alternative formatted string of APR's version */ +/* macro for Win32 .rc files using numeric csv representation */ +#define APR_VERSION_STRING_CSV APR_MAJOR_VERSION, \ + APR_MINOR_VERSION, \ + APR_PATCH_VERSION + + +#ifndef APR_VERSION_ONLY + +/* The C language API to access the version at run time, + * as opposed to compile time. APR_VERSION_ONLY may be defined + * externally when preprocessing apr_version.h to obtain strictly + * the C Preprocessor macro declarations. + */ + +#include "apr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * The numeric version information is broken out into fields within this + * structure. + */ +typedef struct { + int major; /**< major number */ + int minor; /**< minor number */ + int patch; /**< patch number */ + int is_dev; /**< is development (1 or 0) */ +} apr_version_t; + +/** + * Return APR's version information information in a numeric form. + * + * @param pvsn Pointer to a version structure for returning the version + * information. + */ +APR_DECLARE(void) apr_version(apr_version_t *pvsn); + +/** Return APR's version information as a string. */ +APR_DECLARE(const char *) apr_version_string(void); + +#ifdef __cplusplus +} +#endif + +#endif /* ndef APR_VERSION_ONLY */ + +#endif /* ndef APR_VERSION_H */ diff --git a/include/apr_want.h b/include/apr_want.h new file mode 100644 index 00000000000..2863b0018a1 --- /dev/null +++ b/include/apr_want.h @@ -0,0 +1,124 @@ +/* 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" /* configuration data */ +/** + * @file apr_want.h + * @brief APR Standard Headers Support + * + * <PRE> + * Features: + * + * APR_WANT_STRFUNC: strcmp, strcat, strcpy, etc + * APR_WANT_MEMFUNC: memcmp, memcpy, etc + * APR_WANT_STDIO: <stdio.h> and related bits + * APR_WANT_IOVEC: struct iovec + * APR_WANT_BYTEFUNC: htons, htonl, ntohl, ntohs + * + * Typical usage: + * + * \#define APR_WANT_STRFUNC + * \#define APR_WANT_MEMFUNC + * \#include "apr_want.h" + * + * The appropriate headers will be included. + * + * Note: it is safe to use this in a header (it won't interfere with other + * headers' or source files' use of apr_want.h) + * </PRE> + */ + +/* --------------------------------------------------------------------- */ + +#ifdef APR_WANT_STRFUNC + +#if APR_HAVE_STRING_H +#include <string.h> +#endif +#if APR_HAVE_STRINGS_H +#include <strings.h> +#endif + +#undef APR_WANT_STRFUNC +#endif + +/* --------------------------------------------------------------------- */ + +#ifdef APR_WANT_MEMFUNC + +#if APR_HAVE_STRING_H +#include <string.h> +#endif + +#undef APR_WANT_MEMFUNC +#endif + +/* --------------------------------------------------------------------- */ + +#ifdef APR_WANT_STDIO + +#if APR_HAVE_STDIO_H +#include <stdio.h> +#endif + +#undef APR_WANT_STDIO +#endif + +/* --------------------------------------------------------------------- */ + +#ifdef APR_WANT_IOVEC + +#if APR_HAVE_IOVEC + +#if APR_HAVE_SYS_UIO_H +#include <sys/uio.h> +#endif + +#else + +#ifndef APR_IOVEC_DEFINED +#define APR_IOVEC_DEFINED +struct iovec +{ + void *iov_base; + size_t iov_len; +}; +#endif /* !APR_IOVEC_DEFINED */ + +#endif /* APR_HAVE_IOVEC */ + +#undef APR_WANT_IOVEC +#endif + +/* --------------------------------------------------------------------- */ + +#ifdef APR_WANT_BYTEFUNC + +/* Single Unix says they are in arpa/inet.h. Linux has them in + * netinet/in.h. FreeBSD has them in arpa/inet.h but requires that + * netinet/in.h be included first. + */ +#if APR_HAVE_NETINET_IN_H +#include <netinet/in.h> +#endif +#if APR_HAVE_ARPA_INET_H +#include <arpa/inet.h> +#endif + +#undef APR_WANT_BYTEFUNC +#endif + +/* --------------------------------------------------------------------- */ diff --git a/include/apr_xlate.h b/include/apr_xlate.h index 39c891da7fb..6f27fda0be8 100644 --- a/include/apr_xlate.h +++ b/include/apr_xlate.h @@ -1,169 +1,161 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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. */ #ifndef APR_XLATE_H #define APR_XLATE_H -#include "apr.h" -#include "apr_general.h" -#include "apr_time.h" +#include "apu.h" +#include "apr_pools.h" #include "apr_errno.h" #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ -/* APR_HAS_XLATE determines whether or not useful implementations of - * ap_xlate_open() et al are provided. - * - * If APR_HAS_XLATE is zero, ap_xlate_open() et al will all return - * APR_ENOTIMPL at run-time. +/** + * @file apr_xlate.h + * @brief APR I18N translation library */ -#if ! APR_HAS_XLATE - -typedef void ap_xlate_t; - -/* For platforms where we don't bother with translating between charsets, - * these are macros which always return failure. +/** + * @defgroup APR_XLATE I18N translation library + * @ingroup APR + * @{ */ - -#define ap_xlate_open(convset, topage, frompage, pool) APR_ENOTIMPL - -#define ap_xlate_conv_buffer(convset, inbuf, inbytes_left, outbuf, \ - outbytes_left) APR_ENOTIMPL - -/* The purpose of ap_xlate_conv_char is to translate one character - * at a time. This needs to be written carefully so that it works - * with double-byte character sets. +/** Opaque translation buffer */ +typedef struct apr_xlate_t apr_xlate_t; + +/** + * Set up for converting text from one charset to another. + * @param convset The handle to be filled in by this function + * @param topage The name of the target charset + * @param frompage The name of the source charset + * @param pool The pool to use + * @remark + * Specify APR_DEFAULT_CHARSET for one of the charset + * names to indicate the charset of the source code at + * compile time. This is useful if there are literal + * strings in the source code which must be translated + * according to the charset of the source code. + * APR_DEFAULT_CHARSET is not useful if the source code + * of the caller was not encoded in the same charset as + * APR at compile time. + * + * @remark + * Specify APR_LOCALE_CHARSET for one of the charset + * names to indicate the charset of the current locale. + * + * @remark + * Return APR_EINVAL if unable to procure a convset, or APR_ENOTIMPL + * if charset transcoding is not available in this instance of + * apr-util at all (i.e., APR_HAS_XLATE is undefined). */ -#define ap_xlate_conv_char(convset, inchar, outchar) APR_ENOTIMPL - -#define ap_xlate_close(convset) APR_ENOTIMPL - -#else /* ! APR_HAS_XLATE */ - -typedef struct ap_xlate_t ap_xlate_t; - -/* - -=head1 ap_status_t ap_xlate_open(ap_xlate_t **convset, const char *topage, const char *frompage, ap_pool_t *pool) - -B<Set up for converting text from one charset to another.> - - arg 1) The handle to be filled in by this function - arg 2) The name of the target charset - arg 3) The name of the source charset - arg 4) The pool to use - -B<NOTE>: Specify APR_DEFAULT_CHARSET for one of the charset - names to indicate the charset of the source code at - compile time. This is useful if there are literal - strings in the source code which must be translated - according to the charset of the source code. - APR_DEFAULT_CHARSET is not useful if the source code - of the caller was not encoded in the same charset as - APR at compile time. - -=cut +APR_DECLARE(apr_status_t) apr_xlate_open(apr_xlate_t **convset, + const char *topage, + const char *frompage, + apr_pool_t *pool); + +/** + * This is to indicate the charset of the sourcecode at compile time + * names to indicate the charset of the source code at + * compile time. This is useful if there are literal + * strings in the source code which must be translated + * according to the charset of the source code. */ -ap_status_t ap_xlate_open(ap_xlate_t **convset, const char *topage, - const char *frompage, ap_pool_t *pool); - -#define APR_DEFAULT_CHARSET NULL - -/* - -=head1 ap_status_t ap_xlate_conv_buffer(ap_xlate_t *convset, const char *inbuf, ap_size_t *inbytes_left, char *outbuf, ap_size_t outbytes_left) - -B<Convert a buffer of text from one codepage to another.> - - arg 1) The handle allocated by ap_xlate_open, specifying the parameters - of conversion - arg 2) The address of the source buffer - arg 3) Input: the amount of input data to be translated - Output: the amount of input data not yet translated - arg 4) The address of the destination buffer - arg 5) Input: the size of the output buffer - Output: the amount of the output buffer not yet used - -=cut +#define APR_DEFAULT_CHARSET (const char *)0 +/** + * To indicate charset names of the current locale */ -ap_status_t ap_xlate_conv_buffer(ap_xlate_t *convset, const char *inbuf, - ap_size_t *inbytes_left, char *outbuf, - ap_size_t *outbytes_left); - -/* The purpose of ap_xlate_conv_char is to translate one character +#define APR_LOCALE_CHARSET (const char *)1 + +/** + * Find out whether or not the specified conversion is single-byte-only. + * @param convset The handle allocated by apr_xlate_open, specifying the + * parameters of conversion + * @param onoff Output: whether or not the conversion is single-byte-only + * @remark + * Return APR_ENOTIMPL if charset transcoding is not available + * in this instance of apr-util (i.e., APR_HAS_XLATE is undefined). + */ +APR_DECLARE(apr_status_t) apr_xlate_sb_get(apr_xlate_t *convset, int *onoff); + +/** + * Convert a buffer of text from one codepage to another. + * @param convset The handle allocated by apr_xlate_open, specifying + * the parameters of conversion + * @param inbuf The address of the source buffer + * @param inbytes_left Input: the amount of input data to be translated + * Output: the amount of input data not yet translated + * @param outbuf The address of the destination buffer + * @param outbytes_left Input: the size of the output buffer + * Output: the amount of the output buffer not yet used + * @remark + * Returns APR_ENOTIMPL if charset transcoding is not available + * in this instance of apr-util (i.e., APR_HAS_XLATE is undefined). + * Returns APR_INCOMPLETE if the input buffer ends in an incomplete + * multi-byte character. + * + * To correctly terminate the output buffer for some multi-byte + * character set encodings, a final call must be made to this function + * after the complete input string has been converted, passing + * the inbuf and inbytes_left parameters as NULL. (Note that this + * mode only works from version 1.1.0 onwards) + */ +APR_DECLARE(apr_status_t) apr_xlate_conv_buffer(apr_xlate_t *convset, + const char *inbuf, + apr_size_t *inbytes_left, + char *outbuf, + apr_size_t *outbytes_left); + +/* @see apr_file_io.h the comment in apr_file_io.h about this hack */ +#ifdef APR_NOT_DONE_YET +/** + * The purpose of apr_xlate_conv_char is to translate one character * at a time. This needs to be written carefully so that it works * with double-byte character sets. + * @param convset The handle allocated by apr_xlate_open, specifying the + * parameters of conversion + * @param inchar The character to convert + * @param outchar The converted character */ -ap_status_t ap_xlate_conv_char(ap_xlate_t *convset, char inchar, char outchar); - -/* - -=head1 ap_status_t ap_xlate_close(ap_xlate_t *convset) - -B<Close a codepage translation handle.> - - arg 1) The codepage translation handle to close +APR_DECLARE(apr_status_t) apr_xlate_conv_char(apr_xlate_t *convset, + char inchar, char outchar); +#endif -=cut +/** + * Convert a single-byte character from one charset to another. + * @param convset The handle allocated by apr_xlate_open, specifying the + * parameters of conversion + * @param inchar The single-byte character to convert. + * @warning This only works when converting between single-byte character sets. + * -1 will be returned if the conversion can't be performed. */ -ap_status_t ap_xlate_close(ap_xlate_t *convset); - -#endif /* ! APR_HAS_XLATE */ +APR_DECLARE(apr_int32_t) apr_xlate_conv_byte(apr_xlate_t *convset, + unsigned char inchar); + +/** + * Close a codepage translation handle. + * @param convset The codepage translation handle to close + * @remark + * Return APR_ENOTIMPL if charset transcoding is not available + * in this instance of apr-util (i.e., APR_HAS_XLATE is undefined). + */ +APR_DECLARE(apr_status_t) apr_xlate_close(apr_xlate_t *convset); +/** @} */ #ifdef __cplusplus } #endif diff --git a/include/apr_xml.h b/include/apr_xml.h new file mode 100644 index 00000000000..bd0b1000ca0 --- /dev/null +++ b/include/apr_xml.h @@ -0,0 +1,358 @@ +/* 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. + */ +/** + * @file apr_xml.h + * @brief APR-UTIL XML Library + */ +#ifndef APR_XML_H +#define APR_XML_H + +/** + * @defgroup APR_Util_XML XML + * @ingroup APR + * @{ + */ +#include "apr_pools.h" +#include "apr_tables.h" +#include "apr_file_io.h" + +#include "apu.h" +#if APR_CHARSET_EBCDIC +#include "apr_xlate.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @package Apache XML library + */ + +/* -------------------------------------------------------------------- */ + +/* ### these will need to move at some point to a more logical spot */ + +/** @see apr_text */ +typedef struct apr_text apr_text; + +/** Structure to keep a linked list of pieces of text */ +struct apr_text { + /** The current piece of text */ + const char *text; + /** a pointer to the next piece of text */ + struct apr_text *next; +}; + +/** @see apr_text_header */ +typedef struct apr_text_header apr_text_header; + +/** A list of pieces of text */ +struct apr_text_header { + /** The first piece of text in the list */ + apr_text *first; + /** The last piece of text in the list */ + apr_text *last; +}; + +/** + * Append a piece of text to the end of a list + * @param p The pool to allocate out of + * @param hdr The text header to append to + * @param text The new text to append + */ +APR_DECLARE(void) apr_text_append(apr_pool_t *p, apr_text_header *hdr, + const char *text); + + +/* -------------------------------------------------------------------- +** +** XML PARSING +*/ + +/* +** Qualified namespace values +** +** APR_XML_NS_DAV_ID +** We always insert the "DAV:" namespace URI at the head of the +** namespace array. This means that it will always be at ID==0, +** making it much easier to test for. +** +** APR_XML_NS_NONE +** This special ID is used for two situations: +** +** 1) The namespace prefix begins with "xml" (and we do not know +** what it means). Namespace prefixes with "xml" (any case) as +** their first three characters are reserved by the XML Namespaces +** specification for future use. mod_dav will pass these through +** unchanged. When this identifier is used, the prefix is LEFT in +** the element/attribute name. Downstream processing should not +** prepend another prefix. +** +** 2) The element/attribute does not have a namespace. +** +** a) No prefix was used, and a default namespace has not been +** defined. +** b) No prefix was used, and the default namespace was specified +** to mean "no namespace". This is done with a namespace +** declaration of: xmlns="" +** (this declaration is typically used to override a previous +** specification for the default namespace) +** +** In these cases, we need to record that the elem/attr has no +** namespace so that we will not attempt to prepend a prefix. +** All namespaces that are used will have a prefix assigned to +** them -- mod_dav will never set or use the default namespace +** when generating XML. This means that "no prefix" will always +** mean "no namespace". +** +** In both cases, the XML generation will avoid prepending a prefix. +** For the first case, this means the original prefix/name will be +** inserted into the output stream. For the latter case, it means +** the name will have no prefix, and since we never define a default +** namespace, this means it will have no namespace. +** +** Note: currently, mod_dav understands the "xmlns" prefix and the +** "xml:lang" attribute. These are handled specially (they aren't +** left within the XML tree), so the APR_XML_NS_NONE value won't ever +** really apply to these values. +*/ +#define APR_XML_NS_DAV_ID 0 /**< namespace ID for "DAV:" */ +#define APR_XML_NS_NONE -10 /**< no namespace for this elem/attr */ + +#define APR_XML_NS_ERROR_BASE -100 /**< used only during processing */ +/** Is this namespace an error? */ +#define APR_XML_NS_IS_ERROR(e) ((e) <= APR_XML_NS_ERROR_BASE) + +/** @see apr_xml_attr */ +typedef struct apr_xml_attr apr_xml_attr; +/** @see apr_xml_elem */ +typedef struct apr_xml_elem apr_xml_elem; +/** @see apr_xml_doc */ +typedef struct apr_xml_doc apr_xml_doc; + +/** apr_xml_attr: holds a parsed XML attribute */ +struct apr_xml_attr { + /** attribute name */ + const char *name; + /** index into namespace array */ + int ns; + + /** attribute value */ + const char *value; + + /** next attribute */ + struct apr_xml_attr *next; +}; + +/** apr_xml_elem: holds a parsed XML element */ +struct apr_xml_elem { + /** element name */ + const char *name; + /** index into namespace array */ + int ns; + /** xml:lang for attrs/contents */ + const char *lang; + + /** cdata right after start tag */ + apr_text_header first_cdata; + /** cdata after MY end tag */ + apr_text_header following_cdata; + + /** parent element */ + struct apr_xml_elem *parent; + /** next (sibling) element */ + struct apr_xml_elem *next; + /** first child element */ + struct apr_xml_elem *first_child; + /** first attribute */ + struct apr_xml_attr *attr; + + /* used only during parsing */ + /** last child element */ + struct apr_xml_elem *last_child; + /** namespaces scoped by this elem */ + struct apr_xml_ns_scope *ns_scope; + + /* used by modules during request processing */ + /** Place for modules to store private data */ + void *priv; +}; + +/** Is this XML element empty? */ +#define APR_XML_ELEM_IS_EMPTY(e) ((e)->first_child == NULL && \ + (e)->first_cdata.first == NULL) + +/** apr_xml_doc: holds a parsed XML document */ +struct apr_xml_doc { + /** root element */ + apr_xml_elem *root; + /** array of namespaces used */ + apr_array_header_t *namespaces; +}; + +/** Opaque XML parser structure */ +typedef struct apr_xml_parser apr_xml_parser; + +/** + * Create an XML parser + * @param pool The pool for allocating the parser and the parse results. + * @return The new parser. + */ +APR_DECLARE(apr_xml_parser *) apr_xml_parser_create(apr_pool_t *pool); + +/** + * Parse a File, producing a xml_doc + * @param p The pool for allocating the parse results. + * @param parser A pointer to *parser (needed so calling function can get + * errors), will be set to NULL on successful completion. + * @param ppdoc A pointer to *apr_xml_doc (which has the parsed results in it) + * @param xmlfd A file to read from. + * @param buffer_length Buffer length which would be suitable + * @return Any errors found during parsing. + */ +APR_DECLARE(apr_status_t) apr_xml_parse_file(apr_pool_t *p, + apr_xml_parser **parser, + apr_xml_doc **ppdoc, + apr_file_t *xmlfd, + apr_size_t buffer_length); + + +/** + * Feed input into the parser + * @param parser The XML parser for parsing this data. + * @param data The data to parse. + * @param len The length of the data. + * @return Any errors found during parsing. + * @remark Use apr_xml_parser_geterror() to get more error information. + */ +APR_DECLARE(apr_status_t) apr_xml_parser_feed(apr_xml_parser *parser, + const char *data, + apr_size_t len); + +/** + * Terminate the parsing and return the result + * @param parser The XML parser for parsing this data. + * @param pdoc The resulting parse information. May be NULL to simply + * terminate the parsing without fetching the info. + * @return Any errors found during the final stage of parsing. + * @remark Use apr_xml_parser_geterror() to get more error information. + */ +APR_DECLARE(apr_status_t) apr_xml_parser_done(apr_xml_parser *parser, + apr_xml_doc **pdoc); + +/** + * Fetch additional error information from the parser. + * @param parser The XML parser to query for errors. + * @param errbuf A buffer for storing error text. + * @param errbufsize The length of the error text buffer. + * @return The error buffer + */ +APR_DECLARE(char *) apr_xml_parser_geterror(apr_xml_parser *parser, + char *errbuf, + apr_size_t errbufsize); + + +/** + * Converts an XML element tree to flat text + * @param p The pool to allocate out of + * @param elem The XML element to convert + * @param style How to covert the XML. One of: + * <PRE> + * APR_XML_X2T_FULL start tag, contents, end tag + * APR_XML_X2T_INNER contents only + * APR_XML_X2T_LANG_INNER xml:lang + inner contents + * APR_XML_X2T_FULL_NS_LANG FULL + ns defns + xml:lang + * APR_XML_X2T_PARSED original prefixes + * </PRE> + * @param namespaces The namespace of the current XML element + * @param ns_map Namespace mapping + * @param pbuf Buffer to put the converted text into + * @param psize Size of the converted text + */ +APR_DECLARE(void) apr_xml_to_text(apr_pool_t *p, const apr_xml_elem *elem, + int style, apr_array_header_t *namespaces, + int *ns_map, const char **pbuf, + apr_size_t *psize); + +/* style argument values: */ +#define APR_XML_X2T_FULL 0 /**< start tag, contents, end tag */ +#define APR_XML_X2T_INNER 1 /**< contents only */ +#define APR_XML_X2T_LANG_INNER 2 /**< xml:lang + inner contents */ +#define APR_XML_X2T_FULL_NS_LANG 3 /**< FULL + ns defns + xml:lang */ +#define APR_XML_X2T_PARSED 4 /**< original prefixes */ + +/** + * empty XML element + * @param p The pool to allocate out of + * @param elem The XML element to empty + * @return the string that was stored in the XML element + */ +APR_DECLARE(const char *) apr_xml_empty_elem(apr_pool_t *p, + const apr_xml_elem *elem); + +/** + * quote an XML string + * Replace '\<', '\>', and '\&' with '\<', '\>', and '\&'. + * @param p The pool to allocate out of + * @param s The string to quote + * @param quotes If quotes is true, then replace '"' with '\"'. + * @return The quoted string + * @note If the string does not contain special characters, it is not + * duplicated into the pool and the original string is returned. + */ +APR_DECLARE(const char *) apr_xml_quote_string(apr_pool_t *p, const char *s, + int quotes); + +/** + * Quote an XML element + * @param p The pool to allocate out of + * @param elem The element to quote + */ +APR_DECLARE(void) apr_xml_quote_elem(apr_pool_t *p, apr_xml_elem *elem); + +/* manage an array of unique URIs: apr_xml_insert_uri() and APR_XML_URI_ITEM() */ + +/** + * return the URI's (existing) index, or insert it and return a new index + * @param uri_array array to insert into + * @param uri The uri to insert + * @return int The uri's index + */ +APR_DECLARE(int) apr_xml_insert_uri(apr_array_header_t *uri_array, + const char *uri); + +/** Get the URI item for this XML element */ +#define APR_XML_GET_URI_ITEM(ary, i) (((const char * const *)(ary)->elts)[i]) + +#if APR_CHARSET_EBCDIC +/** + * Convert parsed tree in EBCDIC + * @param p The pool to allocate out of + * @param pdoc The apr_xml_doc to convert. + * @param xlate The translation handle to use. + * @return Any errors found during conversion. + */ +APR_DECLARE(apr_status_t) apr_xml_parser_convert_doc(apr_pool_t *p, + apr_xml_doc *pdoc, + apr_xlate_t *convset); +#endif + +#ifdef __cplusplus +} +#endif +/** @} */ +#endif /* APR_XML_H */ diff --git a/include/apu.h b/include/apu.h new file mode 100644 index 00000000000..ab119730fd5 --- /dev/null +++ b/include/apu.h @@ -0,0 +1,23 @@ +/* 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. + */ + +/* @file apu.h + * @brief APR-Utility main file + * @deprecated @see apr.h + */ + +#include <apr.h> + diff --git a/include/apu_errno.h b/include/apu_errno.h new file mode 100644 index 00000000000..58585b71483 --- /dev/null +++ b/include/apu_errno.h @@ -0,0 +1,173 @@ +/* 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. + */ + +#ifndef APU_ERRNO_H +#define APU_ERRNO_H + +/** + * @file apu_errno.h + * @brief APR-Util Error Codes + */ + +#include "apr.h" +#include "apr_errno.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup apu_errno Error Codes + * @ingroup APR + * @{ + */ + +/** + * @defgroup APR_Util_Error APR_Util Error Values + * <PRE> + * <b>APU ERROR VALUES</b> + * APR_ENOKEY The key provided was empty or NULL + * APR_ENOIV The initialisation vector provided was NULL + * APR_EKEYTYPE The key type was not recognised + * APR_ENOSPACE The buffer supplied was not big enough + * APR_ECRYPT An error occurred while encrypting or decrypting + * APR_EPADDING Padding was not supported + * APR_EKEYLENGTH The key length was incorrect + * APR_ENOCIPHER The cipher provided was not recognised + * APR_ENODIGEST The digest provided was not recognised + * APR_ENOENGINE The engine provided was not recognised + * APR_EINITENGINE The engine could not be initialised + * APR_EREINIT Underlying crypto has already been initialised + * </PRE> + * + * <PRE> + * <b>APR STATUS VALUES</b> + * APR_INCHILD Program is currently executing in the child + * </PRE> + * @{ + */ +/** @see APR_STATUS_IS_ENOKEY */ +#define APR_ENOKEY (APR_UTIL_START_STATUS + 1) +/** @see APR_STATUS_IS_ENOIV */ +#define APR_ENOIV (APR_UTIL_START_STATUS + 2) +/** @see APR_STATUS_IS_EKEYTYPE */ +#define APR_EKEYTYPE (APR_UTIL_START_STATUS + 3) +/** @see APR_STATUS_IS_ENOSPACE */ +#define APR_ENOSPACE (APR_UTIL_START_STATUS + 4) +/** @see APR_STATUS_IS_ECRYPT */ +#define APR_ECRYPT (APR_UTIL_START_STATUS + 5) +/** @see APR_STATUS_IS_EPADDING */ +#define APR_EPADDING (APR_UTIL_START_STATUS + 6) +/** @see APR_STATUS_IS_EKEYLENGTH */ +#define APR_EKEYLENGTH (APR_UTIL_START_STATUS + 7) +/** @see APR_STATUS_IS_ENOCIPHER */ +#define APR_ENOCIPHER (APR_UTIL_START_STATUS + 8) +/** @see APR_STATUS_IS_ENODIGEST */ +#define APR_ENODIGEST (APR_UTIL_START_STATUS + 9) +/** @see APR_STATUS_IS_ENOENGINE */ +#define APR_ENOENGINE (APR_UTIL_START_STATUS + 10) +/** @see APR_STATUS_IS_EINITENGINE */ +#define APR_EINITENGINE (APR_UTIL_START_STATUS + 11) +/** @see APR_STATUS_IS_EREINIT */ +#define APR_EREINIT (APR_UTIL_START_STATUS + 12) +/** @} */ + +/** + * @defgroup APU_STATUS_IS Status Value Tests + * @warning For any particular error condition, more than one of these tests + * may match. This is because platform-specific error codes may not + * always match the semantics of the POSIX codes these tests (and the + * corresponding APR error codes) are named after. A notable example + * are the APR_STATUS_IS_ENOENT and APR_STATUS_IS_ENOTDIR tests on + * Win32 platforms. The programmer should always be aware of this and + * adjust the order of the tests accordingly. + * @{ + */ + +/** @} */ + +/** + * @addtogroup APR_Util_Error + * @{ + */ +/** + * The key was empty or not provided + */ +#define APR_STATUS_IS_ENOKEY(s) ((s) == APR_ENOKEY) +/** + * The initialisation vector was not provided + */ +#define APR_STATUS_IS_ENOIV(s) ((s) == APR_ENOIV) +/** + * The key type was not recognised + */ +#define APR_STATUS_IS_EKEYTYPE(s) ((s) == APR_EKEYTYPE) +/** + * The buffer provided was not big enough + */ +#define APR_STATUS_IS_ENOSPACE(s) ((s) == APR_ENOSPACE) +/** + * An error occurred while encrypting or decrypting + */ +#define APR_STATUS_IS_ECRYPT(s) ((s) == APR_ECRYPT) +/** + * An error occurred while padding + */ +#define APR_STATUS_IS_EPADDING(s) ((s) == APR_EPADDING) +/** + * An error occurred with the key length + */ +#define APR_STATUS_IS_EKEYLENGTH(s) ((s) == APR_EKEYLENGTH) +/** + * The cipher provided was not recognised + */ +#define APR_STATUS_IS_ENOCIPHER(s) ((s) == APR_ENOCIPHER) +/** + * The digest provided was not recognised + */ +#define APR_STATUS_IS_ENODIGEST(s) ((s) == APR_ENODIGEST) +/** + * The engine provided was not recognised + */ +#define APR_STATUS_IS_ENOENGINE(s) ((s) == APR_ENOENGINE) +/** + * The engine could not be initialised + */ +#define APR_STATUS_IS_EINITENGINE(s) ((s) == APR_EINITENGINE) +/** + * Crypto has already been initialised + */ +#define APR_STATUS_IS_EREINIT(s) ((s) == APR_EREINIT) +/** @} */ + +/** + * This structure allows the underlying API error codes to be returned + * along with plain text error messages that explain to us mere mortals + * what really happened. + */ +typedef struct apu_err_t { + const char *reason; + const char *msg; + int rc; +} apu_err_t; + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* ! APU_ERRNO_H */ diff --git a/include/apu_version.h b/include/apu_version.h new file mode 100644 index 00000000000..b46aad5033f --- /dev/null +++ b/include/apu_version.h @@ -0,0 +1,87 @@ +/* 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. + */ + +#ifndef APU_VERSION_H +#define APU_VERSION_H + +/** + * @file apu_version.h + * @brief APR-util Versioning Interface + * + * APR-util's Version + * + * There are several different mechanisms for accessing the version. There + * is a string form, and a set of numbers; in addition, there are constants + * which can be compiled into your application, and you can query the library + * being used for its actual version. + * + * Note that it is possible for an application to detect that it has been + * compiled against a different version of APU by use of the compile-time + * constants and the use of the run-time query function. + * + * APU version numbering follows the guidelines specified in: + * + * http://apr.apache.org/versioning.html + */ + + +#include "apr_version.h" + +/* The numeric compile-time version constants. These constants are the + * authoritative version numbers for APU. This file remains as strictly + * a compatibility stub. + */ + +/** major version + * Major API changes that could cause compatibility problems for older + * programs such as structure size changes. No binary compatibility is + * possible across a change in the major version. + * In 2.0, for legacy support, this is an identity of the APR version. + * @deprecated @see APR_MAJOR_VERSION + */ +#define APU_MAJOR_VERSION APR_MAJOR_VERSION + +/** minor version + * Minor API changes that do not cause binary compatibility problems. + * Reset to 0 when upgrading APU_MAJOR_VERSION + * In 2.0, for legacy support, this is an identity of the APR version. + * @deprecated @see APR_MINOR_VERSION + */ +#define APU_MINOR_VERSION APR_MINOR_VERSION + +/** patch level + * The Patch Level never includes API changes, simply bug fixes. + * Reset to 0 when upgrading APR_MINOR_VERSION + * In 2.0, for legacy support, this is an identity of the APR version. + * @deprecated @see APR_PATCH_VERSION + */ +#define APU_PATCH_VERSION APR_PATCH_VERSION + +/** + * The symbol APU_IS_DEV_VERSION is only defined for internal, + * "development" copies of APU. It is undefined for released versions + * of APU. + * In 2.0, for legacy support, this is an identity of the APR version. + * @deprecated @see APR_IS_DEV_VERSION + */ +#ifdef APR_IS_DEV_VERSION +# define APU_IS_DEV_VERSION +#endif + +/** Internal: string form of the "is dev" flag */ +#define APU_IS_DEV_STRING APR_IS_DEV_STRING + +#endif /* ndef APU_VERSION_H */ diff --git a/include/apu_want.h.in b/include/apu_want.h.in new file mode 100644 index 00000000000..a296e5c5c69 --- /dev/null +++ b/include/apu_want.h.in @@ -0,0 +1,51 @@ +/* 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 "apu.h" /* configuration data */ + +/** + * @file apu_want.h + * @brief APR Standard Headers Support + * + * <PRE> + * Features: + * + * APU_WANT_DB: <@apu_db_header@> + * + * Typical usage: + * + * #define APU_WANT_DB + * #include "apu_want.h" + * + * The appropriate headers will be included. + * + * Note: it is safe to use this in a header (it won't interfere with other + * headers' or source files' use of apu_want.h) + * </PRE> + */ + +/* --------------------------------------------------------------------- */ + +#ifdef APU_WANT_DB + +#if APU_HAVE_DB +#include <@apu_db_header@> +#endif + +#undef APU_WANT_DB +#endif + +/* --------------------------------------------------------------------- */ diff --git a/include/apu_want.hnw b/include/apu_want.hnw new file mode 100644 index 00000000000..afdc9f74ca6 --- /dev/null +++ b/include/apu_want.hnw @@ -0,0 +1,52 @@ +/* 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 "apu.h" /* configuration data */ + +/** + * @file apu_want.h + * @brief APR Standard Headers Support + * + * <PRE> + * Features: + * + * APU_WANT_DB: <@apu_db_header> + * + * Typical usage: + * + * #define APU_WANT_DB + * #include "apu_want.h" + * + * The appropriate headers will be included. + * + * Note: it is safe to use this in a header (it won't interfere with other + * headers' or source files' use of apu_want.h) + * </PRE> + */ + +/* --------------------------------------------------------------------- */ + +#ifdef APU_WANT_DB + +#if APU_HAVE_DB +/* win32 note.. you will need to change this for db1 */ +#include <db.h> +#endif + +#undef APU_WANT_DB +#endif + +/* --------------------------------------------------------------------- */ diff --git a/include/apu_want.hw b/include/apu_want.hw new file mode 100644 index 00000000000..8bb56ce79f0 --- /dev/null +++ b/include/apu_want.hw @@ -0,0 +1,52 @@ +/* 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 "apu.h" /* configuration data */ + +/** + * @file apu_want.h + * @brief APR Standard Headers Support + * + * <PRE> + * Features: + * + * APU_WANT_DB: <db.h> + * + * Typical usage: + * + * #define APU_WANT_DB + * #include "apu_want.h" + * + * The appropriate headers will be included. + * + * Note: it is safe to use this in a header (it won't interfere with other + * headers' or source files' use of apu_want.h) + * </PRE> + */ + +/* --------------------------------------------------------------------- */ + +#ifdef APU_WANT_DB + +#if APU_HAVE_DB +/* win32 note.. you will need to change this for db1 */ +#include <db.h> +#endif + +#undef APU_WANT_DB +#endif + +/* --------------------------------------------------------------------- */ diff --git a/include/arch/aix/apr_arch_dso.h b/include/arch/aix/apr_arch_dso.h new file mode 100644 index 00000000000..d1cac684f6e --- /dev/null +++ b/include/arch/aix/apr_arch_dso.h @@ -0,0 +1,41 @@ +/* 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. + */ + +#ifndef DSO_H +#define DSO_H + +#include "apr_private.h" +#include "apr_general.h" +#include "apr_pools.h" +#include "apr_dso.h" +#include "apr.h" + +#if APR_HAS_DSO + +void *dlopen(const char *path, int mode); +void *dlsym(void *handle, const char *symbol); +const char *dlerror(void); +int dlclose(void *handle); + +struct apr_dso_handle_t { + apr_pool_t *pool; + void *handle; + const char *errormsg; +}; + +#endif + +#endif diff --git a/include/arch/aix/dso.h b/include/arch/aix/dso.h deleted file mode 100644 index 392a92015ab..00000000000 --- a/include/arch/aix/dso.h +++ /dev/null @@ -1,73 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#ifndef DSO_H -#define DSO_H - -#include "apr_private.h" -#include "apr_general.h" -#include "apr_pools.h" -#include "apr_dso.h" - -void *dlopen(const char *path, int mode); -void *dlsym(void *handle, const char *symbol); -const char *dlerror(void); -int dlclose(void *handle); - -struct ap_dso_handle_t { - ap_pool_t *cont; - void *handle; -}; - -#endif diff --git a/include/arch/beos/apr_arch_dso.h b/include/arch/beos/apr_arch_dso.h new file mode 100644 index 00000000000..fbc5c2ff013 --- /dev/null +++ b/include/arch/beos/apr_arch_dso.h @@ -0,0 +1,41 @@ +/* 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. + */ + +#ifndef DSO_H +#define DSO_H + +#include "apr_private.h" +#include "apr_general.h" +#include "apr_pools.h" +#include "apr_errno.h" +#include "apr_dso.h" +#include "apr.h" +#include <kernel/image.h> +#include <string.h> + +#if APR_HAS_DSO + +struct apr_dso_handle_t { + image_id handle; /* Handle to the DSO loaded */ + apr_pool_t *pool; + const char *errormsg; /* if the load fails, we have an error + * message here :) + */ +}; + +#endif + +#endif diff --git a/include/arch/beos/apr_arch_proc_mutex.h b/include/arch/beos/apr_arch_proc_mutex.h new file mode 100644 index 00000000000..c60d8c6228a --- /dev/null +++ b/include/arch/beos/apr_arch_proc_mutex.h @@ -0,0 +1,36 @@ +/* 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. + */ + +#ifndef PROC_MUTEX_H +#define PROC_MUTEX_H + +#include "apr_pools.h" +#include "apr_proc_mutex.h" +#include "apr_file_io.h" +#include "apr_general.h" +#include "apr_lib.h" +#include "apr_portable.h" + +struct apr_proc_mutex_t { + apr_pool_t *pool; + + /* Our lock :) */ + sem_id Lock; + int32 LockCount; +}; + +#endif /* PROC_MUTEX_H */ + diff --git a/include/arch/beos/apr_arch_thread_cond.h b/include/arch/beos/apr_arch_thread_cond.h new file mode 100644 index 00000000000..c9420b53cb0 --- /dev/null +++ b/include/arch/beos/apr_arch_thread_cond.h @@ -0,0 +1,46 @@ +/* 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. + */ + +#ifndef THREAD_COND_H +#define THREAD_COND_H + +#include <kernel/OS.h> +#include "apr_pools.h" +#include "apr_thread_cond.h" +#include "apr_file_io.h" +#include "apr_general.h" +#include "apr_lib.h" +#include "apr_portable.h" +#include "apr_ring.h" + +struct waiter_t { + APR_RING_ENTRY(waiter_t) link; + sem_id sem; +}; + +struct apr_thread_cond_t { + apr_pool_t *pool; + sem_id lock; + apr_thread_mutex_t *condlock; + thread_id owner; + /* active list */ + APR_RING_HEAD(active_list, waiter_t) alist; + /* free list */ + APR_RING_HEAD(free_list, waiter_t) flist; +}; + +#endif /* THREAD_COND_H */ + diff --git a/include/arch/beos/apr_arch_thread_mutex.h b/include/arch/beos/apr_arch_thread_mutex.h new file mode 100644 index 00000000000..bb7d4ae80ba --- /dev/null +++ b/include/arch/beos/apr_arch_thread_mutex.h @@ -0,0 +1,42 @@ +/* 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. + */ + +#ifndef THREAD_MUTEX_H +#define THREAD_MUTEX_H + +#include <kernel/OS.h> +#include "apr_pools.h" +#include "apr_thread_mutex.h" +#include "apr_file_io.h" +#include "apr_general.h" +#include "apr_lib.h" +#include "apr_portable.h" + +struct apr_thread_mutex_t { + apr_pool_t *pool; + + /* Our lock :) */ + sem_id Lock; + int32 LockCount; + + /* If we nest locks we need these... */ + int nested; + apr_os_thread_t owner; + int owner_ref; +}; + +#endif /* THREAD_MUTEX_H */ + diff --git a/include/arch/beos/apr_arch_thread_rwlock.h b/include/arch/beos/apr_arch_thread_rwlock.h new file mode 100644 index 00000000000..694b0d50465 --- /dev/null +++ b/include/arch/beos/apr_arch_thread_rwlock.h @@ -0,0 +1,45 @@ +/* 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. + */ + +#ifndef THREAD_RWLOCK_H +#define THREAD_RWLOCK_H + +#include <kernel/OS.h> +#include "apr_pools.h" +#include "apr_thread_rwlock.h" +#include "apr_file_io.h" +#include "apr_general.h" +#include "apr_lib.h" +#include "apr_portable.h" + +struct apr_thread_rwlock_t { + apr_pool_t *pool; + + /* Our lock :) */ + sem_id Lock; + int32 LockCount; + /* Read/Write lock stuff */ + sem_id Read; + int32 ReadCount; + sem_id Write; + int32 WriteCount; + int32 Nested; + + thread_id writer; +}; + +#endif /* THREAD_RWLOCK_H */ + diff --git a/include/arch/beos/apr_arch_threadproc.h b/include/arch/beos/apr_arch_threadproc.h new file mode 100644 index 00000000000..13de0536345 --- /dev/null +++ b/include/arch/beos/apr_arch_threadproc.h @@ -0,0 +1,95 @@ +/* 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_thread_proc.h" +#include "apr_arch_file_io.h" +#include "apr_file_io.h" +#include "apr_thread_proc.h" +#include "apr_general.h" +#include "apr_portable.h" +#include <kernel/OS.h> +#include <signal.h> +#include <string.h> +#include <sys/wait.h> +#include <image.h> + +#ifndef THREAD_PROC_H +#define THREAD_PROC_H + +#define SHELL_PATH "/bin/sh" + +#define PTHREAD_CANCEL_AYNCHRONOUS CANCEL_ASYNCH; +#define PTHREAD_CANCEL_DEFERRED CANCEL_DEFER; + +#define PTHREAD_CANCEL_ENABLE CANCEL_ENABLE; +#define PTHREAD_CANCEL_DISABLE CANCEL_DISABLE; + +#define BEOS_MAX_DATAKEYS 128 + +struct apr_thread_t { + apr_pool_t *pool; + thread_id td; + void *data; + apr_thread_start_t func; + apr_status_t exitval; +}; + +struct apr_threadattr_t { + apr_pool_t *pool; + int32 attr; + int detached; + int joinable; +}; + +struct apr_threadkey_t { + apr_pool_t *pool; + int32 key; +}; + +struct beos_private_data { + const void ** data; + int count; + volatile thread_id td; +}; + +struct beos_key { + int assigned; + int count; + sem_id lock; + int32 ben_lock; + void (* destructor) (void *); +}; + +struct apr_procattr_t { + apr_pool_t *pool; + apr_file_t *parent_in; + apr_file_t *child_in; + apr_file_t *parent_out; + apr_file_t *child_out; + apr_file_t *parent_err; + apr_file_t *child_err; + char *currdir; + apr_int32_t cmdtype; + apr_int32_t detached; +}; + +struct apr_thread_once_t { + sem_id sem; + int hit; +}; + +#endif /* ! THREAD_PROC_H */ + diff --git a/include/arch/beos/dso.h b/include/arch/beos/dso.h deleted file mode 100644 index 2666d779ad2..00000000000 --- a/include/arch/beos/dso.h +++ /dev/null @@ -1,70 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#ifndef DSO_H -#define DSO_H - -#include "apr_private.h" -#include "apr_general.h" -#include "apr_pools.h" -#include "apr_errno.h" -#include "apr_dso.h" -#include <kernel/image.h> - -struct ap_dso_handle_t { - image_id handle; /* Handle to the DSO loaded */ - ap_pool_t *cont; -}; - -#endif diff --git a/include/arch/beos/locks.h b/include/arch/beos/locks.h deleted file mode 100644 index 0160b5e71aa..00000000000 --- a/include/arch/beos/locks.h +++ /dev/null @@ -1,82 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#ifndef LOCKS_H -#define LOCKS_H - -#include <kernel/OS.h> -#include "apr_lock.h" -#include "apr_file_io.h" -#include "apr_general.h" -#include "apr_lib.h" - -struct ap_lock_t { - ap_pool_t *cntxt; - ap_locktype_e type; - ap_lockscope_e scope; - int curr_locked; - char *fname; - /* Inter proc */ - sem_id sem_interproc; - int32 ben_interproc; - /* Intra Proc */ - sem_id sem_intraproc; - int32 ben_intraproc; - /* At some point, we should do a scope for both inter and intra process - * locking here. Something like pthread_mutex with PTHREAD_PROCESS_SHARED - */ -}; - -#endif /* LOCKS_H */ - diff --git a/include/arch/beos/networkio.h b/include/arch/beos/networkio.h deleted file mode 100644 index 3966acf433b..00000000000 --- a/include/arch/beos/networkio.h +++ /dev/null @@ -1,112 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#ifndef NETWORK_IO_H -#define NETWORK_IO_H - -#include <socket.h> -#include <netdb.h> -#include <errno.h> -#include <string.h> -#include <stdlib.h> -#include <sys/time.h> -#include "apr_network_io.h" -#include "apr_general.h" -#include "apr_portable.h" -#include "apr_lib.h" -#include "fileio.h" -#include "apr_errno.h" - -/* The definition of isascii was missed from the PowerPC ctype.h - * - * It will be included in the next release, but until then... */ -#if __POWERPC__ -#define isascii(c) (((c) & ~0x7f)==0) -#endif - -#include "apr_general.h" -#include <ByteOrder.h> /* for the ntohs definition */ - -#define POLLIN 1 -#define POLLPRI 2 -#define POLLOUT 4 -#define POLLERR 8 -#define POLLHUP 16 -#define POLLNVAL 32 - -struct ap_socket_t { - ap_pool_t *cntxt; - int socketdes; - struct sockaddr_in *local_addr; - struct sockaddr_in *remote_addr; - int addr_len; - ap_interval_time_t timeout; - int connected; -}; - -struct ap_pollfd_t { - ap_pool_t *cntxt; - struct ap_socket_t *sock; - fd_set *read; - fd_set *write; - fd_set *except; - int highsock; -}; - -ap_int16_t get_event(ap_int16_t); - -int inet_aton(const char *cp, struct in_addr *addr); - -#endif /* ! NETWORK_IO_H */ - diff --git a/include/arch/beos/threadproc.h b/include/arch/beos/threadproc.h deleted file mode 100644 index 4588105d15f..00000000000 --- a/include/arch/beos/threadproc.h +++ /dev/null @@ -1,134 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#include "apr_thread_proc.h" -#include "fileio.h" -#include "apr_file_io.h" -#include "apr_thread_proc.h" -#include "apr_file_io.h" -#include "apr_general.h" -#include "apr_portable.h" -#include <kernel/OS.h> -#include <signal.h> -#include <string.h> -#include <sys/wait.h> - -#ifndef THREAD_PROC_H -#define THREAD_PROC_H - -#define SHELL_PATH "/bin/sh" - -#define PTHREAD_CANCEL_AYNCHRONOUS CANCEL_ASYNCH; -#define PTHREAD_CANCEL_DEFERRED CANCEL_DEFER; - -#define PTHREAD_CANCEL_ENABLE CANCEL_ENABLE; -#define PTHREAD_CANCEL_DISABLE CANCEL_DISABLE; - -#define BEOS_MAX_DATAKEYS 128 - -struct ap_thread_t { - ap_pool_t *cntxt; - thread_id td; -}; - -struct ap_threadattr_t { - ap_pool_t *cntxt; - int32 attr; - int detached; - int joinable; -}; - -struct ap_threadkey_t { - ap_pool_t *cntxt; - int32 key; -}; - -struct beos_private_data { - const void ** data; - int count; - volatile thread_id td; -}; - -struct beos_key { - int assigned; - int count; - sem_id lock; - int32 ben_lock; - void (* destructor) (); -}; - -struct ap_procattr_t { - ap_pool_t *cntxt; - ap_file_t *parent_in; - ap_file_t *child_in; - ap_file_t *parent_out; - ap_file_t *child_out; - ap_file_t *parent_err; - ap_file_t *child_err; - char *currdir; - ap_int32_t cmdtype; - ap_int32_t detached; -}; - -struct ap_proc_t { - ap_pool_t *cntxt; - thread_id pid; - struct ap_procattr_t *attr; -}; - -/* we need a structure to pass off to the thread that will run any - * new process we create */ - -#endif /* ! THREAD_PROC_H */ - diff --git a/include/arch/netware/apr_arch_dso.h b/include/arch/netware/apr_arch_dso.h new file mode 100644 index 00000000000..ea0fe8c254c --- /dev/null +++ b/include/arch/netware/apr_arch_dso.h @@ -0,0 +1,43 @@ +/* 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. + */ + +#ifndef DSO_H +#define DSO_H + +#include "apr_private.h" +#include "apr_general.h" +#include "apr_pools.h" +#include "apr_dso.h" +#include "apr.h" + +#include <dlfcn.h> + +typedef struct sym_list sym_list; + +struct sym_list { + sym_list *next; + char *symbol; +}; + +struct apr_dso_handle_t { + apr_pool_t *pool; + void *handle; + const char *errormsg; + sym_list *symbols; + char *path; +}; + +#endif diff --git a/include/arch/netware/apr_arch_file_io.h b/include/arch/netware/apr_arch_file_io.h new file mode 100644 index 00000000000..659eb200625 --- /dev/null +++ b/include/arch/netware/apr_arch_file_io.h @@ -0,0 +1,187 @@ +/* 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. + */ + +#ifndef FILE_IO_H +#define FILE_IO_H + +#include "apr.h" +#include "apr_private.h" +#include "apr_general.h" +#include "apr_tables.h" +#include "apr_file_io.h" +#include "apr_file_info.h" +#include "apr_errno.h" +#include "apr_lib.h" +#include "apr_poll.h" +#include "apr_time.h" + +/* System headers the file I/O library needs */ +#if APR_HAVE_FCNTL_H +#include <fcntl.h> +#endif +#if APR_HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#if APR_HAVE_ERRNO_H +#include <errno.h> +#endif +#if APR_HAVE_STRING_H +#include <string.h> +#endif +#if APR_HAVE_STRINGS_H +#include <strings.h> +#endif +#if APR_HAVE_DIRENT_H +#include <dirent.h> +#endif +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif +#if APR_HAVE_UNISTD_H +#include <unistd.h> +#endif +#if APR_HAVE_STDIO_H +#include <stdio.h> +#endif +#if APR_HAVE_STDLIB_H +#include <stdlib.h> +#endif +#if APR_HAVE_SYS_UIO_H +#include <sys/uio.h> +#endif +#if APR_HAVE_SYS_TIME_H +#include <sys/time.h> +#endif + +#include <fsio.h> + +/* End System headers */ + +#define APR_FILE_DEFAULT_BUFSIZE 4096 +/* For backwards compat */ +#define APR_FILE_BUFSIZE APR_FILE_DEFAULT_BUFSIZE + +#if APR_HAS_THREADS +#define file_lock(f) do { \ + if ((f)->thlock) \ + apr_thread_mutex_lock((f)->thlock); \ + } while (0) +#define file_unlock(f) do { \ + if ((f)->thlock) \ + apr_thread_mutex_unlock((f)->thlock); \ + } while (0) +#else +#define file_lock(f) do {} while (0) +#define file_unlock(f) do {} while (0) +#endif + +#if APR_HAS_LARGE_FILES +#define lseek(f,o,w) lseek64(f,o,w) +#define ftruncate(f,l) ftruncate64(f,l) +#endif + +typedef struct stat struct_stat; + +typedef struct apr_rotating_info_t { + apr_finfo_t finfo; + apr_interval_time_t timeout; + apr_time_t lastcheck; + int oflags; + int manual; + apr_fileperms_t perm; +} apr_rotating_info_t; + +struct apr_file_t { + apr_pool_t *pool; + int filedes; + char *fname; + apr_int32_t flags; + int eof_hit; + int is_pipe; + apr_interval_time_t timeout; + int buffered; + enum {BLK_UNKNOWN, BLK_OFF, BLK_ON } blocking; + int ungetchar; /* Last char provided by an unget op. (-1 = no char)*/ + + /* if there is a timeout set, then this pollset is used */ + apr_pollset_t *pollset; + + /* Stuff for buffered mode */ + char *buffer; + apr_size_t bufpos; /* Read/Write position in buffer */ + apr_size_t bufsize; /* The buffer size */ + apr_off_t dataRead; /* amount of valid data read into buffer */ + int direction; /* buffer being used for 0 = read, 1 = write */ + apr_off_t filePtr; /* position in file of handle */ +#if APR_HAS_THREADS + struct apr_thread_mutex_t *thlock; +#endif + apr_rotating_info_t *rotating; +}; + +struct apr_dir_t { + apr_pool_t *pool; + char *dirname; + DIR *dirstruct; + struct dirent *entry; +}; + +typedef struct apr_stat_entry_t apr_stat_entry_t; + +struct apr_stat_entry_t { + struct stat info; + char *casedName; + apr_time_t expire; + NXPathCtx_t pathCtx; +}; + +#define MAX_SERVER_NAME 64 +#define MAX_VOLUME_NAME 64 +#define MAX_PATH_NAME 256 +#define MAX_FILE_NAME 256 + +#define DRIVE_ONLY 1 + +/* If the user passes d: vs. D: (or //mach/share vs. //MACH/SHARE), + * we need to fold the case to canonical form. This function is + * supposed to do so. + */ +apr_status_t filepath_root_case(char **rootpath, char *root, apr_pool_t *p); + +/* This function check to see of the given path includes a drive/volume + * specifier. If the _only_ parameter is set to DRIVE_ONLY then it + * check to see of the path only contains a drive/volume specifier and + * nothing else. + */ +apr_status_t filepath_has_drive(const char *rootpath, int only, apr_pool_t *p); + +/* This function compares the drive/volume specifiers for each given path. + * It returns zero if they match or non-zero if not. + */ +apr_status_t filepath_compare_drive(const char *path1, const char *path2, apr_pool_t *p); + +apr_status_t apr_unix_file_cleanup(void *); +apr_status_t apr_unix_child_file_cleanup(void *); + +mode_t apr_unix_perms2mode(apr_fileperms_t perms); +apr_fileperms_t apr_unix_mode2perms(mode_t mode); + +apr_status_t apr_file_flush_locked(apr_file_t *thefile); +apr_status_t apr_file_info_get_locked(apr_finfo_t *finfo, apr_int32_t wanted, + apr_file_t *thefile); + +#endif /* ! FILE_IO_H */ + diff --git a/include/arch/netware/apr_arch_global_mutex.h b/include/arch/netware/apr_arch_global_mutex.h new file mode 100644 index 00000000000..4167d378211 --- /dev/null +++ b/include/arch/netware/apr_arch_global_mutex.h @@ -0,0 +1,29 @@ +/* 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. + */ + +#ifndef GLOBAL_MUTEX_H +#define GLOBAL_MUTEX_H + +#include "apr_global_mutex.h" +#include "apr_thread_mutex.h" + +struct apr_global_mutex_t { + apr_pool_t *pool; + apr_thread_mutex_t *mutex; +}; + +#endif /* GLOBAL_MUTEX_H */ + diff --git a/include/arch/netware/apr_arch_internal_time.h b/include/arch/netware/apr_arch_internal_time.h new file mode 100644 index 00000000000..59f1067208a --- /dev/null +++ b/include/arch/netware/apr_arch_internal_time.h @@ -0,0 +1,26 @@ +/* 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. + */ + +#ifndef TIME_INTERNAL_H +#define TIME_INTERNAL_H + +#include "apr.h" + +#define TZONE (*___timezone()) + +void apr_netware_setup_time(void); + +#endif /* TIME_INTERNAL_H */ diff --git a/include/arch/netware/apr_arch_networkio.h b/include/arch/netware/apr_arch_networkio.h new file mode 100644 index 00000000000..63f17abe595 --- /dev/null +++ b/include/arch/netware/apr_arch_networkio.h @@ -0,0 +1,31 @@ +/* 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. + */ + +#ifndef NETWORK_IO_H + +#ifdef USE_WINSOCK +/* Making sure that we include the correct networkio.h since the + the project file is configured to first look for headers in + arch/netware and then arch/unix. But in this specific case we + want arch/win32. +*/ +#include <../win32/apr_arch_networkio.h> +#else +#include <../unix/apr_arch_networkio.h> +#endif + +#endif /* ! NETWORK_IO_H */ + diff --git a/include/arch/netware/apr_arch_pre_nw.h b/include/arch/netware/apr_arch_pre_nw.h new file mode 100644 index 00000000000..9b441402ccc --- /dev/null +++ b/include/arch/netware/apr_arch_pre_nw.h @@ -0,0 +1,60 @@ +/* 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. + */ +#ifndef __pre_nw__ +#define __pre_nw__ + +#include <stdint.h> + +#ifdef __MWERKS__ +#pragma precompile_target "precomp.mch" +#endif + +#ifndef NETWARE +#define NETWARE +#endif + +#ifndef N_PLAT_NLM +#define N_PLAT_NLM +#endif + +#define FAR +#define far + +/* no-op for Codewarrior C compiler; all functions are cdecl by default */ +#define cdecl + +/* if we have wchar_t enabled in C++, predefine this type to avoid + a conflict in Novell's header files */ +#ifndef __GNUC__ +#ifndef DOXYGEN +#if (__option(cplusplus) && __option(wchar_type)) +#define _WCHAR_T +#endif +#endif +#endif + +/* C9X defintion used by MSL C++ library */ +#define DECIMAL_DIG 17 + +/* some code may want to use the MS convention for long long */ +#ifndef __int64 +#define __int64 long long +#endif + +#endif + + + diff --git a/include/arch/netware/apr_arch_proc_mutex.h b/include/arch/netware/apr_arch_proc_mutex.h new file mode 100644 index 00000000000..7a634c2e50d --- /dev/null +++ b/include/arch/netware/apr_arch_proc_mutex.h @@ -0,0 +1,29 @@ +/* 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. + */ + +#ifndef PROC_MUTEX_H +#define PROC_MUTEX_H + +#include "apr_proc_mutex.h" +#include "apr_thread_mutex.h" + +struct apr_proc_mutex_t { + apr_pool_t *pool; + apr_thread_mutex_t *mutex; +}; + +#endif /* PROC_MUTEX_H */ + diff --git a/include/arch/netware/apr_arch_thread_cond.h b/include/arch/netware/apr_arch_thread_cond.h new file mode 100644 index 00000000000..b11a5f86a74 --- /dev/null +++ b/include/arch/netware/apr_arch_thread_cond.h @@ -0,0 +1,29 @@ +/* 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. + */ + +#ifndef THREAD_COND_H +#define THREAD_COND_H + +#include "apr_thread_cond.h" +#include <nks/synch.h> + +struct apr_thread_cond_t { + apr_pool_t *pool; + NXCond_t *cond; +}; + +#endif /* THREAD_COND_H */ + diff --git a/include/arch/netware/apr_arch_thread_mutex.h b/include/arch/netware/apr_arch_thread_mutex.h new file mode 100644 index 00000000000..18702fc7d03 --- /dev/null +++ b/include/arch/netware/apr_arch_thread_mutex.h @@ -0,0 +1,32 @@ +/* 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. + */ + +#ifndef THREAD_MUTEX_H +#define THREAD_MUTEX_H + +#include "apr_thread_mutex.h" +#include "apr_thread_cond.h" +#include <nks/synch.h> + +struct apr_thread_mutex_t { + apr_pool_t *pool; + NXMutex_t *mutex; + apr_thread_cond_t *cond; + int locked, num_waiters; +}; + +#endif /* THREAD_MUTEX_H */ + diff --git a/include/arch/netware/apr_arch_thread_rwlock.h b/include/arch/netware/apr_arch_thread_rwlock.h new file mode 100644 index 00000000000..d2dbd42f798 --- /dev/null +++ b/include/arch/netware/apr_arch_thread_rwlock.h @@ -0,0 +1,29 @@ +/* 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. + */ + +#ifndef THREAD_RWLOCK_H +#define THREAD_RWLOCK_H + +#include "apr_thread_rwlock.h" +#include <nks/synch.h> + +struct apr_thread_rwlock_t { + apr_pool_t *pool; + NXRwLock_t *rwlock; +}; + +#endif /* THREAD_RWLOCK_H */ + diff --git a/include/arch/netware/apr_arch_threadproc.h b/include/arch/netware/apr_arch_threadproc.h new file mode 100644 index 00000000000..2fee2c00eeb --- /dev/null +++ b/include/arch/netware/apr_arch_threadproc.h @@ -0,0 +1,80 @@ +/* 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_thread_proc.h" +#include "apr_file_io.h" + +#include <sys/wait.h> + +#ifndef THREAD_PROC_H +#define THREAD_PROC_H + +#define SHELL_PATH "" +#define APR_DEFAULT_STACK_SIZE 65536 + +struct apr_thread_t { + apr_pool_t *pool; + NXContext_t ctx; + NXThreadId_t td; + char *thread_name; + apr_int32_t cancel; + apr_int32_t cancel_how; + void *data; + apr_thread_start_t func; + apr_status_t exitval; +}; + +struct apr_threadattr_t { + apr_pool_t *pool; + apr_size_t stack_size; + apr_int32_t detach; + char *thread_name; +}; + +struct apr_threadkey_t { + apr_pool_t *pool; + NXKey_t key; +}; + +struct apr_procattr_t { + apr_pool_t *pool; + apr_file_t *parent_in; + apr_file_t *child_in; + apr_file_t *parent_out; + apr_file_t *child_out; + apr_file_t *parent_err; + apr_file_t *child_err; + char *currdir; + apr_int32_t cmdtype; + apr_int32_t detached; + apr_int32_t addrspace; +}; + +struct apr_thread_once_t { + unsigned long value; +}; + +/* +struct apr_proc_t { + apr_pool_t *pool; + pid_t pid; + apr_procattr_t *attr; +}; +*/ + +#endif /* ! THREAD_PROC_H */ + diff --git a/include/arch/netware/apr_private.h b/include/arch/netware/apr_private.h new file mode 100644 index 00000000000..c4558afa78c --- /dev/null +++ b/include/arch/netware/apr_private.h @@ -0,0 +1,210 @@ +/* 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. + */ + +/* + * Note: + * This is the netware-specific autoconf-like config file + * which unix creates at ./configure time. + */ + +#ifndef APR_PRIVATE_H +#define APR_PRIVATE_H + +/* Pick up publicly advertised headers and symbols before the + * APR internal private headers and symbols + */ +#include <apr.h> + +/* Pick up privately consumed headers */ +#include <ndkvers.h> + +/* Include alloca.h to get compiler-dependent defines */ +#include <alloca.h> + +/* Use this section to define all of the HAVE_FOO_H + * that are required to build properly. + */ +#define HAVE_ALLOCA_H 1 +#define HAVE_DLFCN_H 1 +#define HAVE_LIMITS_H 1 +#define HAVE_SIGNAL_H 1 +#define HAVE_STDDEF_H 1 +#define HAVE_STDLIB_H 1 +#ifndef USE_WINSOCK +#define HAVE_SYS_SELECT_H 1 +#define HAVE_WRITEV 1 +#endif +#define HAVE_SYS_STAT_H 1 +#define HAVE_SYS_MMAN_H 1 +#define HAVE_FCNTL_H 1 +#define HAVE_ICONV_H 1 +#define HAVE_UTIME_H 1 + +#define HAVE_STRICMP 1 +#define HAVE_STRNICMP 1 +#define HAVE_STRDUP 1 +#define HAVE_STRSTR 1 +#define HAVE_MEMCHR 1 +#define HAVE_CALLOC 1 +#define HAVE_UTIME 1 + +#define HAVE_GETENV 1 +#define HAVE_SETENV 1 +#define HAVE_UNSETENV 1 + +#define HAVE_WRITEV 1 + +#define HAVE_GETPASS_R 1 +/* + * Hack around older NDKs which have only the getpassword() function, + * a threadsafe, API-equivalent of getpass_r(). + */ +#if (CURRENT_NDK_THRESHOLD < 709060000) +#define getpass_r getpassword +#endif + +#ifdef NW_BUILD_IPV6 +#define HAVE_GETADDRINFO 1 +#define HAVE_GETNAMEINFO 1 +#endif + +/* 1 is used for SIGABRT on netware */ +/* 2 is used for SIGFPE on netware */ +/* 3 is used for SIGILL on netware */ +/* 4 is used for SIGINT on netware */ +/* 5 is used for SIGSEGV on netware */ +/* 6 is used for SIGTERM on netware */ +/* 7 is used for SIGPOLL on netware */ + +#if (CURRENT_NDK_THRESHOLD < 306030000) +#define SIGKILL 11 +#define SIGALRM 13 +#define SIGCHLD 14 +#define SIGCONT 15 +#define SIGHUP 16 +#define SIGPIPE 17 +#define SIGQUIT 18 +#define SIGSTOP 19 +#define SIGTSTP 20 +#define SIGTTIN 21 +#define SIGTTOU 22 +#define SIGUSR1 23 +#define SIGUSR2 24 +#endif + +#define SIGTRAP 25 +#define SIGIOT 26 +#define SIGSTKFLT 28 +#define SIGURG 29 +#define SIGXCPU 30 +#define SIGXFSZ 31 +#define SIGVTALRM 32 +#define SIGPROF 33 +#define SIGWINCH 34 +#define SIGIO 35 + +#if (CURRENT_NDK_THRESHOLD < 406230000) +#undef SA_NOCLDSTOP +#define SA_NOCLDSTOP 0x00000001 +#endif +#ifndef SIGBUS +#define SIGBUS SIGSEGV +#endif + +#define _getch() getcharacter() + +#define SIZEOF_CHAR 1 +#define SIZEOF_SHORT 2 +#define SIZEOF_INT 4 +#define SIZEOF_LONGLONG 8 +#define SIZEOF_SSIZE_T SIZEOF_INT + +void netware_pool_proc_cleanup(); + +/* NLM registration routines for managing which NLMs + are using the library. */ +int register_NLM(void *NLMHandle); +int unregister_NLM(void *NLMHandle); + +/* Application global data management */ +extern int gLibId; +extern void *gLibHandle; + +typedef struct app_data { + int initialized; + void* gPool; + void* gs_aHooksToSort; + void* gs_phOptionalHooks; + void* gs_phOptionalFunctions; + void* gs_nlmhandle; + rtag_t gs_startup_rtag; + rtag_t gs_socket_rtag; + rtag_t gs_lookup_rtag; + rtag_t gs_event_rtag; + rtag_t gs_pcp_rtag; + void* gs_xref_head; +} APP_DATA; + +int setGlobalPool(void *data); +void* getGlobalPool(); +int setStatCache(void *data); +void* getStatCache(); + +/* Redefine malloc to use the library malloc call so + that all of the memory resources will be owned + and can be shared by the library. */ +#undef malloc +#define malloc(x) library_malloc(gLibHandle,x) +#ifndef __MWERKS__ +#define _alloca alloca +#endif + +/* 64-bit integer conversion function */ +#define APR_INT64_STRFN strtoll + +#if APR_HAS_LARGE_FILES +#define APR_OFF_T_STRFN strtoll +#else +#define APR_OFF_T_STRFN strtol +#endif + +/* used to check DWORD overflow for 64bit compiles */ +#define APR_DWORD_MAX 0xFFFFFFFFUL + +/* Always compile Netware with DSO support for .nlm builds */ +#define APU_DSO_BUILD 0 + +/* + * NetWare does not have GDBM, and we always use the bundled (new) Expat + */ + +/* Define if you have the gdbm library (-lgdbm). */ +/* #undef HAVE_LIBGDBM */ + +/* define if Expat 1.0 or 1.1 was found */ +/* #undef APR_HAVE_OLD_EXPAT */ + +/* NetWare uses its own ICONV implementation. */ +#define HAVE_ICONV_H 1 + +/* + * check for newer NDKs which use now correctly 'const char*' with iconv. + */ +#if (CURRENT_NDK_THRESHOLD >= 705110000) +#define APU_ICONV_INBUF_CONST +#endif + +#endif /*APR_PRIVATE_H*/ diff --git a/include/arch/os2/apr_arch_dso.h b/include/arch/os2/apr_arch_dso.h new file mode 100644 index 00000000000..2bda6b7c663 --- /dev/null +++ b/include/arch/os2/apr_arch_dso.h @@ -0,0 +1,37 @@ +/* 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. + */ + +#ifndef DSO_H +#define DSO_H + +#include "apr_private.h" +#include "apr_general.h" +#include "apr_pools.h" +#include "apr_dso.h" +#include "apr.h" + +#if APR_HAS_DSO + +struct apr_dso_handle_t { + apr_pool_t *cont; /* Context for returning error strings */ + HMODULE handle; /* Handle to the DSO loaded */ + apr_status_t load_error; + char *failed_module; +}; + +#endif + +#endif diff --git a/include/arch/os2/apr_arch_file_io.h b/include/arch/os2/apr_arch_file_io.h new file mode 100644 index 00000000000..a742bf47729 --- /dev/null +++ b/include/arch/os2/apr_arch_file_io.h @@ -0,0 +1,87 @@ +/* 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. + */ + +#ifndef FILE_IO_H +#define FILE_IO_H + +#include "apr_private.h" +#include "apr_general.h" +#include "apr_thread_mutex.h" +#include "apr_file_io.h" +#include "apr_file_info.h" +#include "apr_errno.h" +#include "apr_poll.h" + +/* We have an implementation of mkstemp but it's not very multi-threading + * friendly & is part of the POSIX emulation rather than native so don't + * use it. + */ +#undef HAVE_MKSTEMP + +#define APR_FILE_DEFAULT_BUFSIZE 4096 +#define APR_FILE_BUFSIZE APR_FILE_DEFAULT_BUFSIZE + +struct apr_file_t { + apr_pool_t *pool; + HFILE filedes; + char * fname; + int isopen; + int buffered; + int eof_hit; + apr_int32_t flags; + int timeout; + int pipe; + HEV pipeSem; + enum { BLK_UNKNOWN, BLK_OFF, BLK_ON } blocking; + + /* Stuff for buffered mode */ + char *buffer; + apr_size_t bufsize; /* The size of the buffer */ + apr_size_t bufpos; /* Read/Write position in buffer */ + unsigned long dataRead; /* amount of valid data read into buffer */ + int direction; /* buffer being used for 0 = read, 1 = write */ + unsigned long filePtr; /* position in file of handle */ + apr_thread_mutex_t *mutex; /* mutex semaphore, must be owned to access + the above fields */ + int ungetchar; +}; + +struct apr_dir_t { + apr_pool_t *pool; + char *dirname; + ULONG handle; + FILEFINDBUF3 entry; + int validentry; +}; + +apr_status_t apr_file_cleanup(void *); +apr_status_t apr_os2_time_to_apr_time(apr_time_t *result, FDATE os2date, + FTIME os2time); +apr_status_t apr_apr_time_to_os2_time(FDATE *os2date, FTIME *os2time, + apr_time_t aprtime); + +/* see win32/fileio.h for description of these */ +extern const char c_is_fnchar[256]; + +#define IS_FNCHAR(c) c_is_fnchar[(unsigned char)c] + +apr_status_t filepath_root_test(char *path, apr_pool_t *p); +apr_status_t filepath_drive_get(char **rootpath, char drive, + apr_int32_t flags, apr_pool_t *p); +apr_status_t filepath_root_case(char **rootpath, char *root, apr_pool_t *p); + +#endif /* ! FILE_IO_H */ + diff --git a/include/arch/os2/apr_arch_networkio.h b/include/arch/os2/apr_arch_networkio.h new file mode 100644 index 00000000000..10c6de81fbb --- /dev/null +++ b/include/arch/os2/apr_arch_networkio.h @@ -0,0 +1,76 @@ +/* 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. + */ + +#ifndef NETWORK_IO_H +#define NETWORK_IO_H + +#include "apr_private.h" +#include "apr_network_io.h" +#include "apr_general.h" +#include "apr_arch_os2calls.h" +#include "apr_poll.h" + +#if APR_HAVE_NETDB_H +#include <netdb.h> +#endif + +typedef struct sock_userdata_t sock_userdata_t; +struct sock_userdata_t { + sock_userdata_t *next; + const char *key; + void *data; +}; + +struct apr_socket_t { + apr_pool_t *pool; + int socketdes; + int type; + int protocol; + apr_sockaddr_t *local_addr; + apr_sockaddr_t *remote_addr; + apr_interval_time_t timeout; + int nonblock; + int local_port_unknown; + int local_interface_unknown; + int remote_addr_unknown; + apr_int32_t options; + apr_int32_t inherit; + sock_userdata_t *userdata; + + /* if there is a timeout set, then this pollset is used */ + apr_pollset_t *pollset; +}; + +/* Error codes returned from sock_errno() */ +#define SOCBASEERR 10000 +#define SOCEPERM (SOCBASEERR+1) /* Not owner */ +#define SOCESRCH (SOCBASEERR+3) /* No such process */ +#define SOCEINTR (SOCBASEERR+4) /* Interrupted system call */ +#define SOCENXIO (SOCBASEERR+6) /* No such device or address */ +#define SOCEBADF (SOCBASEERR+9) /* Bad file number */ +#define SOCEACCES (SOCBASEERR+13) /* Permission denied */ +#define SOCEFAULT (SOCBASEERR+14) /* Bad address */ +#define SOCEINVAL (SOCBASEERR+22) /* Invalid argument */ +#define SOCEMFILE (SOCBASEERR+24) /* Too many open files */ +#define SOCEPIPE (SOCBASEERR+32) /* Broken pipe */ +#define SOCEOS2ERR (SOCBASEERR+100) /* OS/2 Error */ + +const char *apr_inet_ntop(int af, const void *src, char *dst, apr_size_t size); +int apr_inet_pton(int af, const char *src, void *dst); +void apr_sockaddr_vars_set(apr_sockaddr_t *, int, apr_port_t); + +#endif /* ! NETWORK_IO_H */ + diff --git a/include/arch/os2/apr_arch_os2calls.h b/include/arch/os2/apr_arch_os2calls.h new file mode 100644 index 00000000000..3c739bfd19f --- /dev/null +++ b/include/arch/os2/apr_arch_os2calls.h @@ -0,0 +1,59 @@ +/* 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_errno.h" +#include <sys/types.h> +#include <sys/socket.h> + +extern int (*apr_os2_socket)(int, int, int); +extern int (*apr_os2_select)(int *, int, int, int, long); +extern int (*apr_os2_sock_errno)(); +extern int (*apr_os2_accept)(int, struct sockaddr *, int *); +extern int (*apr_os2_bind)(int, struct sockaddr *, int); +extern int (*apr_os2_connect)(int, struct sockaddr *, int); +extern int (*apr_os2_getpeername)(int, struct sockaddr *, int *); +extern int (*apr_os2_getsockname)(int, struct sockaddr *, int *); +extern int (*apr_os2_getsockopt)(int, int, int, char *, int *); +extern int (*apr_os2_ioctl)(int, int, caddr_t, int); +extern int (*apr_os2_listen)(int, int); +extern int (*apr_os2_recv)(int, char *, int, int); +extern int (*apr_os2_send)(int, const char *, int, int); +extern int (*apr_os2_setsockopt)(int, int, int, char *, int); +extern int (*apr_os2_shutdown)(int, int); +extern int (*apr_os2_soclose)(int); +extern int (*apr_os2_writev)(int, struct iovec *, int); +extern int (*apr_os2_sendto)(int, const char *, int, int, const struct sockaddr *, int); +extern int (*apr_os2_recvfrom)(int, char *, int, int, struct sockaddr *, int *); + +#define socket apr_os2_socket +#define select apr_os2_select +#define sock_errno apr_os2_sock_errno +#define accept apr_os2_accept +#define bind apr_os2_bind +#define connect apr_os2_connect +#define getpeername apr_os2_getpeername +#define getsockname apr_os2_getsockname +#define getsockopt apr_os2_getsockopt +#define ioctl apr_os2_ioctl +#define listen apr_os2_listen +#define recv apr_os2_recv +#define send apr_os2_send +#define setsockopt apr_os2_setsockopt +#define shutdown apr_os2_shutdown +#define soclose apr_os2_soclose +#define writev apr_os2_writev +#define sendto apr_os2_sendto +#define recvfrom apr_os2_recvfrom diff --git a/include/arch/os2/apr_arch_proc_mutex.h b/include/arch/os2/apr_arch_proc_mutex.h new file mode 100644 index 00000000000..8caf3369dcc --- /dev/null +++ b/include/arch/os2/apr_arch_proc_mutex.h @@ -0,0 +1,31 @@ +/* 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. + */ + +#ifndef PROC_MUTEX_H +#define PROC_MUTEX_H + +#include "apr_proc_mutex.h" +#include "apr_file_io.h" + +struct apr_proc_mutex_t { + apr_pool_t *pool; + HMTX hMutex; + TID owner; + int lock_count; +}; + +#endif /* PROC_MUTEX_H */ + diff --git a/include/arch/os2/apr_arch_thread_cond.h b/include/arch/os2/apr_arch_thread_cond.h new file mode 100644 index 00000000000..aa0a7ca6f8e --- /dev/null +++ b/include/arch/os2/apr_arch_thread_cond.h @@ -0,0 +1,33 @@ +/* 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. + */ + +#ifndef THREAD_COND_H +#define THREAD_COND_H + +#include "apr_thread_cond.h" +#include "apr_file_io.h" + +struct apr_thread_cond_t { + apr_pool_t *pool; + HEV semaphore; + HMTX mutex; + unsigned long num_waiting; + unsigned long num_wake; + unsigned long generation; +}; + +#endif /* THREAD_COND_H */ + diff --git a/include/arch/os2/apr_arch_thread_mutex.h b/include/arch/os2/apr_arch_thread_mutex.h new file mode 100644 index 00000000000..3ae2a41db78 --- /dev/null +++ b/include/arch/os2/apr_arch_thread_mutex.h @@ -0,0 +1,29 @@ +/* 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. + */ + +#ifndef THREAD_MUTEX_H +#define THREAD_MUTEX_H + +#include "apr_thread_mutex.h" +#include "apr_file_io.h" + +struct apr_thread_mutex_t { + apr_pool_t *pool; + HMTX hMutex; +}; + +#endif /* THREAD_MUTEX_H */ + diff --git a/include/arch/os2/apr_arch_thread_rwlock.h b/include/arch/os2/apr_arch_thread_rwlock.h new file mode 100644 index 00000000000..7187d5cb2e5 --- /dev/null +++ b/include/arch/os2/apr_arch_thread_rwlock.h @@ -0,0 +1,31 @@ +/* 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. + */ + +#ifndef THREAD_RWLOCK_H +#define THREAD_RWLOCK_H + +#include "apr_thread_rwlock.h" +#include "apr_file_io.h" + +struct apr_thread_rwlock_t { + apr_pool_t *pool; + int readers; + HMTX write_lock; + HEV read_done; +}; + +#endif /* THREAD_RWLOCK_H */ + diff --git a/include/arch/os2/apr_arch_threadproc.h b/include/arch/os2/apr_arch_threadproc.h new file mode 100644 index 00000000000..c8017adbff3 --- /dev/null +++ b/include/arch/os2/apr_arch_threadproc.h @@ -0,0 +1,67 @@ +/* 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_thread_proc.h" +#include "apr_file_io.h" + +#ifndef THREAD_PROC_H +#define THREAD_PROC_H + +#define APR_THREADATTR_DETACHED 1 + +#define SHELL_PATH "cmd.exe" +#define APR_THREAD_STACKSIZE 65536 + +struct apr_threadattr_t { + apr_pool_t *pool; + unsigned long attr; + apr_size_t stacksize; +}; + +struct apr_thread_t { + apr_pool_t *pool; + struct apr_threadattr_t *attr; + unsigned long tid; + apr_thread_start_t func; + void *data; + apr_status_t exitval; +}; + +struct apr_threadkey_t { + apr_pool_t *pool; + unsigned long *key; +}; + +struct apr_procattr_t { + apr_pool_t *pool; + apr_file_t *parent_in; + apr_file_t *child_in; + apr_file_t *parent_out; + apr_file_t *child_out; + apr_file_t *parent_err; + apr_file_t *child_err; + char *currdir; + apr_int32_t cmdtype; + apr_int32_t detached; +}; + +struct apr_thread_once_t { + unsigned long sem; + char hit; +}; + +#endif /* ! THREAD_PROC_H */ + diff --git a/include/arch/os2/dso.h b/include/arch/os2/dso.h deleted file mode 100644 index 02855bb0c7b..00000000000 --- a/include/arch/os2/dso.h +++ /dev/null @@ -1,72 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#ifndef DSO_H -#define DSO_H - -#define INCL_DOS -#include <os2.h> - -#include "apr_private.h" -#include "apr_general.h" -#include "apr_pools.h" -#include "apr_dso.h" - -struct ap_dso_handle_t { - ap_pool_t *cont; /* Context for returning error strings */ - HMODULE handle; /* Handle to the DSO loaded */ - char *failed_module; -}; - -#endif diff --git a/include/arch/os2/fileio.h b/include/arch/os2/fileio.h deleted file mode 100644 index b2d6d6d2ef0..00000000000 --- a/include/arch/os2/fileio.h +++ /dev/null @@ -1,102 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#ifndef FILE_IO_H -#define FILE_IO_H - -#define INCL_DOS -#include <os2.h> - -#include "apr_private.h" -#include "apr_general.h" -#include "apr_lock.h" -#include "apr_file_io.h" -#include "apr_errno.h" - -#define APR_FILE_BUFSIZE 4096 - -struct ap_file_t { - ap_pool_t *cntxt; - HFILE filedes; - char * fname; - int isopen; - int buffered; - int eof_hit; - ap_int32_t flags; - int timeout; - int pipe; - HEV pipeSem; - - /* Stuff for buffered mode */ - char *buffer; - int bufpos; // Read/Write position in buffer - unsigned long dataRead; // amount of valid data read into buffer - int direction; // buffer being used for 0 = read, 1 = write - unsigned long filePtr; // position in file of handle - ap_lock_t *mutex; // mutex semaphore, must be owned to access the above fields -}; - -struct ap_dir_t { - ap_pool_t *cntxt; - char *dirname; - ULONG handle; - FILEFINDBUF3 entry; - int validentry; -}; - -ap_status_t apr_file_cleanup(void *); -ap_status_t ap_os2_time_to_ap_time(ap_time_t *result, FDATE os2date, FTIME os2time); - -#endif /* ! FILE_IO_H */ - diff --git a/include/arch/os2/locks.h b/include/arch/os2/locks.h deleted file mode 100644 index d416b6b0833..00000000000 --- a/include/arch/os2/locks.h +++ /dev/null @@ -1,77 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#ifndef LOCKS_H -#define LOCKS_H - -#include "apr_lock.h" -#include "apr_file_io.h" -#define INCL_DOS -#include <os2.h> - -struct ap_lock_t { - ap_pool_t *cntxt; - ap_locktype_e type; - ap_lockscope_e scope; - char *fname; - HMTX hMutex; - TID owner; - int lock_count; - TIB *tib; -}; - -void setup_lock(); - -#endif /* LOCKS_H */ - diff --git a/include/arch/os2/networkio.h b/include/arch/os2/networkio.h deleted file mode 100644 index 63424de6a74..00000000000 --- a/include/arch/os2/networkio.h +++ /dev/null @@ -1,97 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#ifndef NETWORK_IO_H -#define NETWORK_IO_H - -#include "apr_network_io.h" -#include "apr_general.h" -#include "os2calls.h" - -struct ap_socket_t { - ap_pool_t *cntxt; - int socketdes; - struct sockaddr_in *local_addr; - struct sockaddr_in *remote_addr; - int addr_len; - ap_interval_time_t timeout; - int nonblock; -}; - -struct ap_pollfd_t { - ap_pool_t *cntxt; - int *socket_list; - int *r_socket_list; - int num_read; - int num_write; - int num_except; - int num_total; -}; - -/* Error codes returned from sock_errno() */ -#define SOCBASEERR 10000 -#define SOCEPERM (SOCBASEERR+1) /* Not owner */ -#define SOCESRCH (SOCBASEERR+3) /* No such process */ -#define SOCEINTR (SOCBASEERR+4) /* Interrupted system call */ -#define SOCENXIO (SOCBASEERR+6) /* No such device or address */ -#define SOCEBADF (SOCBASEERR+9) /* Bad file number */ -#define SOCEACCES (SOCBASEERR+13) /* Permission denied */ -#define SOCEFAULT (SOCBASEERR+14) /* Bad address */ -#define SOCEINVAL (SOCBASEERR+22) /* Invalid argument */ -#define SOCEMFILE (SOCBASEERR+24) /* Too many open files */ -#define SOCEPIPE (SOCBASEERR+32) /* Broken pipe */ -#define SOCEOS2ERR (SOCBASEERR+100) /* OS/2 Error */ - -#endif /* ! NETWORK_IO_H */ - diff --git a/include/arch/os2/os2calls.h b/include/arch/os2/os2calls.h deleted file mode 100644 index 40d54ee6e68..00000000000 --- a/include/arch/os2/os2calls.h +++ /dev/null @@ -1,140 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#include <sys/types.h> -#include <sys/socket.h> - -extern int (*apr_os2_socket)(int, int, int); -extern int (*apr_os2_select)(int *, int, int, int, long); -extern int (*apr_os2_sock_errno)(); -extern int (*apr_os2_accept)(int, struct sockaddr *, int *); -extern int (*apr_os2_bind)(int, struct sockaddr *, int); -extern int (*apr_os2_connect)(int, struct sockaddr *, int); -extern int (*apr_os2_getpeername)(int, struct sockaddr *, int *); -extern int (*apr_os2_getsockname)(int, struct sockaddr *, int *); -extern int (*apr_os2_getsockopt)(int, int, int, char *, int *); -extern int (*apr_os2_ioctl)(int, int, caddr_t, int); -extern int (*apr_os2_listen)(int, int); -extern int (*apr_os2_recv)(int, char *, int, int); -extern int (*apr_os2_send)(int, const char *, int, int); -extern int (*apr_os2_setsockopt)(int, int, int, char *, int); -extern int (*apr_os2_shutdown)(int, int); -extern int (*apr_os2_soclose)(int); -extern int (*apr_os2_writev)(int, struct iovec *, int); - -#define socket apr_os2_socket -#define select apr_os2_select -#define sock_errno apr_os2_sock_errno -#define accept apr_os2_accept -#define bind apr_os2_bind -#define connect apr_os2_connect -#define getpeername apr_os2_getpeername -#define getsockname apr_os2_getsockname -#define getsockopt apr_os2_getsockopt -#define ioctl apr_os2_ioctl -#define listen apr_os2_listen -#define recv apr_os2_recv -#define send apr_os2_send -#define setsockopt apr_os2_setsockopt -#define shutdown apr_os2_shutdown -#define soclose apr_os2_soclose -#define writev apr_os2_writev - - -/* Error codes returned by above calls */ -#define SOCBASEERR 10000 - -#define SOCEPERM (SOCBASEERR+1) /* Not owner */ -#define SOCESRCH (SOCBASEERR+3) /* No such process */ -#define SOCEINTR (SOCBASEERR+4) /* Interrupted system call */ -#define SOCENXIO (SOCBASEERR+6) /* No such device or address */ -#define SOCEBADF (SOCBASEERR+9) /* Bad file number */ -#define SOCEACCES (SOCBASEERR+13) /* Permission denied */ -#define SOCEFAULT (SOCBASEERR+14) /* Bad address */ -#define SOCEINVAL (SOCBASEERR+22) /* Invalid argument */ -#define SOCEMFILE (SOCBASEERR+24) /* Too many open files */ -#define SOCEPIPE (SOCBASEERR+32) /* Broken pipe */ -#define SOCEOS2ERR (SOCBASEERR+100) /* OS/2 Error */ -#define SOCEWOULDBLOCK (SOCBASEERR+35) /* Operation would block */ -#define SOCEINPROGRESS (SOCBASEERR+36) /* Operation now in progress */ -#define SOCEALREADY (SOCBASEERR+37) /* Operation already in progress */ -#define SOCENOTSOCK (SOCBASEERR+38) /* Socket operation on non-socket */ -#define SOCEDESTADDRREQ (SOCBASEERR+39) /* Destination address required */ -#define SOCEMSGSIZE (SOCBASEERR+40) /* Message too long */ -#define SOCEPROTOTYPE (SOCBASEERR+41) /* Protocol wrong type for socket */ -#define SOCENOPROTOOPT (SOCBASEERR+42) /* Protocol not available */ -#define SOCEPROTONOSUPPORT (SOCBASEERR+43) /* Protocol not supported */ -#define SOCESOCKTNOSUPPORT (SOCBASEERR+44) /* Socket type not supported */ -#define SOCEOPNOTSUPP (SOCBASEERR+45) /* Operation not supported on socket */ -#define SOCEPFNOSUPPORT (SOCBASEERR+46) /* Protocol family not supported */ -#define SOCEAFNOSUPPORT (SOCBASEERR+47) /* Address family not supported by protocol family */ -#define SOCEADDRINUSE (SOCBASEERR+48) /* Address already in use */ -#define SOCEADDRNOTAVAIL (SOCBASEERR+49) /* Can't assign requested address */ -#define SOCENETDOWN (SOCBASEERR+50) /* Network is down */ -#define SOCENETUNREACH (SOCBASEERR+51) /* Network is unreachable */ -#define SOCENETRESET (SOCBASEERR+52) /* Network dropped connection on reset */ -#define SOCECONNABORTED (SOCBASEERR+53) /* Software caused connection abort */ -#define SOCECONNRESET (SOCBASEERR+54) /* Connection reset by peer */ -#define SOCENOBUFS (SOCBASEERR+55) /* No buffer space available */ -#define SOCEISCONN (SOCBASEERR+56) /* Socket is already connected */ -#define SOCENOTCONN (SOCBASEERR+57) /* Socket is not connected */ -#define SOCESHUTDOWN (SOCBASEERR+58) /* Can't send after socket shutdown */ -#define SOCETOOMANYREFS (SOCBASEERR+59) /* Too many references: can't splice */ -#define SOCETIMEDOUT (SOCBASEERR+60) /* Connection timed out */ -#define SOCECONNREFUSED (SOCBASEERR+61) /* Connection refused */ -#define SOCELOOP (SOCBASEERR+62) /* Too many levels of symbolic links */ -#define SOCENAMETOOLONG (SOCBASEERR+63) /* File name too long */ -#define SOCEHOSTDOWN (SOCBASEERR+64) /* Host is down */ -#define SOCEHOSTUNREACH (SOCBASEERR+65) /* No route to host */ -#define SOCENOTEMPTY (SOCBASEERR+66) /* Directory not empty */ diff --git a/include/arch/os2/threadproc.h b/include/arch/os2/threadproc.h deleted file mode 100644 index cfcca8d621c..00000000000 --- a/include/arch/os2/threadproc.h +++ /dev/null @@ -1,108 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#include "apr_thread_proc.h" -#include "apr_file_io.h" - -#ifndef THREAD_PROC_H -#define THREAD_PROC_H - -#define APR_THREADATTR_DETACHED 1 - -#define SHELL_PATH "cmd.exe" -#define APR_THREAD_STACKSIZE 65536 - -struct ap_threadattr_t { - ap_pool_t *cntxt; - unsigned long attr; -}; - -struct ap_thread_t { - ap_pool_t *cntxt; - struct ap_threadattr_t *attr; - unsigned long tid; - ap_thread_start_t func; - void *data; - void *rv; -}; - -struct ap_threadkey_t { - ap_pool_t *cntxt; - unsigned long *key; -}; - -struct ap_procattr_t { - ap_pool_t *cntxt; - ap_file_t *parent_in; - ap_file_t *child_in; - ap_file_t *parent_out; - ap_file_t *child_out; - ap_file_t *parent_err; - ap_file_t *child_err; - char *currdir; - ap_int32_t cmdtype; - ap_int32_t detached; -}; - -struct ap_proc_t { - ap_pool_t *cntxt; - pid_t pid; - struct ap_procattr_t *attr; - int running; -}; - -typedef void (*os2_thread_start_t)(void *); - -#endif /* ! THREAD_PROC_H */ - diff --git a/include/arch/os390/apr_arch_dso.h b/include/arch/os390/apr_arch_dso.h new file mode 100644 index 00000000000..4263297b407 --- /dev/null +++ b/include/arch/os390/apr_arch_dso.h @@ -0,0 +1,39 @@ +/* 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. + */ + +#ifndef DSO_H +#define DSO_H + +#include "apr_private.h" +#include "apr_general.h" +#include "apr_pools.h" +#include "apr_dso.h" +#include "apr.h" + +#if APR_HAS_DSO + +#include <dll.h> + +struct apr_dso_handle_t { + dllhandle *handle; /* Handle to the DSO loaded */ + int failing_errno; /* Don't save the buffer returned by + strerror(); it gets reused */ + apr_pool_t *pool; +}; + +#endif + +#endif diff --git a/include/arch/unix/apr_arch_atomic.h b/include/arch/unix/apr_arch_atomic.h new file mode 100644 index 00000000000..f8019060e50 --- /dev/null +++ b/include/arch/unix/apr_arch_atomic.h @@ -0,0 +1,45 @@ +/* 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. + */ + +#ifndef ATOMIC_H +#define ATOMIC_H + +#include "apr.h" +#include "apr_private.h" +#include "apr_atomic.h" +#include "apr_thread_mutex.h" + +#if defined(USE_ATOMICS_GENERIC) +/* noop */ +#elif defined(__GNUC__) && defined(__STRICT_ANSI__) +/* force use of generic atomics if building e.g. with -std=c89, which + * doesn't allow inline asm */ +# define USE_ATOMICS_GENERIC +#elif HAVE_ATOMIC_BUILTINS +# define USE_ATOMICS_BUILTINS +#elif defined(SOLARIS2) && SOLARIS2 >= 10 +# define USE_ATOMICS_SOLARIS +#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) +# define USE_ATOMICS_IA32 +#elif defined(__GNUC__) && (defined(__PPC__) || defined(__ppc__)) +# define USE_ATOMICS_PPC +#elif defined(__GNUC__) && (defined(__s390__) || defined(__s390x__)) +# define USE_ATOMICS_S390 +#else +# define USE_ATOMICS_GENERIC +#endif + +#endif /* ATOMIC_H */ diff --git a/include/arch/unix/apr_arch_dso.h b/include/arch/unix/apr_arch_dso.h new file mode 100644 index 00000000000..d82182d48b8 --- /dev/null +++ b/include/arch/unix/apr_arch_dso.h @@ -0,0 +1,63 @@ +/* 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. + */ + +#ifndef DSO_H +#define DSO_H + +#include "apr_private.h" +#include "apr_general.h" +#include "apr_pools.h" +#include "apr_dso.h" +#include "apr.h" + +#if APR_HAS_DSO + +#ifdef HAVE_MACH_O_DYLD_H +#include <mach-o/dyld.h> +#endif + +#ifdef HAVE_DLFCN_H +#include <dlfcn.h> +#endif + +#ifdef HAVE_DL_H +#include <dl.h> +#endif + +#ifndef RTLD_NOW +#define RTLD_NOW 1 +#endif + +#ifndef RTLD_GLOBAL +#define RTLD_GLOBAL 0 +#endif + +#if (defined(__DragonFly__) ||\ + defined(__FreeBSD__) ||\ + defined(__OpenBSD__) ||\ + defined(__NetBSD__) ) && !defined(__ELF__) +#define DLSYM_NEEDS_UNDERSCORE +#endif + +struct apr_dso_handle_t { + apr_pool_t *pool; + void *handle; + const char *errormsg; +}; + +#endif + +#endif diff --git a/include/arch/unix/apr_arch_file_io.h b/include/arch/unix/apr_arch_file_io.h new file mode 100644 index 00000000000..5847cdc2c79 --- /dev/null +++ b/include/arch/unix/apr_arch_file_io.h @@ -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. + */ + +#ifndef FILE_IO_H +#define FILE_IO_H + +#include "apr.h" +#include "apr_private.h" +#include "apr_general.h" +#include "apr_tables.h" +#include "apr_file_io.h" +#include "apr_file_info.h" +#include "apr_errno.h" +#include "apr_lib.h" +#include "apr_thread_mutex.h" +#ifndef WAITIO_USES_POLL +#include "apr_poll.h" +#endif +#include "apr_time.h" + + +/* System headers the file I/O library needs */ +#if APR_HAVE_FCNTL_H +#include <fcntl.h> +#endif +#if APR_HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#if APR_HAVE_ERRNO_H +#include <errno.h> +#endif +#if APR_HAVE_STRING_H +#include <string.h> +#endif +#if APR_HAVE_STRINGS_H +#include <strings.h> +#endif +#if APR_HAVE_DIRENT_H +#include <dirent.h> +#endif +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif +#if APR_HAVE_UNISTD_H +#include <unistd.h> +#endif +#if APR_HAVE_STDIO_H +#include <stdio.h> +#endif +#if APR_HAVE_STDLIB_H +#include <stdlib.h> +#endif +#if APR_HAVE_SYS_UIO_H +#include <sys/uio.h> +#endif +#if APR_HAVE_SYS_TIME_H +#include <sys/time.h> +#endif +#ifdef BEOS +#include <kernel/OS.h> +#endif +/* Hunting down DEV_BSIZE if not from dirent.h, sys/stat.h etc */ +#ifdef HAVE_SYS_PARAM_H +#include <sys/param.h> +#endif + +#if BEOS_BONE +# ifndef BONE7 + /* prior to BONE/7 fd_set & select were defined in sys/socket.h */ +# include <sys/socket.h> +# else + /* Be moved the fd_set stuff and also the FIONBIO definition... */ +# include <sys/ioctl.h> +# endif +#endif +/* End System headers */ + +#define APR_FILE_DEFAULT_BUFSIZE 4096 +/* For backwards-compat */ +#define APR_FILE_BUFSIZE APR_FILE_DEFAULT_BUFSIZE + +typedef struct apr_rotating_info_t { + apr_finfo_t finfo; + apr_interval_time_t timeout; + apr_time_t lastcheck; + int oflags; + int manual; + apr_fileperms_t perm; +} apr_rotating_info_t; + +struct apr_file_t { + apr_pool_t *pool; + int filedes; + char *fname; + apr_int32_t flags; + int eof_hit; + int is_pipe; + apr_interval_time_t timeout; + int buffered; + enum {BLK_UNKNOWN, BLK_OFF, BLK_ON } blocking; + int ungetchar; /* Last char provided by an unget op. (-1 = no char)*/ +#ifndef WAITIO_USES_POLL + /* if there is a timeout set, then this pollset is used */ + apr_pollset_t *pollset; +#endif + /* Stuff for buffered mode */ + char *buffer; + apr_size_t bufpos; /* Read/Write position in buffer */ + apr_size_t bufsize; /* The size of the buffer */ + unsigned long dataRead; /* amount of valid data read into buffer */ + int direction; /* buffer being used for 0 = read, 1 = write */ + apr_off_t filePtr; /* position in file of handle */ +#if APR_HAS_THREADS + struct apr_thread_mutex_t *thlock; +#endif + apr_rotating_info_t *rotating; +}; + +#if APR_HAS_THREADS +#define file_lock(f) do { \ + if ((f)->thlock) \ + apr_thread_mutex_lock((f)->thlock); \ + } while (0) +#define file_unlock(f) do { \ + if ((f)->thlock) \ + apr_thread_mutex_unlock((f)->thlock); \ + } while (0) +#else +#define file_lock(f) do {} while (0) +#define file_unlock(f) do {} while (0) +#endif + +#if APR_HAS_LARGE_FILES && defined(_LARGEFILE64_SOURCE) +#define stat(f,b) stat64(f,b) +#define lstat(f,b) lstat64(f,b) +#define fstat(f,b) fstat64(f,b) +#define lseek(f,o,w) lseek64(f,o,w) +#define ftruncate(f,l) ftruncate64(f,l) +typedef struct stat64 struct_stat; +#else +typedef struct stat struct_stat; +#endif + +/* readdir64_r is only used in specific cases: */ +#if APR_HAS_THREADS && defined(_POSIX_THREAD_SAFE_FUNCTIONS) \ + && !defined(READDIR_IS_THREAD_SAFE) && defined(HAVE_READDIR64_R) +#define APR_USE_READDIR64_R +#endif + +struct apr_dir_t { + apr_pool_t *pool; + char *dirname; + DIR *dirstruct; +#ifdef APR_USE_READDIR64_R + struct dirent64 *entry; +#else + struct dirent *entry; +#endif +}; + +apr_status_t apr_unix_file_cleanup(void *); +apr_status_t apr_unix_child_file_cleanup(void *); + +mode_t apr_unix_perms2mode(apr_fileperms_t perms); +apr_fileperms_t apr_unix_mode2perms(mode_t mode); + +apr_status_t apr_file_flush_locked(apr_file_t *thefile); +apr_status_t apr_file_info_get_locked(apr_finfo_t *finfo, apr_int32_t wanted, + apr_file_t *thefile); + + +#endif /* ! FILE_IO_H */ + diff --git a/include/arch/unix/apr_arch_global_mutex.h b/include/arch/unix/apr_arch_global_mutex.h new file mode 100644 index 00000000000..3add9ecfa75 --- /dev/null +++ b/include/arch/unix/apr_arch_global_mutex.h @@ -0,0 +1,37 @@ +/* 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. + */ + +#ifndef GLOBAL_MUTEX_H +#define GLOBAL_MUTEX_H + +#include "apr.h" +#include "apr_private.h" +#include "apr_general.h" +#include "apr_lib.h" +#include "apr_global_mutex.h" +#include "apr_arch_proc_mutex.h" +#include "apr_arch_thread_mutex.h" + +struct apr_global_mutex_t { + apr_pool_t *pool; + apr_proc_mutex_t *proc_mutex; +#if APR_HAS_THREADS + apr_thread_mutex_t *thread_mutex; +#endif /* APR_HAS_THREADS */ +}; + +#endif /* GLOBAL_MUTEX_H */ + diff --git a/include/arch/unix/apr_arch_inherit.h b/include/arch/unix/apr_arch_inherit.h new file mode 100644 index 00000000000..21543c1e1c3 --- /dev/null +++ b/include/arch/unix/apr_arch_inherit.h @@ -0,0 +1,64 @@ +/* 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. + */ + +#ifndef INHERIT_H +#define INHERIT_H + +#include "apr_inherit.h" + +#define APR_INHERIT (1 << 24) /* Must not conflict with other bits */ + +#define APR_IMPLEMENT_INHERIT_SET(name, flag, pool, cleanup) \ +apr_status_t apr_##name##_inherit_set(apr_##name##_t *the##name) \ +{ \ + if (the##name->flag & APR_FOPEN_NOCLEANUP) \ + return APR_EINVAL; \ + if (!(the##name->flag & APR_INHERIT)) { \ + int flags = fcntl(the##name->name##des, F_GETFD); \ + if (flags == -1) \ + return errno; \ + flags &= ~(FD_CLOEXEC); \ + if (fcntl(the##name->name##des, F_SETFD, flags) == -1) \ + return errno; \ + the##name->flag |= APR_INHERIT; \ + apr_pool_child_cleanup_set(the##name->pool, \ + (void *)the##name, \ + cleanup, apr_pool_cleanup_null); \ + } \ + return APR_SUCCESS; \ +} + +#define APR_IMPLEMENT_INHERIT_UNSET(name, flag, pool, cleanup) \ +apr_status_t apr_##name##_inherit_unset(apr_##name##_t *the##name) \ +{ \ + if (the##name->flag & APR_FOPEN_NOCLEANUP) \ + return APR_EINVAL; \ + if (the##name->flag & APR_INHERIT) { \ + int flags; \ + if ((flags = fcntl(the##name->name##des, F_GETFD)) == -1) \ + return errno; \ + flags |= FD_CLOEXEC; \ + if (fcntl(the##name->name##des, F_SETFD, flags) == -1) \ + return errno; \ + the##name->flag &= ~APR_INHERIT; \ + apr_pool_child_cleanup_set(the##name->pool, \ + (void *)the##name, \ + cleanup, cleanup); \ + } \ + return APR_SUCCESS; \ +} + +#endif /* ! INHERIT_H */ diff --git a/include/arch/unix/apr_arch_internal_time.h b/include/arch/unix/apr_arch_internal_time.h new file mode 100644 index 00000000000..6e12c67439a --- /dev/null +++ b/include/arch/unix/apr_arch_internal_time.h @@ -0,0 +1,24 @@ +/* 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. + */ + +#ifndef TIME_INTERNAL_H +#define TIME_INTERNAL_H + +#include "apr.h" + +void apr_unix_setup_time(void); + +#endif /* TIME_INTERNAL_H */ diff --git a/include/arch/unix/apr_arch_misc.h b/include/arch/unix/apr_arch_misc.h new file mode 100644 index 00000000000..1e8ab0b7541 --- /dev/null +++ b/include/arch/unix/apr_arch_misc.h @@ -0,0 +1,66 @@ +/* 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. + */ + +#ifndef MISC_H +#define MISC_H + +#include "apr.h" +#include "apr_portable.h" +#include "apr_private.h" +#include "apr_general.h" +#include "apr_pools.h" +#include "apr_getopt.h" +#include "apr_thread_proc.h" +#include "apr_file_io.h" +#include "apr_errno.h" +#include "apr_getopt.h" + +#if APR_HAVE_STDIO_H +#include <stdio.h> +#endif +#if APR_HAVE_SIGNAL_H +#include <signal.h> +#endif +#if APR_HAVE_PTHREAD_H +#include <pthread.h> +#endif + +#if APR_HAVE_STDLIB_H +#include <stdlib.h> +#endif +#if APR_HAVE_STRING_H +#include <string.h> +#endif + +#ifdef BEOS +#include <kernel/OS.h> +#endif + +struct apr_other_child_rec_t { + apr_pool_t *p; + struct apr_other_child_rec_t *next; + apr_proc_t *proc; + void (*maintenance) (int, void *, int); + void *data; +}; + +#if defined(WIN32) || defined(NETWARE) +#define WSAHighByte 2 +#define WSALowByte 0 +#endif + +#endif /* ! MISC_H */ + diff --git a/include/arch/unix/apr_arch_networkio.h b/include/arch/unix/apr_arch_networkio.h new file mode 100644 index 00000000000..5f3189d9666 --- /dev/null +++ b/include/arch/unix/apr_arch_networkio.h @@ -0,0 +1,145 @@ +/* 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. + */ + +#ifndef NETWORK_IO_H +#define NETWORK_IO_H + +#include "apr.h" +#include "apr_private.h" +#include "apr_network_io.h" +#include "apr_errno.h" +#include "apr_general.h" +#include "apr_lib.h" +#ifndef WAITIO_USES_POLL +#include "apr_poll.h" +#endif + +/* System headers the network I/O library needs */ +#if APR_HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#if APR_HAVE_SYS_UIO_H +#include <sys/uio.h> +#endif +#ifdef HAVE_SYS_SELECT_H +#include <sys/select.h> +#endif +#if APR_HAVE_ERRNO_H +#include <errno.h> +#endif +#if APR_HAVE_SYS_TIME_H +#include <sys/time.h> +#endif +#if APR_HAVE_UNISTD_H +#include <unistd.h> +#endif +#if APR_HAVE_STRING_H +#include <string.h> +#endif +#if APR_HAVE_NETINET_TCP_H +#include <netinet/tcp.h> +#endif +#if APR_HAVE_NETINET_SCTP_UIO_H +#include <netinet/sctp_uio.h> +#endif +#if APR_HAVE_NETINET_SCTP_H +#include <netinet/sctp.h> +#endif +#if APR_HAVE_NETINET_IN_H +#include <netinet/in.h> +#endif +#if APR_HAVE_ARPA_INET_H +#include <arpa/inet.h> +#endif +#if APR_HAVE_SYS_SOCKET_H +#include <sys/socket.h> +#endif +#if APR_HAVE_SYS_SOCKIO_H +#include <sys/sockio.h> +#endif +#if APR_HAVE_NETDB_H +#include <netdb.h> +#endif +#if APR_HAVE_FCNTL_H +#include <fcntl.h> +#endif +#if APR_HAVE_SYS_SENDFILE_H +#include <sys/sendfile.h> +#endif +#if APR_HAVE_SYS_IOCTL_H +#include <sys/ioctl.h> +#endif +/* End System Headers */ + +#ifndef HAVE_POLLIN +#define POLLIN 1 +#define POLLPRI 2 +#define POLLOUT 4 +#define POLLERR 8 +#define POLLHUP 16 +#define POLLNVAL 32 +#endif + +typedef struct sock_userdata_t sock_userdata_t; +struct sock_userdata_t { + sock_userdata_t *next; + const char *key; + void *data; +}; + +struct apr_socket_t { + apr_pool_t *pool; + int socketdes; + int type; + int protocol; + apr_sockaddr_t *local_addr; + apr_sockaddr_t *remote_addr; + apr_interval_time_t timeout; +#ifndef HAVE_POLL + int connected; +#endif +#if APR_HAVE_SOCKADDR_UN + int bound; +#endif + int local_port_unknown; + int local_interface_unknown; + int remote_addr_unknown; + apr_int32_t options; + apr_int32_t inherit; + sock_userdata_t *userdata; +#ifndef WAITIO_USES_POLL + /* if there is a timeout set, then this pollset is used */ + apr_pollset_t *pollset; +#endif +}; + +const char *apr_inet_ntop(int af, const void *src, char *dst, apr_size_t size); +int apr_inet_pton(int af, const char *src, void *dst); +void apr_sockaddr_vars_set(apr_sockaddr_t *, int, apr_port_t); + +#define apr_is_option_set(skt, option) \ + (((skt)->options & (option)) == (option)) + +#define apr_set_option(skt, option, on) \ + do { \ + if (on) \ + (skt)->options |= (option); \ + else \ + (skt)->options &= ~(option); \ + } while (0) + +#endif /* ! NETWORK_IO_H */ + diff --git a/include/arch/unix/apr_arch_poll_private.h b/include/arch/unix/apr_arch_poll_private.h new file mode 100644 index 00000000000..ff813123134 --- /dev/null +++ b/include/arch/unix/apr_arch_poll_private.h @@ -0,0 +1,189 @@ +/* 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. + */ + +#ifndef APR_ARCH_POLL_PRIVATE_H +#define APR_ARCH_POLL_PRIVATE_H + +#if HAVE_POLL_H +#include <poll.h> +#endif + +#if HAVE_SYS_POLL_H +#include <sys/poll.h> +#endif + +#ifdef HAVE_PORT_CREATE +#include <port.h> +#include <sys/port_impl.h> +#endif + +#ifdef HAVE_KQUEUE +#include <sys/types.h> +#include <sys/event.h> +#include <sys/time.h> +#endif + +#ifdef HAVE_EPOLL +#include <sys/epoll.h> +#endif + +#ifdef NETWARE +#define HAS_SOCKETS(dt) (dt == APR_POLL_SOCKET) ? 1 : 0 +#define HAS_PIPES(dt) (dt == APR_POLL_FILE) ? 1 : 0 +#endif + +#if defined(HAVE_AIO_H) && defined(HAVE_AIO_MSGQ) +#define _AIO_OS390 /* enable a bunch of z/OS aio.h definitions */ +#include <aio.h> /* aiocb */ +#endif + +/* Choose the best method platform specific to use in apr_pollset */ +#ifdef HAVE_KQUEUE +#define POLLSET_USES_KQUEUE +#define POLLSET_DEFAULT_METHOD APR_POLLSET_KQUEUE +#elif defined(HAVE_PORT_CREATE) +#define POLLSET_USES_PORT +#define POLLSET_DEFAULT_METHOD APR_POLLSET_PORT +#elif defined(HAVE_EPOLL) +#define POLLSET_USES_EPOLL +#define POLLSET_DEFAULT_METHOD APR_POLLSET_EPOLL +#elif defined(HAVE_AIO_MSGQ) +#define POLLSET_USES_AIO_MSGQ +#define POLLSET_DEFAULT_METHOD APR_POLLSET_AIO_MSGQ +#elif defined(HAVE_POLL) +#define POLLSET_USES_POLL +#define POLLSET_DEFAULT_METHOD APR_POLLSET_POLL +#else +#define POLLSET_USES_SELECT +#define POLLSET_DEFAULT_METHOD APR_POLLSET_SELECT +#endif + +#ifdef WIN32 +#define POLL_USES_SELECT +#undef POLLSET_DEFAULT_METHOD +#define POLLSET_DEFAULT_METHOD APR_POLLSET_SELECT +#else +#ifdef HAVE_POLL +#define POLL_USES_POLL +#else +#define POLL_USES_SELECT +#endif +#endif + +#if defined(POLLSET_USES_KQUEUE) || defined(POLLSET_USES_EPOLL) || defined(POLLSET_USES_PORT) || defined(POLLSET_USES_AIO_MSGQ) + +#include "apr_ring.h" + +#if APR_HAS_THREADS +#include "apr_thread_mutex.h" +#define pollset_lock_rings() \ + if (pollset->flags & APR_POLLSET_THREADSAFE) \ + apr_thread_mutex_lock(pollset->p->ring_lock); +#define pollset_unlock_rings() \ + if (pollset->flags & APR_POLLSET_THREADSAFE) \ + apr_thread_mutex_unlock(pollset->p->ring_lock); +#else +#define pollset_lock_rings() +#define pollset_unlock_rings() +#endif + +typedef struct pfd_elem_t pfd_elem_t; + +struct pfd_elem_t { + APR_RING_ENTRY(pfd_elem_t) link; + apr_pollfd_t pfd; +#ifdef HAVE_PORT_CREATE + int on_query_ring; +#endif +}; + +#endif + +typedef struct apr_pollset_private_t apr_pollset_private_t; +typedef struct apr_pollset_provider_t apr_pollset_provider_t; +typedef struct apr_pollcb_provider_t apr_pollcb_provider_t; + +struct apr_pollset_t +{ + apr_pool_t *pool; + apr_uint32_t nelts; + apr_uint32_t nalloc; + apr_uint32_t flags; + /* Pipe descriptors used for wakeup */ + apr_file_t *wakeup_pipe[2]; + apr_pollfd_t wakeup_pfd; + apr_pollset_private_t *p; + const apr_pollset_provider_t *provider; +}; + +typedef union { +#if defined(HAVE_EPOLL) + struct epoll_event *epoll; +#endif +#if defined(HAVE_PORT_CREATE) + port_event_t *port; +#endif +#if defined(HAVE_KQUEUE) + struct kevent *ke; +#endif +#if defined(HAVE_POLL) + struct pollfd *ps; +#endif + void *undef; +} apr_pollcb_pset; + +struct apr_pollcb_t { + apr_pool_t *pool; + apr_uint32_t nelts; + apr_uint32_t nalloc; + apr_uint32_t flags; + /* Pipe descriptors used for wakeup */ + apr_file_t *wakeup_pipe[2]; + apr_pollfd_t wakeup_pfd; + int fd; + apr_pollcb_pset pollset; + apr_pollfd_t **copyset; + const apr_pollcb_provider_t *provider; +}; + +struct apr_pollset_provider_t { + apr_status_t (*create)(apr_pollset_t *, apr_uint32_t, apr_pool_t *, apr_uint32_t); + apr_status_t (*add)(apr_pollset_t *, const apr_pollfd_t *); + apr_status_t (*remove)(apr_pollset_t *, const apr_pollfd_t *); + apr_status_t (*poll)(apr_pollset_t *, apr_interval_time_t, apr_int32_t *, const apr_pollfd_t **); + apr_status_t (*cleanup)(apr_pollset_t *); + const char *name; +}; + +struct apr_pollcb_provider_t { + apr_status_t (*create)(apr_pollcb_t *, apr_uint32_t, apr_pool_t *, apr_uint32_t); + apr_status_t (*add)(apr_pollcb_t *, apr_pollfd_t *); + apr_status_t (*remove)(apr_pollcb_t *, apr_pollfd_t *); + apr_status_t (*poll)(apr_pollcb_t *, apr_interval_time_t, apr_pollcb_cb_t, void *); + apr_status_t (*cleanup)(apr_pollcb_t *); + const char *name; +}; + +/* + * Private functions used for the implementation of both apr_pollcb_* and + * apr_pollset_* + */ +apr_status_t apr_poll_create_wakeup_pipe(apr_pool_t *pool, apr_pollfd_t *pfd, + apr_file_t **wakeup_pipe); +apr_status_t apr_poll_close_wakeup_pipe(apr_file_t **wakeup_pipe); +void apr_poll_drain_wakeup_pipe(apr_file_t **wakeup_pipe); + +#endif /* APR_ARCH_POLL_PRIVATE_H */ diff --git a/include/arch/unix/apr_arch_proc_mutex.h b/include/arch/unix/apr_arch_proc_mutex.h new file mode 100644 index 00000000000..cfa0049f754 --- /dev/null +++ b/include/arch/unix/apr_arch_proc_mutex.h @@ -0,0 +1,121 @@ +/* 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. + */ + +#ifndef PROC_MUTEX_H +#define PROC_MUTEX_H + +#include "apr.h" +#include "apr_private.h" +#include "apr_general.h" +#include "apr_lib.h" +#include "apr_proc_mutex.h" +#include "apr_pools.h" +#include "apr_portable.h" +#include "apr_file_io.h" +#include "apr_arch_file_io.h" +#include "apr_time.h" + +/* System headers required by Locks library */ +#if APR_HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#if APR_HAVE_STDIO_H +#include <stdio.h> +#endif +#if APR_HAVE_FCNTL_H +#include <fcntl.h> +#endif + +#ifdef HAVE_SYS_IPC_H +#include <sys/ipc.h> +#endif +#ifdef HAVE_SYS_SEM_H +#include <sys/sem.h> +#endif +#ifdef HAVE_SYS_FILE_H +#include <sys/file.h> +#endif +#if APR_HAVE_STDLIB_H +#include <stdlib.h> +#endif +#if APR_HAVE_UNISTD_H +#include <unistd.h> +#endif +#if APR_HAVE_STRING_H +#include <string.h> +#endif +#ifdef HAVE_SYS_MMAN_H +#include <sys/mman.h> +#endif +#if APR_HAVE_PTHREAD_H +#include <pthread.h> +#endif +/* End System Headers */ + +struct apr_proc_mutex_unix_lock_methods_t { + unsigned int flags; + apr_status_t (*create)(apr_proc_mutex_t *, const char *); + apr_status_t (*acquire)(apr_proc_mutex_t *); + apr_status_t (*tryacquire)(apr_proc_mutex_t *); + apr_status_t (*timedacquire)(apr_proc_mutex_t *, apr_interval_time_t); + apr_status_t (*release)(apr_proc_mutex_t *); + apr_status_t (*cleanup)(void *); + apr_status_t (*child_init)(apr_proc_mutex_t **, apr_pool_t *, const char *); + apr_status_t (*perms_set)(apr_proc_mutex_t *, apr_fileperms_t, apr_uid_t, apr_gid_t); + apr_lockmech_e mech; + const char *name; +}; +typedef struct apr_proc_mutex_unix_lock_methods_t apr_proc_mutex_unix_lock_methods_t; + +/* bit values for flags field in apr_unix_lock_methods_t */ +#define APR_PROCESS_LOCK_MECH_IS_GLOBAL 1 + +#if !APR_HAVE_UNION_SEMUN && defined(APR_HAS_SYSVSEM_SERIALIZE) +union semun { + int val; + struct semid_ds *buf; + unsigned short *array; +}; +#endif + +struct apr_proc_mutex_t { + apr_pool_t *pool; + const apr_proc_mutex_unix_lock_methods_t *meth; + int curr_locked; + char *fname; + + apr_os_proc_mutex_t os; /* Native mutex holder. */ + +#if APR_HAS_FCNTL_SERIALIZE || APR_HAS_FLOCK_SERIALIZE + apr_file_t *interproc; /* For apr_file_ calls on native fd. */ + int interproc_closing; /* whether the native fd is opened/closed with + * 'interproc' or apr_os_file_put()ed (hence + * needing an an explicit close for consistency + * with other methods). + */ +#endif +#if APR_HAS_PROC_PTHREAD_SERIALIZE + int pthread_refcounting; /* Whether the native mutex is refcounted or + * apr_os_proc_mutex_put()ed, which makes + * refcounting impossible/undesirable. + */ +#endif +}; + +void apr_proc_mutex_unix_setup_lock(void); + +#endif /* PROC_MUTEX_H */ + diff --git a/include/arch/unix/apr_arch_shm.h b/include/arch/unix/apr_arch_shm.h new file mode 100644 index 00000000000..e9d25cadb40 --- /dev/null +++ b/include/arch/unix/apr_arch_shm.h @@ -0,0 +1,74 @@ +/* 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. + */ + +#ifndef SHM_H +#define SHM_H + +#include "apr.h" +#include "apr_private.h" +#include "apr_general.h" +#include "apr_lib.h" +#include "apr_shm.h" +#include "apr_pools.h" +#include "apr_file_io.h" +#include "apr_network_io.h" +#include "apr_portable.h" + +#if APR_HAVE_UNISTD_H +#include <unistd.h> +#endif +#ifdef HAVE_SYS_MMAN_H +#include <sys/mman.h> +#endif +#ifdef HAVE_SYS_IPC_H +#include <sys/ipc.h> +#endif +#ifdef HAVE_SYS_MUTEX_H +#include <sys/mutex.h> +#endif +#ifdef HAVE_SYS_SHM_H +#include <sys/shm.h> +#endif +#if !defined(SHM_R) +#define SHM_R 0400 +#endif +#if !defined(SHM_W) +#define SHM_W 0200 +#endif +#ifdef HAVE_SYS_FILE_H +#include <sys/file.h> +#endif + +/* Not all systems seem to have MAP_FAILED defined, but it should always + * just be (void *)-1. */ +#ifndef MAP_FAILED +#define MAP_FAILED ((void *)-1) +#endif + +struct apr_shm_t { + apr_pool_t *pool; + void *base; /* base real address */ + void *usable; /* base usable address */ + apr_size_t reqsize; /* requested segment size */ + apr_size_t realsize; /* actual segment size */ + const char *filename; /* NULL if anonymous */ +#if APR_USE_SHMEM_SHMGET || APR_USE_SHMEM_SHMGET_ANON + int shmid; /* shmem ID returned from shmget() */ + key_t shmkey; /* shmem key IPC_ANON or returned from ftok() */ +#endif +}; + +#endif /* SHM_H */ diff --git a/include/arch/unix/apr_arch_thread_cond.h b/include/arch/unix/apr_arch_thread_cond.h new file mode 100644 index 00000000000..5c2b51d1f4b --- /dev/null +++ b/include/arch/unix/apr_arch_thread_cond.h @@ -0,0 +1,42 @@ +/* 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. + */ + +#ifndef THREAD_COND_H +#define THREAD_COND_H + +#include "apr.h" +#include "apr_private.h" +#include "apr_general.h" +#include "apr_lib.h" +#include "apr_thread_mutex.h" +#include "apr_thread_cond.h" +#include "apr_pools.h" + +#if APR_HAVE_PTHREAD_H +#include <pthread.h> +#endif + +/* XXX: Should we have a better autoconf search, something like + * APR_HAS_PTHREAD_COND? -aaron */ +#if APR_HAS_THREADS +struct apr_thread_cond_t { + apr_pool_t *pool; + pthread_cond_t cond; +}; +#endif + +#endif /* THREAD_COND_H */ + diff --git a/include/arch/unix/apr_arch_thread_mutex.h b/include/arch/unix/apr_arch_thread_mutex.h new file mode 100644 index 00000000000..4fe46c3b427 --- /dev/null +++ b/include/arch/unix/apr_arch_thread_mutex.h @@ -0,0 +1,42 @@ +/* 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. + */ + +#ifndef THREAD_MUTEX_H +#define THREAD_MUTEX_H + +#include "apr.h" +#include "apr_private.h" +#include "apr_general.h" +#include "apr_thread_mutex.h" +#include "apr_thread_cond.h" +#include "apr_portable.h" +#include "apr_atomic.h" + +#if APR_HAVE_PTHREAD_H +#include <pthread.h> +#endif + +#if APR_HAS_THREADS +struct apr_thread_mutex_t { + apr_pool_t *pool; + pthread_mutex_t mutex; + apr_thread_cond_t *cond; + int locked, num_waiters; +}; +#endif + +#endif /* THREAD_MUTEX_H */ + diff --git a/include/arch/unix/apr_arch_thread_rwlock.h b/include/arch/unix/apr_arch_thread_rwlock.h new file mode 100644 index 00000000000..2cb43af6a35 --- /dev/null +++ b/include/arch/unix/apr_arch_thread_rwlock.h @@ -0,0 +1,49 @@ +/* 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. + */ + +#ifndef THREAD_RWLOCK_H +#define THREAD_RWLOCK_H + +#include "apr.h" +#include "apr_private.h" +#include "apr_general.h" +#include "apr_thread_rwlock.h" +#include "apr_pools.h" + +#if APR_HAVE_PTHREAD_H +/* this gives us pthread_rwlock_t */ +#include <pthread.h> +#endif + +#if APR_HAS_THREADS +#ifdef HAVE_PTHREAD_RWLOCKS + +struct apr_thread_rwlock_t { + apr_pool_t *pool; + pthread_rwlock_t rwlock; +}; + +#else + +struct apr_thread_rwlock_t { + apr_pool_t *pool; +}; +#endif + +#endif + +#endif /* THREAD_RWLOCK_H */ + diff --git a/include/arch/unix/apr_arch_threadproc.h b/include/arch/unix/apr_arch_threadproc.h new file mode 100644 index 00000000000..7a3b3c0925b --- /dev/null +++ b/include/arch/unix/apr_arch_threadproc.h @@ -0,0 +1,119 @@ +/* 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_thread_proc.h" +#include "apr_file_io.h" +#include "apr_arch_file_io.h" +#include "apr_perms_set.h" + +/* System headers required for thread/process library */ +#if APR_HAVE_PTHREAD_H +#include <pthread.h> +#endif +#ifdef HAVE_SYS_RESOURCE_H +#include <sys/resource.h> +#endif +#if APR_HAVE_SIGNAL_H +#include <signal.h> +#endif +#if APR_HAVE_STRING_H +#include <string.h> +#endif +#if APR_HAVE_SYS_WAIT_H +#include <sys/wait.h> +#endif +#if APR_HAVE_STRING_H +#include <string.h> +#endif +#ifdef HAVE_SCHED_H +#include <sched.h> +#endif +/* End System Headers */ + + +#ifndef THREAD_PROC_H +#define THREAD_PROC_H + +#define SHELL_PATH "/bin/sh" + +#if APR_HAS_THREADS + +struct apr_thread_t { + apr_pool_t *pool; + pthread_t *td; + void *data; + apr_thread_start_t func; + apr_status_t exitval; +}; + +struct apr_threadattr_t { + apr_pool_t *pool; + pthread_attr_t attr; +}; + +struct apr_threadkey_t { + apr_pool_t *pool; + pthread_key_t key; +}; + +struct apr_thread_once_t { + pthread_once_t once; +}; + +#endif + +typedef struct apr_procattr_pscb_t apr_procattr_pscb_t; +struct apr_procattr_pscb_t { + struct apr_procattr_pscb_t *next; + apr_perms_setfn_t *perms_set_fn; + apr_fileperms_t perms; + const void *data; +}; + +struct apr_procattr_t { + apr_pool_t *pool; + apr_file_t *parent_in; + apr_file_t *child_in; + apr_file_t *parent_out; + apr_file_t *child_out; + apr_file_t *parent_err; + apr_file_t *child_err; + char *currdir; + apr_int32_t cmdtype; + apr_int32_t detached; +#ifdef RLIMIT_CPU + struct rlimit *limit_cpu; +#endif +#if defined (RLIMIT_DATA) || defined (RLIMIT_VMEM) || defined(RLIMIT_AS) + struct rlimit *limit_mem; +#endif +#ifdef RLIMIT_NPROC + struct rlimit *limit_nproc; +#endif +#ifdef RLIMIT_NOFILE + struct rlimit *limit_nofile; +#endif + apr_child_errfn_t *errfn; + apr_int32_t errchk; + apr_uid_t uid; + apr_gid_t gid; + apr_procattr_pscb_t *perms_set_callbacks; +}; + +#endif /* ! THREAD_PROC_H */ + diff --git a/include/arch/unix/dso.h b/include/arch/unix/dso.h deleted file mode 100644 index 67bf85104d2..00000000000 --- a/include/arch/unix/dso.h +++ /dev/null @@ -1,90 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#ifndef DSO_H -#define DSO_H - -#include "apr_private.h" -#include "apr_general.h" -#include "apr_pools.h" -#include "apr_dso.h" - -#ifdef HAVE_DLFCN_H -#include <dlfcn.h> -#endif - -#ifdef HAVE_DL_H -#include <dl.h> -#endif - -#ifndef RTLD_NOW -#define RTLD_NOW 1 -#endif - -#ifndef RTLD_GLOBAL -#define RTLD_GLOBAL 0 -#endif - -#if (defined(__FreeBSD__) ||\ - defined(__OpenBSD__) ||\ - defined(__NetBSD__) ) && !defined(__ELF__) -#define DLSYM_NEEDS_UNDERSCORE -#endif - -struct ap_dso_handle_t { - ap_pool_t *cont; - void *handle; -}; - -#endif diff --git a/include/arch/unix/fileio.h b/include/arch/unix/fileio.h deleted file mode 100644 index 1ef43ba0922..00000000000 --- a/include/arch/unix/fileio.h +++ /dev/null @@ -1,138 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#ifndef FILE_IO_H -#define FILE_IO_H - -#include "apr_private.h" -#include "apr_general.h" -#include "apr_file_io.h" -#include "apr_errno.h" -#include "apr_lib.h" - -/* System headers the file I/O library needs */ -#if HAVE_FCNTL_H -#include <fcntl.h> -#endif -#if HAVE_SYS_TYPES_H -#include <sys/types.h> -#endif -#if HAVE_ERRNO_H -#include <errno.h> -#endif -#if HAVE_STRING_H -#include <string.h> -#endif -#if HAVE_DIRENT_H -#include <dirent.h> -#endif -#if HAVE_SYS_STAT_H -#include <sys/stat.h> -#endif -#if HAVE_UNISTD_H -#include <unistd.h> -#endif -#if HAVE_STDIO_H -#include <stdio.h> -#endif -#if HAVE_STDLIB_H -#include <stdlib.h> -#endif -#if HAVE_SYS_UIO_H -#include <sys/uio.h> -#endif -#if HAVE_SYS_TIME_H -#include <sys/time.h> -#endif -#ifdef BEOS -#include <kernel/OS.h> -#endif -/* End System headers */ - -#define APR_FILE_BUFSIZE 4096 - -struct ap_file_t { - ap_pool_t *cntxt; - int filedes; - char * fname; - int oflags; - int eof_hit; - int pipe; - ap_interval_time_t timeout; - int buffered; - int ungetchar; /* Last char provided by an unget op. (-1 = no char)*/ - - /* Stuff for buffered mode */ - char *buffer; - int bufpos; /* Read/Write position in buffer */ - unsigned long dataRead; /* amount of valid data read into buffer */ - int direction; /* buffer being used for 0 = read, 1 = write */ - unsigned long filePtr; /* position in file of handle */ -#if APR_HAS_THREADS - struct ap_lock_t *thlock; -#endif -}; - -struct ap_dir_t { - ap_pool_t *cntxt; - char *dirname; - DIR *dirstruct; - struct dirent *entry; -}; - -ap_status_t ap_unix_file_cleanup(void *); -mode_t ap_unix_get_fileperms(ap_fileperms_t); - -#endif /* ! FILE_IO_H */ - diff --git a/include/arch/unix/locks.h b/include/arch/unix/locks.h deleted file mode 100644 index f6d37100d5e..00000000000 --- a/include/arch/unix/locks.h +++ /dev/null @@ -1,157 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#ifndef LOCKS_H -#define LOCKS_H - -#include "apr_private.h" -#include "apr_general.h" -#include "apr_lib.h" -#include "apr_lock.h" - -/* System headers required by Locks library */ -#if HAVE_UNISTD_H -#include <unistd.h> -#endif -#if HAVE_STRING_H -#include <string.h> -#endif -#if HAVE_USLOCKS_H -#include <uslocks.h> -#endif -#if HAVE_SYS_TYPES_H -#include <sys/types.h> -#endif -#if HAVE_SYS_IPC_H -#include <sys/ipc.h> -#endif -#if HAVE_SYS_SEM_H -#include <sys/sem.h> -#endif -#if HAVE_SYS_FILE_H -#include <sys/file.h> -#endif -#if HAVE_STDIO_H -#include <stdio.h> -#endif -#if HAVE_FCNTL_H -#include <fcntl.h> -#endif -#if HAVE_SYS_MMAN_H -#include <sys/mman.h> -#endif - -#if APR_HAS_THREADS -#if HAVE_PTHREAD_H -#include <pthread.h> -#endif -#endif -/* End System Headers */ - -#if !APR_HAVE_UNION_SEMUN && APR_USE_SYSVSEM_SERIALIZE -/* it makes no sense, but this isn't defined on solaris */ -union semun { - long val; - struct semid_ds *buf; - ushort *array; -}; -#endif - -struct ap_lock_t { - ap_pool_t *cntxt; - ap_locktype_e type; - ap_lockscope_e scope; - int curr_locked; - char *fname; -#if USE_SYSVSEM_SERIALIZE - int interproc; -#elif USE_FCNTL_SERIALIZE - int interproc; -#elif USE_PROC_PTHREAD_SERIALIZE - pthread_mutex_t *interproc; -#elif USE_FLOCK_SERIALIZE - int interproc; -#else - /* No Interprocess serialization. Too bad. */ -#endif -#if APR_HAS_THREADS - /* APR doesn't have threads, no sense in having an thread lock mechanism. - */ -#if USE_PTHREAD_SERIALIZE - pthread_mutex_t *intraproc; -#endif -#endif - /* At some point, we should do a scope for both inter and intra process - * locking here. Something like pthread_mutex with PTHREAD_PROCESS_SHARED - */ -}; - -#if APR_HAS_THREADS -ap_status_t ap_unix_create_intra_lock(struct ap_lock_t *new); -ap_status_t ap_unix_lock_intra(struct ap_lock_t *lock); -ap_status_t ap_unix_unlock_intra(struct ap_lock_t *lock); -ap_status_t ap_unix_destroy_intra_lock(struct ap_lock_t *lock); -#endif - -void ap_unix_setup_lock(void); -ap_status_t ap_unix_create_inter_lock(struct ap_lock_t *new); -ap_status_t ap_unix_lock_inter(struct ap_lock_t *lock); -ap_status_t ap_unix_unlock_inter(struct ap_lock_t *lock); -ap_status_t ap_unix_destroy_inter_lock(struct ap_lock_t *lock); - -ap_status_t ap_unix_child_init_lock(struct ap_lock_t **lock, ap_pool_t *cont, - const char *fname); - -#endif /* LOCKS_H */ - diff --git a/include/arch/unix/misc.h b/include/arch/unix/misc.h deleted file mode 100644 index bb754bbf62e..00000000000 --- a/include/arch/unix/misc.h +++ /dev/null @@ -1,98 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#ifndef MISC_H -#define MISC_H - -#include "apr.h" -#include "apr_private.h" -#include "apr_general.h" -#include "apr_pools.h" -#include "apr_getopt.h" -#include "apr_thread_proc.h" -#include "apr_errno.h" -#ifdef HAVE_STDLIB_H -#include <stdlib.h> -#endif -#ifdef HAVE_STDIO_H -#include <stdio.h> -#endif -#ifdef HAVE_STRING_H -#include <string.h> -#endif -#ifdef HAVE_SIGNAL_H -#include <signal.h> -#endif -#ifdef HAVE_PTHREAD_H -#include <pthread.h> -#endif - -typedef struct datastruct { - void *data; - char *key; - struct datastruct *next; - struct datastruct *prev; -} datastruct; - -struct ap_other_child_rec_t { - struct ap_other_child_rec_t *next; - int pid; - void (*maintenance) (int, void *, int); - void *data; - int write_fd; -}; - - -#endif /* ! MISC_H */ - diff --git a/include/arch/unix/mmap.c b/include/arch/unix/mmap.c deleted file mode 100644 index 5e5b571f7d1..00000000000 --- a/include/arch/unix/mmap.c +++ /dev/null @@ -1,120 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#ifdef BEOS -#include "../beos/mmap_h.h" -#else -#include "mmap_h.h" -#endif - -#include "apr_portable.h" - -#if HAVE_MMAP - -static ap_status_t mmap_cleanup(void *themmap) -{ - ap_mmap_t *mm = themmap; - int rv; - rv = munmap(mm->mm, mm->size); - - if (rv == 0) { - mm->mm = (caddr_t)-1; - return APR_SUCCESS; - } - else - return errno; -} - -ap_status_t ap_mmap_create(ap_mmap_t **new, ap_file_t *file, ap_off_t offset, - ap_size_t size, ap_pool_t *cont) -{ - caddr_t mm; - - if (file == NULL || file->filedes == -1) - return APR_EBADF; - - (*new) = (ap_mmap_t *)ap_palloc(cont, sizeof(ap_mmap_t)); - - ap_seek(file, APR_SET, &offset); - mm = mmap(NULL, size, PROT_READ, MAP_SHARED, file->filedes ,0); - - if (mm == (caddr_t)-1) { - /* we failed to get an mmap'd file... */ - return APR_ENOMEM; - } - (*new)->mm = mm; - (*new)->size = size; - (*new)->cntxt = cont; - - /* register the cleanup... */ - ap_register_cleanup((*new)->cntxt, (void*)(*new), mmap_cleanup, - ap_null_cleanup); - return APR_SUCCESS; -} - -ap_status_t ap_mmap_delete(ap_mmap_t *mmap) -{ - ap_status_t rv; - - if (mmap->mm == (caddr_t) -1) - return APR_ENOENT; - - if ((rv = mmap_cleanup(mmap)) == APR_SUCCESS) { - ap_kill_cleanup(mmap->cntxt, mmap, mmap_cleanup); - return APR_SUCCESS; - } - return rv; -} - -#endif diff --git a/include/arch/unix/networkio.h b/include/arch/unix/networkio.h deleted file mode 100644 index 9880b04318d..00000000000 --- a/include/arch/unix/networkio.h +++ /dev/null @@ -1,139 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#ifndef NETWORK_IO_H -#define NETWORK_IO_H - -#include "apr_private.h" -#include "apr_network_io.h" -#include "apr_errno.h" -#include "apr_general.h" -#include "apr_lib.h" - -/* System headers the network I/O library needs */ -#if HAVE_SYS_TYPES_H -#include <sys/types.h> -#endif -#if HAVE_SYS_UIO_H -#include <sys/uio.h> -#endif -#if HAVE_POLL_H -#include <poll.h> -#endif -#if HAVE_ERRNO_H -#include <errno.h> -#endif -#if HAVE_SYS_TIME_H -#include <sys/time.h> -#endif -#if HAVE_UNISTD_H -#include <unistd.h> -#endif -#if HAVE_STRING_H -#include <string.h> -#endif -#if HAVE_NETINET_TCP_H -#include <netinet/tcp.h> -#endif -#if HAVE_NETINET_IN_H -#include <netinet/in.h> -#endif -#if HAVE_ARPA_INET_H -#include <arpa/inet.h> -#endif -#if HAVE_SYS_SOCKET_H -#include <sys/socket.h> -#endif -#if HAVE_NETDB_H -#include <netdb.h> -#endif -#if HAVE_FCNTL_H -#include <fcntl.h> -#endif -#if HAVE_SYS_SENDFILE_H -#include <sys/sendfile.h> -#endif -/* End System Headers */ - -struct ap_socket_t { - ap_pool_t *cntxt; - int socketdes; - struct sockaddr_in *local_addr; - struct sockaddr_in *remote_addr; - socklen_t addr_len; - ap_interval_time_t timeout; -#ifndef HAVE_POLL - int connected; -#endif -}; - -struct ap_pollfd_t { - ap_pool_t *cntxt; -#ifdef HAVE_POLL - struct pollfd *pollset; - int num; - int curpos; -#else - fd_set *read; - fd_set *write; - fd_set *except; - int highsock; -#endif - ap_int16_t *events; - ap_int16_t *revents; - -}; - -#endif /* ! NETWORK_IO_H */ - diff --git a/include/arch/unix/threadproc.h b/include/arch/unix/threadproc.h deleted file mode 100644 index ea4c8289db7..00000000000 --- a/include/arch/unix/threadproc.h +++ /dev/null @@ -1,126 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#include "apr_private.h" -#include "apr_thread_proc.h" -#include "apr_file_io.h" -#include "fileio.h" - -/* System headers required for thread/process library */ -#if HAVE_PTHREAD_H -#include <pthread.h> -#endif -#if HAVE_SIGNAL_H -#include <signal.h> -#endif -#if HAVE_STRING_H -#include <string.h> -#endif -#if HAVE_SYS_WAIT_H -#include <sys/wait.h> -#endif -#if HAVE_STRING_H -#include <string.h> -#endif -/* End System Headers */ - - -#ifndef THREAD_PROC_H -#define THREAD_PROC_H - -#define SHELL_PATH "/bin/sh" - -#if APR_HAS_THREADS -struct ap_thread_t { - ap_pool_t *cntxt; - pthread_t *td; -}; - -struct ap_threadattr_t { - ap_pool_t *cntxt; - pthread_attr_t *attr; -}; - -struct ap_threadkey_t { - ap_pool_t *cntxt; - pthread_key_t key; -}; -#endif - -struct ap_procattr_t { - ap_pool_t *cntxt; - ap_file_t *parent_in; - ap_file_t *child_in; - ap_file_t *parent_out; - ap_file_t *child_out; - ap_file_t *parent_err; - ap_file_t *child_err; - char *currdir; - ap_int32_t cmdtype; - ap_int32_t detached; -}; - -struct ap_proc_t { - ap_pool_t *cntxt; - pid_t pid; - struct ap_procattr_t *attr; -}; - -/*This will move to ap_threadproc.h in time, but I need to figure it out - * on windows first. :) - */ -ap_status_t ap_detach(struct ap_proc_t **, ap_pool_t *); - -#endif /* ! THREAD_PROC_H */ - diff --git a/include/arch/win32/apr_arch_atime.h b/include/arch/win32/apr_arch_atime.h new file mode 100644 index 00000000000..35f2041a971 --- /dev/null +++ b/include/arch/win32/apr_arch_atime.h @@ -0,0 +1,63 @@ +/* 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. + */ + +#ifndef ATIME_H +#define ATIME_H + +#include "apr_private.h" +#include "apr_time.h" +#if APR_HAVE_TIME_H +#include <time.h> +#endif + +struct atime_t { + apr_pool_t *cntxt; + apr_time_t currtime; + SYSTEMTIME *explodedtime; +}; + + +/* Number of micro-seconds between the beginning of the Windows epoch + * (Jan. 1, 1601) and the Unix epoch (Jan. 1, 1970) + */ +#define APR_DELTA_EPOCH_IN_USEC APR_TIME_C(11644473600000000); + + +static APR_INLINE void FileTimeToAprTime(apr_time_t *result, FILETIME *input) +{ + /* Convert FILETIME one 64 bit number so we can work with it. */ + *result = input->dwHighDateTime; + *result = (*result) << 32; + *result |= input->dwLowDateTime; + *result /= 10; /* Convert from 100 nano-sec periods to micro-seconds. */ + *result -= APR_DELTA_EPOCH_IN_USEC; /* Convert from Windows epoch to Unix epoch */ + return; +} + + +static APR_INLINE void AprTimeToFileTime(LPFILETIME pft, apr_time_t t) +{ + LONGLONG ll; + t += APR_DELTA_EPOCH_IN_USEC; + ll = t * 10; + pft->dwLowDateTime = (DWORD)ll; + pft->dwHighDateTime = (DWORD) (ll >> 32); + return; +} + + +#endif /* ! ATIME_H */ + diff --git a/include/arch/win32/apr_arch_dso.h b/include/arch/win32/apr_arch_dso.h new file mode 100644 index 00000000000..e2e4e40f2ea --- /dev/null +++ b/include/arch/win32/apr_arch_dso.h @@ -0,0 +1,36 @@ +/* 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. + */ + +#ifndef DSO_H +#define DSO_H + +#include "apr_private.h" +#include "apr_general.h" +#include "apr_pools.h" +#include "apr_dso.h" +#include "apr.h" + +#if APR_HAS_DSO + +struct apr_dso_handle_t { + apr_pool_t *cont; + void *handle; + apr_status_t load_error; +}; + +#endif + +#endif diff --git a/include/arch/win32/apr_arch_file_io.h b/include/arch/win32/apr_arch_file_io.h new file mode 100644 index 00000000000..7c5996cab3b --- /dev/null +++ b/include/arch/win32/apr_arch_file_io.h @@ -0,0 +1,263 @@ +/* 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. + */ + +#ifndef FILE_IO_H +#define FILE_IO_H + +#include "apr.h" +#include "apr_private.h" +#include "apr_pools.h" +#include "apr_general.h" +#include "apr_tables.h" +#include "apr_thread_mutex.h" +#include "apr_file_io.h" +#include "apr_file_info.h" +#include "apr_errno.h" +#include "apr_arch_misc.h" +#include "apr_poll.h" + +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif +#if APR_HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#ifdef HAVE_SYS_FCNTL_H +#include <fcntl.h> +#endif +#ifdef HAVE_TIME_H +#include <time.h> +#endif +#if APR_HAVE_DIRENT_H +#include <dirent.h> +#endif +#ifdef HAVE_MALLOC_H +#include <malloc.h> +#endif + +#if APR_HAS_UNICODE_FS +#include "arch/win32/apr_arch_utf8.h" +#include <wchar.h> + +/* Helper functions for the WinNT ApiW() functions. APR treats all + * resource identifiers (files, etc) by their UTF-8 name, to provide + * access to all named identifiers. [UTF-8 completely maps Unicode + * into char type strings.] + * + * The _path flavors below provide us fast mappings of the + * Unicode filename //?/D:/path and //?/UNC/mach/share/path mappings, + * which allow unlimited (well, 32000 wide character) length names. + * These prefixes may appear in Unicode, but must not appear in the + * Ascii API calls. So we tack them on in utf8_to_unicode_path, and + * strip them right back off in unicode_to_utf8_path. + */ +apr_status_t utf8_to_unicode_path(apr_wchar_t* dststr, apr_size_t dstchars, + const char* srcstr); +apr_status_t unicode_to_utf8_path(char* dststr, apr_size_t dstchars, + const apr_wchar_t* srcstr); + +#endif /* APR_HAS_UNICODE_FS */ + +/* Another Helper functions for the WinNT ApiW() functions. We need to + * derive some 'resource' names (max length 255 characters, prefixed with + * Global/ or Local/ on WinNT) from something that looks like a filename. + * Since 'resource' names never contain slashes, convert these to '_'s + * and return the appropriate char* or wchar* for ApiA or ApiW calls. + */ + +void *res_name_from_filename(const char *file, int global, apr_pool_t *pool); + +#define APR_FILE_MAX MAX_PATH + +#define APR_FILE_DEFAULT_BUFSIZE 4096 +/* For backwards-compat */ +#define APR_FILE_BUFSIZE APR_FILE_DEFAULT_BUFSIZE + +/* obscure ommissions from msvc's sys/stat.h */ +#ifdef _MSC_VER +#define S_IFIFO _S_IFIFO /* pipe */ +#define S_IFBLK 0060000 /* Block Special */ +#define S_IFLNK 0120000 /* Symbolic Link */ +#define S_IFSOCK 0140000 /* Socket */ +#define S_IFWHT 0160000 /* Whiteout */ +#endif + +/* Internal Flags for apr_file_open */ +#define APR_OPENINFO 0x00100000 /* Open without READ or WRITE access */ +#define APR_OPENLINK 0x00200000 /* Open a link itself, if supported */ +#define APR_READCONTROL 0x00400000 /* Read the file's owner/perms */ +#define APR_WRITECONTROL 0x00800000 /* Modify the file's owner/perms */ +/* #define APR_INHERIT 0x01000000 -- Defined in apr_arch_inherit.h! */ +#define APR_STDIN_FLAG 0x02000000 /* Obtained via apr_file_open_stdin() */ +#define APR_STDOUT_FLAG 0x04000000 /* Obtained via apr_file_open_stdout() */ +#define APR_STDERR_FLAG 0x06000000 /* Obtained via apr_file_open_stderr() */ +#define APR_STD_FLAGS (APR_STDIN_FLAG | APR_STDOUT_FLAG | APR_STDERR_FLAG) +#define APR_WRITEATTRS 0x08000000 /* Modify the file's attributes */ + +/* Entries missing from the MSVC 5.0 Win32 SDK: + */ +#ifndef FILE_ATTRIBUTE_DEVICE +#define FILE_ATTRIBUTE_DEVICE 0x00000040 +#endif +#ifndef FILE_ATTRIBUTE_REPARSE_POINT +#define FILE_ATTRIBUTE_REPARSE_POINT 0x00000400 +#endif +#ifndef FILE_FLAG_OPEN_NO_RECALL +#define FILE_FLAG_OPEN_NO_RECALL 0x00100000 +#endif +#ifndef FILE_FLAG_OPEN_REPARSE_POINT +#define FILE_FLAG_OPEN_REPARSE_POINT 0x00200000 +#endif +#ifndef TRUSTEE_IS_WELL_KNOWN_GROUP +#define TRUSTEE_IS_WELL_KNOWN_GROUP 5 +#endif + +/* Information bits available from the WIN32 FindFirstFile function */ +#define APR_FINFO_WIN32_DIR (APR_FINFO_NAME | APR_FINFO_TYPE \ + | APR_FINFO_CTIME | APR_FINFO_ATIME \ + | APR_FINFO_MTIME | APR_FINFO_SIZE) + +/* Sneak the Readonly bit through finfo->protection for internal use _only_ */ +#define APR_FREADONLY 0x10000000 + +/* Private function for apr_stat/lstat/getfileinfo/dir_read */ +int fillin_fileinfo(apr_finfo_t *finfo, WIN32_FILE_ATTRIBUTE_DATA *wininfo, + int byhandle, apr_int32_t wanted); + +/* Private function that extends apr_stat/lstat/getfileinfo/dir_read */ +apr_status_t more_finfo(apr_finfo_t *finfo, const void *ufile, + apr_int32_t wanted, int whatfile); + +/* whatfile types for the ufile arg */ +#define MORE_OF_HANDLE 0 +#define MORE_OF_FSPEC 1 +#define MORE_OF_WFSPEC 2 + +/* quick run-down of fields in windows' apr_file_t structure that may have + * obvious uses. + * fname -- the filename as passed to the open call. + * dwFileAttricutes -- Attributes used to open the file. + * append -- Windows doesn't support the append concept when opening files. + * APR needs to keep track of this, and always make sure we append + * correctly when writing to a file with this flag set TRUE. + */ + +/* for apr_poll.c */ +#define filedes filehand + +struct apr_file_t { + apr_pool_t *pool; + HANDLE filehand; + BOOLEAN pipe; /* Is this a pipe of a file? */ + OVERLAPPED *pOverlapped; + apr_interval_time_t timeout; + apr_int32_t flags; + + /* File specific info */ + apr_finfo_t *finfo; + char *fname; + DWORD dwFileAttributes; + int eof_hit; + BOOLEAN buffered; /* Use buffered I/O? */ + int ungetchar; /* Last char provided by an unget op. (-1 = no char) */ + int append; + + /* Stuff for buffered mode */ + char *buffer; + apr_size_t bufpos; /* Read/Write position in buffer */ + apr_size_t bufsize; /* The size of the buffer */ + apr_size_t dataRead; /* amount of valid data read into buffer */ + int direction; /* buffer being used for 0 = read, 1 = write */ + apr_off_t filePtr; /* position in file of handle */ + apr_thread_mutex_t *mutex; /* mutex semaphore, must be owned to access + the above fields */ + +#if APR_FILES_AS_SOCKETS + /* if there is a timeout set, then this pollset is used */ + apr_pollset_t *pollset; +#endif + /* Pipe specific info */ +}; + +struct apr_dir_t { + apr_pool_t *pool; + HANDLE dirhand; + apr_size_t rootlen; + char *dirname; + char *name; + union { +#if APR_HAS_UNICODE_FS + struct { + WIN32_FIND_DATAW *entry; + } w; +#endif +#if APR_HAS_ANSI_FS + struct { + WIN32_FIND_DATAA *entry; + } n; +#endif + }; + int bof; +}; + +/* There are many goofy characters the filesystem can't accept + * or can confound the cmd.exe shell. Here's the list + * [declared in filesys.c] + */ +extern const char apr_c_is_fnchar[256]; + +#define IS_FNCHAR(c) (apr_c_is_fnchar[(unsigned char)(c)] & 1) +#define IS_SHCHAR(c) ((apr_c_is_fnchar[(unsigned char)(c)] & 2) == 2) + + +/* If the user passes APR_FILEPATH_TRUENAME to either + * apr_filepath_root or apr_filepath_merge, this fn determines + * that the root really exists. It's expensive, wouldn't want + * to do this too frequenly. + */ +apr_status_t filepath_root_test(char *path, apr_pool_t *p); + + +/* The apr_filepath_merge wants to canonicalize the cwd to the + * addpath if the user passes NULL as the old root path (this + * isn't true of an empty string "", which won't be concatenated. + * + * But we need to figure out what the cwd of a given volume is, + * when the user passes D:foo. This fn will determine D:'s cwd. + * + * If flags includes the bit APR_FILEPATH_NATIVE, the path returned + * is in the os-native format. + */ +apr_status_t filepath_drive_get(char **rootpath, char drive, + apr_int32_t flags, apr_pool_t *p); + + +/* If the user passes d: vs. D: (or //mach/share vs. //MACH/SHARE), + * we need to fold the case to canonical form. This function is + * supposed to do so. + */ +apr_status_t filepath_root_case(char **rootpath, char *root, apr_pool_t *p); + + +apr_status_t file_cleanup(void *); + +apr_status_t file_socket_pipe_create(apr_file_t **in, + apr_file_t **out, + apr_pool_t *p); + +apr_status_t file_socket_pipe_close(apr_file_t *file); + +#endif /* ! FILE_IO_H */ diff --git a/include/arch/win32/apr_arch_inherit.h b/include/arch/win32/apr_arch_inherit.h new file mode 100644 index 00000000000..8969af664d8 --- /dev/null +++ b/include/arch/win32/apr_arch_inherit.h @@ -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. + */ + +#ifndef INHERIT_H +#define INHERIT_H + +#include "apr_inherit.h" + +#define APR_INHERIT (1 << 24) /* Must not conflict with other bits */ + +#if APR_HAS_UNICODE_FS && APR_HAS_ANSI_FS +/* !defined(_WIN32_WCE) is implicit here */ + +#define APR_IMPLEMENT_INHERIT_SET(name, flag, pool, cleanup) \ +APR_DECLARE(apr_status_t) apr_##name##_inherit_set(apr_##name##_t *the##name) \ +{ \ + IF_WIN_OS_IS_UNICODE \ + { \ +/* if (!SetHandleInformation(the##name->filehand, \ + * HANDLE_FLAG_INHERIT, \ + * HANDLE_FLAG_INHERIT)) \ + * return apr_get_os_error(); \ + */ } \ + ELSE_WIN_OS_IS_ANSI \ + { \ + HANDLE temp, hproc = GetCurrentProcess(); \ + if (!DuplicateHandle(hproc, the##name->filehand, \ + hproc, &temp, 0, TRUE, \ + DUPLICATE_SAME_ACCESS)) \ + return apr_get_os_error(); \ + CloseHandle(the##name->filehand); \ + the##name->filehand = temp; \ + } \ + return APR_SUCCESS; \ +} + +#define APR_IMPLEMENT_INHERIT_UNSET(name, flag, pool, cleanup) \ +APR_DECLARE(apr_status_t) apr_##name##_inherit_unset(apr_##name##_t *the##name)\ +{ \ + IF_WIN_OS_IS_UNICODE \ + { \ +/* if (!SetHandleInformation(the##name->filehand, \ + * HANDLE_FLAG_INHERIT, 0)) \ + * return apr_get_os_error(); \ + */ } \ + ELSE_WIN_OS_IS_ANSI \ + { \ + HANDLE temp, hproc = GetCurrentProcess(); \ + if (!DuplicateHandle(hproc, the##name->filehand, \ + hproc, &temp, 0, FALSE, \ + DUPLICATE_SAME_ACCESS)) \ + return apr_get_os_error(); \ + CloseHandle(the##name->filehand); \ + the##name->filehand = temp; \ + } \ + return APR_SUCCESS; \ +} + +#elif APR_HAS_ANSI_FS || defined(_WIN32_WCE) + +#define APR_IMPLEMENT_INHERIT_SET(name, flag, pool, cleanup) \ +APR_DECLARE(apr_status_t) apr_##name##_inherit_set(apr_##name##_t *the##name) \ +{ \ + HANDLE temp, hproc = GetCurrentProcess(); \ + if (!DuplicateHandle(hproc, the##name->filehand, \ + hproc, &temp, 0, TRUE, \ + DUPLICATE_SAME_ACCESS)) \ + return apr_get_os_error(); \ + CloseHandle(the##name->filehand); \ + the##name->filehand = temp; \ + return APR_SUCCESS; \ +} + +#define APR_IMPLEMENT_INHERIT_UNSET(name, flag, pool, cleanup) \ +APR_DECLARE(apr_status_t) apr_##name##_inherit_unset(apr_##name##_t *the##name)\ +{ \ + HANDLE temp, hproc = GetCurrentProcess(); \ + if (!DuplicateHandle(hproc, the##name->filehand, \ + hproc, &temp, 0, FALSE, \ + DUPLICATE_SAME_ACCESS)) \ + return apr_get_os_error(); \ + CloseHandle(the##name->filehand); \ + the##name->filehand = temp; \ + return APR_SUCCESS; \ +} + +#else /* APR_HAS_UNICODE_FS && !APR_HAS_ANSI_FS && !defined(_WIN32_WCE) */ + +#define APR_IMPLEMENT_INHERIT_SET(name, flag, pool, cleanup) \ +APR_DECLARE(apr_status_t) apr_##name##_inherit_set(apr_##name##_t *the##name) \ +{ \ +/* if (!SetHandleInformation(the##name->filehand, \ + * HANDLE_FLAG_INHERIT, \ + * HANDLE_FLAG_INHERIT)) \ + * return apr_get_os_error(); \ + */ return APR_SUCCESS; \ +} + +#define APR_IMPLEMENT_INHERIT_UNSET(name, flag, pool, cleanup) \ +APR_DECLARE(apr_status_t) apr_##name##_inherit_unset(apr_##name##_t *the##name)\ +{ \ +/* if (!SetHandleInformation(the##name->filehand, \ + * HANDLE_FLAG_INHERIT, 0)) \ + * return apr_get_os_error(); \ + */ return APR_SUCCESS; \ +} + +#endif /* defined(APR_HAS_UNICODE_FS) */ + +#endif /* ! INHERIT_H */ diff --git a/include/arch/win32/apr_arch_misc.h b/include/arch/win32/apr_arch_misc.h new file mode 100644 index 00000000000..2ee562ec375 --- /dev/null +++ b/include/arch/win32/apr_arch_misc.h @@ -0,0 +1,386 @@ +/* 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. + */ + +#ifndef MISC_H +#define MISC_H + +#include "apr.h" +#include "apr_portable.h" +#include "apr_private.h" +#include "apr_general.h" +#include "apr_pools.h" +#include "apr_getopt.h" +#include "apr_thread_proc.h" +#include "apr_file_io.h" +#include "apr_errno.h" +#include "apr_getopt.h" + +#if APR_HAVE_STDIO_H +#include <stdio.h> +#endif +#if APR_HAVE_SIGNAL_H +#include <signal.h> +#endif +#if APR_HAVE_PTHREAD_H +#include <pthread.h> +#endif +#if APR_HAVE_STDLIB_H +#include <stdlib.h> +#endif +#if APR_HAVE_STRING_H +#include <string.h> +#endif +#ifndef _WIN32_WCE +#include <tlhelp32.h> +#endif + +struct apr_other_child_rec_t { + apr_pool_t *p; + struct apr_other_child_rec_t *next; + apr_proc_t *proc; + void (*maintenance) (int, void *, int); + void *data; +}; + +#define WSAHighByte 2 +#define WSALowByte 0 + +/* start.c and apr_app.c helpers and communication within misc.c + * + * They are not for public consumption, although apr_app_init_complete + * must be an exported symbol to avoid reinitialization. + */ +extern int APR_DECLARE_DATA apr_app_init_complete; + +int apr_wastrtoastr(char const * const * *retarr, + wchar_t const * const *arr, int args); + +/* Platform specific designation of run time os version. + * Gaps allow for specific service pack levels that + * export new kernel or winsock functions or behavior. + */ +typedef enum { + APR_WIN_UNK = 0, + APR_WIN_UNSUP = 1, + APR_WIN_95 = 10, + APR_WIN_95_B = 11, + APR_WIN_95_OSR2 = 12, + APR_WIN_98 = 14, + APR_WIN_98_SE = 16, + APR_WIN_ME = 18, + + APR_WIN_UNICODE = 20, /* Prior versions support only narrow chars */ + + APR_WIN_CE_3 = 23, /* CE is an odd beast, not supporting */ + /* some pre-NT features, such as the */ + APR_WIN_NT = 30, /* narrow charset APIs (fooA fns), while */ + APR_WIN_NT_3_5 = 35, /* not supporting some NT-family features. */ + APR_WIN_NT_3_51 = 36, + + APR_WIN_NT_4 = 40, + APR_WIN_NT_4_SP2 = 42, + APR_WIN_NT_4_SP3 = 43, + APR_WIN_NT_4_SP4 = 44, + APR_WIN_NT_4_SP5 = 45, + APR_WIN_NT_4_SP6 = 46, + + APR_WIN_2000 = 50, + APR_WIN_2000_SP1 = 51, + APR_WIN_2000_SP2 = 52, + APR_WIN_XP = 60, + APR_WIN_XP_SP1 = 61, + APR_WIN_XP_SP2 = 62, + APR_WIN_2003 = 70, + APR_WIN_VISTA = 80, + APR_WIN_7 = 90, + APR_WIN_8 = 100 +} apr_oslevel_e; + +extern APR_DECLARE_DATA apr_oslevel_e apr_os_level; + +apr_status_t apr_get_oslevel(apr_oslevel_e *); + +/* The APR_HAS_ANSI_FS symbol is PRIVATE, and internal to APR. + * APR only supports char data for filenames. Like most applications, + * characters >127 are essentially undefined. APR_HAS_UNICODE_FS lets + * the application know that utf-8 is the encoding method of APR, and + * only incidently hints that we have Wide OS calls. + * + * APR_HAS_ANSI_FS is simply an OS flag to tell us all calls must be + * the unicode eqivilant. + */ + +#define APR_HAS_ANSI_FS 0 + +/* IF_WIN_OS_IS_UNICODE / ELSE_WIN_OS_IS_ANSI help us keep the code trivial + * where have runtime tests for unicode-ness, that aren't needed in any + * build which supports only WINNT or WCE. + */ +#if APR_HAS_ANSI_FS && APR_HAS_UNICODE_FS +#define IF_WIN_OS_IS_UNICODE if (apr_os_level >= APR_WIN_UNICODE) +#define ELSE_WIN_OS_IS_ANSI else +#else /* APR_HAS_UNICODE_FS */ +#define IF_WIN_OS_IS_UNICODE +#define ELSE_WIN_OS_IS_ANSI +#endif /* APR_HAS_ANSI_FS && APR_HAS_UNICODE_FS */ + +#if defined(_MSC_VER) && !defined(_WIN32_WCE) +#include "crtdbg.h" + +static APR_INLINE void* apr_malloc_dbg(size_t size, const char* filename, + int linenumber) +{ + return _malloc_dbg(size, _CRT_BLOCK, filename, linenumber); +} + +static APR_INLINE void* apr_realloc_dbg(void* userData, size_t newSize, + const char* filename, int linenumber) +{ + return _realloc_dbg(userData, newSize, _CRT_BLOCK, filename, linenumber); +} + +#else + +static APR_INLINE void* apr_malloc_dbg(size_t size, const char* filename, + int linenumber) +{ + return malloc(size); +} + +static APR_INLINE void* apr_realloc_dbg(void* userData, size_t newSize, + const char* filename, int linenumber) +{ + return realloc(userData, newSize); +} + +#endif /* ! _MSC_VER */ + +typedef enum { + DLL_WINBASEAPI = 0, /* kernel32 From WinBase.h */ + DLL_WINADVAPI = 1, /* advapi32 From WinBase.h */ + DLL_WINSOCKAPI = 2, /* mswsock From WinSock.h */ + DLL_WINSOCK2API = 3, /* ws2_32 From WinSock2.h */ + DLL_SHSTDAPI = 4, /* shell32 From ShellAPI.h */ + DLL_NTDLL = 5, /* shell32 From our real kernel */ + DLL_defined = 6 /* must define as last idx_ + 1 */ +} apr_dlltoken_e; + +FARPROC apr_load_dll_func(apr_dlltoken_e fnLib, char *fnName, int ordinal); + +/* The apr_load_dll_func call WILL return 0 set error to + * ERROR_INVALID_FUNCTION if the function cannot be loaded + */ +#define APR_DECLARE_LATE_DLL_FUNC(lib, rettype, calltype, fn, ord, args, names) \ + typedef rettype (calltype *apr_winapi_fpt_##fn) args; \ + static apr_winapi_fpt_##fn apr_winapi_pfn_##fn = NULL; \ + static int apr_winapi_chk_##fn = 0; \ + static APR_INLINE int apr_winapi_ld_##fn(void) \ + { if (apr_winapi_pfn_##fn) return 1; \ + if (apr_winapi_chk_##fn ++) return 0; \ + if (!apr_winapi_pfn_##fn) \ + apr_winapi_pfn_##fn = (apr_winapi_fpt_##fn) \ + apr_load_dll_func(lib, #fn, ord); \ + if (apr_winapi_pfn_##fn) return 1; else return 0; }; \ + static APR_INLINE rettype apr_winapi_##fn args \ + { if (apr_winapi_ld_##fn()) \ + return (*(apr_winapi_pfn_##fn)) names; \ + else { SetLastError(ERROR_INVALID_FUNCTION); return 0;} }; \ + +#define APR_HAVE_LATE_DLL_FUNC(fn) apr_winapi_ld_##fn() + +/* Provide late bound declarations of every API function missing from + * one or more supported releases of the Win32 API + * + * lib is the enumerated token from apr_dlltoken_e, and must correspond + * to the string table entry in start.c used by the apr_load_dll_func(). + * Token names (attempt to) follow Windows.h declarations prefixed by DLL_ + * in order to facilitate comparison. Use the exact declaration syntax + * and names from Windows.h to prevent ambigutity and bugs. + * + * rettype and calltype follow the original declaration in Windows.h + * fn is the true function name - beware Ansi/Unicode #defined macros + * ord is the ordinal within the library, use 0 if it varies between versions + * args is the parameter list following the original declaration, in parens + * names is the parameter list sans data types, enclosed in parens + * + * #undef/re#define the Ansi/Unicode generic name to abate confusion + * In the case of non-text functions, simply #define the original name + */ + +#if !defined(_WIN32_WCE) +/* This group is NOT available to all versions of WinNT, + * these we must always look up + */ + +#ifdef GetCompressedFileSizeA +#undef GetCompressedFileSizeA +#endif +APR_DECLARE_LATE_DLL_FUNC(DLL_WINBASEAPI, DWORD, WINAPI, GetCompressedFileSizeA, 0, ( + IN LPCSTR lpFileName, + OUT LPDWORD lpFileSizeHigh), + (lpFileName, lpFileSizeHigh)); +#define GetCompressedFileSizeA apr_winapi_GetCompressedFileSizeA +#undef GetCompressedFileSize +#define GetCompressedFileSize apr_winapi_GetCompressedFileSizeA + +#ifdef GetCompressedFileSizeW +#undef GetCompressedFileSizeW +#endif +APR_DECLARE_LATE_DLL_FUNC(DLL_WINBASEAPI, DWORD, WINAPI, GetCompressedFileSizeW, 0, ( + IN LPCWSTR lpFileName, + OUT LPDWORD lpFileSizeHigh), + (lpFileName, lpFileSizeHigh)); +#define GetCompressedFileSizeW apr_winapi_GetCompressedFileSizeW + + +APR_DECLARE_LATE_DLL_FUNC(DLL_NTDLL, LONG, WINAPI, NtQueryTimerResolution, 0, ( + ULONG *pMaxRes, /* Minimum NS Resolution */ + ULONG *pMinRes, /* Maximum NS Resolution */ + ULONG *pCurRes), /* Current NS Resolution */ + (pMaxRes, pMinRes, pCurRes)); +#define QueryTimerResolution apr_winapi_NtQueryTimerResolution + +APR_DECLARE_LATE_DLL_FUNC(DLL_NTDLL, LONG, WINAPI, NtSetTimerResolution, 0, ( + ULONG ReqRes, /* Requested NS Clock Resolution */ + BOOL Acquire, /* Aquire (1) or Release (0) our interest */ + ULONG *pNewRes), /* The NS Clock Resolution granted */ + (ReqRes, Acquire, pNewRes)); +#define SetTimerResolution apr_winapi_NtSetTimerResolution + +typedef struct PBI { + LONG ExitStatus; + PVOID PebBaseAddress; + apr_uintptr_t AffinityMask; + LONG BasePriority; + apr_uintptr_t UniqueProcessId; + apr_uintptr_t InheritedFromUniqueProcessId; +} PBI, *PPBI; + +APR_DECLARE_LATE_DLL_FUNC(DLL_NTDLL, LONG, WINAPI, NtQueryInformationProcess, 0, ( + HANDLE hProcess, /* Obvious */ + INT info, /* Use 0 for PBI documented above */ + PVOID pPI, /* The PIB buffer */ + ULONG LenPI, /* Use sizeof(PBI) */ + ULONG *pSizePI), /* returns pPI buffer used (may pass NULL) */ + (hProcess, info, pPI, LenPI, pSizePI)); +#define QueryInformationProcess apr_winapi_NtQueryInformationProcess + +APR_DECLARE_LATE_DLL_FUNC(DLL_NTDLL, LONG, WINAPI, NtQueryObject, 0, ( + HANDLE hObject, /* Obvious */ + INT info, /* Use 0 for PBI documented above */ + PVOID pOI, /* The PIB buffer */ + ULONG LenOI, /* Use sizeof(PBI) */ + ULONG *pSizeOI), /* returns pPI buffer used (may pass NULL) */ + (hObject, info, pOI, LenOI, pSizeOI)); +#define QueryObject apr_winapi_NtQueryObject + +typedef struct IOSB { + union { + UINT Status; + PVOID reserved; + }; + apr_uintptr_t Information; /* Varies by op, consumed buffer size for FSI below */ +} IOSB, *PIOSB; + +typedef struct FSI { + LONGLONG AllocationSize; + LONGLONG EndOfFile; + ULONG NumberOfLinks; + BOOL DeletePending; + BOOL Directory; +} FSI, *PFSI; + +APR_DECLARE_LATE_DLL_FUNC(DLL_NTDLL, LONG, WINAPI, ZwQueryInformationFile, 0, ( + HANDLE hObject, /* Obvious */ + PVOID pIOSB, /* Point to the IOSB buffer for detailed return results */ + PVOID pFI, /* The buffer, using FIB above */ + ULONG LenFI, /* Use sizeof(FI) */ + ULONG info), /* Use 5 for FSI documented above*/ + (hObject, pIOSB, pFI, LenFI, info)); +#define ZwQueryInformationFile apr_winapi_ZwQueryInformationFile + +#ifdef CreateToolhelp32Snapshot +#undef CreateToolhelp32Snapshot +#endif +APR_DECLARE_LATE_DLL_FUNC(DLL_WINBASEAPI, HANDLE, WINAPI, CreateToolhelp32Snapshot, 0, ( + DWORD dwFlags, + DWORD th32ProcessID), + (dwFlags, th32ProcessID)); +#define CreateToolhelp32Snapshot apr_winapi_CreateToolhelp32Snapshot + +#ifdef Process32FirstW +#undef Process32FirstW +#endif +APR_DECLARE_LATE_DLL_FUNC(DLL_WINBASEAPI, BOOL, WINAPI, Process32FirstW, 0, ( + HANDLE hSnapshot, + LPPROCESSENTRY32W lppe), + (hSnapshot, lppe)); +#define Process32FirstW apr_winapi_Process32FirstW + +#ifdef Process32NextW +#undef Process32NextW +#endif +APR_DECLARE_LATE_DLL_FUNC(DLL_WINBASEAPI, BOOL, WINAPI, Process32NextW, 0, ( + HANDLE hSnapshot, + LPPROCESSENTRY32W lppe), + (hSnapshot, lppe)); +#define Process32NextW apr_winapi_Process32NextW + +#if !defined(POLLERR) +/* Event flag definitions for WSAPoll(). */ +#define POLLRDNORM 0x0100 +#define POLLRDBAND 0x0200 +#define POLLIN (POLLRDNORM | POLLRDBAND) +#define POLLPRI 0x0400 + +#define POLLWRNORM 0x0010 +#define POLLOUT (POLLWRNORM) +#define POLLWRBAND 0x0020 + +#define POLLERR 0x0001 +#define POLLHUP 0x0002 +#define POLLNVAL 0x0004 + +typedef struct pollfd { + SOCKET fd; + SHORT events; + SHORT revents; + +} WSAPOLLFD, *PWSAPOLLFD, FAR *LPWSAPOLLFD; + +#endif /* !defined(POLLERR) */ +#ifdef WSAPoll +#undef WSAPoll +#endif +APR_DECLARE_LATE_DLL_FUNC(DLL_WINSOCK2API, int, WSAAPI, WSAPoll, 0, ( + IN OUT LPWSAPOLLFD fdArray, + IN ULONG fds, + IN INT timeout), + (fdArray, fds, timeout)); +#define WSAPoll apr_winapi_WSAPoll +#define HAVE_POLL 1 + +#ifdef SetDllDirectoryW +#undef SetDllDirectoryW +#endif +APR_DECLARE_LATE_DLL_FUNC(DLL_WINBASEAPI, BOOL, WINAPI, SetDllDirectoryW, 0, ( + IN LPCWSTR lpPathName), + (lpPathName)); +#define SetDllDirectoryW apr_winapi_SetDllDirectoryW + +#endif /* !defined(_WIN32_WCE) */ + +#endif /* ! MISC_H */ diff --git a/include/arch/win32/apr_arch_networkio.h b/include/arch/win32/apr_arch_networkio.h new file mode 100644 index 00000000000..04be55595d1 --- /dev/null +++ b/include/arch/win32/apr_arch_networkio.h @@ -0,0 +1,90 @@ +/* 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. + */ + +#ifndef NETWORK_IO_H +#define NETWORK_IO_H + +#include "apr_network_io.h" +#include "apr_general.h" +#include "apr_poll.h" + +typedef struct sock_userdata_t sock_userdata_t; +struct sock_userdata_t { + sock_userdata_t *next; + const char *key; + void *data; +}; + +struct apr_socket_t { + apr_pool_t *pool; + SOCKET socketdes; + int type; /* SOCK_STREAM, SOCK_DGRAM */ + int protocol; + apr_sockaddr_t *local_addr; + apr_sockaddr_t *remote_addr; + int timeout_ms; /* MUST MATCH if timeout > 0 */ + apr_interval_time_t timeout; + apr_int32_t disconnected; + int local_port_unknown; + int local_interface_unknown; + int remote_addr_unknown; + apr_int32_t options; + apr_int32_t inherit; +#if APR_HAS_SENDFILE + /* As of 07.20.04, the overlapped structure is only used by + * apr_socket_sendfile and that's where it will be allocated + * and initialized. + */ + OVERLAPPED *overlapped; +#endif + sock_userdata_t *userdata; + + /* if there is a timeout set, then this pollset is used */ + apr_pollset_t *pollset; +}; + +#ifdef _WIN32_WCE +#ifndef WSABUF +typedef struct _WSABUF { + u_long len; /* the length of the buffer */ + char FAR * buf; /* the pointer to the buffer */ +} WSABUF, FAR * LPWSABUF; +#endif +#else +#ifdef _MSC_VER +#define HAVE_STRUCT_IPMREQ +#endif +#endif + +apr_status_t status_from_res_error(int); + +const char *apr_inet_ntop(int af, const void *src, char *dst, apr_size_t size); +int apr_inet_pton(int af, const char *src, void *dst); +void apr_sockaddr_vars_set(apr_sockaddr_t *, int, apr_port_t); + +#define apr_is_option_set(skt, option) \ + (((skt)->options & (option)) == (option)) + +#define apr_set_option(skt, option, on) \ + do { \ + if (on) \ + (skt)->options |= (option); \ + else \ + (skt)->options &= ~(option); \ + } while (0) + +#endif /* ! NETWORK_IO_H */ + diff --git a/include/arch/win32/apr_arch_proc_mutex.h b/include/arch/win32/apr_arch_proc_mutex.h new file mode 100644 index 00000000000..4e3e3993996 --- /dev/null +++ b/include/arch/win32/apr_arch_proc_mutex.h @@ -0,0 +1,29 @@ +/* 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. + */ + +#ifndef PROC_MUTEX_H +#define PROC_MUTEX_H + +#include "apr_proc_mutex.h" + +struct apr_proc_mutex_t { + apr_pool_t *pool; + HANDLE handle; + const char *fname; +}; + +#endif /* PROC_MUTEX_H */ + diff --git a/include/arch/win32/apr_arch_thread_cond.h b/include/arch/win32/apr_arch_thread_cond.h new file mode 100644 index 00000000000..c7f69f80646 --- /dev/null +++ b/include/arch/win32/apr_arch_thread_cond.h @@ -0,0 +1,32 @@ +/* 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. + */ + +#ifndef THREAD_COND_H +#define THREAD_COND_H + +#include "apr_thread_cond.h" + +struct apr_thread_cond_t { + apr_pool_t *pool; + HANDLE semaphore; + CRITICAL_SECTION csection; + unsigned long num_waiting; + unsigned long num_wake; + unsigned long generation; +}; + +#endif /* THREAD_COND_H */ + diff --git a/include/arch/win32/apr_arch_thread_mutex.h b/include/arch/win32/apr_arch_thread_mutex.h new file mode 100644 index 00000000000..13d3c1cbd57 --- /dev/null +++ b/include/arch/win32/apr_arch_thread_mutex.h @@ -0,0 +1,40 @@ +/* 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. + */ + +#ifndef THREAD_MUTEX_H +#define THREAD_MUTEX_H + +#include "apr_pools.h" + +typedef enum thread_mutex_type { + thread_mutex_critical_section, + thread_mutex_unnested_event, + thread_mutex_nested_mutex +} thread_mutex_type; + +/* handle applies only to unnested_event on all platforms + * and nested_mutex on Win9x only. Otherwise critical_section + * is used for NT nexted mutexes providing optimal performance. + */ +struct apr_thread_mutex_t { + apr_pool_t *pool; + thread_mutex_type type; + HANDLE handle; + CRITICAL_SECTION section; +}; + +#endif /* THREAD_MUTEX_H */ + diff --git a/include/arch/win32/apr_arch_thread_rwlock.h b/include/arch/win32/apr_arch_thread_rwlock.h new file mode 100644 index 00000000000..1177e529103 --- /dev/null +++ b/include/arch/win32/apr_arch_thread_rwlock.h @@ -0,0 +1,30 @@ +/* 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. + */ + +#ifndef THREAD_RWLOCK_H +#define THREAD_RWLOCK_H + +#include "apr_thread_rwlock.h" + +struct apr_thread_rwlock_t { + apr_pool_t *pool; + HANDLE write_mutex; + HANDLE read_event; + LONG readers; +}; + +#endif /* THREAD_RWLOCK_H */ + diff --git a/include/arch/win32/apr_arch_threadproc.h b/include/arch/win32/apr_arch_threadproc.h new file mode 100644 index 00000000000..d3ce9c51860 --- /dev/null +++ b/include/arch/win32/apr_arch_threadproc.h @@ -0,0 +1,74 @@ +/* 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_thread_proc.h" +#include "apr_file_io.h" + +#ifndef THREAD_PROC_H +#define THREAD_PROC_H + +#define SHELL_PATH "cmd.exe" + +struct apr_thread_t { + apr_pool_t *pool; + HANDLE td; + apr_int32_t cancel; + apr_int32_t cancel_how; + void *data; + apr_thread_start_t func; + apr_status_t exitval; +}; + +struct apr_threadattr_t { + apr_pool_t *pool; + apr_int32_t detach; + apr_size_t stacksize; +}; + +struct apr_threadkey_t { + apr_pool_t *pool; + DWORD key; +}; + +struct apr_procattr_t { + apr_pool_t *pool; + apr_file_t *parent_in; + apr_file_t *child_in; + apr_file_t *parent_out; + apr_file_t *child_out; + apr_file_t *parent_err; + apr_file_t *child_err; + char *currdir; + apr_int32_t cmdtype; + apr_int32_t detached; + apr_child_errfn_t *errfn; + apr_int32_t errchk; +#ifndef _WIN32_WCE + HANDLE user_token; + LPSECURITY_ATTRIBUTES sa; + LPVOID sd; +#endif +}; + +struct apr_thread_once_t { + long value; +}; + +extern apr_status_t apr_threadproc_init(apr_pool_t *pool); + +#endif /* ! THREAD_PROC_H */ + diff --git a/include/arch/win32/apr_arch_utf8.h b/include/arch/win32/apr_arch_utf8.h new file mode 100644 index 00000000000..84f8bf775ef --- /dev/null +++ b/include/arch/win32/apr_arch_utf8.h @@ -0,0 +1,56 @@ +/* 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. + */ + +#ifndef UTF8_H +#define UTF8_H + +#include "apr.h" +#include "apr_lib.h" +#include "apr_errno.h" + +/* If we ever support anything more exciting than char... this could move. + */ +typedef apr_uint16_t apr_wchar_t; + +/** + * An APR internal function for fast utf-8 octet-encoded Unicode conversion + * to the ucs-2 wide Unicode format. This function is used for filename and + * other resource conversions for platforms providing native Unicode support. + * + * @tip Only the errors APR_EINVAL and APR_INCOMPLETE may occur, the former + * when the character code is invalid (in or out of context) and the later + * when more characters were expected, but insufficient characters remain. + */ +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); + +/** + * An APR internal function for fast ucs-2 wide Unicode format conversion to + * the utf-8 octet-encoded Unicode. This function is used for filename and + * other resource conversions for platforms providing native Unicode support. + * + * @tip Only the errors APR_EINVAL and APR_INCOMPLETE may occur, the former + * when the character code is invalid (in or out of context) and the later + * when more words were expected, but insufficient words remain. + */ +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); + +#endif /* def UTF8_H */ diff --git a/include/arch/win32/apr_dbg_win32_handles.h b/include/arch/win32/apr_dbg_win32_handles.h new file mode 100644 index 00000000000..471cd66dbfc --- /dev/null +++ b/include/arch/win32/apr_dbg_win32_handles.h @@ -0,0 +1,217 @@ +/* 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. + */ + +#ifndef APR_DBG_WIN32_HANDLES_H +#define APR_DBG_WIN32_HANDLES_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* USAGE: + * + * Add the following include to apr_private.h for internal debugging, + * or copy this header into apr/include add the include below to apr.h + * for really global debugging; + * + * #include "apr_dbg_win32_handles.h" + * + * apr_dbg_log is the crux of this function ... it uses Win32 API and + * no apr calls itself to log all activity to a file named for the + * executing application with a .pid suffix. Ergo several instances + * may be executing and logged at once. + * + * HANDLE apr_dbg_log(char* fn, HANDLE ha, char* fl, int ln, int nh + * [, HANDLE *hv, char *dsc...]) + * + * returns: the handle passed in ha, which is cast back to the real return type. + * + * formats one line into the debug log file if nh is zero; + * ha (hex) seq(hex) tid(hex) fn fl ln + * xxxxxxxx xxxxxxxx xxxxxxxx func() sourcefile:lineno + * The macro apr_dbg_rv makes this simple to implement for many APIs + * that simply take args that don't interest us, and return a handle. + * + * formats multiple lines (nh) into the debug log file for each hv/dsc pair + * (nh must correspond to the number of pairs); + * hv (hex) seq(hex) tid(hex) fn dsc fl ln + * xxxxxxxx xxxxxxxx xxxxxxxx func(arg) sourcefile:lineno + * In this later usage, hv is the still the return value but is not + * treated as a handle. + */ + +APR_DECLARE_NONSTD(HANDLE) apr_dbg_log(char* fn, HANDLE ha, char* fl, int ln, + int nh,/* HANDLE *hv, char *dsc */...); + +#define apr_dbg_rv(fn, args) (apr_dbg_log(#fn,(fn) args,__FILE__,__LINE__,0)) + +#define CloseHandle(h) \ + ((BOOL)apr_dbg_log("CloseHandle", \ + (HANDLE)(CloseHandle)(h), \ + __FILE__,__LINE__,1, \ + &(h),"")) + +#define CreateEventA(sd,b1,b2,nm) apr_dbg_rv(CreateEventA,(sd,b1,b2,nm)) +#define CreateEventW(sd,b1,b2,nm) apr_dbg_rv(CreateEventW,(sd,b1,b2,nm)) + +#define CreateFileA(nm,d1,d2,sd,d3,d4,h) apr_dbg_rv(CreateFileA,(nm,d1,d2,sd,d3,d4,h)) +#define CreateFileW(nm,d1,d2,sd,d3,d4,h) apr_dbg_rv(CreateFileW,(nm,d1,d2,sd,d3,d4,h)) + +#define CreateFileMappingA(fh,sd,d1,d2,d3,nm) apr_dbg_rv(CreateFileMappingA,(fh,sd,d1,d2,d3,nm)) +#define CreateFileMappingW(fh,sd,d1,d2,d3,nm) apr_dbg_rv(CreateFileMappingW,(fh,sd,d1,d2,d3,nm)) + +#define CreateMutexA(sd,b,nm) apr_dbg_rv(CreateMutexA,(sd,b,nm)) +#define CreateMutexW(sd,b,nm) apr_dbg_rv(CreateMutexW,(sd,b,nm)) + +#define CreateIoCompletionPort(h1,h2,pd1,d2) apr_dbg_rv(CreateIoCompletionPort,(h1,h2,pd1,d2)) + +#define CreateNamedPipeA(nm,d1,d2,d3,d4,d5,d6,sd) apr_dbg_rv(CreateNamedPipeA,(nm,d1,d2,d3,d4,d5,d6,sd)) +#define CreateNamedPipeW(nm,d1,d2,d3,d4,d5,d6,sd) apr_dbg_rv(CreateNamedPipeW,(nm,d1,d2,d3,d4,d5,d6,sd)) + +#define CreatePipe(ph1,ph2,sd,d) \ + ((BOOL)apr_dbg_log("CreatePipe", \ + (HANDLE)(CreatePipe)(ph1,ph2,sd,d), \ + __FILE__,__LINE__,2, \ + (ph1),"hRead", \ + (ph2),"hWrite")) + +#define CreateProcessA(s1,s2,sd1,sd2,b,d1,s3,s4,pd2,hr) \ + ((BOOL)apr_dbg_log("CreateProcessA", \ + (HANDLE)(CreateProcessA)(s1,s2,sd1,sd2,b,d1,s3,s4,pd2,hr), \ + __FILE__,__LINE__,2, \ + &((hr)->hProcess),"hProcess", \ + &((hr)->hThread),"hThread")) +#define CreateProcessW(s1,s2,sd1,sd2,b,d1,s3,s4,pd2,hr) \ + ((BOOL)apr_dbg_log("CreateProcessW", \ + (HANDLE)(CreateProcessW)(s1,s2,sd1,sd2,b,d1,s3,s4,pd2,hr), \ + __FILE__,__LINE__,2, \ + &((hr)->hProcess),"hProcess", \ + &((hr)->hThread),"hThread")) + +#define CreateSemaphoreA(sd,d1,d2,nm) apr_dbg_rv(CreateSemaphoreA,(sd,d1,d2,nm)) +#define CreateSemaphoreW(sd,d1,d2,nm) apr_dbg_rv(CreateSemaphoreW,(sd,d1,d2,nm)) + +#define CreateThread(sd,d1,fn,pv,d2,pd3) apr_dbg_rv(CreateThread,(sd,d1,fn,pv,d2,pd3)) + +#define DeregisterEventSource(h) \ + ((BOOL)apr_dbg_log("DeregisterEventSource", \ + (HANDLE)(DeregisterEventSource)(h), \ + __FILE__,__LINE__,1, \ + &(h),"")) + +#define DuplicateHandle(h1,h2,h3,ph4,d1,b,d2) \ + ((BOOL)apr_dbg_log("DuplicateHandle", \ + (HANDLE)(DuplicateHandle)(h1,h2,h3,ph4,d1,b,d2), \ + __FILE__,__LINE__,2, \ + (ph4),((h3)==GetCurrentProcess()) \ + ? "Target" : "EXTERN Target", \ + &(h2),((h1)==GetCurrentProcess()) \ + ? "Source" : "EXTERN Source")) + +#define GetCurrentProcess() \ + (apr_dbg_log("GetCurrentProcess", \ + (GetCurrentProcess)(),__FILE__,__LINE__,0)) + +#define GetCurrentThread() \ + (apr_dbg_log("GetCurrentThread", \ + (GetCurrentThread)(),__FILE__,__LINE__,0)) + +#define GetModuleHandleA(nm) apr_dbg_rv(GetModuleHandleA,(nm)) +#define GetModuleHandleW(nm) apr_dbg_rv(GetModuleHandleW,(nm)) + +#define GetStdHandle(d) apr_dbg_rv(GetStdHandle,(d)) + +#define LoadLibraryA(nm) apr_dbg_rv(LoadLibraryA,(nm)) +#define LoadLibraryW(nm) apr_dbg_rv(LoadLibraryW,(nm)) + +#define LoadLibraryExA(nm,h,d) apr_dbg_rv(LoadLibraryExA,(nm,h,d)) +#define LoadLibraryExW(nm,h,d) apr_dbg_rv(LoadLibraryExW,(nm,h,d)) + +#define OpenEventA(d,b,nm) apr_dbg_rv(OpenEventA,(d,b,nm)) +#define OpenEventW(d,b,nm) apr_dbg_rv(OpenEventW,(d,b,nm)) + +#define OpenFileMappingA(d,b,nm) apr_dbg_rv(OpenFileMappingA,(d,b,nm)) +#define OpenFileMappingW(d,b,nm) apr_dbg_rv(OpenFileMappingW,(d,b,nm)) + +#define RegisterEventSourceA(s1,s2) apr_dbg_rv(RegisterEventSourceA,(s1,s2)) +#define RegisterEventSourceW(s1,s2) apr_dbg_rv(RegisterEventSourceW,(s1,s2)) + +#define SetEvent(h) \ + ((BOOL)apr_dbg_log("SetEvent", \ + (HANDLE)(SetEvent)(h), \ + __FILE__,__LINE__,1, \ + &(h),"")) + +#define SetStdHandle(d,h) \ + ((BOOL)apr_dbg_log("SetStdHandle", \ + (HANDLE)(SetStdHandle)(d,h), \ + __FILE__,__LINE__,1,&(h),"")) + +#define socket(i1,i2,i3) \ + ((SOCKET)apr_dbg_log("socket", \ + (HANDLE)(socket)(i1,i2,i3), \ + __FILE__,__LINE__,0)) + +#define WaitForSingleObject(h,d) \ + ((DWORD)apr_dbg_log("WaitForSingleObject", \ + (HANDLE)(WaitForSingleObject)(h,d), \ + __FILE__,__LINE__,1,&(h),"Signaled")) + +#define WaitForSingleObjectEx(h,d,b) \ + ((DWORD)apr_dbg_log("WaitForSingleObjectEx", \ + (HANDLE)(WaitForSingleObjectEx)(h,d,b), \ + __FILE__,__LINE__,1,&(h),"Signaled")) + +#define WaitForMultipleObjects(d1,ah,b,d2) \ + ((DWORD)apr_dbg_log("WaitForMultipleObjects", \ + (HANDLE)(WaitForMultipleObjects)(d1,ah,b,d2), \ + __FILE__,__LINE__,1,ah,"Signaled")) + +#define WaitForMultipleObjectsEx(d1,ah,b1,d2,b2) \ + ((DWORD)apr_dbg_log("WaitForMultipleObjectsEx", \ + (HANDLE)(WaitForMultipleObjectsEx)(d1,ah,b1,d2,b2), \ + __FILE__,__LINE__,1,ah,"Signaled")) + +#define WSASocketA(i1,i2,i3,pi,g,dw) \ + ((SOCKET)apr_dbg_log("WSASocketA", \ + (HANDLE)(WSASocketA)(i1,i2,i3,pi,g,dw), \ + __FILE__,__LINE__,0)) + +#define WSASocketW(i1,i2,i3,pi,g,dw) \ + ((SOCKET)apr_dbg_log("WSASocketW", \ + (HANDLE)(WSASocketW)(i1,i2,i3,pi,g,dw), \ + __FILE__,__LINE__,0)) + +#define closesocket(sh) \ + ((int)apr_dbg_log("closesocket", \ + (HANDLE)(closesocket)(sh), \ + __FILE__,__LINE__,1,&(sh),"")) + +#define _beginthread(fn,d,pv) \ + ((unsigned long)apr_dbg_log("_beginthread", \ + (HANDLE)(_beginthread)(fn,d,pv), \ + __FILE__,__LINE__,0)) + +#define _beginthreadex(sd,d1,fn,pv,d2,pd3) \ + ((unsigned long)apr_dbg_log("_beginthreadex", \ + (HANDLE)(_beginthreadex)(sd,d1,fn,pv,d2,pd3), \ + __FILE__,__LINE__,0)) + +#ifdef __cplusplus +} +#endif + +#endif /* !defined(APR_DBG_WIN32_HANDLES_H) */ diff --git a/include/arch/win32/apr_private.h b/include/arch/win32/apr_private.h index d3015e35862..9f12efa189d 100644 --- a/include/arch/win32/apr_private.h +++ b/include/arch/win32/apr_private.h @@ -1,99 +1,76 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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. */ /* * Note: - * This is the windows specific autoconf like config file - * which is used to generate apr_private.h at build time. - * Do not put any code into this file which depends on - * APR include files. + * This is the win32-specific autoconf-like config file + * which unix creates at ./configure time. */ -#ifdef WIN32 +#ifndef APR_PRIVATE_H +#define APR_PRIVATE_H -#ifndef APR_CONFIG_H -#define APR_CONFIG_H +/* Pick up publicly advertised headers and symbols before the + * APR internal private headers and symbols + */ +#include <apr.h> -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif -#ifndef _WIN32_WINNT /* - * Compile the server including all the Windows NT 4.0 header files by - * default. + * Add a _very_few_ declarations missing from the restricted set of headers + * (If this list becomes extensive, re-enable the required headers in apr.hw!) + * ACL headers were excluded by default, so include them now. */ -#define _WIN32_WINNT 0x0400 +#ifndef SW_HIDE +#define SW_HIDE 0 #endif -#include <windows.h> -#include <winsock2.h> -#include <mswsock.h> -#include <sys/types.h> -#include <stddef.h> -#include <stdio.h> -#include <time.h> -#define HAVE_SENDFILE 1 +/* For the misc.h late-loaded dynamic symbols, we need some obscure types + * Avoid dragging in wtypes.h unless it's absolutely necessary [generally + * not with APR itself, until some GUI-related security is introduced.] + */ +#ifndef _WIN32_WCE +#define HAVE_ACLAPI 1 +#ifdef __wtypes_h__ +#include <accctrl.h> +#else +#define __wtypes_h__ +#include <accctrl.h> +#undef __wtypes_h__ +#endif +#else +#define HAVE_ACLAPI 0 +#endif /* Use this section to define all of the HAVE_FOO_H * that are required to build properly. */ -#define HAVE_CONIO_H 1 -#define HAVE_MALLOC_H 1 -#define HAVE_STDLIB_H 1 #define HAVE_LIMITS_H 1 +#define HAVE_MALLOC_H 1 +#define HAVE_PROCESS_H APR_NOT_IN_WCE #define HAVE_SIGNAL_H 1 +#define HAVE_STDDEF_H APR_NOT_IN_WCE +#define HAVE_STDLIB_H 1 + +#define HAVE_STRICMP 1 +#define HAVE_STRNICMP 1 +#define HAVE_STRDUP 1 +#define HAVE_STRSTR 1 +#define HAVE_MEMCHR 1 +#ifndef __WATCOMC__ #define SIGHUP 1 /* 2 is used for SIGINT on windows */ #define SIGQUIT 3 @@ -106,6 +83,7 @@ #define SIGUSR1 10 /* 11 is used for SIGSEGV on windows */ #define SIGUSR2 12 +#endif #define SIGPIPE 13 #define SIGALRM 14 /* 15 is used for SIGTERM on windows */ @@ -126,8 +104,6 @@ #define SIGWINCH 30 #define SIGIO 31 -#define __attribute__(__x) - /* APR COMPATABILITY FUNCTIONS * This section should be used to define functions and * macros which are need to make Windows features look @@ -135,15 +111,11 @@ */ typedef void (Sigfunc)(int); -#define strcasecmp(s1, s2) stricmp(s1, s2) -#define sleep(t) Sleep(t * 1000) - - -/* APR FEATURE MACROS. - * This section should be used to define feature macros - * that the windows port needs. - */ -#define APR_HAS_THREADS 1 +#define sleep(t) Sleep((t) * 1000) +/* For now workaround for Watcom'S lack of _commit() */ +#ifdef __WATCOMC__ +#define _commit fsync +#endif #define SIZEOF_SHORT 2 #define SIZEOF_INT 4 @@ -154,5 +126,73 @@ typedef void (Sigfunc)(int); unsigned __stdcall SignalHandling(void *); int thread_ready(void); -#endif /*APR_CONFIG_H*/ -#endif /*WIN32*/ +#if !APR_HAVE_ERRNO_H +APR_DECLARE_DATA int errno; +#define ENOSPC 1 +#endif + +#if APR_HAVE_IPV6 +#define HAVE_GETADDRINFO 1 +#define HAVE_GETNAMEINFO 1 +#define HAVE_IF_INDEXTONAME 1 +#define HAVE_IF_NAMETOINDEX 1 +#endif + +/* MSVC 7.0 introduced _strtoi64 */ +#if _MSC_VER >= 1300 && _INTEGRAL_MAX_BITS >= 64 && !defined(_WIN32_WCE) +#define APR_INT64_STRFN _strtoi64 +#endif + +#if APR_HAS_LARGE_FILES +#ifdef APR_INT64_STRFN +#define APR_OFF_T_STRFN APR_INT64_STRFN +#else +#define APR_OFF_T_STRFN apr_strtoi64 +#endif +#else +#if defined(_WIN32_WCE) +#define APR_OFF_T_STRFN strtol +#else +#define APR_OFF_T_STRFN strtoi +#endif +#endif + +/* used to check for DWORD overflow in 64bit compiles */ +#define APR_DWORD_MAX 0xFFFFFFFFUL + +/* Compile win32 with DSO support for .dll builds + * Pair the static xml build for static apr-2.lib + */ +#ifdef APR_DECLARE_STATIC +#define APU_DSO_BUILD 0 +#define XML_STATIC 1 +#else +#define APU_DSO_BUILD 1 +#endif + +/* Presume a standard, modern (5.x) mysql sdk */ +#define HAVE_MY_GLOBAL_H 1 + +/* my_sys.h is broken on VC/Win32, and apparently not required */ +/* #undef HAVE_MY_SYS_H 0 */ + +/* Windows ODBC sql.h is always present */ +#define HAVE_SQL_H 1 + +#define HAVE_ICONV_H 1 + +/* + * Windows does not have GDBM, and we always use the bundled (new) Expat + */ + +/* Define if you have the gdbm library (-lgdbm). */ +/* #undef HAVE_LIBGDBM */ + +/* define if Expat 1.0 or 1.1 was found */ +/* #undef APR_HAVE_OLD_EXPAT */ + +#ifdef HAVE_PROCESS_H +#include <process.h> +#endif + +#endif /*APR_PRIVATE_H*/ diff --git a/include/arch/win32/atime.h b/include/arch/win32/atime.h deleted file mode 100644 index cf5ab487386..00000000000 --- a/include/arch/win32/atime.h +++ /dev/null @@ -1,72 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#ifndef ATIME_H -#define ATIME_H - -#include "apr_private.h" -#include "apr_time.h" -#include <time.h> - -struct atime_t { - ap_pool_t *cntxt; - ap_time_t currtime; - SYSTEMTIME *explodedtime; -}; - -void FileTimeToAprTime(ap_time_t *atime, FILETIME *ft); -void AprTimeToFileTime(LPFILETIME pft, ap_time_t t); - -#endif /* ! ATIME_H */ - diff --git a/include/arch/win32/dso.h b/include/arch/win32/dso.h deleted file mode 100644 index 745db192dce..00000000000 --- a/include/arch/win32/dso.h +++ /dev/null @@ -1,68 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#ifndef DSO_H -#define DSO_H - -#include "apr_private.h" -#include "apr_general.h" -#include "apr_pools.h" -#include "apr_dso.h" - -struct ap_dso_handle_t { - ap_pool_t *cont; - void *handle; -}; - -#endif diff --git a/include/arch/win32/fileio.h b/include/arch/win32/fileio.h deleted file mode 100644 index 974889dd03a..00000000000 --- a/include/arch/win32/fileio.h +++ /dev/null @@ -1,134 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#ifndef FILE_IO_H -#define FILE_IO_H - -#ifdef HAVE_SYS_STAT_H -#include <sys/stat.h> -#endif -#ifdef HAVE_SYS_TYPES_H -#include <sys/types.h> -#endif -#ifdef HAVE_SYS_FCNTL_H -#include <fcntl.h> -#endif -#ifdef HAVE_TIME_H -#include <time.h> -#endif -#ifdef HAVE_DIRENT_H -#include <dirent.h> -#endif -#ifdef HAVE_MALLOC_H -#include <malloc.h> -#endif -#ifdef HAVE_UIO_H -#include <sys/uio.h> -#endif -#include "apr_private.h" -#include "apr_pools.h" -#include "apr_general.h" -#include "apr_file_io.h" -#include "apr_errno.h" - -/* quick run-down of fields in windows' ap_file_t structure that may have - * obvious uses. - * fname -- the filename as passed to the open call. - * dwFileAttricutes -- Attributes used to open the file. - * demonfname -- the canonicalized filename. Used to store the result from - * ap_os_canonicalize_filename. - * lowerdemonfname -- inserted at Ken Parzygnat's request, because of the - * ugly way windows deals with case in the filesystem. - * append -- Windows doesn't support the append concept when opening files. - * APR needs to keep track of this, and always make sure we append - * correctly when writing to a file with this flag set TRUE. - */ - -struct ap_file_t { - ap_pool_t *cntxt; - HANDLE filehand; - char *fname; - DWORD dwFileAttributes; - int eof_hit; - int pipe; - ap_interval_time_t timeout; - int buffered; /* Not currently used on Windows */ - int ungetchar; /* Not used. Last char provided by an unget op. (-1 = no char)*/ - - char *demonfname; - char *lowerdemonfname; - int append; - - off_t size; - ap_time_t atime; - ap_time_t mtime; - ap_time_t ctime; -}; - -struct ap_dir_t { - ap_pool_t *cntxt; - char *dirname; - HANDLE dirhand; - WIN32_FIND_DATA *entry; -}; - -ap_status_t file_cleanup(void *); -/*mode_t get_fileperms(ap_fileperms_t); -*/ -API_EXPORT(char *) ap_os_systemcase_filename(struct ap_pool_t *pCont, - const char *szFile); -char * canonical_filename(struct ap_pool_t *pCont, const char *szFile); - -#endif /* ! FILE_IO_H */ - diff --git a/include/arch/win32/locks.h b/include/arch/win32/locks.h deleted file mode 100644 index 602c2eb673f..00000000000 --- a/include/arch/win32/locks.h +++ /dev/null @@ -1,70 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#ifndef LOCKS_H -#define LOCKS_H - -#include "apr_lock.h" - -struct ap_lock_t { - ap_pool_t *cntxt; - ap_locktype_e type; - ap_lockscope_e scope; - HANDLE mutex; - CRITICAL_SECTION section; - char *fname; -}; - -#endif /* LOCKS_H */ - diff --git a/include/arch/win32/misc.h b/include/arch/win32/misc.h deleted file mode 100644 index bb754bbf62e..00000000000 --- a/include/arch/win32/misc.h +++ /dev/null @@ -1,98 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#ifndef MISC_H -#define MISC_H - -#include "apr.h" -#include "apr_private.h" -#include "apr_general.h" -#include "apr_pools.h" -#include "apr_getopt.h" -#include "apr_thread_proc.h" -#include "apr_errno.h" -#ifdef HAVE_STDLIB_H -#include <stdlib.h> -#endif -#ifdef HAVE_STDIO_H -#include <stdio.h> -#endif -#ifdef HAVE_STRING_H -#include <string.h> -#endif -#ifdef HAVE_SIGNAL_H -#include <signal.h> -#endif -#ifdef HAVE_PTHREAD_H -#include <pthread.h> -#endif - -typedef struct datastruct { - void *data; - char *key; - struct datastruct *next; - struct datastruct *prev; -} datastruct; - -struct ap_other_child_rec_t { - struct ap_other_child_rec_t *next; - int pid; - void (*maintenance) (int, void *, int); - void *data; - int write_fd; -}; - - -#endif /* ! MISC_H */ - diff --git a/include/arch/win32/networkio.h b/include/arch/win32/networkio.h deleted file mode 100644 index 58d82f8b126..00000000000 --- a/include/arch/win32/networkio.h +++ /dev/null @@ -1,83 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#ifndef NETWORK_IO_H -#define NETWORK_IO_H - -#include "apr_network_io.h" -#include "apr_general.h" - -struct ap_socket_t { - ap_pool_t *cntxt; - SOCKET sock; - struct sockaddr_in *local_addr; - struct sockaddr_in *remote_addr; - size_t addr_len; - ap_interval_time_t timeout; -}; - -struct ap_pollfd_t { - ap_pool_t *cntxt; - fd_set *read; - int numread; - fd_set *write; - int numwrite; - fd_set *except; - int numexcept; -}; - -ap_status_t status_from_res_error(int); - -#endif /* ! NETWORK_IO_H */ - diff --git a/include/arch/win32/threadproc.h b/include/arch/win32/threadproc.h deleted file mode 100644 index 16667de67e7..00000000000 --- a/include/arch/win32/threadproc.h +++ /dev/null @@ -1,103 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#include "apr_private.h" -#include "apr_thread_proc.h" -#include "apr_file_io.h" -#include <windows.h> - -#ifndef THREAD_PROC_H -#define THREAD_PROC_H - -#define SHELL_PATH "cmd.exe" - -struct ap_thread_t { - ap_pool_t *cntxt; - HANDLE td; - ap_int32_t cancel; - ap_int32_t cancel_how; -}; - -struct ap_threadattr_t { - ap_pool_t *cntxt; - ap_int32_t detach; -}; - -struct ap_threadkey_t { - ap_pool_t *cntxt; - DWORD key; -}; - -struct ap_procattr_t { - ap_pool_t *cntxt; - STARTUPINFO si; - ap_file_t *parent_in; - ap_file_t *child_in; - ap_file_t *parent_out; - ap_file_t *child_out; - ap_file_t *parent_err; - ap_file_t *child_err; - char *currdir; - ap_int32_t cmdtype; - ap_int32_t detached; -}; - -struct ap_proc_t { - ap_pool_t *cntxt; - PROCESS_INFORMATION pi; - struct ap_procattr_t *attr; -}; - -#endif /* ! THREAD_PROC_H */ - diff --git a/include/private/apr_crypto_internal.h b/include/private/apr_crypto_internal.h new file mode 100644 index 00000000000..1ea838bfb7d --- /dev/null +++ b/include/private/apr_crypto_internal.h @@ -0,0 +1,297 @@ +/* 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. + */ + +#ifndef APR_CRYPTO_INTERNAL_H +#define APR_CRYPTO_INTERNAL_H + +#include <stdarg.h> + +#include "apr_crypto.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if APU_HAVE_CRYPTO + +struct apr_crypto_driver_t { + + /** name */ + const char *name; + + /** + * @brief: allow driver to perform once-only initialisation. + * Called once only. + * @param pool The pool to register the cleanup in. + * @param params Optional init parameter string. + * @param rc Driver-specific additional error code + */ + apr_status_t (*init)(apr_pool_t *pool, const char *params, + const apu_err_t **result); + + /** + * @brief Create a context for supporting encryption. Keys, certificates, + * algorithms and other parameters will be set per context. More than + * one context can be created at one time. A cleanup will be automatically + * registered with the given pool to guarantee a graceful shutdown. + * @param f - context pointer will be written here + * @param provider - provider to use + * @param params - array of key parameters + * @param pool - process pool + * @return APR_ENOENGINE when the engine specified does not exist. APR_EINITENGINE + * if the engine cannot be initialised. + */ + apr_status_t (*make)(apr_crypto_t **f, const apr_crypto_driver_t *provider, + const char *params, apr_pool_t *pool); + + /** + * @brief Get a hash table of key types, keyed by the name of the type against + * a pointer to apr_crypto_block_key_type_t. + * + * @param types - hashtable of key types keyed to constants. + * @param f - encryption context + * @return APR_SUCCESS for success + */ + apr_status_t (*get_block_key_types)(apr_hash_t **types, + const apr_crypto_t *f); + + /** + * @brief Get a hash table of key modes, keyed by the name of the mode against + * a pointer to apr_crypto_block_key_mode_t. + * + * @param modes - hashtable of key modes keyed to constants. + * @param f - encryption context + * @return APR_SUCCESS for success + */ + apr_status_t (*get_block_key_modes)(apr_hash_t **modes, + const apr_crypto_t *f); + + /** + * @brief Create a key from the given passphrase. By default, the PBKDF2 + * algorithm is used to generate the key from the passphrase. It is expected + * that the same pass phrase will generate the same key, regardless of the + * backend crypto platform used. The key is cleaned up when the context + * is cleaned, and may be reused with multiple encryption or decryption + * operations. + * @note If *key is NULL, a apr_crypto_key_t will be created from a pool. If + * *key is not NULL, *key must point at a previously created structure. + * @param key The key returned, see note. + * @param ivSize The size of the initialisation vector will be returned, based + * on whether an IV is relevant for this type of crypto. + * @param pass The passphrase to use. + * @param passLen The passphrase length in bytes + * @param salt The salt to use. + * @param saltLen The salt length in bytes + * @param type 3DES_192, AES_128, AES_192, AES_256. + * @param mode Electronic Code Book / Cipher Block Chaining. + * @param doPad Pad if necessary. + * @param iterations Iteration count + * @param f The context to use. + * @param p The pool to use. + * @return Returns APR_ENOKEY if the pass phrase is missing or empty, or if a backend + * error occurred while generating the key. APR_ENOCIPHER if the type or mode + * is not supported by the particular backend. APR_EKEYTYPE if the key type is + * not known. APR_EPADDING if padding was requested but is not supported. + * APR_ENOTIMPL if not implemented. + */ + apr_status_t (*passphrase)(apr_crypto_key_t **key, apr_size_t *ivSize, + const char *pass, apr_size_t passLen, const unsigned char * salt, + apr_size_t saltLen, const apr_crypto_block_key_type_e type, + const apr_crypto_block_key_mode_e mode, const int doPad, + const int iterations, const apr_crypto_t *f, apr_pool_t *p); + + /** + * @brief Initialise a context for encrypting arbitrary data using the given key. + * @note If *ctx is NULL, a apr_crypto_block_t will be created from a pool. If + * *ctx is not NULL, *ctx must point at a previously created structure. + * @param ctx The block context returned, see note. + * @param iv Optional initialisation vector. If the buffer pointed to is NULL, + * an IV will be created at random, in space allocated from the pool. + * If the buffer pointed to is not NULL, the IV in the buffer will be + * used. + * @param key The key structure. + * @param blockSize The block size of the cipher. + * @param p The pool to use. + * @return Returns APR_ENOIV if an initialisation vector is required but not specified. + * Returns APR_EINIT if the backend failed to initialise the context. Returns + * APR_ENOTIMPL if not implemented. + */ + apr_status_t (*block_encrypt_init)(apr_crypto_block_t **ctx, + const unsigned char **iv, const apr_crypto_key_t *key, + apr_size_t *blockSize, apr_pool_t *p); + + /** + * @brief Encrypt data provided by in, write it to out. + * @note The number of bytes written will be written to outlen. If + * out is NULL, outlen will contain the maximum size of the + * buffer needed to hold the data, including any data + * generated by apr_crypto_block_encrypt_finish below. If *out points + * to NULL, a buffer sufficiently large will be created from + * the pool provided. If *out points to a not-NULL value, this + * value will be used as a buffer instead. + * @param out Address of a buffer to which data will be written, + * see note. + * @param outlen Length of the output will be written here. + * @param in Address of the buffer to read. + * @param inlen Length of the buffer to read. + * @param ctx The block context to use. + * @return APR_ECRYPT if an error occurred. Returns APR_ENOTIMPL if + * not implemented. + */ + apr_status_t (*block_encrypt)(unsigned char **out, apr_size_t *outlen, + const unsigned char *in, apr_size_t inlen, apr_crypto_block_t *ctx); + + /** + * @brief Encrypt final data block, write it to out. + * @note If necessary the final block will be written out after being + * padded. Typically the final block will be written to the + * same buffer used by apr_crypto_block_encrypt, offset by the + * number of bytes returned as actually written by the + * apr_crypto_block_encrypt() call. After this call, the context + * is cleaned and can be reused by apr_crypto_block_encrypt_init(). + * @param out Address of a buffer to which data will be written. This + * buffer must already exist, and is usually the same + * buffer used by apr_evp_crypt(). See note. + * @param outlen Length of the output will be written here. + * @param ctx The block context to use. + * @return APR_ECRYPT if an error occurred. + * @return APR_EPADDING if padding was enabled and the block was incorrectly + * formatted. + * @return APR_ENOTIMPL if not implemented. + */ + apr_status_t (*block_encrypt_finish)(unsigned char *out, + apr_size_t *outlen, apr_crypto_block_t *ctx); + + /** + * @brief Initialise a context for decrypting arbitrary data using the given key. + * @note If *ctx is NULL, a apr_crypto_block_t will be created from a pool. If + * *ctx is not NULL, *ctx must point at a previously created structure. + * @param ctx The block context returned, see note. + * @param blockSize The block size of the cipher. + * @param iv Optional initialisation vector. If the buffer pointed to is NULL, + * an IV will be created at random, in space allocated from the pool. + * If the buffer is not NULL, the IV in the buffer will be used. + * @param key The key structure. + * @param p The pool to use. + * @return Returns APR_ENOIV if an initialisation vector is required but not specified. + * Returns APR_EINIT if the backend failed to initialise the context. Returns + * APR_ENOTIMPL if not implemented. + */ + apr_status_t (*block_decrypt_init)(apr_crypto_block_t **ctx, + apr_size_t *blockSize, const unsigned char *iv, + const apr_crypto_key_t *key, apr_pool_t *p); + + /** + * @brief Decrypt data provided by in, write it to out. + * @note The number of bytes written will be written to outlen. If + * out is NULL, outlen will contain the maximum size of the + * buffer needed to hold the data, including any data + * generated by apr_crypto_block_decrypt_finish below. If *out points + * to NULL, a buffer sufficiently large will be created from + * the pool provided. If *out points to a not-NULL value, this + * value will be used as a buffer instead. + * @param out Address of a buffer to which data will be written, + * see note. + * @param outlen Length of the output will be written here. + * @param in Address of the buffer to read. + * @param inlen Length of the buffer to read. + * @param ctx The block context to use. + * @return APR_ECRYPT if an error occurred. Returns APR_ENOTIMPL if + * not implemented. + */ + apr_status_t (*block_decrypt)(unsigned char **out, apr_size_t *outlen, + const unsigned char *in, apr_size_t inlen, apr_crypto_block_t *ctx); + + /** + * @brief Decrypt final data block, write it to out. + * @note If necessary the final block will be written out after being + * padded. Typically the final block will be written to the + * same buffer used by apr_crypto_block_decrypt, offset by the + * number of bytes returned as actually written by the + * apr_crypto_block_decrypt() call. After this call, the context + * is cleaned and can be reused by apr_crypto_block_decrypt_init(). + * @param out Address of a buffer to which data will be written. This + * buffer must already exist, and is usually the same + * buffer used by apr_evp_crypt(). See note. + * @param outlen Length of the output will be written here. + * @param ctx The block context to use. + * @return APR_ECRYPT if an error occurred. + * @return APR_EPADDING if padding was enabled and the block was incorrectly + * formatted. + * @return APR_ENOTIMPL if not implemented. + */ + apr_status_t (*block_decrypt_finish)(unsigned char *out, + apr_size_t *outlen, apr_crypto_block_t *ctx); + + /** + * @brief Clean encryption / decryption context. + * @note After cleanup, a context is free to be reused if necessary. + * @param ctx The block context to use. + * @return Returns APR_ENOTIMPL if not supported. + */ + apr_status_t (*block_cleanup)(apr_crypto_block_t *ctx); + + /** + * @brief Clean encryption / decryption context. + * @note After cleanup, a context is free to be reused if necessary. + * @param f The context to use. + * @return Returns APR_ENOTIMPL if not supported. + */ + apr_status_t (*cleanup)(apr_crypto_t *f); + + /** + * @brief Clean encryption / decryption context. + * @note After cleanup, a context is free to be reused if necessary. + * @return Returns APR_ENOTIMPL if not supported. + */ + apr_status_t (*shutdown)(void); + + /** + * @brief: fetch the most recent error from this driver. + * @param result - the result structure + * @param f - context pointer + * @return APR_SUCCESS for success. + */ + apr_status_t (*error)(const apu_err_t **result, const apr_crypto_t *f); + + /** + * @brief Create a key from the provided secret or passphrase. The key is cleaned + * up when the context is cleaned, and may be reused with multiple encryption + * or decryption operations. + * @note If *key is NULL, a apr_crypto_key_t will be created from a pool. If + * *key is not NULL, *key must point at a previously created structure. + * @param key The key returned, see note. + * @param rec The key record, from which the key will be derived. + * @param f The context to use. + * @param p The pool to use. + * @return Returns APR_ENOKEY if the pass phrase is missing or empty, or if a backend + * error occurred while generating the key. APR_ENOCIPHER if the type or mode + * is not supported by the particular backend. APR_EKEYTYPE if the key type is + * not known. APR_EPADDING if padding was requested but is not supported. + * APR_ENOTIMPL if not implemented. + */ + apr_status_t (*key)(apr_crypto_key_t **key, const apr_crypto_key_rec_t *rec, + const apr_crypto_t *f, apr_pool_t *p); + +}; + +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/private/apr_dbd_internal.h b/include/private/apr_dbd_internal.h new file mode 100644 index 00000000000..3d50cc603e1 --- /dev/null +++ b/include/private/apr_dbd_internal.h @@ -0,0 +1,365 @@ +/* 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. + */ + +/* Overview of what this is and does: + * http://www.apache.org/~niq/dbd.html + */ + +#ifndef APR_DBD_INTERNAL_H +#define APR_DBD_INTERNAL_H + +#include <stdarg.h> + +#include "apr_dbd.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define TXN_IGNORE_ERRORS(t) \ + ((t) && ((t)->mode & APR_DBD_TRANSACTION_IGNORE_ERRORS)) +#define TXN_NOTICE_ERRORS(t) \ + ((t) && !((t)->mode & APR_DBD_TRANSACTION_IGNORE_ERRORS)) + +#define TXN_DO_COMMIT(t) (!((t)->mode & APR_DBD_TRANSACTION_ROLLBACK)) +#define TXN_DO_ROLLBACK(t) ((t)->mode & APR_DBD_TRANSACTION_ROLLBACK) + +#define TXN_MODE_BITS \ + (APR_DBD_TRANSACTION_ROLLBACK|APR_DBD_TRANSACTION_IGNORE_ERRORS) + +struct apr_dbd_driver_t { + /** name */ + const char *name; + + /** init: allow driver to perform once-only initialisation. + * Called once only. May be NULL + */ + void (*init)(apr_pool_t *pool); + + /** native_handle: return the native database handle of the underlying db + * + * @param handle - apr_dbd handle + * @return - native handle + */ + void *(*native_handle)(apr_dbd_t *handle); + + /** open: obtain a database connection from the server rec. + * Must be explicitly closed when you're finished with it. + * WARNING: only use this when you need a connection with + * a lifetime other than a request + * + * @param pool - a pool to use for error messages (if any). + * @param params - connection parameters. + * @param error - descriptive error. + * @return database handle, or NULL on error. + */ + apr_dbd_t *(*open)(apr_pool_t *pool, const char *params, + const char **error); + + /** check_conn: check status of a database connection + * + * @param pool - a pool to use for error messages (if any). + * @param handle - the connection to check + * @return APR_SUCCESS or error + */ + apr_status_t (*check_conn)(apr_pool_t *pool, apr_dbd_t *handle); + + /** close: close/release a connection obtained from open() + * + * @param handle - the connection to release + * @return APR_SUCCESS or error + */ + apr_status_t (*close)(apr_dbd_t *handle); + + /** set_dbname: select database name. May be a no-op if not supported. + * + * @param pool - working pool + * @param handle - the connection + * @param name - the database to select + * @return 0 for success or error code + */ + int (*set_dbname)(apr_pool_t* pool, apr_dbd_t *handle, const char *name); + + /** transaction: start a transaction. May be a no-op. + * + * @param pool - a pool to use for error messages (if any). + * @param handle - the connection + * @param trans - ptr to a transaction. May be null on entry + * @return 0 for success or error code + */ + int (*start_transaction)(apr_pool_t *pool, apr_dbd_t *handle, + apr_dbd_transaction_t **trans); + + /** end_transaction: end a transaction + * (commit on success, rollback on error). + * May be a no-op. + * + * @param trans - the transaction. + * @return 0 for success or error code + */ + int (*end_transaction)(apr_dbd_transaction_t *trans); + + /** query: execute an SQL query that doesn't return a result set + * + * @param handle - the connection + * @param nrows - number of rows affected. + * @param statement - the SQL statement to execute + * @return 0 for success or error code + */ + int (*query)(apr_dbd_t *handle, int *nrows, const char *statement); + + /** select: execute an SQL query that returns a result set + * + * @param pool - pool to allocate the result set + * @param handle - the connection + * @param res - pointer to result set pointer. May point to NULL on entry + * @param statement - the SQL statement to execute + * @param random - 1 to support random access to results (seek any row); + * 0 to support only looping through results in order + * (async access - faster) + * @return 0 for success or error code + */ + int (*select)(apr_pool_t *pool, apr_dbd_t *handle, apr_dbd_results_t **res, + const char *statement, int random); + + /** num_cols: get the number of columns in a results set + * + * @param res - result set. + * @return number of columns + */ + int (*num_cols)(apr_dbd_results_t *res); + + /** num_tuples: get the number of rows in a results set + * of a synchronous select + * + * @param res - result set. + * @return number of rows, or -1 if the results are asynchronous + */ + int (*num_tuples)(apr_dbd_results_t *res); + + /** get_row: get a row from a result set + * + * @param pool - pool to allocate the row + * @param res - result set pointer + * @param row - pointer to row pointer. May point to NULL on entry + * @param rownum - row number, or -1 for "next row". Ignored if random + * access is not supported. + * @return 0 for success, -1 for rownum out of range or data finished + */ + int (*get_row)(apr_pool_t *pool, apr_dbd_results_t *res, + apr_dbd_row_t **row, int rownum); + + /** get_entry: get an entry from a row + * + * @param row - row pointer + * @param col - entry number + * @param val - entry to fill + * @return 0 for success, -1 for no data, +1 for general error + */ + const char* (*get_entry)(const apr_dbd_row_t *row, int col); + + /** error: get current error message (if any) + * + * @param handle - the connection + * @param errnum - error code from operation that returned an error + * @return the database current error message, or message for errnum + * (implementation-dependent whether errnum is ignored) + */ + const char *(*error)(apr_dbd_t *handle, int errnum); + + /** escape: escape a string so it is safe for use in query/select + * + * @param pool - pool to alloc the result from + * @param string - the string to escape + * @param handle - the connection + * @return the escaped, safe string + */ + const char *(*escape)(apr_pool_t *pool, const char *string, + apr_dbd_t *handle); + + /** prepare: prepare a statement + * + * @param pool - pool to alloc the result from + * @param handle - the connection + * @param query - the SQL query + * @param label - A label for the prepared statement. + * use NULL for temporary prepared statements + * (eg within a Request in httpd) + * @param nargs - number of parameters in the query + * @param nvals - number of values passed in p[b]query/select + * @param types - pointer to an array with types of parameters + * @param statement - statement to prepare. May point to null on entry. + * @return 0 for success or error code + */ + int (*prepare)(apr_pool_t *pool, apr_dbd_t *handle, const char *query, + const char *label, int nargs, int nvals, + apr_dbd_type_e *types, apr_dbd_prepared_t **statement); + + /** pvquery: query using a prepared statement + args + * + * @param pool - working pool + * @param handle - the connection + * @param nrows - number of rows affected. + * @param statement - the prepared statement to execute + * @param args - args to prepared statement + * @return 0 for success or error code + */ + int (*pvquery)(apr_pool_t *pool, apr_dbd_t *handle, int *nrows, + apr_dbd_prepared_t *statement, va_list args); + + /** pvselect: select using a prepared statement + args + * + * @param pool - working pool + * @param handle - the connection + * @param res - pointer to query results. May point to NULL on entry + * @param statement - the prepared statement to execute + * @param random - Whether to support random-access to results + * @param args - args to prepared statement + * @return 0 for success or error code + */ + int (*pvselect)(apr_pool_t *pool, apr_dbd_t *handle, + apr_dbd_results_t **res, + apr_dbd_prepared_t *statement, int random, va_list args); + + /** pquery: query using a prepared statement + args + * + * @param pool - working pool + * @param handle - the connection + * @param nrows - number of rows affected. + * @param statement - the prepared statement to execute + * @param args - args to prepared statement + * @return 0 for success or error code + */ + int (*pquery)(apr_pool_t *pool, apr_dbd_t *handle, int *nrows, + apr_dbd_prepared_t *statement, const char **args); + + /** pselect: select using a prepared statement + args + * + * @param pool - working pool + * @param handle - the connection + * @param res - pointer to query results. May point to NULL on entry + * @param statement - the prepared statement to execute + * @param random - Whether to support random-access to results + * @param args - args to prepared statement + * @return 0 for success or error code + */ + int (*pselect)(apr_pool_t *pool, apr_dbd_t *handle, + apr_dbd_results_t **res, apr_dbd_prepared_t *statement, + int random, const char **args); + + + /** get_name: get a column title from a result set + * + * @param res - result set pointer + * @param col - entry number + * @return param name, or NULL if col is out of bounds. + */ + const char* (*get_name)(const apr_dbd_results_t *res, int col); + + /** transaction_mode_get: get the mode of transaction + * + * @param trans - the transaction. + * @return mode of transaction + */ + int (*transaction_mode_get)(apr_dbd_transaction_t *trans); + + /** transaction_mode_set: get the mode of transaction + * + * @param trans - the transaction. + * @param mode - new mode of the transaction + * @return the mode of transaction in force after the call + */ + int (*transaction_mode_set)(apr_dbd_transaction_t *trans, int mode); + + /** format of prepared statement parameters */ + const char *pformat; + + /** pvbquery: query using a prepared statement + binary args + * + * @param pool - working pool + * @param handle - the connection + * @param nrows - number of rows affected. + * @param statement - the prepared statement to execute + * @param args - binary args to prepared statement + * @return 0 for success or error code + */ + int (*pvbquery)(apr_pool_t *pool, apr_dbd_t *handle, int *nrows, + apr_dbd_prepared_t *statement, va_list args); + + /** pvbselect: select using a prepared statement + binary args + * + * @param pool - working pool + * @param handle - the connection + * @param res - pointer to query results. May point to NULL on entry + * @param statement - the prepared statement to execute + * @param random - Whether to support random-access to results + * @param args - binary args to prepared statement + * @return 0 for success or error code + */ + int (*pvbselect)(apr_pool_t *pool, apr_dbd_t *handle, + apr_dbd_results_t **res, + apr_dbd_prepared_t *statement, int random, va_list args); + + /** pbquery: query using a prepared statement + binary args + * + * @param pool - working pool + * @param handle - the connection + * @param nrows - number of rows affected. + * @param statement - the prepared statement to execute + * @param args - binary args to prepared statement + * @return 0 for success or error code + */ + int (*pbquery)(apr_pool_t *pool, apr_dbd_t *handle, int *nrows, + apr_dbd_prepared_t *statement,const void **args); + + /** pbselect: select using a prepared statement + binary args + * + * @param pool - working pool + * @param handle - the connection + * @param res - pointer to query results. May point to NULL on entry + * @param statement - the prepared statement to execute + * @param random - Whether to support random-access to results + * @param args - binary args to prepared statement + * @return 0 for success or error code + */ + int (*pbselect)(apr_pool_t *pool, apr_dbd_t *handle, + apr_dbd_results_t **res, apr_dbd_prepared_t *statement, + int random, const void **args); + + /** datum_get: get a binary entry from a row + * + * @param row - row pointer + * @param col - entry number + * @param type - type of data to get + * @param data - pointer to data, allocated by the caller + * @return APR_SUCCESS, an error code on error or if col is out of bounds + */ + apr_status_t (*datum_get)(const apr_dbd_row_t *row, int col, + apr_dbd_type_e type, void *data); +}; + +/* Export mutex lock/unlock for drivers that need it + * deprecated; create a per-dbd mutex within the (*init) function + * to avoid blocking other providers running on other threads + */ +APR_DECLARE(apr_status_t) apr_dbd_mutex_lock(void); +APR_DECLARE(apr_status_t) apr_dbd_mutex_unlock(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/private/apr_dbd_odbc_v2.h b/include/private/apr_dbd_odbc_v2.h new file mode 100644 index 00000000000..b8da7b181f9 --- /dev/null +++ b/include/private/apr_dbd_odbc_v2.h @@ -0,0 +1,119 @@ +/* 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. + */ + + +/* ONLY USED FOR ODBC Version 2 -DODBCV2 +* +* Re-define everything to work (more-or-less) in an ODBC V2 environment +* Random access to retrieved rows is not supported - i.e. calls to apr_dbd_select() cannot +* have a 'random' argument of 1. apr_dbd_get_row() must always pass rownum as 0 (get next row) +* +*/ + +#define SQLHANDLE SQLHENV /* Presumes that ENV, DBC, and STMT handles are all the same datatype */ +#define SQL_NULL_HANDLE 0 +#define SQL_HANDLE_STMT 1 +#define SQL_HANDLE_DBC 2 +#define SQL_HANDLE_ENV 3 +#define SQL_NO_DATA SQL_NO_DATA_FOUND + +#ifndef SQL_SUCCEEDED +#define SQL_SUCCEEDED(rc) (((rc)&(~1))==0) +#endif + +#undef SQLSetEnvAttr +#define SQLSetEnvAttr(henv, Attribute, Value, StringLength) (0) + +#undef SQLAllocHandle +#define SQLAllocHandle(type, parent, hndl) \ +( (type == SQL_HANDLE_STMT) ? SQLAllocStmt(parent, hndl) \ + : (type == SQL_HANDLE_ENV) ? SQLAllocEnv(hndl) \ + : SQLAllocConnect(parent, hndl) \ +) + +#undef SQLFreeHandle +#define SQLFreeHandle(type, hndl) \ +( (type == SQL_HANDLE_STMT) ? SQLFreeStmt(hndl, SQL_DROP) \ + : (type == SQL_HANDLE_ENV) ? SQLFreeEnv(hndl) \ + : SQLFreeConnect(hndl) \ +) + +#undef SQLGetDiagRec +#define SQLGetDiagRec(type, h, i, state, native, buffer, bufsize, reslen) \ + SQLError( (type == SQL_HANDLE_ENV) ? h : NULL, \ + (type == SQL_HANDLE_DBC) ? h : NULL, \ + (type == SQL_HANDLE_STMT) ? h : NULL, \ + state, native, buffer, bufsize, reslen) + +#undef SQLCloseCursor +#define SQLCloseCursor(stmt) SQLFreeStmt(stmt, SQL_CLOSE) + +#undef SQLGetConnectAttr +#define SQLGetConnectAttr(hdbc, fOption, ValuePtr, BufferLength, NULL) \ + SQLGetConnectOption(hdbc, fOption, ValuePtr) + +#undef SQLSetConnectAttr +#define SQLSetConnectAttr(hdbc, fOption, ValuePtr, BufferLength) \ + SQLSetConnectOption(hdbc, fOption, (SQLUINTEGER) ValuePtr) + +#undef SQLSetStmtAttr +#define SQLSetStmtAttr(hstmt, fOption, ValuePtr, BufferLength) (0); return APR_ENOTIMPL; + +#undef SQLEndTran +#define SQLEndTran(hType, hdbc,type) SQLTransact(henv, hdbc, type) + +#undef SQLFetchScroll +#define SQLFetchScroll(stmt, orient, rownum) (0); return APR_ENOTIMPL; + +#define SQL_DESC_TYPE SQL_COLUMN_TYPE +#define SQL_DESC_CONCISE_TYPE SQL_COLUMN_TYPE +#define SQL_DESC_DISPLAY_SIZE SQL_COLUMN_DISPLAY_SIZE +#define SQL_DESC_OCTET_LENGTH SQL_COLUMN_LENGTH +#define SQL_DESC_UNSIGNED SQL_COLUMN_UNSIGNED + +#undef SQLColAttribute +#define SQLColAttribute(s, c, f, a, l, m, n) SQLColAttributes(s, c, f, a, l, m, n) + +#define SQL_ATTR_ACCESS_MODE SQL_ACCESS_MODE +#define SQL_ATTR_AUTOCOMMIT SQL_AUTOCOMMIT +#define SQL_ATTR_CONNECTION_TIMEOUT 113 +#define SQL_ATTR_CURRENT_CATALOG SQL_CURRENT_QUALIFIER +#define SQL_ATTR_DISCONNECT_BEHAVIOR 114 +#define SQL_ATTR_ENLIST_IN_DTC 1207 +#define SQL_ATTR_ENLIST_IN_XA 1208 + +#define SQL_ATTR_CONNECTION_DEAD 1209 +#define SQL_CD_TRUE 1L /* Connection is closed/dead */ +#define SQL_CD_FALSE 0L /* Connection is open/available */ + +#define SQL_ATTR_LOGIN_TIMEOUT SQL_LOGIN_TIMEOUT +#define SQL_ATTR_ODBC_CURSORS SQL_ODBC_CURSORS +#define SQL_ATTR_PACKET_SIZE SQL_PACKET_SIZE +#define SQL_ATTR_QUIET_MODE SQL_QUIET_MODE +#define SQL_ATTR_TRACE SQL_OPT_TRACE +#define SQL_ATTR_TRACEFILE SQL_OPT_TRACEFILE +#define SQL_ATTR_TRANSLATE_LIB SQL_TRANSLATE_DLL +#define SQL_ATTR_TRANSLATE_OPTION SQL_TRANSLATE_OPTION +#define SQL_ATTR_TXN_ISOLATION SQL_TXN_ISOLATION + +#define SQL_ATTR_CURSOR_SCROLLABLE -1 + +#define SQL_C_SBIGINT (SQL_BIGINT+SQL_SIGNED_OFFSET) /* SIGNED BIGINT */ +#define SQL_C_UBIGINT (SQL_BIGINT+SQL_UNSIGNED_OFFSET) /* UNSIGNED BIGINT */ + +#define SQL_FALSE 0 +#define SQL_TRUE 1 + diff --git a/include/private/apr_dbm_private.h b/include/private/apr_dbm_private.h new file mode 100644 index 00000000000..1844435f20d --- /dev/null +++ b/include/private/apr_dbm_private.h @@ -0,0 +1,121 @@ +/* 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. + */ + +#ifndef APR_DBM_PRIVATE_H +#define APR_DBM_PRIVATE_H + +#include "apr.h" +#include "apr_errno.h" +#include "apr_pools.h" +#include "apr_dbm.h" +#include "apr_file_io.h" + +#include "apu.h" + +/* ### for now, include the DBM selection; this will go away once we start + ### building and linking all of the DBMs at once. */ +#include "apu_select_dbm.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** @internal */ + +/** + * Most DBM libraries take a POSIX mode for creating files. Don't trust + * the mode_t type, some platforms may not support it, int is safe. + */ +APR_DECLARE(int) apr_posix_perms2mode(apr_fileperms_t perm); + +/** + * Structure to describe the operations of the DBM + */ +typedef struct { + /** The name of the DBM Type */ + const char *name; + + /** Open the DBM */ + apr_status_t (*open)(apr_dbm_t **pdb, const char *pathname, + apr_int32_t mode, apr_fileperms_t perm, + apr_pool_t *pool); + + /** Close the DBM */ + void (*close)(apr_dbm_t *dbm); + + /** Fetch a dbm record value by key */ + apr_status_t (*fetch)(apr_dbm_t *dbm, apr_datum_t key, + apr_datum_t * pvalue); + + /** Store a dbm record value by key */ + apr_status_t (*store)(apr_dbm_t *dbm, apr_datum_t key, apr_datum_t value); + + /** Delete a dbm record value by key */ + apr_status_t (*del)(apr_dbm_t *dbm, apr_datum_t key); + + /** Search for a key within the dbm */ + int (*exists)(apr_dbm_t *dbm, apr_datum_t key); + + /** Retrieve the first record key from a dbm */ + apr_status_t (*firstkey)(apr_dbm_t *dbm, apr_datum_t * pkey); + + /** Retrieve the next record key from a dbm */ + apr_status_t (*nextkey)(apr_dbm_t *dbm, apr_datum_t * pkey); + + /** Proactively toss any memory associated with the apr_datum_t. */ + void (*freedatum)(apr_dbm_t *dbm, apr_datum_t data); + + /** Get the names that the DBM will use for a given pathname. */ + void (*getusednames)(apr_pool_t *pool, + const char *pathname, + const char **used1, + const char **used2); + +} apr_dbm_type_t; + + +/** + * The actual DBM + */ +struct apr_dbm_t +{ + /** Associated pool */ + apr_pool_t *pool; + + /** pointer to DB Implementation Specific data */ + void *file; + + /** Current integer error code */ + int errcode; + /** Current string error code */ + const char *errmsg; + + /** the type of DBM */ + const apr_dbm_type_t *type; +}; + + +/* Declare all of the DBM provider tables */ +APR_MODULE_DECLARE_DATA extern const apr_dbm_type_t apr_dbm_type_sdbm; +APR_MODULE_DECLARE_DATA extern const apr_dbm_type_t apr_dbm_type_gdbm; +APR_MODULE_DECLARE_DATA extern const apr_dbm_type_t apr_dbm_type_ndbm; +APR_MODULE_DECLARE_DATA extern const apr_dbm_type_t apr_dbm_type_db; + +#ifdef __cplusplus +} +#endif + +#endif /* APR_DBM_PRIVATE_H */ diff --git a/include/private/apr_support.h b/include/private/apr_support.h new file mode 100644 index 00000000000..90491ec7604 --- /dev/null +++ b/include/private/apr_support.h @@ -0,0 +1,77 @@ +/* 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. + */ + +#ifndef APR_SUPPORT_H +#define APR_SUPPORT_H + +/** + * @file apr_support.h + * @brief APR Support functions + */ + +#include "apr.h" +#include "apr_network_io.h" +#include "apr_file_io.h" +#include "apr_private.h" + +#if HAVE_VALGRIND +#include <valgrind.h> +#include <memcheck.h> + +extern int apr_running_on_valgrind; + +#define APR_IF_VALGRIND(x) \ + do { if (apr_running_on_valgrind) { x; } } while (0) + +#else +#define APR_IF_VALGRIND(x) +#endif /* HAVE_VALGRIND */ + +#define APR_VALGRIND_NOACCESS(addr_, size_) \ + APR_IF_VALGRIND(VALGRIND_MAKE_MEM_NOACCESS(addr_, size_)) +#define APR_VALGRIND_UNDEFINED(addr_, size_) \ + APR_IF_VALGRIND(VALGRIND_MAKE_MEM_UNDEFINED(addr_, size_)) + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup apr_support Internal APR support functions + * @ingroup APR + * @{ + */ + +/** + * Wait for IO to occur or timeout. + * + * @param f The file to wait on. + * @param s The socket to wait on if @a f is @c NULL. + * @param for_read If non-zero wait for data to be available to read, + * otherwise wait for data to be able to be written. + * @return APR_TIMEUP if we run out of time. + */ +apr_status_t apr_wait_for_io_or_timeout(apr_file_t *f, apr_socket_t *s, + int for_read); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* ! APR_SUPPORT_H */ diff --git a/include/private/apu_internal.h b/include/private/apu_internal.h new file mode 100644 index 00000000000..21075c5c4a4 --- /dev/null +++ b/include/private/apu_internal.h @@ -0,0 +1,51 @@ +/* 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_dso.h" +#include "apu.h" + +#ifndef APU_INTERNAL_H +#define APU_INTERNAL_H + +#if APR_HAVE_MODULAR_DSO + +#ifdef __cplusplus +extern "C" { +#endif + +/* For modular dso loading, an internal interlock to allow us to + * continue to initialize modules by multiple threads, the caller + * of apu_dso_load must lock first, and not unlock until any init + * finalization is complete. + */ +apr_status_t apu_dso_init(apr_pool_t *pool); + +apr_status_t apu_dso_mutex_lock(void); +apr_status_t apu_dso_mutex_unlock(void); + +apr_status_t apu_dso_load(apr_dso_handle_t **dso, apr_dso_handle_sym_t *dsoptr, + const char *module, const char *modsym, + apr_pool_t *pool); + +#ifdef __cplusplus +} +#endif + +#endif /* APR_HAVE_MODULAR_DSO */ + +#endif /* APU_INTERNAL_H */ + diff --git a/include/private/apu_select_dbm.h.in b/include/private/apu_select_dbm.h.in new file mode 100644 index 00000000000..b69aec032cd --- /dev/null +++ b/include/private/apu_select_dbm.h.in @@ -0,0 +1,28 @@ +/* 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. + */ + +#ifndef APU_SELECT_DBM_H +#define APU_SELECT_DBM_H + +/* +** The following macros control what features APRUTIL will use +*/ +#define APU_USE_SDBM @apu_use_sdbm@ +#define APU_USE_NDBM @apu_use_ndbm@ +#define APU_USE_GDBM @apu_use_gdbm@ +#define APU_USE_DB @apu_use_db@ + +#endif /* !APU_SELECT_DBM_H */ diff --git a/include/private/apu_select_dbm.hw b/include/private/apu_select_dbm.hw new file mode 100644 index 00000000000..97c7b6c22ba --- /dev/null +++ b/include/private/apu_select_dbm.hw @@ -0,0 +1,28 @@ +/* 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. + */ + +#ifndef APU_SELECT_DBM_H +#define APU_SELECT_DBM_H + +/* +** The following macros control what features APRUTIL will use +*/ +#define APU_USE_SDBM 1 +#define APU_USE_GDBM 0 +#define APU_USE_NDBM 0 +#define APU_USE_DB 0 + +#endif /* !APU_SELECT_DBM_H */ diff --git a/lib/.cvsignore b/lib/.cvsignore deleted file mode 100644 index f3c7a7c5da6..00000000000 --- a/lib/.cvsignore +++ /dev/null @@ -1 +0,0 @@ -Makefile diff --git a/lib/Makefile.in b/lib/Makefile.in deleted file mode 100644 index 183a3293264..00000000000 --- a/lib/Makefile.in +++ /dev/null @@ -1,101 +0,0 @@ -#CFLAGS=$(OPTIM) $(CFLAGS1) $(EXTRA_CFLAGS) -#LIBS=$(EXTRA_LIBS) $(LIBS1) -#INCLUDES=$(INCLUDES1) $(INCLUDES0) $(EXTRA_INCLUDES) -#LDFLAGS=$(LDFLAGS1) $(EXTRA_LDFLAGS) - -CC=@CC@ -RANLIB=@RANLIB@ -AR=@AR@ -RM=@RM@ -CFLAGS=@CFLAGS@ @OPTIM@ -LIBS=@LIBS@ -LDFLAGS=@LDFLAGS@ $(LIBS) -INCDIR=../include -INCDIR1=../misc/@OSDIR@ -INCLUDES=-I$(INCDIR) -I$(INCDIR1) - -#LIB=@LIBPREFIX@apr.a - -OBJS=apr_cpystrn.o \ - apr_fnmatch.o \ - apr_execve.o \ - apr_md5.o \ - apr_pools.o \ - apr_signal.o \ - apr_snprintf.o \ - apr_tables.o \ - apr_getpass.o \ - apr_strnatcmp.o - -.c.o: - $(CC) $(CFLAGS) -c $(INCLUDES) $< - -all: $(OBJS) - -clean: - $(RM) -f *.o *.a *.so - -distclean: clean - -$(RM) -f Makefile - -$(OBJS): Makefile - -#$(LIB): $(OBJS) -# $(RM) -f $@ -# $(AR) cr $@ $(OBJS) -# $(RANLIB) $@ - -# -# We really don't expect end users to use this rule. It works only with -# gcc, and rebuilds Makefile.tmpl. You have to re-run Configure after -# using it. -# -depend: - cp Makefile.in Makefile.in.bak \ - && sed -ne '1,/^# DO NOT REMOVE/p' Makefile.in > Makefile.new \ - && gcc -MM $(INCLUDES) $(CFLAGS) *.c >> Makefile.new \ - && sed -e '1,$$s: $(INCDIR)/: $$(INCDIR)/:g' \ - -e '1,$$s: $(OSDIR)/: $$(OSDIR)/:g' Makefile.new \ - > Makefile.in \ - && rm Makefile.new - -# DO NOT REMOVE -apr_cpystrn.o: apr_cpystrn.c $(INCDIR)/apr_private.h \ - $(INCDIR)/apr_lib.h $(INCDIR)/apr_general.h $(INCDIR)/apr.h \ - $(INCDIR)/apr_errno.h $(INCDIR)/apr_file_io.h $(INCDIR)/apr_time.h \ - $(INCDIR)/apr_thread_proc.h -apr_execve.o: apr_execve.c $(INCDIR)/apr_private.h -apr_fnmatch.o: apr_fnmatch.c $(INCDIR)/apr_private.h \ - $(INCDIR)/apr_fnmatch.h $(INCDIR)/apr_errno.h $(INCDIR)/apr.h \ - $(INCDIR)/apr_lib.h $(INCDIR)/apr_general.h \ - $(INCDIR)/apr_file_io.h $(INCDIR)/apr_time.h \ - $(INCDIR)/apr_thread_proc.h -apr_getpass.o: apr_getpass.c $(INCDIR)/apr_private.h \ - $(INCDIR)/apr_lib.h $(INCDIR)/apr_general.h $(INCDIR)/apr.h \ - $(INCDIR)/apr_errno.h $(INCDIR)/apr_file_io.h $(INCDIR)/apr_time.h \ - $(INCDIR)/apr_thread_proc.h -apr_md5.o: apr_md5.c $(INCDIR)/apr_private.h $(INCDIR)/apr_md5.h \ - $(INCDIR)/apr_lib.h $(INCDIR)/apr_general.h $(INCDIR)/apr.h \ - $(INCDIR)/apr_errno.h $(INCDIR)/apr_file_io.h $(INCDIR)/apr_time.h \ - $(INCDIR)/apr_thread_proc.h -apr_pools.o: apr_pools.c $(INCDIR)/apr_private.h \ - $(INCDIR)/apr_portable.h $(INCDIR)/apr_general.h $(INCDIR)/apr.h \ - $(INCDIR)/apr_errno.h $(INCDIR)/apr_thread_proc.h \ - $(INCDIR)/apr_file_io.h $(INCDIR)/apr_time.h \ - $(INCDIR)/apr_network_io.h $(INCDIR)/apr_lock.h \ - $(INCDIR)/apr_pools.h $(INCDIR)/apr_lib.h ../misc/unix/misc.h \ - $(INCDIR)/apr_getopt.h -apr_signal.o: apr_signal.c $(INCDIR)/apr_private.h \ - $(INCDIR)/apr_lib.h $(INCDIR)/apr_general.h $(INCDIR)/apr.h \ - $(INCDIR)/apr_errno.h $(INCDIR)/apr_file_io.h $(INCDIR)/apr_time.h \ - $(INCDIR)/apr_thread_proc.h -apr_snprintf.o: apr_snprintf.c $(INCDIR)/apr_private.h \ - $(INCDIR)/apr_lib.h $(INCDIR)/apr_general.h $(INCDIR)/apr.h \ - $(INCDIR)/apr_errno.h $(INCDIR)/apr_file_io.h $(INCDIR)/apr_time.h \ - $(INCDIR)/apr_thread_proc.h -apr_strnatcmp.o: apr_strnatcmp.c $(INCDIR)/apr_strnatcmp.h -apr_tables.o: apr_tables.c $(INCDIR)/apr_private.h \ - $(INCDIR)/apr_general.h $(INCDIR)/apr.h $(INCDIR)/apr_errno.h \ - $(INCDIR)/apr_pools.h $(INCDIR)/apr_lib.h $(INCDIR)/apr_file_io.h \ - $(INCDIR)/apr_time.h $(INCDIR)/apr_thread_proc.h \ - ../misc/unix/misc.h $(INCDIR)/apr_getopt.h diff --git a/lib/apr_cpystrn.c b/lib/apr_cpystrn.c deleted file mode 100644 index 7dbb615a9ae..00000000000 --- a/lib/apr_cpystrn.c +++ /dev/null @@ -1,241 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#include "apr_private.h" -#include "apr_lib.h" - -#if HAVE_SYS_TYPES_H -#include <sys/types.h> -#endif -#if HAVE_STRING_H -#include <string.h> -#endif -#if HAVE_CTYPE_H -#include <ctype.h> -#endif - -/* - * Apache's "replacement" for the strncpy() function. We roll our - * own to implement these specific changes: - * (1) strncpy() doesn't always null terminate and we want it to. - * (2) strncpy() null fills, which is bogus, esp. when copy 8byte - * strings into 8k blocks. - * (3) Instead of returning the pointer to the beginning of - * the destination string, we return a pointer to the - * terminating '\0' to allow us to "check" for truncation - * - * ap_cpystrn() follows the same call structure as strncpy(). - */ - -API_EXPORT(char *) ap_cpystrn(char *dst, const char *src, size_t dst_size) -{ - - char *d, *end; - - if (dst_size == 0) { - return (dst); - } - - d = dst; - end = dst + dst_size - 1; - - for (; d < end; ++d, ++src) { - if (!(*d = *src)) { - return (d); - } - } - - *d = '\0'; /* always null terminate */ - - return (d); -} - - -/* - * This function provides a way to parse a generic argument string - * into a standard argv[] form of argument list. It respects the - * usual "whitespace" and quoteing rules. In the future this could - * be expanded to include support for the ap_call_exec command line - * string processing (including converting '+' to ' ' and doing the - * url processing. It does not currently support this function. - * - * token_context: Context from which pool allocations will occur. - * arg_str: Input argument string for conversion to argv[]. - * argv_out: Output location. This is a pointer to an array - * of pointers to strings (ie. &(char *argv[]). - * This value will be allocated from the contexts - * pool and filled in with copies of the tokens - * found during parsing of the arg_str. - */ -API_EXPORT(ap_status_t) ap_tokenize_to_argv(char *arg_str, char ***argv_out, - ap_pool_t *token_context) -{ - char *cp, *tmpCnt; - int isquoted, numargs = 0, rc = APR_SUCCESS; - -#define SKIP_WHITESPACE(cp) \ - for ( ; *cp == ' ' || *cp == '\t'; ) { \ - cp++; \ - }; - -#define CHECK_QUOTATION(cp,isquoted) \ - isquoted = 0; \ - if (*cp == '"') { \ - isquoted = 1; \ - cp++; \ - } - -/* DETERMINE_NEXTSTRING: - * At exit, cp will point to one of the following: NULL, SPACE, TAB or QUOTE. - * NULL implies the argument string has been fully traversed. - */ -#define DETERMINE_NEXTSTRING(cp,isquoted) \ - for ( ; *cp != '\0'; cp++) { \ - if ( (isquoted && (*cp == ' ' || *cp == '\t')) \ - || (*cp == '\\' && (*(cp+1) == ' ' || *(cp+1) == '\t'))) { \ - cp++; \ - continue; \ - } \ - if ( (!isquoted && (*cp == ' ' || *cp == '\t')) \ - || (isquoted && *cp == '"') ) { \ - break; \ - } \ - } - - cp = arg_str; - SKIP_WHITESPACE(cp); - tmpCnt = cp; - - /* This is ugly and expensive, but if anyone wants to figure a - * way to support any number of args without counting and - * allocating, please go ahead and change the code. - */ - while (*tmpCnt != '\0') { - CHECK_QUOTATION(tmpCnt, isquoted); - DETERMINE_NEXTSTRING(tmpCnt, isquoted); - numargs++; - SKIP_WHITESPACE(tmpCnt); - } - - *argv_out = ap_palloc(token_context, numargs*sizeof(char*)); - if (*argv_out == NULL) { - return (APR_ENOMEM); - } - - /* determine first argument */ - numargs = 0; - while (*cp != '\0') { - CHECK_QUOTATION(cp, isquoted); - tmpCnt = cp; - DETERMINE_NEXTSTRING(cp, isquoted); - if (*cp == '\0') { - (*argv_out)[numargs] = ap_pstrdup(token_context, tmpCnt); - numargs++; - (*argv_out)[numargs] = '\0'; - break; - } - else { - *cp++ = '\0'; - (*argv_out)[numargs] = ap_pstrdup(token_context, tmpCnt); - numargs++; - } - - SKIP_WHITESPACE(cp); - } - - return(rc); -} - -/* Filename_of_pathname returns the final element of the pathname. - * Using the current platform's filename syntax. - * "/foo/bar/gum" -> "gum" - * "/foo/bar/gum/" -> "" - * "gum" -> "gum" - * "wi\\n32\\stuff" -> "stuff - * - * Corrected Win32 to accept "a/b\\stuff", "a:stuff" - */ - -const char *ap_filename_of_pathname(const char *pathname) -{ - const char path_separator = '/'; - const char *s = strrchr(pathname, path_separator); - -#ifdef WIN32 - const char path_separator_win = '\\'; - const char drive_separator_win = ':'; - const char *s2 = strrchr(pathname, path_separator_win); - - if (s2 > s) s = s2; - - if (!s) s = strrchr(pathname, drive_separator_win); -#endif - - return s ? ++s : pathname; -} - -/* length of dest assumed >= length of src - * collapse in place (src == dest) is legal. - * returns terminating null ptr to dest string. - */ -API_EXPORT(char *) ap_collapse_spaces(char *dest, const char *src) -{ - while (*src) { - if (!ap_isspace(*src)) - *dest++ = *src; - ++src; - } - *dest = 0; - return (dest); -} diff --git a/lib/apr_execve.c b/lib/apr_execve.c deleted file mode 100644 index d972a182148..00000000000 --- a/lib/apr_execve.c +++ /dev/null @@ -1,386 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -/* - * Portions of this code are under this license: - * - * Copyright (c) 1980, 1991 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. - */ -#ifndef WIN32 -#include "apr_private.h" -#endif -/*---------------------------------------------------------------*/ - -#ifdef NEED_HASHBANG_EMUL - -#undef execle -#undef execve - -static const char **hashbang(const char *filename, char * const *argv); - - -/* Historically, a list of arguments on the stack was often treated as - * being equivalent to an array (since they already were "contiguous" - * on the stack, and the arguments were pushed in the correct order). - * On today's processors, this is not necessarily equivalent, because - * often arguments are padded or passed partially in registers, - * or the stack direction is backwards. - * To be on the safe side, we copy the argument list to our own - * local argv[] array. The va_arg logic makes sure we do the right thing. - * XXX: malloc() is used because we expect to be overlaid soon. - */ -APR_EXPORT_NONSTD(ap_status_t) ap_execle(const char *filename, - const char *argv0, ...) -{ - va_list adummy; - char **envp; - char **argv; - int argc, ret; - - /* First pass: Count arguments on stack */ - va_start(adummy, argv0); - for (argc = 1; va_arg(adummy, char *) != NULL; ++argc) { - continue; - } - va_end(adummy); - - if ((argv = (char **) malloc((argc + 2) * sizeof(*argv))) == NULL) { - return APR_ENOMEM; - } - - /* Pass two --- copy the argument strings into the result space */ - va_start(adummy, argv0); - argv[0] = (char *)argv0; - for (argc = 1; (argv[argc] = va_arg(adummy, char *)) != NULL; ++argc) { - continue; - } - envp = va_arg(adummy, char **); - va_end(adummy); - - ap_execve(filename, argv, envp); - ret = errno; - free(argv); - - return ret; -} - -/* Count number of entries in vector "args", including the trailing NULL entry - */ -static int -count_args(char * const *args) -{ - int i; - for (i = 0; args[i] != NULL; ++i) { - continue; - } - return i+1; -} - -/* Emulate the execve call, respecting a #!/interpreter line if present. - * On "real" unixes, the kernel does this. - * We have to fiddle with the argv array to make it work on platforms - * which don't support the "hashbang" interpreter line by default. - */ -APR_EXPORT(ap_status_t) ap_execve(const char *filename, char * const argv[], - char * const envp[]) -{ - char **script_argv; - extern char **environ; - - if (envp == NULL) { - envp = (char * const *) environ; - } - - /* Try to execute the file directly first: */ - execve(filename, argv, envp); - - /* Still with us? Then something went seriously wrong. - * From the (linux) man page: - * EACCES The file is not a regular file. - * EACCES Execute permission is denied for the file. - * EACCES Search permission is denied on a component of the path prefix. - * EPERM The file system is mounted noexec. - * EPERM The file system is mounted nosuid and the file has an SUID - * or SGID bit set. - * E2BIG The argument list is too big. - * ENOEXEC The magic number in the file is incorrect. - * EFAULT filename points outside your accessible address space. - * ENAMETOOLONG filename is too long. - * ENOENT The file does not exist. - * ENOMEM Insufficient kernel memory was available. - * ENOTDIR A component of the path prefix is not a directory. - * ELOOP filename contains a circular reference (i.e., via a symbolic link) - */ - - if (errno == ENOEXEC) { - /* Probably a script. - * Have a look; if there's a "#!" header then try to emulate - * the feature found in all modern OS's: - * Interpret the line following the #! as a command line - * in shell style. - */ - if ((script_argv = (char **)hashbang(filename, argv)) != NULL) { - - /* new filename is the interpreter to call */ - filename = script_argv[0]; - - /* Restore argv[0] as on entry */ - if (argv[0] != NULL) { - script_argv[0] = argv[0]; - } - - execve(filename, script_argv, envp); - - free(script_argv); - } - /* - * Script doesn't start with a hashbang line! - * So, try to have the default shell execute it. - * For this, the size of argv must be increased by one - * entry: the shell's name. The remaining args are appended. - */ - else { - int i = count_args(argv) + 1; /* +1 for leading SHELL_PATH */ - - if ((script_argv = malloc(sizeof(*script_argv) * i)) == NULL) { - return APR_ENOMEM; - } - - script_argv[0] = SHELL_PATH; - - while (i > 0) { - script_argv[i] = argv[i-1]; - --i; - } - - execve(SHELL_PATH, script_argv, envp); - - free(script_argv); - } - } - return errno; -} - -/*---------------------------------------------------------------*/ - -/* - * From: peter@zeus.dialix.oz.au (Peter Wemm) - * (taken from tcsh) - * If exec() fails look first for a #! [word] [word] .... - * If it is, splice the header into the argument list and retry. - * Return value: the original argv array (sans argv[0]), with the - * script's argument list prepended. - * XXX: malloc() is used so that everything can be free()ed after a failure. - */ -#define HACKBUFSZ 1024 /* Max chars in #! vector */ -#define HACKVECSZ 128 /* Max words in #! vector */ -static const char **hashbang(const char *filename, char * const *argv) -{ - char lbuf[HACKBUFSZ]; - char *sargv[HACKVECSZ]; - const char **newargv; - char *p, *ws; - int fd; - int sargc = 0; - int i, j; -#ifdef WIN32 - int fw = 0; /* found at least one word */ - int first_word = 0; -#endif /* WIN32 */ - - if ((fd = open(filename, O_RDONLY)) == -1) { - return NULL; - } - - if (read(fd, (char *) lbuf, 2) != 2 - || lbuf[0] != '#' || lbuf[1] != '!' - || read(fd, (char *) lbuf, HACKBUFSZ) <= 0) { - close(fd); - return NULL; - } - - close(fd); - - ws = NULL; /* word started = 0 */ - - for (p = lbuf; p < &lbuf[HACKBUFSZ];) { - switch (*p) { - case ' ': - case '\t': -#ifdef NEW_CRLF - case '\r': -#endif /*NEW_CRLF */ - if (ws) { /* a blank after a word.. save it */ - *p = '\0'; -#ifndef WIN32 - if (sargc < HACKVECSZ - 1) { - sargv[sargc++] = ws; - } - ws = NULL; -#else /* WIN32 */ - if (sargc < HACKVECSZ - 1) { - sargv[sargc] = first_word ? NULL : hb_subst(ws); - if (sargv[sargc] == NULL) { - sargv[sargc] = ws; - } - sargc++; - } - ws = NULL; - fw = 1; - first_word = 1; -#endif /* WIN32 */ - } - p++; - continue; - - case '\0': /* Whoa!! what the hell happened */ - return NULL; - - case '\n': /* The end of the line. */ - if ( -#ifdef WIN32 - fw || -#endif /* WIN32 */ - ws) { /* terminate the last word */ - *p = '\0'; -#ifndef WIN32 - if (sargc < HACKVECSZ - 1) { - sargv[sargc++] = ws; - } -#else /* WIN32 */ - if (sargc < HACKVECSZ - 1) { /* deal with the 1-word case */ - sargv[sargc] = first_word ? NULL : hb_subst(ws); - if (sargv[sargc] == NULL) { - sargv[sargc] = ws; - } - sargc++; - } -#endif /* !WIN32 */ - sargv[sargc] = NULL; - } - /* Count number of entries in the old argv vector */ - for (i = 0; argv[i] != NULL; ++i) { - continue; - } - ++i; - - newargv = (const char **) malloc((p - lbuf + 1) - + (i + sargc + 1) * sizeof(*newargv)); - if (newargv == NULL) { - return NULL; - } - ws = &((char *) newargv)[(i + sargc + 1) * sizeof(*newargv)]; - - /* Copy entries to allocated memory */ - for (j = 0; j < sargc; ++j) { - newargv[j] = strcpy(ws, sargv[j]); - ws += strlen(ws) + 1; /* skip trailing '\0' */ - } - newargv[sargc] = filename; - - /* Append the old array. The old argv[0] is skipped. */ - if (i > 1) { - memcpy(&newargv[sargc + 1], &argv[1], - (i - 1) * sizeof(*newargv)); - } - - newargv[sargc + i] = NULL; - - ws = NULL; - - return newargv; - - default: - if (!ws) { /* Start a new word? */ - ws = p; - } - p++; - break; - } - } - return NULL; -} -#else -extern void ap_execve_is_not_here(void); -void ap_execve_is_not_here(void) {} -#endif /* NEED_HASHBANG_EMUL */ diff --git a/lib/apr_fnmatch.c b/lib/apr_fnmatch.c deleted file mode 100644 index 9936917b53f..00000000000 --- a/lib/apr_fnmatch.c +++ /dev/null @@ -1,243 +0,0 @@ -/* - * Copyright (c) 1989, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Guido van Rossum. - * - * 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. - */ - -#if defined(LIBC_SCCS) && !defined(lint) -static char sccsid[] = "@(#)fnmatch.c 8.2 (Berkeley) 4/16/94"; -#endif /* LIBC_SCCS and not lint */ - -/* - * Function fnmatch() as specified in POSIX 1003.2-1992, section B.6. - * Compares a filename or pathname to a pattern. - */ -#ifndef WIN32 -#include "apr_private.h" -#endif -#include "apr_fnmatch.h" -#include "apr_lib.h" -#include <string.h> -#ifdef HAVE_CTYPE_H -# include <ctype.h> -#endif - -#define EOS '\0' - -static const char *rangematch(const char *, int, int); - -API_EXPORT(ap_status_t) ap_fnmatch(const char *pattern, const char *string, int flags) -{ - const char *stringstart; - char c, test; - - for (stringstart = string;;) { - switch (c = *pattern++) { - case EOS: - return (*string == EOS ? APR_SUCCESS : FNM_NOMATCH); - case '?': - if (*string == EOS) { - return (FNM_NOMATCH); - } - if (*string == '/' && (flags & FNM_PATHNAME)) { - return (FNM_NOMATCH); - } - if (*string == '.' && (flags & FNM_PERIOD) && - (string == stringstart || - ((flags & FNM_PATHNAME) && *(string - 1) == '/'))) { - return (FNM_NOMATCH); - } - ++string; - break; - case '*': - c = *pattern; - /* Collapse multiple stars. */ - while (c == '*') { - c = *++pattern; - } - - if (*string == '.' && (flags & FNM_PERIOD) && - (string == stringstart || - ((flags & FNM_PATHNAME) && *(string - 1) == '/'))) { - return (FNM_NOMATCH); - } - - /* Optimize for pattern with * at end or before /. */ - if (c == EOS) { - if (flags & FNM_PATHNAME) { - return (strchr(string, '/') == NULL ? APR_SUCCESS : FNM_NOMATCH); - } - else { - return (APR_SUCCESS); - } - } - else if (c == '/' && flags & FNM_PATHNAME) { - if ((string = strchr(string, '/')) == NULL) { - return (FNM_NOMATCH); - } - break; - } - - /* General case, use recursion. */ - while ((test = *string) != EOS) { - if (!ap_fnmatch(pattern, string, flags & ~FNM_PERIOD)) { - return (APR_SUCCESS); - } - if (test == '/' && flags & FNM_PATHNAME) { - break; - } - ++string; - } - return (FNM_NOMATCH); - case '[': - if (*string == EOS) { - return (FNM_NOMATCH); - } - if (*string == '/' && flags & FNM_PATHNAME) { - return (FNM_NOMATCH); - } - if (*string == '.' && (flags & FNM_PERIOD) && - (string == stringstart || - ((flags & FNM_PATHNAME) && *(string - 1) == '/'))) { - return (FNM_NOMATCH); - } - if ((pattern = rangematch(pattern, *string, flags)) == NULL) { - return (FNM_NOMATCH); - } - ++string; - break; - case '\\': - if (!(flags & FNM_NOESCAPE)) { - if ((c = *pattern++) == EOS) { - c = '\\'; - --pattern; - } - } - /* FALLTHROUGH */ - default: - if (flags & FNM_CASE_BLIND) { - if (ap_tolower(c) != ap_tolower(*string)) { - return (FNM_NOMATCH); - } - } - else if (c != *string) { - return (FNM_NOMATCH); - } - string++; - break; - } - /* NOTREACHED */ - } -} - -static const char *rangematch(const char *pattern, int test, int flags) -{ - int negate, ok; - char c, c2; - - /* - * A bracket expression starting with an unquoted circumflex - * character produces unspecified results (IEEE 1003.2-1992, - * 3.13.2). This implementation treats it like '!', for - * consistency with the regular expression syntax. - * J.T. Conklin (conklin@ngai.kaleida.com) - */ - if ((negate = (*pattern == '!' || *pattern == '^'))) { - ++pattern; - } - - for (ok = 0; (c = *pattern++) != ']';) { - if (c == '\\' && !(flags & FNM_NOESCAPE)) { - c = *pattern++; - } - if (c == EOS) { - return (NULL); - } - if (*pattern == '-' && (c2 = *(pattern + 1)) != EOS && c2 != ']') { - pattern += 2; - if (c2 == '\\' && !(flags & FNM_NOESCAPE)) { - c2 = *pattern++; - } - if (c2 == EOS) { - return (NULL); - } - if ((c <= test && test <= c2) - || ((flags & FNM_CASE_BLIND) - && ((ap_tolower(c) <= ap_tolower(test)) - && (ap_tolower(test) <= ap_tolower(c2))))) { - ok = 1; - } - } - else if ((c == test) - || ((flags & FNM_CASE_BLIND) - && (ap_tolower(c) == ap_tolower(test)))) { - ok = 1; - } - } - return (ok == negate ? NULL : pattern); -} - - -/* This function is an Apache addition */ -/* return non-zero if pattern has any glob chars in it */ -API_EXPORT(int) ap_is_fnmatch(const char *pattern) -{ - int nesting; - - nesting = 0; - while (*pattern) { - switch (*pattern) { - case '?': - case '*': - return 1; - - case '\\': - if (*pattern++ == '\0') { - return 0; - } - break; - - case '[': /* '[' is only a glob if it has a matching ']' */ - ++nesting; - break; - - case ']': - if (nesting) { - return 1; - } - break; - } - ++pattern; - } - return 0; -} diff --git a/lib/apr_getpass.c b/lib/apr_getpass.c deleted file mode 100644 index 1eaf30346ad..00000000000 --- a/lib/apr_getpass.c +++ /dev/null @@ -1,216 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -/* ap_getpass.c: abstraction to provide for obtaining a password from the - * command line in whatever way the OS supports. In the best case, it's a - * wrapper for the system library's getpass() routine; otherwise, we - * use one we define ourselves. - */ -#include "apr_private.h" -#include "apr_lib.h" -#include "apr_errno.h" -#include <sys/types.h> -#include <errno.h> - -#if HAVE_UNISTD_H -#include <unistd.h> -#endif -#if HAVE_CONIO_H -#include <conio.h> -#endif - -#if defined(HAVE_TERMIOS_H) && !defined(HAVE_GETPASS) -#include <termios.h> -#endif - -#ifndef CHARSET_EBCDIC -#define LF 10 -#define CR 13 -#else /* CHARSET_EBCDIC */ -#define LF '\n' -#define CR '\r' -#endif /* CHARSET_EBCDIC */ - -#define MAX_STRING_LEN 256 - -#define ERR_OVERFLOW 5 - -#ifndef HAVE_GETPASS - -/* MPE, Win32 and BeOS all lack a native getpass() */ - -#if !defined(HAVE_TERMIOS_H) && !defined(WIN32) -/* - * MPE lacks getpass() and a way to suppress stdin echo. So for now, just - * issue the prompt and read the results with echo. (Ugh). - */ - -static char *getpass(const char *prompt) -{ - static char password[MAX_STRING_LEN]; - - fputs(prompt, stderr); - gets((char *) &password); - - if (strlen((char *) &password) > (MAX_STRING_LEN - 1)) { - password[MAX_STRING_LEN - 1] = '\0'; - } - - return (char *) &password; -} - -#elif defined (HAVE_TERMIOS_H) -static char *getpass(const char *prompt) -{ - struct termios attr; - static char password[MAX_STRING_LEN]; - int n=0; - fputs(prompt, stderr); - fflush(stderr); - - if (tcgetattr(STDIN_FILENO, &attr) != 0) - return NULL; - attr.c_lflag &= ~(ECHO); - - if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &attr) != 0) - return NULL; - while ((password[n] = getchar()) != '\n') { - if (password[n] >= ' ' && password[n] <= '~') { - n++; - } else { - fprintf(stderr,"\n"); - fputs(prompt, stderr); - fflush(stderr); - n = 0; - } - } - - password[n] = '\0'; - printf("\n"); - if (n > (MAX_STRING_LEN - 1)) { - password[MAX_STRING_LEN - 1] = '\0'; - } - - attr.c_lflag |= ECHO; - tcsetattr(STDIN_FILENO, TCSANOW, &attr); - return (char*) &password; -} - -#else - -/* - * Windows lacks getpass(). So we'll re-implement it here. - */ - -static char *getpass(const char *prompt) -{ - static char password[MAX_STRING_LEN]; - int n = 0; - - fputs(prompt, stderr); - - while ((password[n] = _getch()) != '\r') { - if (password[n] >= ' ' && password[n] <= '~') { - n++; - printf("*"); - } - else { - printf("\n"); - fputs(prompt, stderr); - n = 0; - } - } - - password[n] = '\0'; - printf("\n"); - - if (n > (MAX_STRING_LEN - 1)) { - password[MAX_STRING_LEN - 1] = '\0'; - } - - return (char *) &password; -} - -#endif /* no getchar or _getch */ - -#endif /* no getpass */ - -/* - * Use the OS getpass() routine (or our own) to obtain a password from - * the input stream. - * - * Exit values: - * 0: Success - * 5: Partial success; entered text truncated to the size of the - * destination buffer - * - * Restrictions: Truncation also occurs according to the host system's - * getpass() semantics, or at position 255 if our own version is used, - * but the caller is *not* made aware of it. - */ - -API_EXPORT(ap_status_t) ap_getpass(const char *prompt, char *pwbuf, size_t *bufsiz) -{ - char *pw_got = NULL; - int result = 0; - - pw_got = getpass(prompt); - if (strlen(pw_got) > (*bufsiz - 1)) { - *bufsiz = ERR_OVERFLOW; - return APR_ENAMETOOLONG; - } - ap_cpystrn(pwbuf, pw_got, *bufsiz); - *bufsiz = result; - return APR_SUCCESS; -} diff --git a/lib/apr_md5.c b/lib/apr_md5.c deleted file mode 100644 index 6db49eda742..00000000000 --- a/lib/apr_md5.c +++ /dev/null @@ -1,620 +0,0 @@ -/* - * This is work is derived from material Copyright RSA Data Security, Inc. - * - * The RSA copyright statement and Licence for that original material is - * included below. This is followed by the Apache copyright statement and - * licence for the modifications made to that material. - */ - -/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm - */ - -/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All - rights reserved. - - License to copy and use this software is granted provided that it - is identified as the "RSA Data Security, Inc. MD5 Message-Digest - Algorithm" in all material mentioning or referencing this software - or this function. - - License is also granted to make and use derivative works provided - that such works are identified as "derived from the RSA Data - Security, Inc. MD5 Message-Digest Algorithm" in all material - mentioning or referencing the derived work. - - RSA Data Security, Inc. makes no representations concerning either - the merchantability of this software or the suitability of this - software for any particular purpose. It is provided "as is" - without express or implied warranty of any kind. - - These notices must be retained in any copies of any part of this - documentation and/or software. - */ - -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -/* - * The ap_MD5Encode() routine uses much code obtained from the FreeBSD 3.0 - * MD5 crypt() function, which is licenced as follows: - * ---------------------------------------------------------------------------- - * "THE BEER-WARE LICENSE" (Revision 42): - * <phk@login.dknet.dk> wrote this file. As long as you retain this notice you - * can do whatever you want with this stuff. If we meet some day, and you think - * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp - * ---------------------------------------------------------------------------- - */ -#ifndef WIN32 -#include "apr_private.h" -#endif -#include "apr_md5.h" -#include "apr_lib.h" - -#ifdef HAVE_STRING_H -#include <string.h> -#endif -#ifdef HAVE_CRYPT_H -#include <crypt.h> -#endif -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif - -/* Constants for MD5Transform routine. - */ - -#define S11 7 -#define S12 12 -#define S13 17 -#define S14 22 -#define S21 5 -#define S22 9 -#define S23 14 -#define S24 20 -#define S31 4 -#define S32 11 -#define S33 16 -#define S34 23 -#define S41 6 -#define S42 10 -#define S43 15 -#define S44 21 - -static void MD5Transform(UINT4 state[4], const unsigned char block[64]); -static void Encode(unsigned char *output, const UINT4 *input, - unsigned int len); -static void Decode(UINT4 *output, const unsigned char *input, - unsigned int len); - -static unsigned char PADDING[64] = -{ - 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 -}; - -/* F, G, H and I are basic MD5 functions. - */ -#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) -#define G(x, y, z) (((x) & (z)) | ((y) & (~z))) -#define H(x, y, z) ((x) ^ (y) ^ (z)) -#define I(x, y, z) ((y) ^ ((x) | (~z))) - -/* ROTATE_LEFT rotates x left n bits. - */ -#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) - -/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. - Rotation is separate from addition to prevent recomputation. - */ -#define FF(a, b, c, d, x, s, ac) { \ - (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \ - (a) = ROTATE_LEFT ((a), (s)); \ - (a) += (b); \ - } -#define GG(a, b, c, d, x, s, ac) { \ - (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \ - (a) = ROTATE_LEFT ((a), (s)); \ - (a) += (b); \ - } -#define HH(a, b, c, d, x, s, ac) { \ - (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \ - (a) = ROTATE_LEFT ((a), (s)); \ - (a) += (b); \ - } -#define II(a, b, c, d, x, s, ac) { \ - (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \ - (a) = ROTATE_LEFT ((a), (s)); \ - (a) += (b); \ - } - -/* MD5 initialization. Begins an MD5 operation, writing a new context. - */ -API_EXPORT(ap_status_t) ap_MD5Init(ap_md5_ctx_t *context) -{ - context->count[0] = context->count[1] = 0; - /* Load magic initialization constants. */ - context->state[0] = 0x67452301; - context->state[1] = 0xefcdab89; - context->state[2] = 0x98badcfe; - context->state[3] = 0x10325476; - return APR_SUCCESS; -} - -/* MD5 block update operation. Continues an MD5 message-digest - operation, processing another message block, and updating the - context. - */ -API_EXPORT(ap_status_t) ap_MD5Update(ap_md5_ctx_t *context, - const unsigned char *input, - unsigned int inputLen) -{ - unsigned int i, idx, partLen; - - /* Compute number of bytes mod 64 */ - idx = (unsigned int) ((context->count[0] >> 3) & 0x3F); - - /* Update number of bits */ - if ((context->count[0] += ((UINT4) inputLen << 3)) < ((UINT4) inputLen << 3)) - context->count[1]++; - context->count[1] += (UINT4) inputLen >> 29; - - partLen = 64 - idx; - - /* Transform as many times as possible. */ -#ifndef CHARSET_EBCDIC - if (inputLen >= partLen) { - memcpy(&context->buffer[idx], input, partLen); - MD5Transform(context->state, context->buffer); - - for (i = partLen; i + 63 < inputLen; i += 64) - MD5Transform(context->state, &input[i]); - - idx = 0; - } - else - i = 0; - - /* Buffer remaining input */ - memcpy(&context->buffer[idx], &input[i], inputLen - i); -#else /*CHARSET_EBCDIC*/ - if (inputLen >= partLen) { - ebcdic2ascii_strictly(&context->buffer[idx], input, partLen); - MD5Transform(context->state, context->buffer); - - for (i = partLen; i + 63 < inputLen; i += 64) { - unsigned char inp_tmp[64]; - ebcdic2ascii_strictly(inp_tmp, &input[i], 64); - MD5Transform(context->state, inp_tmp); - } - - idx = 0; - } - else - i = 0; - - /* Buffer remaining input */ - ebcdic2ascii_strictly(&context->buffer[idx], &input[i], inputLen - i); -#endif /*CHARSET_EBCDIC*/ - return APR_SUCCESS; -} - -/* MD5 finalization. Ends an MD5 message-digest operation, writing the - the message digest and zeroizing the context. - */ -API_EXPORT(ap_status_t) ap_MD5Final(unsigned char digest[MD5_DIGESTSIZE], - ap_md5_ctx_t *context) -{ - unsigned char bits[8]; - unsigned int idx, padLen; - - - /* Save number of bits */ - Encode(bits, context->count, 8); - -#ifdef CHARSET_EBCDIC - /* XXX: @@@: In order to make this no more complex than necessary, - * this kludge converts the bits[] array using the ascii-to-ebcdic - * table, because the following ap_MD5Update() re-translates - * its input (ebcdic-to-ascii). - * Otherwise, we would have to pass a "conversion" flag to ap_MD5Update() - */ - ascii2ebcdic(bits,bits,8); - - /* Since everything is converted to ascii within ap_MD5Update(), - * the initial 0x80 (PADDING[0]) must be stored as 0x20 - */ - PADDING[0] = os_toebcdic[0x80]; -#endif /*CHARSET_EBCDIC*/ - - /* Pad out to 56 mod 64. */ - idx = (unsigned int) ((context->count[0] >> 3) & 0x3f); - padLen = (idx < 56) ? (56 - idx) : (120 - idx); - ap_MD5Update(context, PADDING, padLen); - - /* Append length (before padding) */ - ap_MD5Update(context, bits, 8); - - /* Store state in digest */ - Encode(digest, context->state, MD5_DIGESTSIZE); - - /* Zeroize sensitive information. */ - memset(context, 0, sizeof(*context)); - - return APR_SUCCESS; -} - -/* MD5 basic transformation. Transforms state based on block. */ -static void MD5Transform(UINT4 state[4], const unsigned char block[64]) -{ - UINT4 a = state[0], b = state[1], c = state[2], d = state[3], - x[MD5_DIGESTSIZE]; - - Decode(x, block, 64); - - /* Round 1 */ - FF(a, b, c, d, x[0], S11, 0xd76aa478); /* 1 */ - FF(d, a, b, c, x[1], S12, 0xe8c7b756); /* 2 */ - FF(c, d, a, b, x[2], S13, 0x242070db); /* 3 */ - FF(b, c, d, a, x[3], S14, 0xc1bdceee); /* 4 */ - FF(a, b, c, d, x[4], S11, 0xf57c0faf); /* 5 */ - FF(d, a, b, c, x[5], S12, 0x4787c62a); /* 6 */ - FF(c, d, a, b, x[6], S13, 0xa8304613); /* 7 */ - FF(b, c, d, a, x[7], S14, 0xfd469501); /* 8 */ - FF(a, b, c, d, x[8], S11, 0x698098d8); /* 9 */ - FF(d, a, b, c, x[9], S12, 0x8b44f7af); /* 10 */ - FF(c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ - FF(b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ - FF(a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ - FF(d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ - FF(c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ - FF(b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ - - /* Round 2 */ - GG(a, b, c, d, x[1], S21, 0xf61e2562); /* 17 */ - GG(d, a, b, c, x[6], S22, 0xc040b340); /* 18 */ - GG(c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ - GG(b, c, d, a, x[0], S24, 0xe9b6c7aa); /* 20 */ - GG(a, b, c, d, x[5], S21, 0xd62f105d); /* 21 */ - GG(d, a, b, c, x[10], S22, 0x2441453); /* 22 */ - GG(c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ - GG(b, c, d, a, x[4], S24, 0xe7d3fbc8); /* 24 */ - GG(a, b, c, d, x[9], S21, 0x21e1cde6); /* 25 */ - GG(d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ - GG(c, d, a, b, x[3], S23, 0xf4d50d87); /* 27 */ - GG(b, c, d, a, x[8], S24, 0x455a14ed); /* 28 */ - GG(a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ - GG(d, a, b, c, x[2], S22, 0xfcefa3f8); /* 30 */ - GG(c, d, a, b, x[7], S23, 0x676f02d9); /* 31 */ - GG(b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ - - /* Round 3 */ - HH(a, b, c, d, x[5], S31, 0xfffa3942); /* 33 */ - HH(d, a, b, c, x[8], S32, 0x8771f681); /* 34 */ - HH(c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ - HH(b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ - HH(a, b, c, d, x[1], S31, 0xa4beea44); /* 37 */ - HH(d, a, b, c, x[4], S32, 0x4bdecfa9); /* 38 */ - HH(c, d, a, b, x[7], S33, 0xf6bb4b60); /* 39 */ - HH(b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ - HH(a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ - HH(d, a, b, c, x[0], S32, 0xeaa127fa); /* 42 */ - HH(c, d, a, b, x[3], S33, 0xd4ef3085); /* 43 */ - HH(b, c, d, a, x[6], S34, 0x4881d05); /* 44 */ - HH(a, b, c, d, x[9], S31, 0xd9d4d039); /* 45 */ - HH(d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ - HH(c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ - HH(b, c, d, a, x[2], S34, 0xc4ac5665); /* 48 */ - - /* Round 4 */ - II(a, b, c, d, x[0], S41, 0xf4292244); /* 49 */ - II(d, a, b, c, x[7], S42, 0x432aff97); /* 50 */ - II(c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ - II(b, c, d, a, x[5], S44, 0xfc93a039); /* 52 */ - II(a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ - II(d, a, b, c, x[3], S42, 0x8f0ccc92); /* 54 */ - II(c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ - II(b, c, d, a, x[1], S44, 0x85845dd1); /* 56 */ - II(a, b, c, d, x[8], S41, 0x6fa87e4f); /* 57 */ - II(d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ - II(c, d, a, b, x[6], S43, 0xa3014314); /* 59 */ - II(b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ - II(a, b, c, d, x[4], S41, 0xf7537e82); /* 61 */ - II(d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ - II(c, d, a, b, x[2], S43, 0x2ad7d2bb); /* 63 */ - II(b, c, d, a, x[9], S44, 0xeb86d391); /* 64 */ - - state[0] += a; - state[1] += b; - state[2] += c; - state[3] += d; - - /* Zeroize sensitive information. */ - memset(x, 0, sizeof(x)); -} - -/* Encodes input (UINT4) into output (unsigned char). Assumes len is - a multiple of 4. - */ -static void Encode(unsigned char *output, const UINT4 *input, unsigned int len) -{ - unsigned int i, j; - UINT4 k; - - for (i = 0, j = 0; j < len; i++, j += 4) { - k = input[i]; - output[j] = (unsigned char) (k & 0xff); - output[j + 1] = (unsigned char) ((k >> 8) & 0xff); - output[j + 2] = (unsigned char) ((k >> 16) & 0xff); - output[j + 3] = (unsigned char) ((k >> 24) & 0xff); - } -} - -/* Decodes input (unsigned char) into output (UINT4). Assumes len is - * a multiple of 4. - */ -static void Decode(UINT4 *output, const unsigned char *input, unsigned int len) -{ - unsigned int i, j; - - for (i = 0, j = 0; j < len; i++, j += 4) - output[i] = ((UINT4) input[j]) | (((UINT4) input[j + 1]) << 8) | - (((UINT4) input[j + 2]) << 16) | (((UINT4) input[j + 3]) << 24); -} - -/* - * Define the Magic String prefix that identifies a password as being - * hashed using our algorithm. - */ -static const char *apr1_id = "$apr1$"; - -/* - * The following MD5 password encryption code was largely borrowed from - * the FreeBSD 3.0 /usr/src/lib/libcrypt/crypt.c file, which is - * licenced as stated at the top of this file. - */ - -static void to64(char *s, unsigned long v, int n) -{ - static unsigned char itoa64[] = /* 0 ... 63 => ASCII - 64 */ - "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; - - while (--n >= 0) { - *s++ = itoa64[v&0x3f]; - v >>= 6; - } -} - -API_EXPORT(ap_status_t) ap_MD5Encode(const char *pw, const char *salt, - char *result, size_t nbytes) -{ - /* - * Minimum size is 8 bytes for salt, plus 1 for the trailing NUL, - * plus 4 for the '$' separators, plus the password hash itself. - * Let's leave a goodly amount of leeway. - */ - - char passwd[120], *p; - const char *sp, *ep; - unsigned char final[MD5_DIGESTSIZE]; - int sl, pl, i; - ap_md5_ctx_t ctx, ctx1; - unsigned long l; - - /* - * Refine the salt first. It's possible we were given an already-hashed - * string as the salt argument, so extract the actual salt value from it - * if so. Otherwise just use the string up to the first '$' as the salt. - */ - sp = salt; - - /* - * If it starts with the magic string, then skip that. - */ - if (!strncmp(sp, apr1_id, strlen(apr1_id))) { - sp += strlen(apr1_id); - } - - /* - * It stops at the first '$' or 8 chars, whichever comes first - */ - for (ep = sp; (*ep != '\0') && (*ep != '$') && (ep < (sp + 8)); ep++) { - continue; - } - - /* - * Get the length of the true salt - */ - sl = ep - sp; - - /* - * 'Time to make the doughnuts..' - */ - ap_MD5Init(&ctx); - - /* - * The password first, since that is what is most unknown - */ - ap_MD5Update(&ctx, (unsigned char *)pw, strlen(pw)); - - /* - * Then our magic string - */ - ap_MD5Update(&ctx, (unsigned char *)apr1_id, strlen(apr1_id)); - - /* - * Then the raw salt - */ - ap_MD5Update(&ctx, (unsigned char *)sp, sl); - - /* - * Then just as many characters of the MD5(pw, salt, pw) - */ - ap_MD5Init(&ctx1); - ap_MD5Update(&ctx1, (unsigned char *)pw, strlen(pw)); - ap_MD5Update(&ctx1, (unsigned char *)sp, sl); - ap_MD5Update(&ctx1, (unsigned char *)pw, strlen(pw)); - ap_MD5Final(final, &ctx1); - for (pl = strlen(pw); pl > 0; pl -= MD5_DIGESTSIZE) { - ap_MD5Update(&ctx, final, (pl > MD5_DIGESTSIZE) ? MD5_DIGESTSIZE : pl); - } - - /* - * Don't leave anything around in vm they could use. - */ - memset(final, 0, sizeof(final)); - - /* - * Then something really weird... - */ - for (i = strlen(pw); i != 0; i >>= 1) { - if (i & 1) { - ap_MD5Update(&ctx, final, 1); - } - else { - ap_MD5Update(&ctx, (unsigned char *)pw, 1); - } - } - - /* - * Now make the output string. We know our limitations, so we - * can use the string routines without bounds checking. - */ - strcpy(passwd, apr1_id); - strncat(passwd, sp, sl); - strcat(passwd, "$"); - - ap_MD5Final(final, &ctx); - - /* - * And now, just to make sure things don't run too fast.. - * On a 60 Mhz Pentium this takes 34 msec, so you would - * need 30 seconds to build a 1000 entry dictionary... - */ - for (i = 0; i < 1000; i++) { - ap_MD5Init(&ctx1); - if (i & 1) { - ap_MD5Update(&ctx1, (unsigned char *)pw, strlen(pw)); - } - else { - ap_MD5Update(&ctx1, final, MD5_DIGESTSIZE); - } - if (i % 3) { - ap_MD5Update(&ctx1, (unsigned char *)sp, sl); - } - - if (i % 7) { - ap_MD5Update(&ctx1, (unsigned char *)pw, strlen(pw)); - } - - if (i & 1) { - ap_MD5Update(&ctx1, final, MD5_DIGESTSIZE); - } - else { - ap_MD5Update(&ctx1, (unsigned char *)pw, strlen(pw)); - } - ap_MD5Final(final,&ctx1); - } - - p = passwd + strlen(passwd); - - l = (final[ 0]<<16) | (final[ 6]<<8) | final[12]; to64(p, l, 4); p += 4; - l = (final[ 1]<<16) | (final[ 7]<<8) | final[13]; to64(p, l, 4); p += 4; - l = (final[ 2]<<16) | (final[ 8]<<8) | final[14]; to64(p, l, 4); p += 4; - l = (final[ 3]<<16) | (final[ 9]<<8) | final[15]; to64(p, l, 4); p += 4; - l = (final[ 4]<<16) | (final[10]<<8) | final[ 5]; to64(p, l, 4); p += 4; - l = final[11] ; to64(p, l, 2); p += 2; - *p = '\0'; - - /* - * Don't leave anything around in vm they could use. - */ - memset(final, 0, sizeof(final)); - - ap_cpystrn(result, passwd, nbytes - 1); - return APR_SUCCESS; -} - -/* - * Validate a plaintext password against a smashed one. Use either - * crypt() (if available) or ap_MD5Encode(), depending upon the format - * of the smashed input password. Return APR_SUCCESS if they match, or - * APR_EMISMATCH if they don't. - */ - -API_EXPORT(ap_status_t) ap_validate_password(const char *passwd, const char *hash) -{ - char sample[120]; -#ifndef WIN32 - char *crypt_pw; -#endif - if (!strncmp(hash, apr1_id, strlen(apr1_id))) { - /* - * The hash was created using our custom algorithm. - */ - ap_MD5Encode(passwd, hash, sample, sizeof(sample)); - } - else { - /* - * It's not our algorithm, so feed it to crypt() if possible. - */ -#if defined(WIN32) || defined(BEOS) - ap_cpystrn(sample, passwd, sizeof(sample) - 1); -#else - crypt_pw = crypt(passwd, hash); - ap_cpystrn(sample, crypt_pw, sizeof(sample) - 1); -#endif - } - return (strcmp(sample, hash) == 0) ? APR_SUCCESS : APR_EMISMATCH; -} diff --git a/lib/apr_pools.c b/lib/apr_pools.c deleted file mode 100644 index 0d853a730ab..00000000000 --- a/lib/apr_pools.c +++ /dev/null @@ -1,1364 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -/* - * Resource allocation code... the code here is responsible for making - * sure that nothing leaks. - * - * rst --- 4/95 --- 6/95 - */ - -#include "apr_private.h" - -#include "apr_portable.h" /* for get_os_proc */ -#include "apr_general.h" -#include "apr_pools.h" -#include "apr_lib.h" -#include "apr_lock.h" -#include "misc.h" - -#ifdef HAVE_SYS_STAT_H -#include <sys/stat.h> -#endif -#ifdef HAVE_SYS_SIGNAL_H -#include <sys/signal.h> -#endif -#ifdef HAVE_SIGNAL_H -#include <signal.h> -#endif -#ifdef HAVE_SYS_WAIT_H -#include <sys/wait.h> -#endif -#ifdef HAVE_SYS_TYPES_H -#include <sys/types.h> -#endif -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif -#ifdef HAVE_FCNTL_H -#include <fcntl.h> -#endif - -#ifdef HAVE_STDLIB_H -#include <stdlib.h> -#endif -#ifdef HAVE_MALLOC_H -#include <malloc.h> -#endif - -/* - * Debugging support: Define this to enable code which helps detect re-use - * of freed memory and other such nonsense. - * - * The theory is simple. The FILL_BYTE (0xa5) is written over all malloc'd - * memory as we receive it, and is written over everything that we free up - * during a clear_pool. We check that blocks on the free list always - * have the FILL_BYTE in them, and we check during palloc() that the bytes - * still have FILL_BYTE in them. If you ever see garbage URLs or whatnot - * containing lots of 0xa5s then you know something used data that's been - * freed or uninitialized. - */ -/* #define ALLOC_DEBUG */ - -/* - * Debugging support: If defined all allocations will be done with - * malloc and free()d appropriately at the end. This is intended to be - * used with something like Electric Fence or Purify to help detect - * memory problems. Note that if you're using efence then you should also - * add in ALLOC_DEBUG. But don't add in ALLOC_DEBUG if you're using Purify - * because ALLOC_DEBUG would hide all the uninitialized read errors that - * Purify can diagnose. - */ -/* #define ALLOC_USE_MALLOC */ - -/* - * Pool debugging support: This is intended to detect cases where the - * wrong pool is used when assigning data to an object in another pool. - * In particular, it causes the table_{set,add,merge}n routines to check - * that their arguments are safe for the ap_table_t they're being placed in. - * It currently only works with the unix multiprocess model, but could - * be extended to others. - */ -/* #define POOL_DEBUG */ - -/* - * Provide diagnostic information about make_table() calls which are - * possibly too small. This requires a recent gcc which supports - * __builtin_return_address(). The error_log output will be a - * message such as: - * table_push: ap_table_t created by 0x804d874 hit limit of 10 - * Use "l *0x804d874" to find the source that corresponds to. It - * indicates that a ap_table_t allocated by a call at that address has - * possibly too small an initial ap_table_t size guess. - */ -/* #define MAKE_TABLE_PROFILE */ - -/* - * Provide some statistics on the cost of allocations. It requires a - * bit of an understanding of how alloc.c works. - */ -/* #define ALLOC_STATS */ - -#ifdef POOL_DEBUG -#ifdef ALLOC_USE_MALLOC -#error "sorry, no support for ALLOC_USE_MALLOC and POOL_DEBUG at the same time" -#endif /* ALLOC_USE_MALLOC */ - -#ifdef MULTITHREAD -# error "sorry, no support for MULTITHREAD and POOL_DEBUG at the same time" -#endif /* MULTITHREAD */ - -#endif /* POOL_DEBUG */ - -#ifdef ALLOC_USE_MALLOC -#undef BLOCK_MINFREE -#undef BLOCK_MINALLOC -#define BLOCK_MINFREE 0 -#define BLOCK_MINALLOC 0 -#endif /* ALLOC_USE_MALLOC */ - -#define AP_SLACK_LOW 1 -#define AP_SLACK_HIGH 2 - - -/***************************************************************** - * - * Managing free storage blocks... - */ - -union align { - /* - * Types which are likely to have the longest RELEVANT alignment - * restrictions... - */ - - char *cp; - void (*f) (void); - long l; - FILE *fp; - double d; -}; - -#define CLICK_SZ (sizeof(union align)) - -union block_hdr { - union align a; - - /* Actual header... */ - - struct { - char *endp; - union block_hdr *next; - char *first_avail; -#ifdef POOL_DEBUG - union block_hdr *global_next; - ap_pool_t *owning_pool; -#endif /* POOL_DEBUG */ - } h; -}; - -#define APR_ABORT(conditional, retcode, func, str) \ - if (conditional) { \ - if ((func) == NULL) { \ - return NULL; \ - } \ - else { \ - fprintf(stderr, "%s", str); \ - (*(func))(retcode); \ - } \ - } - -/* - * Static cells for managing our internal synchronisation. - */ -static union block_hdr *block_freelist = NULL; - -#if APR_HAS_THREADS -static ap_lock_t *alloc_mutex; -static ap_lock_t *spawn_mutex; -#endif - -#ifdef POOL_DEBUG -static char *known_stack_point; -static int stack_direction; -static union block_hdr *global_block_list; -#define FREE_POOL ((ap_pool_t *)(-1)) -#endif /* POOL_DEBUG */ - -#ifdef ALLOC_STATS -static unsigned long long num_free_blocks_calls; -static unsigned long long num_blocks_freed; -static unsigned max_blocks_in_one_free; -static unsigned num_malloc_calls; -static unsigned num_malloc_bytes; -#endif /* ALLOC_STATS */ - -#ifdef ALLOC_DEBUG -#define FILL_BYTE ((char)(0xa5)) -#define debug_fill(ptr,size) ((void)memset((ptr), FILL_BYTE, (size))) - -static APR_INLINE void debug_verify_filled(const char *ptr, const char *endp, - const char *error_msg) -{ - for ( ; ptr < endp; ++ptr) { - if (*ptr != FILL_BYTE) { - fputs(error_msg, stderr); - abort(); - exit(1); - } - } -} - -#else /* ALLOC_DEBUG */ -#define debug_fill(a,b) -#define debug_verify_filled(a,b,c) -#endif /* ALLOC_DEBUG */ - -/* - * Get a completely new block from the system pool. Note that we rely on - * malloc() to provide aligned memory. - */ - -static union block_hdr *malloc_block(int size, int (*apr_abort)(int retcode)) -{ - union block_hdr *blok; - -#ifdef ALLOC_DEBUG - /* make some room at the end which we'll fill and expect to be - * always filled - */ - size += CLICK_SZ; -#endif /* ALLOC_DEBUG */ - -#ifdef ALLOC_STATS - ++num_malloc_calls; - num_malloc_bytes += size + sizeof(union block_hdr); -#endif /* ALLOC_STATS */ - - blok = (union block_hdr *) malloc(size + sizeof(union block_hdr)); - APR_ABORT(blok == NULL, APR_ENOMEM, apr_abort, - "Ouch! malloc failed in malloc_block()\n"); - debug_fill(blok, size + sizeof(union block_hdr)); - blok->h.next = NULL; - blok->h.first_avail = (char *) (blok + 1); - blok->h.endp = size + blok->h.first_avail; - -#ifdef ALLOC_DEBUG - blok->h.endp -= CLICK_SZ; -#endif /* ALLOC_DEBUG */ - -#ifdef POOL_DEBUG - blok->h.global_next = global_block_list; - global_block_list = blok; - blok->h.owning_pool = NULL; -#endif /* POOL_DEBUG */ - - return blok; -} - - - -#if defined(ALLOC_DEBUG) && !defined(ALLOC_USE_MALLOC) -static void chk_on_blk_list(union block_hdr *blok, union block_hdr *free_blk) -{ - debug_verify_filled(blok->h.endp, blok->h.endp + CLICK_SZ, - "Ouch! Someone trounced the padding " - "at the end of a block!\n"); - while (free_blk) { - if (free_blk == blok) { - fprintf(stderr, "Ouch! Freeing free block\n"); - abort(); - exit(1); - } - free_blk = free_blk->h.next; - } -} -#else /* defined(ALLOC_DEBUG) && !defined(ALLOC_USE_MALLOC) */ -#define chk_on_blk_list(_x, _y) -#endif /* defined(ALLOC_DEBUG) && !defined(ALLOC_USE_MALLOC) */ - -/* Free a chain of blocks --- must be called with alarms blocked. */ - -static void free_blocks(union block_hdr *blok) -{ -#ifdef ALLOC_USE_MALLOC - union block_hdr *next; - - for ( ; blok; blok = next) { - next = blok->h.next; - free(blok); - } -#else /* ALLOC_USE_MALLOC */ - -#ifdef ALLOC_STATS - unsigned num_blocks; -#endif /* ALLOC_STATS */ - - /* - * First, put new blocks at the head of the free list --- - * we'll eventually bash the 'next' pointer of the last block - * in the chain to point to the free blocks we already had. - */ - - union block_hdr *old_free_list; - - if (blok == NULL) { - return; /* Sanity check --- freeing empty pool? */ - } - -#if APR_HAS_THREADS - ap_lock(alloc_mutex); -#endif - old_free_list = block_freelist; - block_freelist = blok; - - /* - * Next, adjust first_avail pointers of each block --- have to do it - * sooner or later, and it simplifies the search in new_block to do it - * now. - */ - -#ifdef ALLOC_STATS - num_blocks = 1; -#endif /* ALLOC_STATS */ - - while (blok->h.next != NULL) { - -#ifdef ALLOC_STATS - ++num_blocks; -#endif /* ALLOC_STATS */ - - chk_on_blk_list(blok, old_free_list); - blok->h.first_avail = (char *) (blok + 1); - debug_fill(blok->h.first_avail, blok->h.endp - blok->h.first_avail); -#ifdef POOL_DEBUG - blok->h.owning_pool = FREE_POOL; -#endif /* POOL_DEBUG */ - blok = blok->h.next; - } - - chk_on_blk_list(blok, old_free_list); - blok->h.first_avail = (char *) (blok + 1); - debug_fill(blok->h.first_avail, blok->h.endp - blok->h.first_avail); -#ifdef POOL_DEBUG - blok->h.owning_pool = FREE_POOL; -#endif /* POOL_DEBUG */ - - /* Finally, reset next pointer to get the old free blocks back */ - - blok->h.next = old_free_list; - -#ifdef ALLOC_STATS - if (num_blocks > max_blocks_in_one_free) { - max_blocks_in_one_free = num_blocks; - } - ++num_free_blocks_calls; - num_blocks_freed += num_blocks; -#endif /* ALLOC_STATS */ - -#if APR_HAS_THREADS - ap_unlock(alloc_mutex); -#endif /* APR_HAS_THREADS */ -#endif /* ALLOC_USE_MALLOC */ -} - -/* - * Get a new block, from our own free list if possible, from the system - * if necessary. Must be called with alarms blocked. - */ - -static union block_hdr *new_block(int min_size, int (*apr_abort)(int retcode)) -{ - union block_hdr **lastptr = &block_freelist; - union block_hdr *blok = block_freelist; - - /* First, see if we have anything of the required size - * on the free list... - */ - - while (blok != NULL) { - if (min_size + BLOCK_MINFREE <= blok->h.endp - blok->h.first_avail) { - *lastptr = blok->h.next; - blok->h.next = NULL; - debug_verify_filled(blok->h.first_avail, blok->h.endp, - "Ouch! Someone trounced a block " - "on the free list!\n"); - return blok; - } - else { - lastptr = &blok->h.next; - blok = blok->h.next; - } - } - - /* Nope. */ - - min_size += BLOCK_MINFREE; - blok = malloc_block((min_size > BLOCK_MINALLOC) - ? min_size : BLOCK_MINALLOC, apr_abort); - return blok; -} - - -/* Accounting */ - -static long bytes_in_block_list(union block_hdr *blok) -{ - long size = 0; - - while (blok) { - size += blok->h.endp - (char *) (blok + 1); - blok = blok->h.next; - } - - return size; -} - - -/***************************************************************** - * - * Pool internals and management... - * NB that subprocesses are not handled by the generic cleanup code, - * basically because we don't want cleanups for multiple subprocesses - * to result in multiple three-second pauses. - */ - -struct process_chain; -struct cleanup; - -static void run_cleanups(struct cleanup *c); -static void free_proc_chain(struct process_chain *p); - -static ap_pool_t *permanent_pool; - -/* Each pool structure is allocated in the start of its own first block, - * so we need to know how many bytes that is (once properly aligned...). - * This also means that when a pool's sub-pool is destroyed, the storage - * associated with it is *completely* gone, so we have to make sure it - * gets taken off the parent's sub-pool list... - */ - -#define POOL_HDR_CLICKS (1 + ((sizeof(struct ap_pool_t) - 1) / CLICK_SZ)) -#define POOL_HDR_BYTES (POOL_HDR_CLICKS * CLICK_SZ) - -API_EXPORT(ap_pool_t *) ap_make_sub_pool(ap_pool_t *p, int (*apr_abort)(int retcode)) -{ - union block_hdr *blok; - ap_pool_t *new_pool; - - ap_block_alarms(); - -#if APR_HAS_THREADS - ap_lock(alloc_mutex); -#endif - - blok = new_block(POOL_HDR_BYTES, apr_abort); - new_pool = (ap_pool_t *) blok->h.first_avail; - blok->h.first_avail += POOL_HDR_BYTES; -#ifdef POOL_DEBUG - blok->h.owning_pool = new_pool; -#endif - - memset((char *) new_pool, '\0', sizeof(struct ap_pool_t)); - new_pool->free_first_avail = blok->h.first_avail; - new_pool->first = new_pool->last = blok; - - if (p) { - new_pool->parent = p; - new_pool->sub_next = p->sub_pools; - if (new_pool->sub_next) { - new_pool->sub_next->sub_prev = new_pool; - } - p->sub_pools = new_pool; - } - else { - permanent_pool = new_pool; - } - -#if APR_HAS_THREADS - ap_unlock(alloc_mutex); -#endif - ap_unblock_alarms(); - - return new_pool; -} - -#ifdef POOL_DEBUG -static void stack_var_init(char *s) -{ - char t; - - if (s < &t) { - stack_direction = 1; /* stack grows up */ - } - else { - stack_direction = -1; /* stack grows down */ - } -} -#endif - -#ifdef ALLOC_STATS -static void dump_stats(void) -{ - fprintf(stderr, - "alloc_stats: [%d] #free_blocks %llu #blocks %llu max " - "%u #malloc %u #bytes %u\n", - (int) getpid(), - num_free_blocks_calls, - num_blocks_freed, - max_blocks_in_one_free, - num_malloc_calls, - num_malloc_bytes); -} -#endif - -/***************************************************************** - * - * Managing generic cleanups. - */ - -struct cleanup { - void *data; - ap_status_t (*plain_cleanup) (void *); - ap_status_t (*child_cleanup) (void *); - struct cleanup *next; -}; - -static void * ap_pool_palloc(ap_pool_t *a, int reqsize, int (*apr_abort)(int retcode)); - -#if 0 -static void ap_register_pool_cleanup(struct ap_pool_t *p, void *data, - ap_status_t (*plain_cleanup) (void *), - ap_status_t (*child_cleanup) (void *)) -{ - struct cleanup *c; - - if (p != NULL) { - c = (struct cleanup *) ap_pool_palloc(p, sizeof(struct cleanup), NULL); - c->data = data; - c->plain_cleanup = plain_cleanup; - c->child_cleanup = child_cleanup; - c->next = p->cleanups; - p->cleanups = c; - } -} -#endif - -API_EXPORT(void) ap_register_cleanup(ap_pool_t *p, void *data, - ap_status_t (*plain_cleanup) (void *), - ap_status_t (*child_cleanup) (void *)) -{ - struct cleanup *c; - - if (p != NULL) { - c = (struct cleanup *) ap_palloc(p, sizeof(struct cleanup)); - c->data = data; - c->plain_cleanup = plain_cleanup; - c->child_cleanup = child_cleanup; - c->next = p->cleanups; - p->cleanups = c; - } -} - -API_EXPORT(void) ap_kill_cleanup(ap_pool_t *p, void *data, - ap_status_t (*cleanup) (void *)) -{ - struct cleanup *c; - struct cleanup **lastp; - - if (p == NULL) - return; - c = p->cleanups; - lastp = &p->cleanups; - while (c) { - if (c->data == data && c->plain_cleanup == cleanup) { - *lastp = c->next; - break; - } - - lastp = &c->next; - c = c->next; - } -} - -API_EXPORT(void) ap_run_cleanup(ap_pool_t *p, void *data, - ap_status_t (*cleanup) (void *)) -{ - ap_block_alarms(); /* Run cleanup only once! */ - (*cleanup) (data); - ap_kill_cleanup(p, data, cleanup); - ap_unblock_alarms(); -} - -static void run_cleanups(struct cleanup *c) -{ - while (c) { - (*c->plain_cleanup) (c->data); - c = c->next; - } -} - -static void run_child_cleanups(struct cleanup *c) -{ - while (c) { - (*c->child_cleanup) (c->data); - c = c->next; - } -} - -static void cleanup_pool_for_exec(ap_pool_t *p) -{ - run_child_cleanups(p->cleanups); - p->cleanups = NULL; - - for (p = p->sub_pools; p; p = p->sub_next) { - cleanup_pool_for_exec(p); - } -} - -API_EXPORT(void) ap_cleanup_for_exec(void) -{ -#if !defined(WIN32) && !defined(OS2) - /* - * Don't need to do anything on NT or OS/2, because I - * am actually going to spawn the new process - not - * exec it. All handles that are not inheritable, will - * be automajically closed. The only problem is with - * file handles that are open, but there isn't much - * I can do about that (except if the child decides - * to go out and close them - */ - ap_block_alarms(); - cleanup_pool_for_exec(permanent_pool); - ap_unblock_alarms(); -#endif /* ndef WIN32 */ -} - -API_EXPORT_NONSTD(ap_status_t) ap_null_cleanup(void *data) -{ - /* do nothing cleanup routine */ - return APR_SUCCESS; -} - -ap_status_t ap_init_alloc(void) -{ -#if APR_HAS_THREADS - ap_status_t status; -#endif -#ifdef POOL_DEBUG - char s; - - known_stack_point = &s; - stack_var_init(&s); -#endif -#if APR_HAS_THREADS - status = ap_create_lock(&alloc_mutex, APR_MUTEX, APR_INTRAPROCESS, - NULL, NULL); - if (status != APR_SUCCESS) { - ap_destroy_lock(alloc_mutex); - return status; - } - status = ap_create_lock(&spawn_mutex, APR_MUTEX, APR_INTRAPROCESS, - NULL, NULL); - if (status != APR_SUCCESS) { - ap_destroy_lock(spawn_mutex); - return status; - } -#endif - -#ifdef ALLOC_STATS - atexit(dump_stats); -#endif - - return APR_SUCCESS; -} - -void ap_term_alloc(void) -{ -#if APR_HAS_THREADS - ap_destroy_lock(alloc_mutex); - ap_destroy_lock(spawn_mutex); -#endif -} - -/* We only want to lock the mutex if we are being called from ap_clear_pool. - * This is because if we also call this function from ap_destroy_real_pool, - * which also locks the same mutex, and recursive locks aren't portable. - * This way, we are garaunteed that we only lock this mutex once when calling - * either one of these functions. - */ -API_EXPORT(void) ap_clear_pool(ap_pool_t *a) -{ - ap_block_alarms(); - - while (a->sub_pools) { - ap_destroy_pool(a->sub_pools); - } - /* - * Don't hold the mutex during cleanups. - */ - run_cleanups(a->cleanups); - a->cleanups = NULL; - free_proc_chain(a->subprocesses); - a->subprocesses = NULL; - free_blocks(a->first->h.next); - a->first->h.next = NULL; - - a->last = a->first; - a->first->h.first_avail = a->free_first_avail; - debug_fill(a->first->h.first_avail, - a->first->h.endp - a->first->h.first_avail); - -#ifdef ALLOC_USE_MALLOC - { - void *c, *n; - - for (c = a->allocation_list; c; c = n) { - n = *(void **)c; - free(c); - } - a->allocation_list = NULL; - } -#endif - - ap_unblock_alarms(); -} - -API_EXPORT(void) ap_destroy_pool(ap_pool_t *a) -{ - ap_block_alarms(); - ap_clear_pool(a); -#if APR_HAS_THREADS - ap_lock(alloc_mutex); -#endif - - if (a->parent) { - if (a->parent->sub_pools == a) { - a->parent->sub_pools = a->sub_next; - } - if (a->sub_prev) { - a->sub_prev->sub_next = a->sub_next; - } - if (a->sub_next) { - a->sub_next->sub_prev = a->sub_prev; - } - } -#if APR_HAS_THREADS - ap_unlock(alloc_mutex); -#endif - free_blocks(a->first); - ap_unblock_alarms(); -} - -API_EXPORT(long) ap_bytes_in_pool(ap_pool_t *p) -{ - return bytes_in_block_list(p->first); -} -API_EXPORT(long) ap_bytes_in_free_blocks(void) -{ - return bytes_in_block_list(block_freelist); -} - -/***************************************************************** - * POOL_DEBUG support - */ -#ifdef POOL_DEBUG - -/* the unix linker defines this symbol as the last byte + 1 of - * the executable... so it includes TEXT, BSS, and DATA - */ -extern char _end; - -/* is ptr in the range [lo,hi) */ -#define is_ptr_in_range(ptr, lo, hi) \ - (((unsigned long)(ptr) - (unsigned long)(lo)) \ - < (unsigned long)(hi) - (unsigned long)(lo)) - -/* Find the pool that ts belongs to, return NULL if it doesn't - * belong to any pool. - */ -API_EXPORT(ap_pool_t *) ap_find_pool(const void *ts, int (apr_abort)(int retcode)) -{ - const char *s = ts; - union block_hdr **pb; - union block_hdr *b; - - /* short-circuit stuff which is in TEXT, BSS, or DATA */ - if (is_ptr_in_range(s, 0, &_end)) { - return NULL; - } - /* consider stuff on the stack to also be in the NULL pool... - * XXX: there's cases where we don't want to assume this - */ - APR_ABORT((stack_direction == -1 && - is_ptr_in_range(s, &ts, known_stack_point)) || - (stack_direction == 1 && - is_ptr_in_range(s, known_stack_point, &ts)), 1, apr_abort, - "Ouch! find_pool() called on pointer in a free block\n"); - ap_block_alarms(); - /* search the global_block_list */ - for (pb = &global_block_list; *pb; pb = &b->h.global_next) { - b = *pb; - if (is_ptr_in_range(s, b, b->h.endp)) { - if (b->h.owning_pool == FREE_POOL) { - abort(); - exit(1); - } - if (b != global_block_list) { - /* - * promote b to front of list, this is a hack to speed - * up the lookup - */ - *pb = b->h.global_next; - b->h.global_next = global_block_list; - global_block_list = b; - } - ap_unblock_alarms(); - return b->h.owning_pool; - } - } - ap_unblock_alarms(); - return NULL; -} - -/* return TRUE iff a is an ancestor of b - * NULL is considered an ancestor of all pools - */ -API_EXPORT(int) ap_pool_is_ancestor(ap_pool_t *a, ap_pool_t *b) -{ - if (a == NULL) { - return 1; - } - while (a->joined) { - a = a->joined; - } - while (b) { - if (a == b) { - return 1; - } - b = b->parent; - } - return 0; -} - -/* - * All blocks belonging to sub will be changed to point to p - * instead. This is a guarantee by the caller that sub will not - * be destroyed before p is. - */ -API_EXPORT(void) ap_pool_join(ap_pool_t *p, ap_pool_t *sub, - int (*apr_abort)(int retcode)) -{ - union block_hdr *b; - - /* We could handle more general cases... but this is it for now. */ - APR_ABORT(sub->parent != p, 1, apr_abort, - "pool_join: p is not a parent of sub\n"); - ap_block_alarms(); - while (p->joined) { - p = p->joined; - } - sub->joined = p; - for (b = global_block_list; b; b = b->h.global_next) { - if (b->h.owning_pool == sub) { - b->h.owning_pool = p; - } - } - ap_unblock_alarms(); -} -#endif - -/***************************************************************** - * - * Allocating stuff... - */ - -void * ap_palloc(ap_pool_t *a, int reqsize) -{ -#ifdef ALLOC_USE_MALLOC - int size = reqsize + CLICK_SZ; - void *ptr; - - if (a == NULL) { - return malloc(reqsize); - } - ap_block_alarms(); - if (c == NULL) { - return malloc(reqsize); - } - ptr = malloc(size); - if (ptr == NULL) { - fputs("Ouch! Out of memory!\n", stderr); - exit(1); - } - debug_fill(ptr, size); /* might as well get uninitialized protection */ - *(void **)ptr = a->allocation_list; - a->allocation_list = ptr; - ap_unblock_alarms(); - return (char *)ptr + CLICK_SZ; -#else - - /* - * Round up requested size to an even number of alignment units - * (core clicks) - */ - int nclicks; - int size; - - /* First, see if we have space in the block most recently - * allocated to this pool - */ - - union block_hdr *blok; - char *first_avail; - char *new_first_avail; - - if (a == NULL) { - return malloc(reqsize); - } - - nclicks = 1 + ((reqsize - 1) / CLICK_SZ); - size = nclicks * CLICK_SZ; - - /* First, see if we have space in the block most recently - * allocated to this pool - */ - - blok = a->last; - first_avail = blok->h.first_avail; - - if (reqsize <= 0) { - return NULL; - } - - new_first_avail = first_avail + size; - - if (new_first_avail <= blok->h.endp) { - debug_verify_filled(first_avail, blok->h.endp, - "Ouch! Someone trounced past the end " - "of their allocation!\n"); - blok->h.first_avail = new_first_avail; - return (void *) first_avail; - } - - /* Nope --- get a new one that's guaranteed to be big enough */ - - ap_block_alarms(); - -#if APR_HAS_THREADS - ap_lock(alloc_mutex); -#endif - - blok = new_block(size, a->apr_abort); - a->last->h.next = blok; - a->last = blok; -#ifdef POOL_DEBUG - blok->h.owning_pool = a; -#endif - -#if APR_HAS_THREADS - ap_unlock(alloc_mutex); -#endif - - ap_unblock_alarms(); - - first_avail = blok->h.first_avail; - blok->h.first_avail += size; - - return (void *) first_avail; -#endif -} - -API_EXPORT(void *) ap_pcalloc(ap_pool_t *a, int size) -{ - void *res = ap_palloc(a, size); - memset(res, '\0', size); - return res; -} - -API_EXPORT(char *) ap_pstrdup(ap_pool_t *a, const char *s) -{ - char *res; - size_t len; - - if (s == NULL) { - return NULL; - } - len = strlen(s) + 1; - res = ap_palloc(a, len); - memcpy(res, s, len); - return res; -} - -API_EXPORT(char *) ap_pstrndup(ap_pool_t *a, const char *s, int n) -{ - char *res; - - if (s == NULL) { - return NULL; - } - res = ap_palloc(a, n + 1); - memcpy(res, s, n); - res[n] = '\0'; - return res; -} - -API_EXPORT_NONSTD(char *) ap_pstrcat(ap_pool_t *a, ...) -{ - char *cp, *argp, *res; - - /* Pass one --- find length of required string */ - - int len = 0; - va_list adummy; - - va_start(adummy, a); - - while ((cp = va_arg(adummy, char *)) != NULL) { - len += strlen(cp); - } - - va_end(adummy); - - /* Allocate the required string */ - - res = (char *) ap_palloc(a, len + 1); - cp = res; - *cp = '\0'; - - /* Pass two --- copy the argument strings into the result space */ - - va_start(adummy, a); - - while ((argp = va_arg(adummy, char *)) != NULL) { - strcpy(cp, argp); - cp += strlen(argp); - } - - va_end(adummy); - - /* Return the result string */ - - return res; -} - -/* - * ap_psprintf is implemented by writing directly into the current - * block of the pool, starting right at first_avail. If there's - * insufficient room, then a new block is allocated and the earlier - * output is copied over. The new block isn't linked into the pool - * until all the output is done. - * - * Note that this is completely safe because nothing else can - * allocate in this ap_pool_t while ap_psprintf is running. alarms are - * blocked, and the only thing outside of alloc.c that's invoked - * is ap_vformatter -- which was purposefully written to be - * self-contained with no callouts. - */ - -struct psprintf_data { - ap_vformatter_buff_t vbuff; -#ifdef ALLOC_USE_MALLOC - char *base; -#else - union block_hdr *blok; - int got_a_new_block; -#endif -}; - -static int psprintf_flush(ap_vformatter_buff_t *vbuff) -{ - struct psprintf_data *ps = (struct psprintf_data *)vbuff; -#ifdef ALLOC_USE_MALLOC - int size; - char *ptr; - - size = (char *)ps->vbuff.curpos - ps->base; - ptr = realloc(ps->base, 2*size); - if (ptr == NULL) { - fputs("Ouch! Out of memory!\n", stderr); - exit(1); - } - ps->base = ptr; - ps->vbuff.curpos = ptr + size; - ps->vbuff.endpos = ptr + 2*size - 1; - return 0; -#else - union block_hdr *blok; - union block_hdr *nblok; - size_t cur_len; - char *strp; - - blok = ps->blok; - strp = ps->vbuff.curpos; - cur_len = strp - blok->h.first_avail; - - /* must try another blok */ -#if APR_HAS_THREADS - ap_lock(alloc_mutex); -#endif - nblok = new_block(2 * cur_len, NULL); -#if APR_HAS_THREADS - ap_unlock(alloc_mutex); -#endif - memcpy(nblok->h.first_avail, blok->h.first_avail, cur_len); - ps->vbuff.curpos = nblok->h.first_avail + cur_len; - /* save a byte for the NUL terminator */ - ps->vbuff.endpos = nblok->h.endp - 1; - - /* did we allocate the current blok? if so free it up */ - if (ps->got_a_new_block) { - debug_fill(blok->h.first_avail, blok->h.endp - blok->h.first_avail); -#if APR_HAS_THREADS - ap_lock(alloc_mutex); -#endif - blok->h.next = block_freelist; - block_freelist = blok; -#if APR_HAS_THREADS - ap_unlock(alloc_mutex); -#endif - } - ps->blok = nblok; - ps->got_a_new_block = 1; - /* note that we've deliberately not linked the new block onto - * the pool yet... because we may need to flush again later, and - * we'd have to spend more effort trying to unlink the block. - */ - return 0; -#endif -} - -API_EXPORT(char *) ap_pvsprintf(ap_pool_t *p, const char *fmt, va_list ap) -{ -#ifdef ALLOC_USE_MALLOC - struct psprintf_data ps; - void *ptr; - - ap_block_alarms(); - ps.base = malloc(512); - if (ps.base == NULL) { - fputs("Ouch! Out of memory!\n", stderr); - exit(1); - } - /* need room at beginning for allocation_list */ - ps.vbuff.curpos = ps.base + CLICK_SZ; - ps.vbuff.endpos = ps.base + 511; - ap_vformatter(psprintf_flush, &ps.vbuff, fmt, ap); - *ps.vbuff.curpos++ = '\0'; - ptr = ps.base; - /* shrink */ - ptr = realloc(ptr, (char *)ps.vbuff.curpos - (char *)ptr); - if (ptr == NULL) { - fputs("Ouch! Out of memory!\n", stderr); - exit(1); - } - *(void **)ptr = p->allocation_list; - p->allocation_list = ptr; - ap_unblock_alarms(); - return (char *)ptr + CLICK_SZ; -#else - struct psprintf_data ps; - char *strp; - int size; - - ap_block_alarms(); - ps.blok = p->last; - ps.vbuff.curpos = ps.blok->h.first_avail; - ps.vbuff.endpos = ps.blok->h.endp - 1; /* save one for NUL */ - ps.got_a_new_block = 0; - - ap_vformatter(psprintf_flush, &ps.vbuff, fmt, ap); - - strp = ps.vbuff.curpos; - *strp++ = '\0'; - - size = strp - ps.blok->h.first_avail; - size = (1 + ((size - 1) / CLICK_SZ)) * CLICK_SZ; - strp = ps.blok->h.first_avail; /* save away result pointer */ - ps.blok->h.first_avail += size; - - /* have to link the block in if it's a new one */ - if (ps.got_a_new_block) { - p->last->h.next = ps.blok; - p->last = ps.blok; -#ifdef POOL_DEBUG - ps.blok->h.owning_pool = p; -#endif - } - ap_unblock_alarms(); - - return strp; -#endif -} - -API_EXPORT_NONSTD(char *) ap_psprintf(ap_pool_t *p, const char *fmt, ...) -{ - va_list ap; - char *res; - - va_start(ap, fmt); - res = ap_pvsprintf(p, fmt, ap); - va_end(ap); - return res; -} - - -/***************************************************************** - * - * More grotty system stuff... subprocesses. Frump. These don't use - * the generic cleanup interface because I don't want multiple - * subprocesses to result in multiple three-second pauses; the - * subprocesses have to be "freed" all at once. If someone comes - * along with another resource they want to allocate which has the - * same property, we might want to fold support for that into the - * generic interface, but for now, it's a special case - */ - -API_EXPORT(void) ap_note_subprocess(ap_pool_t *a, ap_proc_t *pid, - enum kill_conditions how) -{ - struct process_chain *new = - (struct process_chain *) ap_palloc(a, sizeof(struct process_chain)); - - new->pid = pid; - new->kill_how = how; - new->next = a->subprocesses; - a->subprocesses = new; -} - -static void free_proc_chain(struct process_chain *procs) -{ - /* Dispose of the subprocesses we've spawned off in the course of - * whatever it was we're cleaning up now. This may involve killing - * some of them off... - */ - struct process_chain *p; - int need_timeout = 0; - - if (procs == NULL) { - return; /* No work. Whew! */ - } - - /* First, check to see if we need to do the SIGTERM, sleep, SIGKILL - * dance with any of the processes we're cleaning up. If we've got - * any kill-on-sight subprocesses, ditch them now as well, so they - * don't waste any more cycles doing whatever it is that they shouldn't - * be doing anymore. - */ - -#ifndef NEED_WAITPID - /* Pick up all defunct processes */ - for (p = procs; p; p = p->next) { - if (ap_wait_proc(p->pid, APR_NOWAIT) == APR_CHILD_DONE) { - p->kill_how = kill_never; - } - } -#endif - - for (p = procs; p; p = p->next) { - if ((p->kill_how == kill_after_timeout) - || (p->kill_how == kill_only_once)) { - /* - * Subprocess may be dead already. Only need the timeout if not. - * Note: ap_kill on Windows is TerminateProcess(), which is - * similar to a SIGKILL, so always give the process a timeout - * under Windows before killing it. - */ -#ifdef WIN32 - need_timeout = 1; -#else - if (ap_kill(p->pid, APR_SIGTERM) == APR_SUCCESS) { - need_timeout = 1; - } -#endif - } - else if (p->kill_how == kill_always) { - ap_kill(p->pid, APR_SIGKILL); - } - } - - /* Sleep only if we have to... */ - if (need_timeout) { - sleep(3); - } - - /* OK, the scripts we just timed out for have had a chance to clean up - * --- now, just get rid of them, and also clean up the system accounting - * goop... - */ - for (p = procs; p; p = p->next) { - if (p->kill_how == kill_after_timeout) { - ap_kill(p->pid, APR_SIGKILL); - } - } -#ifdef WIN32 - /* - * Do we need an APR function to clean-up a proc_t? - */ - { - PROCESS_INFORMATION pi; - for (p = procs; p; p = p->next) { - ap_get_os_proc(&pi, p->pid); - CloseHandle(pi.hProcess); - } - } -#endif /* WIN32 */ - - /* Now wait for all the signaled processes to die */ - for (p = procs; p; p = p->next) { - if (p->kill_how != kill_never) { - (void) ap_wait_proc(p->pid, APR_WAIT); - } - } -} diff --git a/lib/apr_signal.c b/lib/apr_signal.c deleted file mode 100644 index 9fd1164c8a7..00000000000 --- a/lib/apr_signal.c +++ /dev/null @@ -1,84 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#include "apr_private.h" -#include "apr_lib.h" -#ifdef HAVE_SIGNAL_H -#include <signal.h> -#endif - -#if !defined(NO_USE_SIGACTION) && defined(HAVE_SIGACTION) -/* - * Replace standard signal() with the more reliable sigaction equivalent - * from W. Richard Stevens' "Advanced Programming in the UNIX Environment" - * (the version that does not automatically restart system calls). - */ -Sigfunc *ap_signal(int signo, Sigfunc * func) -{ - struct sigaction act, oact; - - act.sa_handler = func; - sigemptyset(&act.sa_mask); - act.sa_flags = 0; -#ifdef SA_INTERRUPT /* SunOS */ - act.sa_flags |= SA_INTERRUPT; -#endif - if (sigaction(signo, &act, &oact) < 0) - return SIG_ERR; - return oact.sa_handler; -} -#else -/* need some function in this file, otherwise the linker on NeXT bitches */ -void ap_signal_is_not_here(void) {} -#endif diff --git a/lib/apr_snprintf.c b/lib/apr_snprintf.c deleted file mode 100644 index c5ea415ec35..00000000000 --- a/lib/apr_snprintf.c +++ /dev/null @@ -1,1194 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#ifdef WIN32 -#include <winsock2.h> -#endif -#include "apr_private.h" - -#include "apr_lib.h" -#include <math.h> -#ifdef HAVE_CTYPE_H -#include <ctype.h> -#endif -#if HAVE_NETINET_IN_H -#include <netinet/in.h> -#endif -#ifdef HAVE_SYS_SOCKET_H -#include <sys/socket.h> -#endif -#ifdef HAVE_ARPA_INET_H -#include <arpa/inet.h> -#endif -#ifdef HAVE_LIMITS_H -#include <limits.h> -#endif -#ifdef HAVE_STRING_H -#include <string.h> -#endif - -typedef enum { - NO = 0, YES = 1 -} boolean_e; - -#ifndef FALSE -#define FALSE 0 -#endif -#ifndef TRUE -#define TRUE 1 -#endif -#ifndef AP_LONGEST_LONG -#define AP_LONGEST_LONG long -#endif -#define NUL '\0' -#define WIDE_INT long -#define WIDEST_INT AP_LONGEST_LONG - -typedef WIDE_INT wide_int; -typedef unsigned WIDE_INT u_wide_int; -typedef WIDEST_INT widest_int; -#ifdef __TANDEM -/* Although Tandem supports "long long" there is no unsigned variant. */ -typedef unsigned long u_widest_int; -#else -typedef unsigned WIDEST_INT u_widest_int; -#endif -typedef int bool_int; - -#define S_NULL "(null)" -#define S_NULL_LEN 6 - -#define FLOAT_DIGITS 6 -#define EXPONENT_LENGTH 10 - -/* - * NUM_BUF_SIZE is the size of the buffer used for arithmetic conversions - * - * XXX: this is a magic number; do not decrease it - */ -#define NUM_BUF_SIZE 512 - -/* - * cvt.c - IEEE floating point formatting routines for FreeBSD - * from GNU libc-4.6.27. Modified to be thread safe. - */ - -/* - * ap_ecvt converts to decimal - * the number of digits is specified by ndigit - * decpt is set to the position of the decimal point - * sign is set to 0 for positive, 1 for negative - */ - -#define NDIG 80 - -/* buf must have at least NDIG bytes */ -static char *ap_cvt(double arg, int ndigits, int *decpt, int *sign, int eflag, char *buf) -{ - register int r2; - double fi, fj; - register char *p, *p1; - - if (ndigits >= NDIG - 1) - ndigits = NDIG - 2; - r2 = 0; - *sign = 0; - p = &buf[0]; - if (arg < 0) { - *sign = 1; - arg = -arg; - } - arg = modf(arg, &fi); - p1 = &buf[NDIG]; - /* - * Do integer part - */ - if (fi != 0) { - p1 = &buf[NDIG]; - while (fi != 0) { - fj = modf(fi / 10, &fi); - *--p1 = (int) ((fj + .03) * 10) + '0'; - r2++; - } - while (p1 < &buf[NDIG]) - *p++ = *p1++; - } - else if (arg > 0) { - while ((fj = arg * 10) < 1) { - arg = fj; - r2--; - } - } - p1 = &buf[ndigits]; - if (eflag == 0) - p1 += r2; - *decpt = r2; - if (p1 < &buf[0]) { - buf[0] = '\0'; - return (buf); - } - while (p <= p1 && p < &buf[NDIG]) { - arg *= 10; - arg = modf(arg, &fj); - *p++ = (int) fj + '0'; - } - if (p1 >= &buf[NDIG]) { - buf[NDIG - 1] = '\0'; - return (buf); - } - p = p1; - *p1 += 5; - while (*p1 > '9') { - *p1 = '0'; - if (p1 > buf) - ++ * --p1; - else { - *p1 = '1'; - (*decpt)++; - if (eflag == 0) { - if (p > buf) - *p = '0'; - p++; - } - } - } - *p = '\0'; - return (buf); -} - -static char *ap_ecvt(double arg, int ndigits, int *decpt, int *sign, char *buf) -{ - return (ap_cvt(arg, ndigits, decpt, sign, 1, buf)); -} - -static char *ap_fcvt(double arg, int ndigits, int *decpt, int *sign, char *buf) -{ - return (ap_cvt(arg, ndigits, decpt, sign, 0, buf)); -} - -/* - * ap_gcvt - Floating output conversion to - * minimal length string - */ - -static char *ap_gcvt(double number, int ndigit, char *buf, boolean_e altform) -{ - int sign, decpt; - register char *p1, *p2; - register int i; - char buf1[NDIG]; - - p1 = ap_ecvt(number, ndigit, &decpt, &sign, buf1); - p2 = buf; - if (sign) - *p2++ = '-'; - for (i = ndigit - 1; i > 0 && p1[i] == '0'; i--) - ndigit--; - if ((decpt >= 0 && decpt - ndigit > 4) - || (decpt < 0 && decpt < -3)) { /* use E-style */ - decpt--; - *p2++ = *p1++; - *p2++ = '.'; - for (i = 1; i < ndigit; i++) - *p2++ = *p1++; - *p2++ = 'e'; - if (decpt < 0) { - decpt = -decpt; - *p2++ = '-'; - } - else - *p2++ = '+'; - if (decpt / 100 > 0) - *p2++ = decpt / 100 + '0'; - if (decpt / 10 > 0) - *p2++ = (decpt % 100) / 10 + '0'; - *p2++ = decpt % 10 + '0'; - } - else { - if (decpt <= 0) { - if (*p1 != '0') - *p2++ = '.'; - while (decpt < 0) { - decpt++; - *p2++ = '0'; - } - } - for (i = 1; i <= ndigit; i++) { - *p2++ = *p1++; - if (i == decpt) - *p2++ = '.'; - } - if (ndigit < decpt) { - while (ndigit++ < decpt) - *p2++ = '0'; - *p2++ = '.'; - } - } - if (p2[-1] == '.' && !altform) - p2--; - *p2 = '\0'; - return (buf); -} - -/* - * The INS_CHAR macro inserts a character in the buffer and writes - * the buffer back to disk if necessary - * It uses the char pointers sp and bep: - * sp points to the next available character in the buffer - * bep points to the end-of-buffer+1 - * While using this macro, note that the nextb pointer is NOT updated. - * - * NOTE: Evaluation of the c argument should not have any side-effects - */ -#define INS_CHAR(c, sp, bep, cc) \ - { \ - if (sp >= bep) { \ - vbuff->curpos = sp; \ - if (flush_func(vbuff)) \ - return -1; \ - sp = vbuff->curpos; \ - bep = vbuff->endpos; \ - } \ - *sp++ = (c); \ - cc++; \ - } - -#define NUM( c ) ( c - '0' ) - -#define STR_TO_DEC( str, num ) \ - num = NUM( *str++ ) ; \ - while ( ap_isdigit( *str ) ) \ - { \ - num *= 10 ; \ - num += NUM( *str++ ) ; \ - } - -/* - * This macro does zero padding so that the precision - * requirement is satisfied. The padding is done by - * adding '0's to the left of the string that is going - * to be printed. - */ -#define FIX_PRECISION( adjust, precision, s, s_len ) \ - if ( adjust ) \ - while ( s_len < precision ) \ - { \ - *--s = '0' ; \ - s_len++ ; \ - } - -/* - * Macro that does padding. The padding is done by printing - * the character ch. - */ -#define PAD( width, len, ch ) do \ - { \ - INS_CHAR( ch, sp, bep, cc ) ; \ - width-- ; \ - } \ - while ( width > len ) - -/* - * Prefix the character ch to the string str - * Increase length - * Set the has_prefix flag - */ -#define PREFIX( str, length, ch ) *--str = ch ; length++ ; has_prefix = YES - - -/* - * Convert num to its decimal format. - * Return value: - * - a pointer to a string containing the number (no sign) - * - len contains the length of the string - * - is_negative is set to TRUE or FALSE depending on the sign - * of the number (always set to FALSE if is_unsigned is TRUE) - * - * The caller provides a buffer for the string: that is the buf_end argument - * which is a pointer to the END of the buffer + 1 (i.e. if the buffer - * is declared as buf[ 100 ], buf_end should be &buf[ 100 ]) - * - * Note: we have 2 versions. One is used when we need to use quads - * (conv_10_quad), the other when we don't (conv_10). We're assuming the - * latter is faster. - */ -static char *conv_10(register wide_int num, register bool_int is_unsigned, - register bool_int *is_negative, char *buf_end, - register int *len) -{ - register char *p = buf_end; - register u_wide_int magnitude; - - if (is_unsigned) { - magnitude = (u_wide_int) num; - *is_negative = FALSE; - } - else { - *is_negative = (num < 0); - - /* - * On a 2's complement machine, negating the most negative integer - * results in a number that cannot be represented as a signed integer. - * Here is what we do to obtain the number's magnitude: - * a. add 1 to the number - * b. negate it (becomes positive) - * c. convert it to unsigned - * d. add 1 - */ - if (*is_negative) { - wide_int t = num + 1; - - magnitude = ((u_wide_int) -t) + 1; - } - else - magnitude = (u_wide_int) num; - } - - /* - * We use a do-while loop so that we write at least 1 digit - */ - do { - register u_wide_int new_magnitude = magnitude / 10; - - *--p = (char) (magnitude - new_magnitude * 10 + '0'); - magnitude = new_magnitude; - } - while (magnitude); - - *len = buf_end - p; - return (p); -} - -static char *conv_10_quad(widest_int num, register bool_int is_unsigned, - register bool_int *is_negative, char *buf_end, - register int *len) -{ - register char *p = buf_end; - u_widest_int magnitude; - - /* - * We see if we can use the faster non-quad version by checking the - * number against the largest long value it can be. If <=, we - * punt to the quicker version. - */ - if ((num <= ULONG_MAX && is_unsigned) || (num <= LONG_MAX && !is_unsigned)) - return(conv_10( (wide_int)num, is_unsigned, is_negative, - buf_end, len)); - - if (is_unsigned) { - magnitude = (u_widest_int) num; - *is_negative = FALSE; - } - else { - *is_negative = (num < 0); - - /* - * On a 2's complement machine, negating the most negative integer - * results in a number that cannot be represented as a signed integer. - * Here is what we do to obtain the number's magnitude: - * a. add 1 to the number - * b. negate it (becomes positive) - * c. convert it to unsigned - * d. add 1 - */ - if (*is_negative) { - widest_int t = num + 1; - - magnitude = ((u_widest_int) -t) + 1; - } - else - magnitude = (u_widest_int) num; - } - - /* - * We use a do-while loop so that we write at least 1 digit - */ - do { - u_widest_int new_magnitude = magnitude / 10; - - *--p = (char) (magnitude - new_magnitude * 10 + '0'); - magnitude = new_magnitude; - } - while (magnitude); - - *len = buf_end - p; - return (p); -} - - - -static char *conv_in_addr(struct in_addr *ia, char *buf_end, int *len) -{ - unsigned addr = ntohl(ia->s_addr); - char *p = buf_end; - bool_int is_negative; - int sub_len; - - p = conv_10((addr & 0x000000FF) , TRUE, &is_negative, p, &sub_len); - *--p = '.'; - p = conv_10((addr & 0x0000FF00) >> 8, TRUE, &is_negative, p, &sub_len); - *--p = '.'; - p = conv_10((addr & 0x00FF0000) >> 16, TRUE, &is_negative, p, &sub_len); - *--p = '.'; - p = conv_10((addr & 0xFF000000) >> 24, TRUE, &is_negative, p, &sub_len); - - *len = buf_end - p; - return (p); -} - - - -static char *conv_sockaddr_in(struct sockaddr_in *si, char *buf_end, int *len) -{ - char *p = buf_end; - bool_int is_negative; - int sub_len; - - p = conv_10(ntohs(si->sin_port), TRUE, &is_negative, p, &sub_len); - *--p = ':'; - p = conv_in_addr(&si->sin_addr, p, &sub_len); - - *len = buf_end - p; - return (p); -} - - - -/* - * Convert a floating point number to a string formats 'f', 'e' or 'E'. - * The result is placed in buf, and len denotes the length of the string - * The sign is returned in the is_negative argument (and is not placed - * in buf). - */ -static char *conv_fp(register char format, register double num, - boolean_e add_dp, int precision, bool_int *is_negative, - char *buf, int *len) -{ - register char *s = buf; - register char *p; - int decimal_point; - char buf1[NDIG]; - - if (format == 'f') - p = ap_fcvt(num, precision, &decimal_point, is_negative, buf1); - else /* either e or E format */ - p = ap_ecvt(num, precision + 1, &decimal_point, is_negative, buf1); - - /* - * Check for Infinity and NaN - */ - if (ap_isalpha(*p)) { - *len = strlen(strcpy(buf, p)); - *is_negative = FALSE; - return (buf); - } - - if (format == 'f') { - if (decimal_point <= 0) { - *s++ = '0'; - if (precision > 0) { - *s++ = '.'; - while (decimal_point++ < 0) - *s++ = '0'; - } - else if (add_dp) - *s++ = '.'; - } - else { - while (decimal_point-- > 0) - *s++ = *p++; - if (precision > 0 || add_dp) - *s++ = '.'; - } - } - else { - *s++ = *p++; - if (precision > 0 || add_dp) - *s++ = '.'; - } - - /* - * copy the rest of p, the NUL is NOT copied - */ - while (*p) - *s++ = *p++; - - if (format != 'f') { - char temp[EXPONENT_LENGTH]; /* for exponent conversion */ - int t_len; - bool_int exponent_is_negative; - - *s++ = format; /* either e or E */ - decimal_point--; - if (decimal_point != 0) { - p = conv_10((wide_int) decimal_point, FALSE, &exponent_is_negative, - &temp[EXPONENT_LENGTH], &t_len); - *s++ = exponent_is_negative ? '-' : '+'; - - /* - * Make sure the exponent has at least 2 digits - */ - if (t_len == 1) - *s++ = '0'; - while (t_len--) - *s++ = *p++; - } - else { - *s++ = '+'; - *s++ = '0'; - *s++ = '0'; - } - } - - *len = s - buf; - return (buf); -} - - -/* - * Convert num to a base X number where X is a power of 2. nbits determines X. - * For example, if nbits is 3, we do base 8 conversion - * Return value: - * a pointer to a string containing the number - * - * The caller provides a buffer for the string: that is the buf_end argument - * which is a pointer to the END of the buffer + 1 (i.e. if the buffer - * is declared as buf[ 100 ], buf_end should be &buf[ 100 ]) - * - * As with conv_10, we have a faster version which is used when - * the number isn't quad size. - */ -static char *conv_p2(register u_wide_int num, register int nbits, - char format, char *buf_end, register int *len) -{ - register int mask = (1 << nbits) - 1; - register char *p = buf_end; - static const char low_digits[] = "0123456789abcdef"; - static const char upper_digits[] = "0123456789ABCDEF"; - register const char *digits = (format == 'X') ? upper_digits : low_digits; - - do { - *--p = digits[num & mask]; - num >>= nbits; - } - while (num); - - *len = buf_end - p; - return (p); -} - -static char *conv_p2_quad(u_widest_int num, register int nbits, - char format, char *buf_end, register int *len) -{ - register int mask = (1 << nbits) - 1; - register char *p = buf_end; - static const char low_digits[] = "0123456789abcdef"; - static const char upper_digits[] = "0123456789ABCDEF"; - register const char *digits = (format == 'X') ? upper_digits : low_digits; - - if (num <= ULONG_MAX) - return(conv_p2( (u_wide_int)num, nbits, format, buf_end, len)); - - do { - *--p = digits[num & mask]; - num >>= nbits; - } - while (num); - - *len = buf_end - p; - return (p); -} - - -/* - * Do format conversion placing the output in buffer - */ -API_EXPORT(int) ap_vformatter(int (*flush_func)(ap_vformatter_buff_t *), - ap_vformatter_buff_t *vbuff, const char *fmt, va_list ap) -{ - register char *sp; - register char *bep; - register int cc = 0; - register int i; - - register char *s = NULL; - char *q; - int s_len; - - register int min_width = 0; - int precision = 0; - enum { - LEFT, RIGHT - } adjust; - char pad_char; - char prefix_char; - - double fp_num; - widest_int i_quad = (widest_int) 0; - u_widest_int ui_quad; - wide_int i_num = (wide_int) 0; - u_wide_int ui_num; - - char num_buf[NUM_BUF_SIZE]; - char char_buf[2]; /* for printing %% and %<unknown> */ - - enum var_type_enum { - IS_QUAD, IS_LONG, IS_SHORT, IS_INT - }; - enum var_type_enum var_type = IS_INT; - - /* - * Flag variables - */ - boolean_e alternate_form; - boolean_e print_sign; - boolean_e print_blank; - boolean_e adjust_precision; - boolean_e adjust_width; - bool_int is_negative; - - sp = vbuff->curpos; - bep = vbuff->endpos; - - while (*fmt) { - if (*fmt != '%') { - INS_CHAR(*fmt, sp, bep, cc); - } - else { - /* - * Default variable settings - */ - adjust = RIGHT; - alternate_form = print_sign = print_blank = NO; - pad_char = ' '; - prefix_char = NUL; - - fmt++; - - /* - * Try to avoid checking for flags, width or precision - */ - if (!ap_islower(*fmt)) { - /* - * Recognize flags: -, #, BLANK, + - */ - for (;; fmt++) { - if (*fmt == '-') - adjust = LEFT; - else if (*fmt == '+') - print_sign = YES; - else if (*fmt == '#') - alternate_form = YES; - else if (*fmt == ' ') - print_blank = YES; - else if (*fmt == '0') - pad_char = '0'; - else - break; - } - - /* - * Check if a width was specified - */ - if (ap_isdigit(*fmt)) { - STR_TO_DEC(fmt, min_width); - adjust_width = YES; - } - else if (*fmt == '*') { - min_width = va_arg(ap, int); - fmt++; - adjust_width = YES; - if (min_width < 0) { - adjust = LEFT; - min_width = -min_width; - } - } - else - adjust_width = NO; - - /* - * Check if a precision was specified - * - * XXX: an unreasonable amount of precision may be specified - * resulting in overflow of num_buf. Currently we - * ignore this possibility. - */ - if (*fmt == '.') { - adjust_precision = YES; - fmt++; - if (ap_isdigit(*fmt)) { - STR_TO_DEC(fmt, precision); - } - else if (*fmt == '*') { - precision = va_arg(ap, int); - fmt++; - if (precision < 0) - precision = 0; - } - else - precision = 0; - } - else - adjust_precision = NO; - } - else - adjust_precision = adjust_width = NO; - - /* - * Modifier check - */ - if (*fmt == 'q') { - var_type = IS_QUAD; - fmt++; - } - else if (*fmt == 'l') { - var_type = IS_LONG; - fmt++; - } - else if (*fmt == 'h') { - var_type = IS_SHORT; - fmt++; - } - else { - var_type = IS_INT; - } - - /* - * Argument extraction and printing. - * First we determine the argument type. - * Then, we convert the argument to a string. - * On exit from the switch, s points to the string that - * must be printed, s_len has the length of the string - * The precision requirements, if any, are reflected in s_len. - * - * NOTE: pad_char may be set to '0' because of the 0 flag. - * It is reset to ' ' by non-numeric formats - */ - switch (*fmt) { - case 'u': - if (var_type == IS_QUAD) { - i_quad = va_arg(ap, u_widest_int); - s = conv_10_quad(i_quad, 1, &is_negative, - &num_buf[NUM_BUF_SIZE], &s_len); - } - else { - if (var_type == IS_LONG) - i_num = (wide_int) va_arg(ap, u_wide_int); - else if (var_type == IS_SHORT) - i_num = (wide_int) (unsigned short) va_arg(ap, unsigned int); - else - i_num = (wide_int) va_arg(ap, unsigned int); - s = conv_10(i_num, 1, &is_negative, - &num_buf[NUM_BUF_SIZE], &s_len); - } - FIX_PRECISION(adjust_precision, precision, s, s_len); - break; - - case 'd': - case 'i': - if (var_type == IS_QUAD) { - i_quad = va_arg(ap, widest_int); - s = conv_10_quad(i_quad, 0, &is_negative, - &num_buf[NUM_BUF_SIZE], &s_len); - } - else { - if (var_type == IS_LONG) - i_num = (wide_int) va_arg(ap, wide_int); - else if (var_type == IS_SHORT) - i_num = (wide_int) (short) va_arg(ap, int); - else - i_num = (wide_int) va_arg(ap, int); - s = conv_10(i_num, 0, &is_negative, - &num_buf[NUM_BUF_SIZE], &s_len); - } - FIX_PRECISION(adjust_precision, precision, s, s_len); - - if (is_negative) - prefix_char = '-'; - else if (print_sign) - prefix_char = '+'; - else if (print_blank) - prefix_char = ' '; - break; - - - case 'o': - if (var_type == IS_QUAD) { - ui_quad = va_arg(ap, u_widest_int); - s = conv_p2_quad(ui_quad, 3, *fmt, - &num_buf[NUM_BUF_SIZE], &s_len); - } - else { - if (var_type == IS_LONG) - ui_num = (u_wide_int) va_arg(ap, u_wide_int); - else if (var_type == IS_SHORT) - ui_num = (u_wide_int) (unsigned short) va_arg(ap, unsigned int); - else - ui_num = (u_wide_int) va_arg(ap, unsigned int); - s = conv_p2(ui_num, 3, *fmt, - &num_buf[NUM_BUF_SIZE], &s_len); - } - FIX_PRECISION(adjust_precision, precision, s, s_len); - if (alternate_form && *s != '0') { - *--s = '0'; - s_len++; - } - break; - - - case 'x': - case 'X': - if (var_type == IS_QUAD) { - ui_quad = va_arg(ap, u_widest_int); - s = conv_p2_quad(ui_quad, 4, *fmt, - &num_buf[NUM_BUF_SIZE], &s_len); - } - else { - if (var_type == IS_LONG) - ui_num = (u_wide_int) va_arg(ap, u_wide_int); - else if (var_type == IS_SHORT) - ui_num = (u_wide_int) (unsigned short) va_arg(ap, unsigned int); - else - ui_num = (u_wide_int) va_arg(ap, unsigned int); - s = conv_p2(ui_num, 4, *fmt, - &num_buf[NUM_BUF_SIZE], &s_len); - } - FIX_PRECISION(adjust_precision, precision, s, s_len); - if (alternate_form && i_num != 0) { - *--s = *fmt; /* 'x' or 'X' */ - *--s = '0'; - s_len += 2; - } - break; - - - case 's': - s = va_arg(ap, char *); - if (s != NULL) { - s_len = strlen(s); - if (adjust_precision && precision < s_len) - s_len = precision; - } - else { - s = S_NULL; - s_len = S_NULL_LEN; - } - pad_char = ' '; - break; - - - case 'f': - case 'e': - case 'E': - fp_num = va_arg(ap, double); - /* - * * We use &num_buf[ 1 ], so that we have room for the sign - */ - s = conv_fp(*fmt, fp_num, alternate_form, - (adjust_precision == NO) ? FLOAT_DIGITS : precision, - &is_negative, &num_buf[1], &s_len); - if (is_negative) - prefix_char = '-'; - else if (print_sign) - prefix_char = '+'; - else if (print_blank) - prefix_char = ' '; - break; - - - case 'g': - case 'G': - if (adjust_precision == NO) - precision = FLOAT_DIGITS; - else if (precision == 0) - precision = 1; - /* - * * We use &num_buf[ 1 ], so that we have room for the sign - */ - s = ap_gcvt(va_arg(ap, double), precision, &num_buf[1], - alternate_form); - if (*s == '-') - prefix_char = *s++; - else if (print_sign) - prefix_char = '+'; - else if (print_blank) - prefix_char = ' '; - - s_len = strlen(s); - - if (alternate_form && (q = strchr(s, '.')) == NULL) { - s[s_len++] = '.'; - s[s_len] = '\0'; /* delimit for following strchr() */ - } - if (*fmt == 'G' && (q = strchr(s, 'e')) != NULL) - *q = 'E'; - break; - - - case 'c': - char_buf[0] = (char) (va_arg(ap, int)); - s = &char_buf[0]; - s_len = 1; - pad_char = ' '; - break; - - - case '%': - char_buf[0] = '%'; - s = &char_buf[0]; - s_len = 1; - pad_char = ' '; - break; - - - case 'n': - if (var_type == IS_QUAD) - *(va_arg(ap, widest_int *)) = cc; - else if (var_type == IS_LONG) - *(va_arg(ap, long *)) = cc; - else if (var_type == IS_SHORT) - *(va_arg(ap, short *)) = cc; - else - *(va_arg(ap, int *)) = cc; - break; - - /* - * This is where we extend the printf format, with a second - * type specifier - */ - case 'p': - switch(*++fmt) { - /* - * If the pointer size is equal to or smaller than the size - * of the largest unsigned int, we convert the pointer to a - * hex number, otherwise we print "%p" to indicate that we - * don't handle "%p". - */ - case 'p': -#ifdef AP_VOID_P_IS_QUAD - if (sizeof(void *) <= sizeof(u_widest_int)) { - ui_quad = (u_widest_int) va_arg(ap, void *); - s = conv_p2_quad(ui_quad, 4, 'x', - &num_buf[NUM_BUF_SIZE], &s_len); - } -#else - if (sizeof(void *) <= sizeof(u_wide_int)) { - ui_num = (u_wide_int) va_arg(ap, void *); - s = conv_p2(ui_num, 4, 'x', - &num_buf[NUM_BUF_SIZE], &s_len); - } -#endif - else { - s = "%p"; - s_len = 2; - prefix_char = NUL; - } - pad_char = ' '; - break; - - /* print a struct sockaddr_in as a.b.c.d:port */ - case 'I': - { - struct sockaddr_in *si; - - si = va_arg(ap, struct sockaddr_in *); - if (si != NULL) { - s = conv_sockaddr_in(si, &num_buf[NUM_BUF_SIZE], &s_len); - if (adjust_precision && precision < s_len) - s_len = precision; - } - else { - s = S_NULL; - s_len = S_NULL_LEN; - } - pad_char = ' '; - } - break; - - /* print a struct in_addr as a.b.c.d */ - case 'A': - { - struct in_addr *ia; - - ia = va_arg(ap, struct in_addr *); - if (ia != NULL) { - s = conv_in_addr(ia, &num_buf[NUM_BUF_SIZE], &s_len); - if (adjust_precision && precision < s_len) - s_len = precision; - } - else { - s = S_NULL; - s_len = S_NULL_LEN; - } - pad_char = ' '; - } - break; - - case NUL: - /* if %p ends the string, oh well ignore it */ - continue; - - default: - s = "bogus %p"; - s_len = 8; - prefix_char = NUL; - break; - } - break; - - case NUL: - /* - * The last character of the format string was %. - * We ignore it. - */ - continue; - - - /* - * The default case is for unrecognized %'s. - * We print %<char> to help the user identify what - * option is not understood. - * This is also useful in case the user wants to pass - * the output of format_converter to another function - * that understands some other %<char> (like syslog). - * Note that we can't point s inside fmt because the - * unknown <char> could be preceded by width etc. - */ - default: - char_buf[0] = '%'; - char_buf[1] = *fmt; - s = char_buf; - s_len = 2; - pad_char = ' '; - break; - } - - if (prefix_char != NUL && s != S_NULL && s != char_buf) { - *--s = prefix_char; - s_len++; - } - - if (adjust_width && adjust == RIGHT && min_width > s_len) { - if (pad_char == '0' && prefix_char != NUL) { - INS_CHAR(*s, sp, bep, cc); - s++; - s_len--; - min_width--; - } - PAD(min_width, s_len, pad_char); - } - - /* - * Print the string s. - */ - for (i = s_len; i != 0; i--) { - INS_CHAR(*s, sp, bep, cc); - s++; - } - - if (adjust_width && adjust == LEFT && min_width > s_len) - PAD(min_width, s_len, pad_char); - } - fmt++; - } - vbuff->curpos = sp; - return cc; -} - - -static int snprintf_flush(ap_vformatter_buff_t *vbuff) -{ - /* if the buffer fills we have to abort immediately, there is no way - * to "flush" an ap_snprintf... there's nowhere to flush it to. - */ - return -1; -} - - -API_EXPORT(int) ap_snprintf(char *buf, size_t len, const char *format,...) -{ - int cc; - va_list ap; - ap_vformatter_buff_t vbuff; - - if (len == 0) - return 0; - - /* save one byte for nul terminator */ - vbuff.curpos = buf; - vbuff.endpos = buf + len - 1; - va_start(ap, format); - cc = ap_vformatter(snprintf_flush, &vbuff, format, ap); - va_end(ap); - *vbuff.curpos = '\0'; - return (cc == -1) ? len : cc; -} - - -API_EXPORT(int) ap_vsnprintf(char *buf, size_t len, const char *format, - va_list ap) -{ - int cc; - ap_vformatter_buff_t vbuff; - - if (len == 0) - return 0; - - /* save one byte for nul terminator */ - vbuff.curpos = buf; - vbuff.endpos = buf + len - 1; - cc = ap_vformatter(snprintf_flush, &vbuff, format, ap); - *vbuff.curpos = '\0'; - return (cc == -1) ? len : cc; -} diff --git a/lib/apr_tables.c b/lib/apr_tables.c deleted file mode 100644 index 79181ab8283..00000000000 --- a/lib/apr_tables.c +++ /dev/null @@ -1,769 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -/* - * Resource allocation code... the code here is responsible for making - * sure that nothing leaks. - * - * rst --- 4/95 --- 6/95 - */ - -#include "apr_private.h" - -#include "apr_general.h" -#include "apr_pools.h" -#include "apr_lib.h" -#include "misc.h" -#ifdef HAVE_STDLIB_H -#include <stdlib.h> -#endif -#ifdef HAVE_MALLOC_H -#include <malloc.h> -#endif -#ifdef HAVE_STRING_H -#include <string.h> -#endif - -/***************************************************************** - * This file contains array and ap_table_t functions only. - */ - -/***************************************************************** - * - * The 'array' functions... - */ - -static void make_array_core(ap_array_header_t *res, ap_pool_t *c, - int nelts, int elt_size) -{ - /* - * Assure sanity if someone asks for - * array of zero elts. - */ - if (nelts < 1) { - nelts = 1; - } - - res->elts = ap_pcalloc(c, nelts * elt_size); - - res->cont = c; - res->elt_size = elt_size; - res->nelts = 0; /* No active elements yet... */ - res->nalloc = nelts; /* ...but this many allocated */ -} - -API_EXPORT(ap_array_header_t *) ap_make_array(ap_pool_t *p, - int nelts, int elt_size) -{ - ap_array_header_t *res; - - res = (ap_array_header_t *) ap_palloc(p, sizeof(ap_array_header_t)); - make_array_core(res, p, nelts, elt_size); - return res; -} - -API_EXPORT(void *) ap_push_array(ap_array_header_t *arr) -{ - if (arr->nelts == arr->nalloc) { - int new_size = (arr->nalloc <= 0) ? 1 : arr->nalloc * 2; - char *new_data; - - new_data = ap_pcalloc(arr->cont, arr->elt_size * new_size); - - memcpy(new_data, arr->elts, arr->nalloc * arr->elt_size); - arr->elts = new_data; - arr->nalloc = new_size; - } - - ++arr->nelts; - return arr->elts + (arr->elt_size * (arr->nelts - 1)); -} - -API_EXPORT(void) ap_array_cat(ap_array_header_t *dst, - const ap_array_header_t *src) -{ - int elt_size = dst->elt_size; - - if (dst->nelts + src->nelts > dst->nalloc) { - int new_size = (dst->nalloc <= 0) ? 1 : dst->nalloc * 2; - char *new_data; - - while (dst->nelts + src->nelts > new_size) { - new_size *= 2; - } - - new_data = ap_pcalloc(dst->cont, elt_size * new_size); - memcpy(new_data, dst->elts, dst->nalloc * elt_size); - - dst->elts = new_data; - dst->nalloc = new_size; - } - - memcpy(dst->elts + dst->nelts * elt_size, src->elts, - elt_size * src->nelts); - dst->nelts += src->nelts; -} - -API_EXPORT(ap_array_header_t *) ap_copy_array(ap_pool_t *p, - const ap_array_header_t *arr) -{ - ap_array_header_t *res = ap_make_array(p, arr->nalloc, arr->elt_size); - - memcpy(res->elts, arr->elts, arr->elt_size * arr->nelts); - res->nelts = arr->nelts; - return res; -} - -/* This cute function copies the array header *only*, but arranges - * for the data section to be copied on the first push or arraycat. - * It's useful when the elements of the array being copied are - * read only, but new stuff *might* get added on the end; we have the - * overhead of the full copy only where it is really needed. - */ - -static APR_INLINE void copy_array_hdr_core(ap_array_header_t *res, - const ap_array_header_t *arr) -{ - res->elts = arr->elts; - res->elt_size = arr->elt_size; - res->nelts = arr->nelts; - res->nalloc = arr->nelts; /* Force overflow on push */ -} - -API_EXPORT(ap_array_header_t *) - ap_copy_array_hdr(ap_pool_t *p, - const ap_array_header_t *arr) -{ - ap_array_header_t *res; - - res = (ap_array_header_t *) ap_palloc(p, sizeof(ap_array_header_t)); - res->cont = p; - copy_array_hdr_core(res, arr); - return res; -} - -/* The above is used here to avoid consing multiple new array bodies... */ - -API_EXPORT(ap_array_header_t *) - ap_append_arrays(ap_pool_t *p, - const ap_array_header_t *first, - const ap_array_header_t *second) -{ - ap_array_header_t *res = ap_copy_array_hdr(p, first); - - ap_array_cat(res, second); - return res; -} - -/* ap_array_pstrcat generates a new string from the ap_pool_t containing - * the concatenated sequence of substrings referenced as elements within - * the array. The string will be empty if all substrings are empty or null, - * or if there are no elements in the array. - * If sep is non-NUL, it will be inserted between elements as a separator. - */ -API_EXPORT(char *) ap_array_pstrcat(ap_pool_t *p, - const ap_array_header_t *arr, - const char sep) -{ - char *cp, *res, **strpp; - int i, len; - - if (arr->nelts <= 0 || arr->elts == NULL) { /* Empty table? */ - return (char *) ap_pcalloc(p, 1); - } - - /* Pass one --- find length of required string */ - - len = 0; - for (i = 0, strpp = (char **) arr->elts; ; ++strpp) { - if (strpp && *strpp != NULL) { - len += strlen(*strpp); - } - if (++i >= arr->nelts) { - break; - } - if (sep) { - ++len; - } - } - - /* Allocate the required string */ - - res = (char *) ap_palloc(p, len + 1); - cp = res; - - /* Pass two --- copy the argument strings into the result space */ - - for (i = 0, strpp = (char **) arr->elts; ; ++strpp) { - if (strpp && *strpp != NULL) { - len = strlen(*strpp); - memcpy(cp, *strpp, len); - cp += len; - } - if (++i >= arr->nelts) { - break; - } - if (sep) { - *cp++ = sep; - } - } - - *cp = '\0'; - - /* Return the result string */ - - return res; -} - - -/***************************************************************** - * - * The "table" functions. - */ - -/* - * XXX: if you tweak this you should look at is_empty_table() and table_elts() - * in alloc.h - */ -#ifdef MAKE_TABLE_PROFILE -static ap_table_entry_t *table_push(ap_table_t *t) -{ - if (t->a.nelts == t->a.nalloc) { - return NULL; - } - return (ap_table_entry_t *) ap_push_array(&t->a); -} -#else /* MAKE_TABLE_PROFILE */ -#define table_push(t) ((ap_table_entry_t *) ap_push_array(&(t)->a)) -#endif /* MAKE_TABLE_PROFILE */ - - -API_EXPORT(ap_table_t *) ap_make_table(ap_pool_t *p, int nelts) -{ - ap_table_t *t = ap_palloc(p, sizeof(ap_table_t)); - - make_array_core(&t->a, p, nelts, sizeof(ap_table_entry_t)); -#ifdef MAKE_TABLE_PROFILE - t->creator = __builtin_return_address(0); -#endif - return t; -} - -API_EXPORT(ap_table_t *) ap_copy_table(ap_pool_t *p, const ap_table_t *t) -{ - ap_table_t *new = ap_palloc(p, sizeof(ap_table_t)); - -#ifdef POOL_DEBUG - /* we don't copy keys and values, so it's necessary that t->a.pool - * have a life span at least as long as p - */ - if (!ap_pool_is_ancestor(t->a.cont->pool, p->pool)) { - fprintf(stderr, "copy_table: t's pool is not an ancestor of p\n"); - abort(); - } -#endif - make_array_core(&new->a, p, t->a.nalloc, sizeof(ap_table_entry_t)); - memcpy(new->a.elts, t->a.elts, t->a.nelts * sizeof(ap_table_entry_t)); - new->a.nelts = t->a.nelts; - return new; -} - -API_EXPORT(void) ap_clear_table(ap_table_t *t) -{ - t->a.nelts = 0; -} - -API_EXPORT(const char *) ap_table_get(const ap_table_t *t, const char *key) -{ - ap_table_entry_t *elts = (ap_table_entry_t *) t->a.elts; - int i; - - if (key == NULL) { - return NULL; - } - - for (i = 0; i < t->a.nelts; ++i) { - if (!strcasecmp(elts[i].key, key)) { - return elts[i].val; - } - } - - return NULL; -} - -API_EXPORT(void) ap_table_set(ap_table_t *t, const char *key, - const char *val) -{ - register int i, j, k; - ap_table_entry_t *elts = (ap_table_entry_t *) t->a.elts; - int done = 0; - - for (i = 0; i < t->a.nelts; ) { - if (!strcasecmp(elts[i].key, key)) { - if (!done) { - elts[i].val = ap_pstrdup(t->a.cont, val); - done = 1; - ++i; - } - else { /* delete an extraneous element */ - for (j = i, k = i + 1; k < t->a.nelts; ++j, ++k) { - elts[j].key = elts[k].key; - elts[j].val = elts[k].val; - } - --t->a.nelts; - } - } - else { - ++i; - } - } - - if (!done) { - elts = (ap_table_entry_t *) table_push(t); - elts->key = ap_pstrdup(t->a.cont, key); - elts->val = ap_pstrdup(t->a.cont, val); - } -} - -API_EXPORT(void) ap_table_setn(ap_table_t *t, const char *key, - const char *val) -{ - register int i, j, k; - ap_table_entry_t *elts = (ap_table_entry_t *) t->a.elts; - int done = 0; - -#ifdef POOL_DEBUG - { - if (!ap_pool_is_ancestor(ap_find_pool(key), t->a.cont->pool)) { - fprintf(stderr, "table_set: key not in ancestor pool of t\n"); - abort(); - } - if (!ap_pool_is_ancestor(ap_find_pool(val), t->a.cont->pool)) { - fprintf(stderr, "table_set: val not in ancestor pool of t\n"); - abort(); - } - } -#endif - - for (i = 0; i < t->a.nelts; ) { - if (!strcasecmp(elts[i].key, key)) { - if (!done) { - elts[i].val = (char *)val; - done = 1; - ++i; - } - else { /* delete an extraneous element */ - for (j = i, k = i + 1; k < t->a.nelts; ++j, ++k) { - elts[j].key = elts[k].key; - elts[j].val = elts[k].val; - } - --t->a.nelts; - } - } - else { - ++i; - } - } - - if (!done) { - elts = (ap_table_entry_t *) table_push(t); - elts->key = (char *)key; - elts->val = (char *)val; - } -} - -API_EXPORT(void) ap_table_unset(ap_table_t *t, const char *key) -{ - register int i, j, k; - ap_table_entry_t *elts = (ap_table_entry_t *) t->a.elts; - - for (i = 0; i < t->a.nelts; ) { - if (!strcasecmp(elts[i].key, key)) { - - /* found an element to skip over - * there are any number of ways to remove an element from - * a contiguous block of memory. I've chosen one that - * doesn't do a memcpy/bcopy/array_delete, *shrug*... - */ - for (j = i, k = i + 1; k < t->a.nelts; ++j, ++k) { - elts[j].key = elts[k].key; - elts[j].val = elts[k].val; - } - --t->a.nelts; - } - else { - ++i; - } - } -} - -API_EXPORT(void) ap_table_merge(ap_table_t *t, const char *key, - const char *val) -{ - ap_table_entry_t *elts = (ap_table_entry_t *) t->a.elts; - int i; - - for (i = 0; i < t->a.nelts; ++i) { - if (!strcasecmp(elts[i].key, key)) { - elts[i].val = ap_pstrcat(t->a.cont, elts[i].val, ", ", val, NULL); - return; - } - } - - elts = (ap_table_entry_t *) table_push(t); - elts->key = ap_pstrdup(t->a.cont, key); - elts->val = ap_pstrdup(t->a.cont, val); -} - -API_EXPORT(void) ap_table_mergen(ap_table_t *t, const char *key, - const char *val) -{ - ap_table_entry_t *elts = (ap_table_entry_t *) t->a.elts; - int i; - -#ifdef POOL_DEBUG - { - if (!ap_pool_is_ancestor(ap_find_pool(key), t->a.cont->pool)) { - fprintf(stderr, "table_set: key not in ancestor pool of t\n"); - abort(); - } - if (!ap_pool_is_ancestor(ap_find_pool(val), t->a.cont->pool)) { - fprintf(stderr, "table_set: key not in ancestor pool of t\n"); - abort(); - } - } -#endif - - for (i = 0; i < t->a.nelts; ++i) { - if (!strcasecmp(elts[i].key, key)) { - elts[i].val = ap_pstrcat(t->a.cont, elts[i].val, ", ", val, NULL); - return; - } - } - - elts = (ap_table_entry_t *) table_push(t); - elts->key = (char *)key; - elts->val = (char *)val; -} - -API_EXPORT(void) ap_table_add(ap_table_t *t, const char *key, - const char *val) -{ - ap_table_entry_t *elts = (ap_table_entry_t *) t->a.elts; - - elts = (ap_table_entry_t *) table_push(t); - elts->key = ap_pstrdup(t->a.cont, key); - elts->val = ap_pstrdup(t->a.cont, val); -} - -API_EXPORT(void) ap_table_addn(ap_table_t *t, const char *key, - const char *val) -{ - ap_table_entry_t *elts = (ap_table_entry_t *) t->a.elts; - -#ifdef POOL_DEBUG - { - if (!ap_pool_is_ancestor(ap_find_pool(key), t->a.cont->pool)) { - fprintf(stderr, "table_set: key not in ancestor pool of t\n"); - abort(); - } - if (!ap_pool_is_ancestor(ap_find_pool(val), t->a.cont->pool)) { - fprintf(stderr, "table_set: key not in ancestor pool of t\n"); - abort(); - } - } -#endif - - elts = (ap_table_entry_t *) table_push(t); - elts->key = (char *)key; - elts->val = (char *)val; -} - -API_EXPORT(ap_table_t *) ap_overlay_tables(ap_pool_t *p, - const ap_table_t *overlay, - const ap_table_t *base) -{ - ap_table_t *res; - -#ifdef POOL_DEBUG - /* we don't copy keys and values, so it's necessary that - * overlay->a.pool and base->a.pool have a life span at least - * as long as p - */ - if (!ap_pool_is_ancestor(overlay->a.cont->pool, p->pool)) { - fprintf(stderr, - "overlay_tables: overlay's pool is not an ancestor of p\n"); - abort(); - } - if (!ap_pool_is_ancestor(base->a.cont->pool, p->pool)) { - fprintf(stderr, - "overlay_tables: base's pool is not an ancestor of p\n"); - abort(); - } -#endif - - res = ap_palloc(p, sizeof(ap_table_t)); - /* behave like append_arrays */ - res->a.cont = p; - copy_array_hdr_core(&res->a, &overlay->a); - ap_array_cat(&res->a, &base->a); - - return res; -} - -/* And now for something completely abstract ... - - * For each key value given as a vararg: - * run the function pointed to as - * int comp(void *r, char *key, char *value); - * on each valid key-value pair in the ap_table_t t that matches the vararg key, - * or once for every valid key-value pair if the vararg list is empty, - * until the function returns false (0) or we finish the table. - * - * Note that we restart the traversal for each vararg, which means that - * duplicate varargs will result in multiple executions of the function - * for each matching key. Note also that if the vararg list is empty, - * only one traversal will be made and will cut short if comp returns 0. - * - * Note that the table_get and table_merge functions assume that each key in - * the ap_table_t is unique (i.e., no multiple entries with the same key). This - * function does not make that assumption, since it (unfortunately) isn't - * true for some of Apache's tables. - * - * Note that rec is simply passed-on to the comp function, so that the - * caller can pass additional info for the task. - */ -API_EXPORT(void) ap_table_do(int (*comp) (void *, const char *, const char *), - void *rec, const ap_table_t *t, ...) -{ - va_list vp; - char *argp; - ap_table_entry_t *elts = (ap_table_entry_t *) t->a.elts; - int rv, i; - - va_start(vp, t); - - argp = va_arg(vp, char *); - - do { - for (rv = 1, i = 0; rv && (i < t->a.nelts); ++i) { - if (elts[i].key && (!argp || !strcasecmp(elts[i].key, argp))) { - rv = (*comp) (rec, elts[i].key, elts[i].val); - } - } - } while (argp && ((argp = va_arg(vp, char *)) != NULL)); - - va_end(vp); -} - -/* Curse libc and the fact that it doesn't guarantee a stable sort. We - * have to enforce stability ourselves by using the order field. If it - * provided a stable sort then we wouldn't even need temporary storage to - * do the work below. -djg - * - * ("stable sort" means that equal keys retain their original relative - * ordering in the output.) - */ -typedef struct { - char *key; - char *val; - int order; -} overlap_key; - -static int sort_overlap(const void *va, const void *vb) -{ - const overlap_key *a = va; - const overlap_key *b = vb; - int r; - - r = strcasecmp(a->key, b->key); - if (r) { - return r; - } - return a->order - b->order; -} - -/* prefer to use the stack for temp storage for overlaps smaller than this */ -#ifndef ap_OVERLAP_TABLES_ON_STACK -#define ap_OVERLAP_TABLES_ON_STACK (512) -#endif - -API_EXPORT(void) ap_overlap_tables(ap_table_t *a, const ap_table_t *b, - unsigned flags) -{ - overlap_key cat_keys_buf[ap_OVERLAP_TABLES_ON_STACK]; - overlap_key *cat_keys; - int nkeys; - ap_table_entry_t *e; - ap_table_entry_t *last_e; - overlap_key *left; - overlap_key *right; - overlap_key *last; - - nkeys = a->a.nelts + b->a.nelts; - if (nkeys < ap_OVERLAP_TABLES_ON_STACK) { - cat_keys = cat_keys_buf; - } - else { - /* XXX: could use scratch free space in a or b's pool instead... - * which could save an allocation in b's pool. - */ - cat_keys = ap_palloc(b->a.cont, sizeof(overlap_key) * nkeys); - } - - nkeys = 0; - - /* Create a list of the entries from a concatenated with the entries - * from b. - */ - e = (ap_table_entry_t *)a->a.elts; - last_e = e + a->a.nelts; - while (e < last_e) { - cat_keys[nkeys].key = e->key; - cat_keys[nkeys].val = e->val; - cat_keys[nkeys].order = nkeys; - ++nkeys; - ++e; - } - - e = (ap_table_entry_t *)b->a.elts; - last_e = e + b->a.nelts; - while (e < last_e) { - cat_keys[nkeys].key = e->key; - cat_keys[nkeys].val = e->val; - cat_keys[nkeys].order = nkeys; - ++nkeys; - ++e; - } - - qsort(cat_keys, nkeys, sizeof(overlap_key), sort_overlap); - - /* Now iterate over the sorted list and rebuild a. - * Start by making sure it has enough space. - */ - a->a.nelts = 0; - if (a->a.nalloc < nkeys) { - a->a.elts = ap_palloc(a->a.cont, a->a.elt_size * nkeys * 2); - a->a.nalloc = nkeys * 2; - } - - /* - * In both the merge and set cases we retain the invariant: - * - * left->key, (left+1)->key, (left+2)->key, ..., (right-1)->key - * are all equal keys. (i.e. strcasecmp returns 0) - * - * We essentially need to find the maximal - * right for each key, then we can do a quick merge or set as - * appropriate. - */ - - if (flags & ap_OVERLAP_TABLES_MERGE) { - left = cat_keys; - last = left + nkeys; - while (left < last) { - right = left + 1; - if (right == last - || strcasecmp(left->key, right->key)) { - ap_table_addn(a, left->key, left->val); - left = right; - } - else { - char *strp; - char *value; - size_t len; - - /* Have to merge some headers. Let's re-use the order field, - * since it's handy... we'll store the length of val there. - */ - left->order = strlen(left->val); - len = left->order; - do { - right->order = strlen(right->val); - len += 2 + right->order; - ++right; - } while (right < last - && !strcasecmp(left->key, right->key)); - /* right points one past the last header to merge */ - value = ap_palloc(a->a.cont, len + 1); - strp = value; - for (;;) { - memcpy(strp, left->val, left->order); - strp += left->order; - ++left; - if (left == right) { - break; - } - *strp++ = ','; - *strp++ = ' '; - } - *strp = 0; - ap_table_addn(a, (left-1)->key, value); - } - } - } - else { - left = cat_keys; - last = left + nkeys; - while (left < last) { - right = left + 1; - while (right < last && !strcasecmp(left->key, right->key)) { - ++right; - } - ap_table_addn(a, (right-1)->key, (right-1)->val); - left = right; - } - } -} - diff --git a/libapr.def b/libapr.def deleted file mode 100644 index b9fe301fef7..00000000000 --- a/libapr.def +++ /dev/null @@ -1,251 +0,0 @@ -; aprlib.def : - -LIBRARY aprlib -DESCRIPTION '' - -EXPORTS - ; Add new API calls to the end of this list. - ap_opendir @1 - ap_closedir @2 - ap_readdir @3 - ap_rewinddir @4 - ap_make_dir @5 - ap_remove_dir @6 - ap_dir_entry_size @7 - ap_dir_entry_mtime @8 - ap_dir_entry_ftype @9 - ap_get_dir_filename @10 -; ap_get_filename @11 - ap_stat @11 -; ap_get_filesize @12 -; ap_get_fileatime @13 -; ap_get_filectime @14 -; ap_make_iov @15 - ap_dupfile @16 - ap_getfileinfo @17 - ap_open @18 - ap_close @19 - ap_remove_file @20 - ap_create_pipe @21 - ap_read @22 - ap_write @23 - ap_seek @24 - ap_get_filedata @25 - ap_set_filedata @26 - ap_get_os_file @27 - ap_put_os_file @28 - ap_get_os_dir @29 - ap_putc @30 - ap_getc @31 - ap_puts @32 - ap_fgets @33 - ap_flush @34 - ap_fprintf @35 - ap_eof @36 -; ap_get_filetype @37 - ap_writev @38 - ; locks - ap_create_lock @39 - ap_lock @40 - ap_unlock @41 - ap_destroy_lock @42 - ap_child_init_lock @43 - ap_get_lockdata @44 - ap_set_lockdata @45 - ap_get_os_lock @46 - ap_create_tcp_socket @47 - ap_shutdown @48 - ap_close_socket @49 - ap_bind @50 - ap_listen @51 - ap_accept @52 - ap_connect @53 - ap_get_remote_hostname @54 - ap_gethostname @55 - ap_send @56 - ap_recv @57 - ap_setsocketopt @58 - ap_sendv @59 - ap_sendfile @60 - ap_setup_poll @61 - ap_poll @62 - ap_add_poll_socket @63 - ap_get_revents @64 - ap_get_socketdata @65 - ap_set_socketdata @66 - ap_get_polldata @67 - ap_set_polldata @68 - ap_put_os_sock @69 - ap_get_os_sock @70 - ap_remove_poll_socket @71 - ap_clear_poll_sockets @72 -; ap_setipaddr @73 -; ap_getipaddr @74 -; ap_create_signal @75 -; ap_setup_signal @76 -; SignalHandling @77 -; ap_send_signal @78 -; thread_ready @79 - ap_createprocattr_init @80 - ap_setprocattr_io @81 - ap_setprocattr_dir @82 - ap_setprocattr_cmdtype @83 - ap_setprocattr_detach @84 - ap_create_process @85 - ap_get_childin @86 - ap_get_childout @87 - ap_get_childerr @88 - ap_wait_proc @89 - ap_kill @90 - ap_create_threadattr @91 - ap_setthreadattr_detach @92 - ap_getthreadattr_detach @93 - ap_create_thread @94 - ap_thread_exit @95 - ap_thread_join @96 - ap_thread_detach @97 -; ap_cancel_thread @98 - ap_create_thread_private @99 - ap_get_thread_private @100 - ap_set_thread_private @101 - ap_delete_thread_private @102 - ap_get_threaddata @103 - ap_set_threaddata @104 - ap_get_threadkeydata @105 - ap_set_threadkeydata @106 - ap_get_procdata @107 -; ap_set_procdata @108 - ap_get_os_proc @109 - ap_get_os_thread @110 - ap_get_os_threadkey @111 - ap_os_systemcase_filename @112 - canonical_filename @113 - ap_create_pool @114 - ap_destroy_context @115 -; WinTimeToUnixTime @116 -; ap_get_oslevel @117 - ap_get_userdata @118 - ap_set_userdata @119 - ap_initialize @120 - ap_getopt @121 - ap_opterr @122 DATA - ap_optind @123 DATA - ap_optopt @124 DATA - ap_optreset @125 DATA - ap_optarg @126 DATA -; ap_make_time @127 - ap_ansi_time_to_ap_time @127 -; ap_current_time @128 - ap_now @128 -; ap_explode_time @129 - ap_explode_gmt @129 -; ap_implode_time @130 - ap_explode_localtime @130 -; ap_get_curtime @131 - ap_implode_time @131 -; ap_get_sec @132 - ap_get_os_imp_time @132 -; ap_get_min @133 - ap_get_os_exp_time @133 -; ap_get_hour @134 - ap_put_os_imp_time @134 -; ap_get_mday @135 - ap_put_os_exp_time @135 -; ap_get_mon @136 - ap_ctime @136 -; ap_get_year @137 - ap_rfc822_date @137 -; ap_get_wday @138 - ap_strftime @138 -; ap_set_sec @139 -; ap_set_min @140 -; ap_set_hour @141 -; ap_set_mday @142 -; ap_set_mon @143 -; ap_set_year @144 -; ap_set_wday @145 -; ap_get_timedata @146 -; ap_set_timedata @147 -; ap_get_os_time @148 -; ap_timediff @149 - ap_MD5Final @150 - ap_MD5Init @151 - ap_MD5Update @152 - ap_cpystrn @153 - ap_register_cleanup @154 - ap_kill_cleanup @155 - ap_fnmatch @156 - ap_is_fnmatch @157 - ap_MD5Encode @158 - ap_validate_password @159 - ap_make_sub_pool @160 - ap_init_alloc @161 - ap_clear_pool @162 - ap_destroy_pool @163 - ap_bytes_in_pool @164 - ap_bytes_in_free_blocks @165 - ap_palloc @166 - ap_pcalloc @167 - ap_pstrdup @168 - ap_pstrndup @169 - ap_pstrcat @170 - ap_pvsprintf @171 - ap_psprintf @172 - ap_make_array @173 - ap_push_array @174 - ap_array_cat @175 - ap_copy_array @176 - ap_copy_array_hdr @177 - ap_append_arrays @178 - ap_array_pstrcat @179 - ap_make_table @180 - ap_copy_table @181 - ap_clear_table @182 - ap_table_get @183 - ap_table_set @184 - ap_table_setn @185 - ap_table_unset @186 - ap_table_merge @187 - ap_table_mergen @188 - ap_table_add @189 - ap_table_addn @190 - ap_overlay_tables @191 - ap_table_do @192 - ap_overlap_tables @193 - ap_run_cleanup @194 - ap_cleanup_for_exec @195 - ap_null_cleanup @196 - ap_note_subprocess @197 -; ap_slack @198 - ap_vformatter @199 - ap_snprintf @200 - ap_vsnprintf @201 - ap_getpass @202 - ap_ungetc @203 - ap_tokenize_to_argv @204 - ap_filename_of_pathname @205 - ap_get_remote_name @206 - ap_get_local_name @207 - ap_get_local_ipaddr @208 - ap_set_local_ipaddr @209 - ap_get_remote_ipaddr @210 - ap_set_remote_ipaddr @211 - ap_get_local_port @212 - ap_set_local_port @213 - ap_get_remote_port @214 - ap_set_remote_port @215 - ap_open_stderr @216 - ap_set_pipe_timeout @217 - ap_terminate @218 - ap_dso_load @219 - ap_dso_unload @220 - ap_dso_sym @221 - ap_dso_init @222 - ap_collapse_spaces @223 - ap_month_snames @224 - ap_day_snames @225 - ap_canonical_error @226 - ap_strerror @227 - ap_generate_random_bytes @228 - ap_strnatcmp @229 - ap_strnatcasecmp @230 diff --git a/libapr.dsp b/libapr.dsp index 05f5831e2a3..3c4e53b54c5 100644 --- a/libapr.dsp +++ b/libapr.dsp @@ -1,36 +1,37 @@ -# Microsoft Developer Studio Project File - Name="aprlibdll" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 5.00 +# Microsoft Developer Studio Project File - Name="libapr" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 # ** DO NOT EDIT ** # TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 -CFG=aprlibdll - Win32 Debug +CFG=libapr - Win32 Release !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run !MESSAGE -!MESSAGE NMAKE /f "aprlibdll.mak". +!MESSAGE NMAKE /f "libapr.mak". !MESSAGE !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE -!MESSAGE NMAKE /f "aprlibdll.mak" CFG="aprlibdll - Win32 Debug" +!MESSAGE NMAKE /f "libapr.mak" CFG="libapr - Win32 Release" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE -!MESSAGE "aprlibdll - Win32 Release" (based on\ - "Win32 (x86) Dynamic-Link Library") -!MESSAGE "aprlibdll - Win32 Debug" (based on\ - "Win32 (x86) Dynamic-Link Library") +!MESSAGE "libapr - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "libapr - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "libapr - x64 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "libapr - x64 Debug" (based on "Win32 (x86) Dynamic-Link Library") !MESSAGE # Begin Project +# PROP AllowPerConfigDependencies 0 # PROP Scc_ProjName "" # PROP Scc_LocalPath "" CPP=cl.exe MTL=midl.exe RSC=rc.exe -!IF "$(CFG)" == "aprlibdll - Win32 Release" +!IF "$(CFG)" == "libapr - Win32 Release" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 0 @@ -43,21 +44,26 @@ RSC=rc.exe # PROP Intermediate_Dir "Release" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" -# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c -# ADD CPP /nologo /MD /W3 /GX /O2 /I "./include" /I "./inc" /I "./misc/win32" /I "./file_io/win32" /I "./time/win32" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c -# SUBTRACT CPP /YX -# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o NUL /win32 -# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o NUL /win32 +# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c +# ADD CPP /nologo /MD /W3 /Zi /O2 /Oy- /I "./include" /I "./include/private" /I "./include/arch/win32" /I "./include/arch/unix" /I "../expat/lib" /D "NDEBUG" /D "APR_DECLARE_EXPORT" /D "WIN32" /D "WINNT" /D "_WINDOWS" /Fo"$(INTDIR)\" /Fd"$(INTDIR)\libapr_src" /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o /win32 "NUL" +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o /win32 "NUL" # ADD BASE RSC /l 0x409 /d "NDEBUG" -# ADD RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /i "./include" /d "NDEBUG" /d "APR_VERSION_ONLY" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe -# ADD BASE LINK32 apr.lib kernel32.lib advapi32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /map /machine:I386 /def:".\aprlib.def" /out:"Release/aprlib.dll" /libpath:"LibR" /base:@"..\..\os\win32\BaseAddr.ref",aprlib -# ADD LINK32 apr.lib kernel32.lib advapi32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /map /machine:I386 /def:".\aprlib.def" /out:"Release/aprlib.dll" /libpath:"LibR" /base:@"..\..\os\win32\BaseAddr.ref",aprlib +# ADD BASE LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib shell32.lib rpcrt4.lib /nologo /base:"0x6EEC0000" /subsystem:windows /dll /incremental:no /debug /opt:ref +# ADD LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib shell32.lib rpcrt4.lib libexpat.lib /nologo /base:"0x6EEC0000" /subsystem:windows /dll /incremental:no /debug /libpath:"..\expat\win32\bin\Release" /out:"Release\libapr-2.dll" /pdb:"Release\libapr-2.pdb" /implib:"Release\libapr-2.lib" /MACHINE:X86 /opt:ref +# Begin Special Build Tool +TargetPath=Release\libapr-2.dll +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2 +# End Special Build Tool -!ELSEIF "$(CFG)" == "aprlibdll - Win32 Debug" +!ELSEIF "$(CFG)" == "libapr - Win32 Debug" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 1 @@ -70,34 +76,1153 @@ LINK32=link.exe # PROP Intermediate_Dir "Debug" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" -# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c -# ADD CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /I "./include" /I "./inc" /I "./misc/win32" /I "./file_io/win32" /I "./time/win32" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /c -# SUBTRACT CPP /YX -# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o NUL /win32 -# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o NUL /win32 +# ADD BASE CPP /nologo /MDd /W3 /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /EHsc /c +# ADD CPP /nologo /MDd /W3 /Zi /Od /I "./include" /I "./include/private" /I "./include/arch/win32" /I "./include/arch/unix" /I "../expat/lib" /D "_DEBUG" /D "APR_DECLARE_EXPORT" /D "WIN32" /D "WINNT" /D "_WINDOWS" /Fo"$(INTDIR)\" /Fd"$(INTDIR)\libapr_src" /FD /EHsc /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o /win32 "NUL" +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o /win32 "NUL" # ADD BASE RSC /l 0x409 /d "_DEBUG" -# ADD RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /i "./include" /d "_DEBUG" /d "APR_VERSION_ONLY" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe -# ADD BASE LINK32 aprlib.lib kernel32.lib advapi32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /map /debug /machine:I386 /def:".\aprlib.def" /out:"Debug/aprlib.dll" /libpath:"LibD" /base:@"..\..\os\win32\BaseAddr.ref",aprlib -# ADD LINK32 apr.lib kernel32.lib advapi32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /map /debug /machine:I386 /def:".\aprlib.def" /out:"Debug/aprlib.dll" /libpath:"LibD" /base:@"..\..\os\win32\BaseAddr.ref",aprlib +# ADD BASE LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib shell32.lib rpcrt4.lib /nologo /base:"0x6EEC0000" /subsystem:windows /dll /incremental:no /debug +# ADD LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib shell32.lib rpcrt4.lib libexpat.lib /nologo /base:"0x6EEC0000" /subsystem:windows /dll /incremental:no /debug /libpath:"..\expat\win32\bin\Debug" /out:"Debug\libapr-2.dll" /pdb:"Debug\libapr-2.pdb" /implib:"Debug\libapr-2.lib" /MACHINE:X86 +# Begin Special Build Tool +TargetPath=Debug\libapr-2.dll +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2 +# End Special Build Tool + +!ELSEIF "$(CFG)" == "libapr - x64 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "x64\Release" +# PROP BASE Intermediate_Dir "x64\Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "x64\Release" +# PROP Intermediate_Dir "x64\Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c +# ADD CPP /nologo /MD /W3 /Zi /O2 /Oy- /I "./include" /I "./include/private" /I "./include/arch/win32" /I "./include/arch/unix" /I "../expat/lib" /D "NDEBUG" /D "APR_DECLARE_EXPORT" /D "WIN32" /D "WINNT" /D "_WINDOWS" /Fo"$(INTDIR)\" /Fd"$(INTDIR)\libapr_src" /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o /win32 "NUL" +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o /win32 "NUL" +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /i "./include" /d "NDEBUG" /d "APR_VERSION_ONLY" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib shell32.lib rpcrt4.lib /nologo /base:"0x6EEC0000" /subsystem:windows /dll /incremental:no /debug /opt:ref +# ADD LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib shell32.lib rpcrt4.lib libexpat.lib /nologo /base:"0x6EEC0000" /subsystem:windows /dll /incremental:no /debug /libpath:"..\expat\win32\bin\x64\Release" /out:"x64\Release\libapr-2.dll" /pdb:"x64\Release\libapr-2.pdb" /implib:"x64\Release\libapr-2.lib" /MACHINE:X64 /opt:ref +# Begin Special Build Tool +TargetPath=x64\Release\libapr-2.dll +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2 +# End Special Build Tool + +!ELSEIF "$(CFG)" == "libapr - x64 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "x64\Debug" +# PROP BASE Intermediate_Dir "x64\Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "x64\Debug" +# PROP Intermediate_Dir "x64\Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /EHsc /c +# ADD CPP /nologo /MDd /W3 /Zi /Od /I "./include" /I "./include/private" /I "./include/arch/win32" /I "./include/arch/unix" /I "../expat/lib" /D "_DEBUG" /D "APR_DECLARE_EXPORT" /D "WIN32" /D "WINNT" /D "_WINDOWS" /Fo"$(INTDIR)\" /Fd"$(INTDIR)\libapr_src" /FD /EHsc /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o /win32 "NUL" +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o /win32 "NUL" +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /i "./include" /d "_DEBUG" /d "APR_VERSION_ONLY" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib shell32.lib rpcrt4.lib /nologo /base:"0x6EEC0000" /subsystem:windows /dll /incremental:no /debug +# ADD LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib ole32.lib shell32.lib rpcrt4.lib libexpat.lib /nologo /base:"0x6EEC0000" /subsystem:windows /dll /incremental:no /debug /libpath:"..\expat\win32\bin\x64\Debug" /out:"x64\Debug\libapr-2.dll" /pdb:"x64\Debug\libapr-2.pdb" /implib:"x64\Debug\libapr-2.lib" /MACHINE:X64 +# Begin Special Build Tool +TargetPath=x64\Debug\libapr-2.dll +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2 +# End Special Build Tool !ENDIF # Begin Target -# Name "aprlibdll - Win32 Release" -# Name "aprlibdll - Win32 Debug" +# Name "libapr - Win32 Release" +# Name "libapr - Win32 Debug" +# Name "libapr - x64 Release" +# Name "libapr - x64 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter ".c" +# Begin Group "atomic" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\atomic\win32\apr_atomic.c +# End Source File +# End Group +# Begin Group "buckets" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\buckets\apr_brigade.c +# End Source File +# Begin Source File + +SOURCE=.\buckets\apr_buckets.c +# End Source File +# Begin Source File + +SOURCE=.\buckets\apr_buckets_alloc.c +# End Source File +# Begin Source File + +SOURCE=.\buckets\apr_buckets_eos.c +# End Source File +# Begin Source File + +SOURCE=.\buckets\apr_buckets_file.c +# End Source File +# Begin Source File + +SOURCE=.\buckets\apr_buckets_flush.c +# End Source File +# Begin Source File + +SOURCE=.\buckets\apr_buckets_heap.c +# End Source File +# Begin Source File + +SOURCE=.\buckets\apr_buckets_mmap.c +# End Source File +# Begin Source File + +SOURCE=.\buckets\apr_buckets_pipe.c +# End Source File +# Begin Source File + +SOURCE=.\buckets\apr_buckets_pool.c +# End Source File +# Begin Source File + +SOURCE=.\buckets\apr_buckets_refcount.c +# End Source File +# Begin Source File + +SOURCE=.\buckets\apr_buckets_simple.c +# End Source File +# Begin Source File + +SOURCE=.\buckets\apr_buckets_socket.c +# End Source File +# End Group +# Begin Group "crypto" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\crypto\apr_crypto.c +# End Source File +# Begin Source File + +SOURCE=.\crypto\apr_md4.c +# End Source File +# Begin Source File + +SOURCE=.\crypto\apr_md5.c +# End Source File +# Begin Source File + +SOURCE=.\crypto\apr_passwd.c +# End Source File +# Begin Source File + +SOURCE=.\crypto\apr_sha1.c +# End Source File +# Begin Source File + +SOURCE=.\crypto\apr_siphash.c +# End Source File +# Begin Source File + +SOURCE=.\crypto\crypt_blowfish.c +# End Source File +# Begin Source File + +SOURCE=.\crypto\crypt_blowfish.h +# End Source File +# Begin Source File + +SOURCE=.\crypto\getuuid.c +# End Source File +# Begin Source File + +SOURCE=.\crypto\uuid.c +# End Source File +# End Group +# Begin Group "dbd" +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\dbd\apr_dbd.c +# End Source File +# Begin Source File + +SOURCE=.\dbd\apr_dbd_mysql.c +# End Source File +# Begin Source File + +SOURCE=.\dbd\apr_dbd_odbc.c +# End Source File +# Begin Source File + +SOURCE=.\dbd\apr_dbd_oracle.c +# End Source File +# Begin Source File + +SOURCE=.\dbd\apr_dbd_pgsql.c +# End Source File +# Begin Source File + +SOURCE=.\dbd\apr_dbd_sqlite2.c +# End Source File +# Begin Source File + +SOURCE=.\dbd\apr_dbd_sqlite3.c +# End Source File +# End Group +# Begin Group "dbm" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\dbm\apr_dbm.c +# End Source File +# Begin Source File + +SOURCE=.\dbm\apr_dbm_berkeleydb.c +# End Source File +# Begin Source File + +SOURCE=.\dbm\apr_dbm_gdbm.c +# End Source File +# Begin Source File + +SOURCE=.\dbm\apr_dbm_sdbm.c +# End Source File +# End Group +# Begin Group "dso" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\dso\win32\dso.c +# End Source File +# End Group +# Begin Group "encoding" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\encoding\apr_base64.c +# End Source File +# Begin Source File + +SOURCE=.\encoding\apr_escape.c +# End Source File +# End Group +# Begin Group "file_io" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\file_io\win32\buffer.c +# End Source File +# Begin Source File + +SOURCE=.\file_io\unix\copy.c +# End Source File +# Begin Source File + +SOURCE=.\file_io\win32\dir.c +# End Source File +# Begin Source File + +SOURCE=.\file_io\unix\fileacc.c +# End Source File +# Begin Source File + +SOURCE=.\file_io\win32\filedup.c +# End Source File +# Begin Source File + +SOURCE=.\file_io\win32\filepath.c +# End Source File +# Begin Source File + +SOURCE=.\file_io\unix\filepath_util.c +# End Source File +# Begin Source File + +SOURCE=.\file_io\win32\filestat.c +# End Source File +# Begin Source File + +SOURCE=.\file_io\win32\filesys.c +# End Source File +# Begin Source File + +SOURCE=.\file_io\win32\flock.c +# End Source File +# Begin Source File + +SOURCE=.\file_io\unix\fullrw.c +# End Source File +# Begin Source File + +SOURCE=.\file_io\unix\mktemp.c +# End Source File +# Begin Source File + +SOURCE=.\file_io\win32\open.c +# End Source File +# Begin Source File + +SOURCE=.\file_io\win32\pipe.c +# End Source File # Begin Source File -SOURCE=.\misc\win32\aprlib.c +SOURCE=.\file_io\win32\readwrite.c # End Source File # Begin Source File -SOURCE=.\aprlib.def +SOURCE=.\file_io\win32\seek.c +# End Source File +# Begin Source File + +SOURCE=.\file_io\unix\tempdir.c +# End Source File +# End Group +# Begin Group "hooks" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\hooks\apr_hooks.c +# End Source File +# End Group +# Begin Group "locks" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\locks\win32\proc_mutex.c +# End Source File +# Begin Source File + +SOURCE=.\locks\win32\thread_cond.c +# End Source File +# Begin Source File + +SOURCE=.\locks\win32\thread_mutex.c +# End Source File +# Begin Source File + +SOURCE=.\locks\win32\thread_rwlock.c +# End Source File +# End Group +# Begin Group "memcache" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\memcache\apr_memcache.c +# End Source File +# End Group +# Begin Group "memory" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\memory\unix\apr_pools.c +# End Source File +# End Group +# Begin Group "misc" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\misc\win32\apr_app.c # PROP Exclude_From_Build 1 # End Source File +# Begin Source File + +SOURCE=.\misc\win32\charset.c +# End Source File +# Begin Source File + +SOURCE=.\misc\win32\env.c +# End Source File +# Begin Source File + +SOURCE=.\misc\unix\errorcodes.c +# End Source File +# Begin Source File + +SOURCE=.\misc\unix\getopt.c +# End Source File +# Begin Source File + +SOURCE=.\misc\win32\internal.c +# End Source File +# Begin Source File + +SOURCE=.\misc\win32\misc.c +# End Source File +# Begin Source File + +SOURCE=.\misc\unix\otherchild.c +# End Source File +# Begin Source File + +SOURCE=.\misc\win32\rand.c +# End Source File +# Begin Source File + +SOURCE=.\misc\win32\start.c +# End Source File +# Begin Source File + +SOURCE=.\misc\win32\utf8.c +# End Source File +# Begin Source File + +SOURCE=.\misc\unix\version.c +# End Source File +# End Group +# Begin Group "mmap" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\mmap\unix\common.c +# End Source File +# Begin Source File + +SOURCE=.\mmap\win32\mmap.c +# End Source File +# End Group +# Begin Group "network_io" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\network_io\unix\inet_ntop.c +# End Source File +# Begin Source File + +SOURCE=.\network_io\unix\inet_pton.c +# End Source File +# Begin Source File + +SOURCE=.\network_io\unix\multicast.c +# End Source File +# Begin Source File + +SOURCE=.\network_io\win32\sendrecv.c +# End Source File +# Begin Source File + +SOURCE=.\network_io\unix\sockaddr.c +# End Source File +# Begin Source File + +SOURCE=.\network_io\win32\sockets.c +# End Source File +# Begin Source File + +SOURCE=.\network_io\unix\socket_util.c +# End Source File +# Begin Source File + +SOURCE=.\network_io\win32\sockopt.c +# End Source File +# End Group +# Begin Group "passwd" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\passwd\apr_getpass.c +# End Source File +# End Group +# Begin Group "poll" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\poll\unix\pollcb.c +# End Source File +# Begin Source File + +SOURCE=.\poll\unix\pollset.c +# End Source File +# Begin Source File + +SOURCE=.\poll\unix\poll.c +# End Source File +# Begin Source File + +SOURCE=.\poll\unix\select.c +# End Source File +# Begin Source File + +SOURCE=.\poll\unix\wakeup.c +# End Source File +# End Group +# Begin Group "random" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\random\unix\apr_random.c +# End Source File +# Begin Source File + +SOURCE=.\random\unix\sha2.c +# End Source File +# Begin Source File + +SOURCE=.\random\unix\sha2_glue.c +# End Source File +# End Group +# Begin Group "sdbm" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\dbm\sdbm\sdbm.c +# End Source File +# Begin Source File + +SOURCE=.\dbm\sdbm\sdbm_hash.c +# End Source File +# Begin Source File + +SOURCE=.\dbm\sdbm\sdbm_lock.c +# End Source File +# Begin Source File + +SOURCE=.\dbm\sdbm\sdbm_pair.c +# End Source File +# Begin Source File + +SOURCE=.\dbm\sdbm\sdbm_pair.h +# End Source File +# Begin Source File + +SOURCE=.\dbm\sdbm\sdbm_private.h +# End Source File +# Begin Source File + +SOURCE=.\dbm\sdbm\sdbm_tune.h +# End Source File +# End Group +# Begin Group "shmem" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\shmem\win32\shm.c +# End Source File +# End Group +# Begin Group "strings" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\strings\apr_cpystrn.c +# End Source File +# Begin Source File + +SOURCE=.\strings\apr_fnmatch.c +# End Source File +# Begin Source File + +SOURCE=.\strings\apr_snprintf.c +# End Source File +# Begin Source File + +SOURCE=.\strings\apr_strings.c +# End Source File +# Begin Source File + +SOURCE=.\strings\apr_strnatcmp.c +# End Source File +# Begin Source File + +SOURCE=.\strings\apr_strtok.c +# End Source File +# End Group +# Begin Group "strmatch" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\strmatch\apr_strmatch.c +# End Source File +# End Group +# Begin Group "tables" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\tables\apr_hash.c +# Begin Source File + +SOURCE=.\tables\apr_tables.c +# End Source File +# Begin Source File + +SOURCE=.\tables\apr_skiplist.c +# End Source File +# End Group +# Begin Group "threadproc" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\threadproc\win32\proc.c +# End Source File +# Begin Source File + +SOURCE=.\threadproc\win32\signals.c +# End Source File +# Begin Source File + +SOURCE=.\threadproc\win32\thread.c +# End Source File +# Begin Source File + +SOURCE=.\threadproc\win32\threadpriv.c +# End Source File +# End Group +# Begin Group "time" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\time\win32\time.c +# End Source File +# Begin Source File + +SOURCE=.\time\win32\timestr.c +# End Source File +# End Group +# Begin Group "uri" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\uri\apr_uri.c +# End Source File +# End Group +# Begin Group "user" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\user\win32\groupinfo.c +# End Source File +# Begin Source File + +SOURCE=.\user\win32\userinfo.c +# End Source File +# End Group +# Begin Group "util-misc" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\util-misc\apr_date.c +# End Source File +# Begin Source File + +SOURCE=.\util-misc\apu_dso.c +# End Source File +# Begin Source File + +SOURCE=.\util-misc\apr_queue.c +# End Source File +# Begin Source File + +SOURCE=.\util-misc\apr_reslist.c +# End Source File +# Begin Source File + +SOURCE=.\util-misc\apr_rmm.c +# End Source File +# Begin Source File + +SOURCE=.\util-misc\apr_thread_pool.c +# End Source File +# End Group +# Begin Group "xlate" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\xlate\xlate.c +# End Source File +# End Group +# Begin Group "xml" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\xml\apr_xml.c +# End Source File +# Begin Source File + +SOURCE=.\xml\apr_xml_expat.c +# End Source File +# End Group +# End Group +# Begin Group "Private Header Files" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\include\arch\win32\apr_arch_atime.h +# End Source File +# Begin Source File + +SOURCE=.\include\arch\win32\apr_arch_dso.h +# End Source File +# Begin Source File + +SOURCE=.\include\arch\win32\apr_arch_file_io.h +# End Source File +# Begin Source File + +SOURCE=.\include\arch\win32\apr_arch_inherit.h +# End Source File +# Begin Source File + +SOURCE=.\include\arch\win32\apr_arch_misc.h +# End Source File +# Begin Source File + +SOURCE=.\include\arch\win32\apr_arch_networkio.h +# End Source File +# Begin Source File + +SOURCE=.\include\arch\win32\apr_arch_thread_mutex.h +# End Source File +# Begin Source File + +SOURCE=.\include\arch\win32\apr_arch_thread_rwlock.h +# End Source File +# Begin Source File + +SOURCE=.\include\arch\win32\apr_arch_threadproc.h +# End Source File +# Begin Source File + +SOURCE=.\include\arch\win32\apr_arch_utf8.h +# End Source File +# Begin Source File + +SOURCE=.\include\arch\win32\apr_private.h +# End Source File +# End Group +# Begin Group "Public Header Files" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\include\apr.h.in +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=.\include\apr.hnw +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=.\include\apr.hw + +!IF "$(CFG)" == "libapr - Win32 Release" + +# Begin Custom Build - Creating apr.h from apr.hw, apr_escape_test_char.h from gen_test_char.exe +InputPath=.\include\apr.hw + +".\include\apr.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + type .\include\apr.hw > .\include\apr.h + +# End Custom Build + +!ELSEIF "$(CFG)" == "libapr - Win32 Debug" + +# Begin Custom Build - Creating apr.h from apr.hw, apr_escape_test_char.h from gen_test_char.exe +InputPath=.\include\apr.hw + +".\include\apr.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + type .\include\apr.hw > .\include\apr.h + +# End Custom Build + +!ELSEIF "$(CFG)" == "libapr - x64 Release" + +# Begin Custom Build - Creating apr.h from apr.hw, apr_escape_test_char.h from gen_test_char.exe +InputPath=.\include\apr.hw + +".\include\apr.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + type .\include\apr.hw > .\include\apr.h + +# End Custom Build + +!ELSEIF "$(CFG)" == "libapr - x64 Debug" + +# Begin Custom Build - Creating apr.h from apr.hw, apr_escape_test_char.h from gen_test_char.exe +InputPath=.\include\apr.hw + +".\include\apr.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + type .\include\apr.hw > .\include\apr.h + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\include\apr_allocator.h +# End Source File +# Begin Source File + +SOURCE=.\include\apr_atomic.h +# End Source File +# Begin Source File + +SOURCE=.\include\apr_dso.h +# End Source File +# Begin Source File + +SOURCE=.\include\apr_env.h +# End Source File +# Begin Source File + +SOURCE=.\include\apr_errno.h +# End Source File +# Begin Source File + +SOURCE=.\include\apr_escape.h + +!IF "$(CFG)" == "libapr - Win32 Release" + +# Begin Custom Build - Creating gen_test_char.exe and apr_escape_test_char.h +InputPath=.\include\apr_escape.h + +".\include\apr_escape_test_char.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cl.exe /nologo /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FD /I ".\include" /Fo.\Release\gen_test_char /Fe.\Release\gen_test_char.exe .\tools\gen_test_char.c + .\Release\gen_test_char.exe > .\include\apr_escape_test_char.h + +# End Custom Build + +!ELSEIF "$(CFG)" == "libapr - Win32 Debug" + +# Begin Custom Build - Creating gen_test_char.exe and apr_escape_test_char.h +InputPath=.\include\apr_escape.h + +".\include\apr_escape_test_char.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cl.exe /nologo /W3 /EHsc /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FD /I ".\include" /Fo.\Debug\gen_test_char /Fe.\Debug\gen_test_char.exe .\tools\gen_test_char.c + .\Debug\gen_test_char.exe > .\include\apr_escape_test_char.h + +# End Custom Build + +!ELSEIF "$(CFG)" == "libapr - x64 Release" + +# Begin Custom Build - Creating gen_test_char.exe and apr_escape_test_char.h +InputPath=.\include\apr_escape.h + +".\include\apr_escape_test_char.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cl.exe /nologo /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FD /I ".\include" /Fo.\x64\Release\gen_test_char /Fe.\x64\Release\gen_test_char.exe .\tools\gen_test_char.c + .\x64\Release\gen_test_char.exe > .\include\apr_escape_test_char.h + +# End Custom Build + +!ELSEIF "$(CFG)" == "libapr - x64 Debug" + +# Begin Custom Build - Creating gen_test_char.exe and apr_escape_test_char.h +InputPath=.\include\apr_escape.h + +".\include\apr_escape_test_char.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + cl.exe /nologo /W3 /EHsc /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FD /I ".\include" /Fo.\x64\Debug\gen_test_char /Fe.\x64\Debug\gen_test_char.exe .\tools\gen_test_char.c + .\x64\Debug\gen_test_char.exe > .\include\apr_escape_test_char.h + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\include\apr_file_info.h +# End Source File +# Begin Source File + +SOURCE=.\include\apr_file_io.h +# End Source File +# Begin Source File + +SOURCE=.\include\apr_fnmatch.h +# End Source File +# Begin Source File + +SOURCE=.\include\apr_general.h +# End Source File +# Begin Source File + +SOURCE=.\include\apr_getopt.h +# End Source File +# Begin Source File + +SOURCE=.\include\apr_global_mutex.h +# End Source File +# Begin Source File + +SOURCE=.\include\apr_hash.h +# End Source File +# Begin Source File + +SOURCE=.\include\apr_inherit.h +# End Source File +# Begin Source File + +SOURCE=.\include\apr_lib.h +# End Source File +# Begin Source File + +SOURCE=.\include\apr_mmap.h +# End Source File +# Begin Source File + +SOURCE=.\include\apr_network_io.h +# End Source File +# Begin Source File + +SOURCE=.\include\apr_poll.h +# End Source File +# Begin Source File + +SOURCE=.\include\apr_pools.h +# End Source File +# Begin Source File + +SOURCE=.\include\apr_portable.h +# End Source File +# Begin Source File + +SOURCE=.\include\apr_proc_mutex.h +# End Source File +# Begin Source File + +SOURCE=.\include\apr_random.h +# End Source File +# Begin Source File + +SOURCE=.\include\apr_ring.h +# End Source File +# Begin Source File + +SOURCE=.\include\apr_shm.h +# End Source File +# Begin Source File + +SOURCE=.\include\apr_signal.h +# End Source File +# Begin Source File + +SOURCE=.\include\apr_skiplist.h +# End Source File +# Begin Source File + +SOURCE=.\include\apr_strings.h +# End Source File +# Begin Source File + +SOURCE=.\include\apr_support.h +# End Source File +# Begin Source File + +SOURCE=.\include\apr_tables.h +# End Source File +# Begin Source File + +SOURCE=.\include\apr_thread_cond.h +# End Source File +# Begin Source File + +SOURCE=.\include\apr_thread_mutex.h +# End Source File +# Begin Source File + +SOURCE=.\include\apr_thread_proc.h +# End Source File +# Begin Source File + +SOURCE=.\include\apr_thread_rwlock.h +# End Source File +# Begin Source File + +SOURCE=.\include\apr_time.h +# End Source File +# Begin Source File + +SOURCE=.\include\apr_user.h +# End Source File +# Begin Source File + +SOURCE=.\include\apr_version.h +# End Source File +# Begin Source File + +SOURCE=.\include\apr_want.h +# End Source File +# Begin Source File + +SOURCE=.\include\apu.h +# End Source File +# Begin Source File + +SOURCE=.\include\private\apu_select_dbm.h.in +# End Source File +# Begin Source File + +SOURCE=.\include\private\apu_select_dbm.hw + +!IF "$(CFG)" == "libapr - Win32 Release" + +# Begin Custom Build - Creating apu_select_dbm.h from apu_select_dbm.hw +InputPath=.\include\private\apu_select_dbm.hw + +".\include\private\apu_select_dbm.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + type .\include\private\apu_select_dbm.hw > .\include\private\apu_select_dbm.h + +# End Custom Build + +!ELSEIF "$(CFG)" == "libapr - Win32 Debug" + +# Begin Custom Build - Creating apu_select_dbm.h from apu_select_dbm.hw +InputPath=.\include\private\apu_select_dbm.hw + +".\include\private\apu_select_dbm.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + type .\include\private\apu_select_dbm.hw > .\include\private\apu_select_dbm.h + +# End Custom Build + +!ELSEIF "$(CFG)" == "libapr - x64 Release" + +# Begin Custom Build - Creating apu_select_dbm.h from apu_select_dbm.hw +InputPath=.\include\private\apu_select_dbm.hw + +".\include\private\apu_select_dbm.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + type .\include\private\apu_select_dbm.hw > .\include\private\apu_select_dbm.h + +# End Custom Build + +!ELSEIF "$(CFG)" == "libapr - x64 Debug" + +# Begin Custom Build - Creating apu_select_dbm.h from apu_select_dbm.hw +InputPath=.\include\private\apu_select_dbm.hw + +".\include\private\apu_select_dbm.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + type .\include\private\apu_select_dbm.hw > .\include\private\apu_select_dbm.h + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\include\apu_want.h.in +# End Source File +# Begin Source File + +SOURCE=.\include\apu_want.hnw +# End Source File +# Begin Source File + +SOURCE=.\include\apu_want.hw + +!IF "$(CFG)" == "libapr - Win32 Release" + +# Begin Custom Build - Creating apu_want.h from apu_want.hw +InputPath=.\include\apu_want.hw + +".\include\apu_want.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + type .\include\apu_want.hw > .\include\apu_want.h + +# End Custom Build + +!ELSEIF "$(CFG)" == "libapr - Win32 Debug" + +# Begin Custom Build - Creating apu_want.h from apu_want.hw +InputPath=.\include\apu_want.hw + +".\include\apu_want.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + type .\include\apu_want.hw > .\include\apu_want.h + +# End Custom Build + +!ELSEIF "$(CFG)" == "libapr - x64 Release" + +# Begin Custom Build - Creating apu_want.h from apu_want.hw +InputPath=.\include\apu_want.hw + +".\include\apu_want.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + type .\include\apu_want.hw > .\include\apu_want.h + +# End Custom Build + +!ELSEIF "$(CFG)" == "libapr - x64 Debug" + +# Begin Custom Build - Creating apu_want.h from apu_want.hw +InputPath=.\include\apu_want.hw + +".\include\apu_want.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + type .\include\apu_want.hw > .\include\apu_want.h + +# End Custom Build + +!ENDIF + +# End Source File +# End Group +# Begin Source File + +SOURCE=.\libapr.rc +# End Source File # End Target # End Project diff --git a/libapr.rc b/libapr.rc new file mode 100644 index 00000000000..f7386f06d97 --- /dev/null +++ b/libapr.rc @@ -0,0 +1,66 @@ +#include "apr_version.h" + +#define APR_LICENSE \ + "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\r\n\r\n" \ + "http://www.apache.org/licenses/LICENSE-2.0\r\n\r\n" \ + "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." + +#ifdef DLL_NAME +#define APR_DLL_BASENAME APR_STRINGIFY(DLL_NAME) "-" APR_STRINGIFY(APR_MAJOR_VERSION) +#define APR_DLL_DESCRIPTION "Apache Portable Runtime " APR_STRINGIFY(DLL_NAME) " Module" +#else +#define APR_DLL_BASENAME "libapr-" APR_STRINGIFY(APR_MAJOR_VERSION) +#define APR_DLL_DESCRIPTION "Apache Portable Runtime Library" +#endif + + +1 VERSIONINFO + FILEVERSION APR_VERSION_STRING_CSV,0 + PRODUCTVERSION APR_VERSION_STRING_CSV,0 + FILEFLAGSMASK 0x3fL +#if defined(APR_IS_DEV_VERSION) +#if defined(_DEBUG) + FILEFLAGS 0x03L +#else + FILEFLAGS 0x02L +#endif +#else +#if defined(_DEBUG) + FILEFLAGS 0x01L +#else + FILEFLAGS 0x00L +#endif +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", APR_LICENSE "\0" + VALUE "CompanyName", "Apache Software Foundation\0" + VALUE "FileDescription", APR_DLL_DESCRIPTION "\0" + VALUE "FileVersion", APR_VERSION_STRING "\0" + VALUE "InternalName", APR_DLL_BASENAME "\0" + VALUE "LegalCopyright", APR_COPYRIGHT "\0" + VALUE "OriginalFilename", APR_DLL_BASENAME ".dll\0" + VALUE "ProductName", "Apache Portable Runtime Project\0" + VALUE "ProductVersion", APR_VERSION_STRING "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END diff --git a/locks/beos/Makefile.in b/locks/beos/Makefile.in deleted file mode 100644 index 7fa364b431d..00000000000 --- a/locks/beos/Makefile.in +++ /dev/null @@ -1,64 +0,0 @@ -#CFLAGS=$(OPTIM) $(CFLAGS1) $(EXTRA_CFLAGS) -#LIBS=$(EXTRA_LIBS) $(LIBS1) -#INCLUDES=$(INCLUDES1) $(INCLUDES0) $(EXTRA_INCLUDES) -#LDFLAGS=$(LDFLAGS1) $(EXTRA_LDFLAGS) - -CC=@CC@ -RANLIB=@RANLIB@ -CFLAGS=@CFLAGS@ @OPTIM@ -LIBS=@LIBS@ -LDFLAGS=@LDFLAGS@ $(LIBS) -INCDIR=../../include -INCDIR1=../../file_io/unix -INCLUDES=-I$(INCDIR) -I$(INCDIR1) -I. - -LIB=liblock.a - -OBJS=locks.o \ - crossproc.o \ - intraproc.o \ - -.c.o: - $(CC) $(CFLAGS) -c $(INCLUDES) $< - -all: $(LIB) - -clean: - $(RM) -f *.o *.a *.so - -distclean: clean - -$(RM) -f Makefile - -$(OBJS): Makefile - -$(LIB): $(OBJS) - $(RM) -f $@ - $(AR) cr $@ $(OBJS) - $(RANLIB) $@ - -# -# We really don't expect end users to use this rule. It works only with -# gcc, and rebuilds Makefile.tmpl. You have to re-run Configure after -# using it. -# -depend: - cp Makefile.in Makefile.in.bak \ - && sed -ne '1,/^# DO NOT REMOVE/p' Makefile.in > Makefile.new \ - && gcc -MM $(INCLUDES) $(CFLAGS) *.c >> Makefile.new \ - && sed -e '1,$$s: $(INCDIR)/: $$(INCDIR)/:g' \ - -e '1,$$s: $(OSDIR)/: $$(OSDIR)/:g' Makefile.new \ - > Makefile.in \ - && rm Makefile.new - -# DO NOT REMOVE -crossproc.o: crossproc.c ../../include/apr_lock.h \ - ../../include/apr_general.h ../../include/apr_private.h \ - ../../include/apr_errno.h ../../include/apr_lib.h \ - ../../include/apr_file_io.h locks.h -intraproc.o: intraproc.c ../../include/apr_lock.h \ - ../../include/apr_general.h ../../include/apr_private.h \ - ../../include/apr_errno.h locks.h ../../include/apr_file_io.h \ - ../../include/apr_lib.h -locks.o: locks.c ../../include/apr_lock.h ../../include/apr_general.h \ - ../../include/apr_private.h ../../include/apr_errno.h locks.h \ - ../../include/apr_file_io.h diff --git a/locks/beos/crossproc.c b/locks/beos/crossproc.c deleted file mode 100644 index 388dba8edfc..00000000000 --- a/locks/beos/crossproc.c +++ /dev/null @@ -1,129 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#include "locks.h" - -ap_status_t lock_inter_cleanup(void * data) -{ - ap_lock_t *lock = (ap_lock_t*)data; - if (lock->curr_locked == 1) { - if (atomic_add(&lock->ben_interproc , -1) > 1){ - release_sem (lock->sem_interproc); - } - } - delete_sem(lock->sem_interproc); - return APR_SUCCESS; -} - -ap_status_t create_inter_lock(ap_lock_t *new) -{ - int32 stat; - - new->sem_interproc = (sem_id)ap_palloc(new->cntxt, sizeof(sem_id)); - new->ben_interproc = (int32)ap_palloc(new->cntxt, sizeof(int32)); - - if ((stat = create_sem(0, "ap_interproc")) < B_NO_ERROR) { - lock_inter_cleanup(new); - return stat; - } - new->ben_interproc = 0; - new->curr_locked = 0; - new->sem_interproc = stat; - ap_register_cleanup(new->cntxt, (void *)new, lock_inter_cleanup, - ap_null_cleanup); - return APR_SUCCESS; -} - -ap_status_t lock_inter(ap_lock_t *lock) -{ - int32 stat; - - if (atomic_add(&lock->ben_interproc, 1) > 0){ - if ((stat = acquire_sem(lock->sem_interproc)) != B_NO_ERROR){ - atomic_add(&lock->ben_interproc, -1); - return stat; - } - } - lock->curr_locked = 1; - return APR_SUCCESS; -} - -ap_status_t unlock_inter(ap_lock_t *lock) -{ - int32 stat; - - if (atomic_add(&lock->ben_interproc, -1) > 1){ - if ((stat = release_sem(lock->sem_interproc)) != B_NO_ERROR) { - atomic_add(&lock->ben_interproc, 1); - return stat; - } - } - lock->curr_locked = 0; - return APR_SUCCESS; -} - -ap_status_t destroy_inter_lock(ap_lock_t *lock) -{ - ap_status_t stat; - if ((stat = lock_inter_cleanup(lock)) == APR_SUCCESS) { - ap_kill_cleanup(lock->cntxt, lock, lock_inter_cleanup); - return APR_SUCCESS; - } - return stat; -} - -ap_status_t child_init_lock(ap_lock_t **lock, ap_pool_t *cont, char *fname) -{ - return APR_SUCCESS; -} diff --git a/locks/beos/intraproc.c b/locks/beos/intraproc.c deleted file mode 100644 index 89bfc17bc01..00000000000 --- a/locks/beos/intraproc.c +++ /dev/null @@ -1,126 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#include "locks.h" - -ap_status_t lock_intra_cleanup(void *data) -{ - ap_lock_t *lock = (ap_lock_t *)data; - if (lock->curr_locked == 1) { - if (atomic_add(&lock->ben_intraproc , -1) > 1){ - release_sem (lock->sem_intraproc); - } else { - return errno; - } - } - delete_sem(lock->sem_intraproc); - return APR_SUCCESS; -} - -ap_status_t create_intra_lock(ap_lock_t *new) -{ - int32 stat; - new->sem_intraproc = (sem_id)ap_palloc(new->cntxt, sizeof(sem_id)); - new->ben_intraproc = (int32)ap_palloc(new->cntxt, sizeof(int32)); - - - if ((stat = create_sem(0, "ap_intraproc")) < B_NO_ERROR){ - lock_intra_cleanup(new); - return stat; - } - new->ben_intraproc = 0; - new->sem_intraproc = stat; - new->curr_locked = 0; - ap_register_cleanup(new->cntxt, (void *)new, lock_intra_cleanup, - ap_null_cleanup); - return APR_SUCCESS; -} - -ap_status_t lock_intra(ap_lock_t *lock) -{ - int32 stat; - - if (atomic_add (&lock->ben_intraproc, 1) > 0){ - if ((stat = acquire_sem(lock->sem_intraproc)) != B_NO_ERROR){ - atomic_add(&lock->ben_intraproc,-1); - return stat; - } - } - lock->curr_locked = 1; - return APR_SUCCESS; -} - -ap_status_t unlock_intra(ap_lock_t *lock) -{ - int32 stat; - - if (atomic_add(&lock->ben_intraproc, -1) > 1){ - if ((stat = release_sem(lock->sem_intraproc)) != B_NO_ERROR) { - atomic_add(&lock->ben_intraproc, 1); - return stat; - } - } - lock->curr_locked = 0; - return APR_SUCCESS; -} - -ap_status_t destroy_intra_lock(ap_lock_t *lock) -{ - ap_status_t stat; - if ((stat = lock_intra_cleanup(lock)) == APR_SUCCESS) { - ap_kill_cleanup(lock->cntxt, lock, lock_intra_cleanup); - return APR_SUCCESS; - } - return stat; -} diff --git a/locks/beos/locks.c b/locks/beos/locks.c deleted file mode 100644 index 362b281771c..00000000000 --- a/locks/beos/locks.c +++ /dev/null @@ -1,171 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#include "locks.h" - -ap_status_t ap_create_lock(ap_lock_t **lock, ap_locktype_e type, - ap_lockscope_e scope, const char *fname, - ap_pool_t *cont) -{ - ap_lock_t *new; - ap_status_t stat; - - new = (ap_lock_t *)ap_palloc(cont, sizeof(ap_lock_t)); - if (new == NULL){ - return APR_ENOMEM; - } - - new->cntxt = cont; - new->type = type; - new->scope = scope; - new->fname = ap_pstrdup(cont, fname); - - if (scope != APR_CROSS_PROCESS) { - if ((stat = create_intra_lock(new)) != APR_SUCCESS) { - return stat; - } - } - if (scope != APR_INTRAPROCESS) { - if ((stat = create_inter_lock(new)) != APR_SUCCESS) { - return stat; - } - } - (*lock) = new; - return APR_SUCCESS; -} - -ap_status_t ap_lock(ap_lock_t *lock) -{ - ap_status_t stat; - - if (lock->scope != APR_CROSS_PROCESS) { - if ((stat = lock_intra(lock)) != APR_SUCCESS) { - return stat; - } - } - if (lock->scope != APR_INTRAPROCESS) { - if ((stat = lock_inter(lock)) != APR_SUCCESS) { - return stat; - } - } - return APR_SUCCESS; -} - -ap_status_t ap_unlock(ap_lock_t *lock) -{ - ap_status_t stat; - if (lock->scope != APR_CROSS_PROCESS) { - if ((stat = unlock_intra(lock)) != APR_SUCCESS) { - return stat; - } - } - if (lock->scope != APR_INTRAPROCESS) { - if ((stat = unlock_inter(lock)) != APR_SUCCESS) { - return stat; - } - } - return APR_SUCCESS; -} - -ap_status_t ap_destroy_lock(ap_lock_t *lock) -{ - ap_status_t stat; - if (lock->scope != APR_CROSS_PROCESS) { - if ((stat = destroy_intra_lock(lock)) != APR_SUCCESS) { - return stat; - } - } - if (lock->scope != APR_INTRAPROCESS) { - if ((stat = destroy_inter_lock(lock)) != APR_SUCCESS) { - return stat; - } - } - return APR_SUCCESS; -} - -ap_status_t ap_child_init_lock(ap_lock_t **lock, const char *fname, - ap_pool_t *cont) -{ - ap_status_t stat; - if ((*lock)->scope != APR_CROSS_PROCESS) { - if ((stat = child_init_lock(lock, cont, fname)) != APR_SUCCESS) { - return stat; - } - } - return APR_SUCCESS; -} - -ap_status_t ap_get_lockdata(ap_lock_t *lock, char *key, void *data) -{ - if (lock != NULL) { - return ap_get_userdata(data, key, lock->cntxt); - } - else { - data = NULL; - return APR_ENOLOCK; - } -} - -ap_status_t ap_set_lockdata(ap_lock_t *lock, void *data, char *key, - ap_status_t (*cleanup) (void *)) -{ - if (lock != NULL) { - return ap_set_userdata(data, key, cleanup, lock->cntxt); - } - else { - data = NULL; - return APR_ENOLOCK; - } -} - diff --git a/locks/beos/locks.h b/locks/beos/locks.h deleted file mode 100644 index 0160b5e71aa..00000000000 --- a/locks/beos/locks.h +++ /dev/null @@ -1,82 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#ifndef LOCKS_H -#define LOCKS_H - -#include <kernel/OS.h> -#include "apr_lock.h" -#include "apr_file_io.h" -#include "apr_general.h" -#include "apr_lib.h" - -struct ap_lock_t { - ap_pool_t *cntxt; - ap_locktype_e type; - ap_lockscope_e scope; - int curr_locked; - char *fname; - /* Inter proc */ - sem_id sem_interproc; - int32 ben_interproc; - /* Intra Proc */ - sem_id sem_intraproc; - int32 ben_intraproc; - /* At some point, we should do a scope for both inter and intra process - * locking here. Something like pthread_mutex with PTHREAD_PROCESS_SHARED - */ -}; - -#endif /* LOCKS_H */ - diff --git a/locks/beos/proc_mutex.c b/locks/beos/proc_mutex.c new file mode 100644 index 00000000000..35a5e8f107e --- /dev/null +++ b/locks/beos/proc_mutex.c @@ -0,0 +1,242 @@ +/* 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. + */ + +/*Read/Write locking implementation based on the MultiLock code from + * Stephen Beaulieu <hippo@be.com> + */ + +#include "apr_arch_proc_mutex.h" +#include "apr_strings.h" +#include "apr_portable.h" + +static apr_status_t _proc_mutex_cleanup(void * data) +{ + apr_proc_mutex_t *lock = (apr_proc_mutex_t*)data; + if (lock->LockCount != 0) { + /* we're still locked... */ + while (atomic_add(&lock->LockCount , -1) > 1){ + /* OK we had more than one person waiting on the lock so + * the sem is also locked. Release it until we have no more + * locks left. + */ + release_sem (lock->Lock); + } + } + delete_sem(lock->Lock); + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_proc_mutex_create(apr_proc_mutex_t **mutex, + const char *fname, + apr_lockmech_e mech, + apr_pool_t *pool) +{ + apr_proc_mutex_t *new; + apr_status_t stat = APR_SUCCESS; + + if (mech != APR_LOCK_DEFAULT && mech != APR_LOCK_DEFAULT_TIMED) { + return APR_ENOTIMPL; + } + + new = (apr_proc_mutex_t *)apr_pcalloc(pool, sizeof(apr_proc_mutex_t)); + if (new == NULL){ + return APR_ENOMEM; + } + + if ((stat = create_sem(0, "APR_Lock")) < B_NO_ERROR) { + _proc_mutex_cleanup(new); + return stat; + } + new->LockCount = 0; + new->Lock = stat; + new->pool = pool; + + apr_pool_cleanup_register(new->pool, (void *)new, _proc_mutex_cleanup, + apr_pool_cleanup_null); + + (*mutex) = new; + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_proc_mutex_child_init(apr_proc_mutex_t **mutex, + const char *fname, + apr_pool_t *pool) +{ + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_proc_mutex_lock(apr_proc_mutex_t *mutex) +{ + int32 stat; + + if (atomic_add(&mutex->LockCount, 1) > 0) { + if ((stat = acquire_sem(mutex->Lock)) < B_NO_ERROR) { + atomic_add(&mutex->LockCount, -1); + return stat; + } + } + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_proc_mutex_trylock(apr_proc_mutex_t *mutex) +{ + int32 stat; + + if (atomic_add(&mutex->LockCount, 1) > 0) { + stat = acquire_sem_etc(mutex->Lock, 1, 0, 0); + if (stat < B_NO_ERROR) { + atomic_add(&mutex->LockCount, -1); + if (stat == B_WOULD_BLOCK) { + stat = APR_EBUSY; + } + return stat; + } + } + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_proc_mutex_timedlock(apr_proc_mutex_t *mutex, + apr_interval_time_t timeout) +{ + int32 stat; + + if (atomic_add(&mutex->LockCount, 1) > 0) { + if (timeout <= 0) { + stat = B_TIMED_OUT; + } + else { + stat = acquire_sem_etc(mutex->Lock, 1, B_RELATIVE_TIMEOUT, + timeout); + } + if (stat < B_NO_ERROR) { + atomic_add(&mutex->LockCount, -1); + if (stat == B_TIMED_OUT) { + stat = APR_TIMEUP; + } + return stat; + } + } + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_proc_mutex_unlock(apr_proc_mutex_t *mutex) +{ + int32 stat; + + if (atomic_add(&mutex->LockCount, -1) > 1) { + if ((stat = release_sem(mutex->Lock)) < B_NO_ERROR) { + atomic_add(&mutex->LockCount, 1); + return stat; + } + } + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_proc_mutex_destroy(apr_proc_mutex_t *mutex) +{ + apr_status_t stat; + if ((stat = _proc_mutex_cleanup(mutex)) == APR_SUCCESS) { + apr_pool_cleanup_kill(mutex->pool, mutex, _proc_mutex_cleanup); + return APR_SUCCESS; + } + return stat; +} + +APR_DECLARE(apr_status_t) apr_proc_mutex_cleanup(void *mutex) +{ + return _proc_mutex_cleanup(mutex); +} + + +APR_DECLARE(const char *) apr_proc_mutex_lockfile(apr_proc_mutex_t *mutex) +{ + return NULL; +} + +APR_DECLARE(apr_lockmech_e) apr_proc_mutex_mech(apr_proc_mutex_t *mutex) +{ + return APR_LOCK_DEFAULT; +} + +APR_DECLARE(const char *) apr_proc_mutex_name(apr_proc_mutex_t *mutex) +{ + return "beossem"; +} + +APR_DECLARE(const char *) apr_proc_mutex_defname(void) +{ + return "beossem"; +} + +APR_PERMS_SET_ENOTIMPL(proc_mutex) + +APR_POOL_IMPLEMENT_ACCESSOR(proc_mutex) + +/* Implement OS-specific accessors defined in apr_portable.h */ + +APR_DECLARE(apr_status_t) apr_os_proc_mutex_get_ex(apr_os_proc_mutex_t *ospmutex, + apr_proc_mutex_t *pmutex, + apr_lockmech_e *mech) +{ + ospmutex->sem = pmutex->Lock; + ospmutex->ben = pmutex->LockCount; + if (mech) { + *mech = APR_LOCK_DEFAULT; + } + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_os_proc_mutex_get(apr_os_proc_mutex_t *ospmutex, + apr_proc_mutex_t *pmutex) +{ + return apr_os_proc_mutex_get_ex(ospmutex, pmutex, NULL); +} + +APR_DECLARE(apr_status_t) apr_os_proc_mutex_put_ex(apr_proc_mutex_t **pmutex, + apr_os_proc_mutex_t *ospmutex, + apr_lockmech_e mech, + int register_cleanup, + apr_pool_t *pool) +{ + if (pool == NULL) { + return APR_ENOPOOL; + } + if (mech != APR_LOCK_DEFAULT && mech != APR_LOCK_DEFAULT_TIMED) { + return APR_ENOTIMPL; + } + + if ((*pmutex) == NULL) { + (*pmutex) = (apr_proc_mutex_t *)apr_pcalloc(pool, sizeof(apr_proc_mutex_t)); + (*pmutex)->pool = pool; + } + (*pmutex)->Lock = ospmutex->sem; + (*pmutex)->LockCount = ospmutex->ben; + + if (register_cleanup) { + apr_pool_cleanup_register(pool, *pmutex, _proc_mutex_cleanup, + apr_pool_cleanup_null); + } + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_os_proc_mutex_put(apr_proc_mutex_t **pmutex, + apr_os_proc_mutex_t *ospmutex, + apr_pool_t *pool) +{ + return apr_os_proc_mutex_put_ex(pmutex, ospmutex, APR_LOCK_DEFAULT, + 0, pool); +} + diff --git a/locks/beos/thread_cond.c b/locks/beos/thread_cond.c new file mode 100644 index 00000000000..a0978c008c8 --- /dev/null +++ b/locks/beos/thread_cond.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 "apr_arch_thread_mutex.h" +#include "apr_arch_thread_cond.h" +#include "apr_strings.h" +#include "apr_portable.h" + +static apr_status_t thread_cond_cleanup(void *data) +{ + struct waiter *w; + apr_thread_cond_t *cond = (apr_thread_cond_t *)data; + + acquire_sem(cond->lock); + delete_sem(cond->lock); + + return APR_SUCCESS; +} + +static struct waiter_t *make_waiter(apr_pool_t *pool) +{ + struct waiter_t *w = (struct waiter_t*) + apr_palloc(pool, sizeof(struct waiter_t)); + if (w == NULL) + return NULL; + + w->sem = create_sem(0, "apr conditional waiter"); + if (w->sem < 0) + return NULL; + + APR_RING_ELEM_INIT(w, link); + + return w; +} + +APR_DECLARE(apr_status_t) apr_thread_cond_create(apr_thread_cond_t **cond, + apr_pool_t *pool) +{ + apr_thread_cond_t *new_cond; + sem_id rv; + int i; + + new_cond = (apr_thread_cond_t *)apr_palloc(pool, sizeof(apr_thread_cond_t)); + + if (new_cond == NULL) + return APR_ENOMEM; + + if ((rv = create_sem(1, "apr conditional lock")) < B_OK) + return rv; + + new_cond->lock = rv; + new_cond->pool = pool; + APR_RING_INIT(&new_cond->alist, waiter_t, link); + APR_RING_INIT(&new_cond->flist, waiter_t, link); + + for (i=0;i < 10 ;i++) { + struct waiter_t *nw = make_waiter(pool); + APR_RING_INSERT_TAIL(&new_cond->flist, nw, waiter_t, link); + } + + apr_pool_cleanup_register(new_cond->pool, + (void *)new_cond, thread_cond_cleanup, + apr_pool_cleanup_null); + + *cond = new_cond; + return APR_SUCCESS; +} + + +static apr_status_t do_wait(apr_thread_cond_t *cond, apr_thread_mutex_t *mutex, + apr_interval_time_t timeout) +{ + struct waiter_t *wait; + thread_id cth = find_thread(NULL); + apr_status_t rv; + int flags = B_RELATIVE_TIMEOUT; + + /* We must be the owner of the mutex or we can't do this... */ + if (mutex->owner != cth) { + /* What should we return??? */ + return APR_EINVAL; + } + + acquire_sem(cond->lock); + wait = APR_RING_FIRST(&cond->flist); + if (wait) + APR_RING_REMOVE(wait, link); + else + wait = make_waiter(cond->pool); + APR_RING_INSERT_TAIL(&cond->alist, wait, waiter_t, link); + cond->condlock = mutex; + release_sem(cond->lock); + + apr_thread_mutex_unlock(cond->condlock); + + if (timeout == 0) + flags = 0; + + rv = acquire_sem_etc(wait->sem, 1, flags, timeout); + + apr_thread_mutex_lock(cond->condlock); + + if (rv != B_OK) { + if (rv == B_TIMED_OUT) + return APR_TIMEUP; + return rv; + } + + acquire_sem(cond->lock); + APR_RING_REMOVE(wait, link); + APR_RING_INSERT_TAIL(&cond->flist, wait, waiter_t, link); + release_sem(cond->lock); + + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_thread_cond_wait(apr_thread_cond_t *cond, + apr_thread_mutex_t *mutex) +{ + return do_wait(cond, mutex, 0); +} + +APR_DECLARE(apr_status_t) apr_thread_cond_timedwait(apr_thread_cond_t *cond, + apr_thread_mutex_t *mutex, + apr_interval_time_t timeout) +{ + return do_wait(cond, mutex, timeout); +} + +APR_DECLARE(apr_status_t) apr_thread_cond_signal(apr_thread_cond_t *cond) +{ + struct waiter_t *wake; + + acquire_sem(cond->lock); + if (!APR_RING_EMPTY(&cond->alist, waiter_t, link)) { + wake = APR_RING_FIRST(&cond->alist); + APR_RING_REMOVE(wake, link); + release_sem(wake->sem); + APR_RING_INSERT_TAIL(&cond->flist, wake, waiter_t, link); + } + release_sem(cond->lock); + + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_thread_cond_broadcast(apr_thread_cond_t *cond) +{ + struct waiter_t *wake; + + acquire_sem(cond->lock); + while (! APR_RING_EMPTY(&cond->alist, waiter_t, link)) { + wake = APR_RING_FIRST(&cond->alist); + APR_RING_REMOVE(wake, link); + release_sem(wake->sem); + APR_RING_INSERT_TAIL(&cond->flist, wake, waiter_t, link); + } + release_sem(cond->lock); + + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_thread_cond_destroy(apr_thread_cond_t *cond) +{ + apr_status_t stat; + if ((stat = thread_cond_cleanup(cond)) == APR_SUCCESS) { + apr_pool_cleanup_kill(cond->pool, cond, thread_cond_cleanup); + return APR_SUCCESS; + } + return stat; +} + +APR_POOL_IMPLEMENT_ACCESSOR(thread_cond) + diff --git a/locks/beos/thread_mutex.c b/locks/beos/thread_mutex.c new file mode 100644 index 00000000000..e4099d8826d --- /dev/null +++ b/locks/beos/thread_mutex.c @@ -0,0 +1,202 @@ +/* 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. + */ + +/*Read/Write locking implementation based on the MultiLock code from + * Stephen Beaulieu <hippo@be.com> + */ + +#include "apr_arch_thread_mutex.h" +#include "apr_strings.h" +#include "apr_portable.h" + +static apr_status_t _thread_mutex_cleanup(void * data) +{ + apr_thread_mutex_t *lock = (apr_thread_mutex_t*)data; + if (lock->LockCount != 0) { + /* we're still locked... */ + while (atomic_add(&lock->LockCount , -1) > 1){ + /* OK we had more than one person waiting on the lock so + * the sem is also locked. Release it until we have no more + * locks left. + */ + release_sem (lock->Lock); + } + } + delete_sem(lock->Lock); + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_thread_mutex_create(apr_thread_mutex_t **mutex, + unsigned int flags, + apr_pool_t *pool) +{ + apr_thread_mutex_t *new_m; + apr_status_t stat = APR_SUCCESS; + + new_m = (apr_thread_mutex_t *)apr_pcalloc(pool, sizeof(apr_thread_mutex_t)); + if (new_m == NULL){ + return APR_ENOMEM; + } + + if ((stat = create_sem(0, "APR_Lock")) < B_NO_ERROR) { + _thread_mutex_cleanup(new_m); + return stat; + } + new_m->LockCount = 0; + new_m->Lock = stat; + new_m->pool = pool; + + /* Optimal default is APR_THREAD_MUTEX_UNNESTED, + * no additional checks required for either flag. + */ + new_m->nested = flags & APR_THREAD_MUTEX_NESTED; + + apr_pool_cleanup_register(new_m->pool, (void *)new_m, _thread_mutex_cleanup, + apr_pool_cleanup_null); + + (*mutex) = new_m; + return APR_SUCCESS; +} + +#if APR_HAS_CREATE_LOCKS_NP +APR_DECLARE(apr_status_t) apr_thread_mutex_create_np(apr_thread_mutex_t **mutex, + const char *fname, + apr_lockmech_e_np mech, + apr_pool_t *pool) +{ + return APR_ENOTIMPL; +} +#endif + +APR_DECLARE(apr_status_t) apr_thread_mutex_lock(apr_thread_mutex_t *mutex) +{ + int32 stat; + thread_id me = find_thread(NULL); + + if (mutex->nested && mutex->owner == me) { + mutex->owner_ref++; + return APR_SUCCESS; + } + + if (atomic_add(&mutex->LockCount, 1) > 0) { + if ((stat = acquire_sem(mutex->Lock)) < B_NO_ERROR) { + /* Oh dear, acquire_sem failed!! */ + atomic_add(&mutex->LockCount, -1); + return stat; + } + } + + mutex->owner = me; + mutex->owner_ref = 1; + + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_thread_mutex_trylock(apr_thread_mutex_t *mutex) +{ + int32 stat; + thread_id me = find_thread(NULL); + + if (mutex->nested && mutex->owner == me) { + mutex->owner_ref++; + return APR_SUCCESS; + } + + if (atomic_add(&mutex->LockCount, 1) > 0) { + if ((stat = acquire_sem_etc(mutex->Lock, 1, 0, 0)) < B_NO_ERROR) { + atomic_add(&mutex->LockCount, -1); + if (stat == B_WOULD_BLOCK) { + stat = APR_EBUSY; + } + return stat; + } + } + + mutex->owner = me; + mutex->owner_ref = 1; + + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_thread_mutex_timedlock(apr_thread_mutex_t *mutex, + apr_interval_time_t timeout) +{ + int32 stat; + thread_id me = find_thread(NULL); + + if (mutex->nested && mutex->owner == me) { + mutex->owner_ref++; + return APR_SUCCESS; + } + + if (atomic_add(&mutex->LockCount, 1) > 0) { + if (timeout <= 0) { + stat = B_TIMED_OUT; + } + else { + stat = acquire_sem_etc(mutex->Lock, 1, B_RELATIVE_TIMEOUT, + timeout); + } + if (stat < B_NO_ERROR) { + atomic_add(&mutex->LockCount, -1); + if (stat == B_TIMED_OUT) { + stat = APR_TIMEUP; + } + return stat; + } + } + + mutex->owner = me; + mutex->owner_ref = 1; + + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_thread_mutex_unlock(apr_thread_mutex_t *mutex) +{ + int32 stat; + + if (mutex->nested && mutex->owner == find_thread(NULL)) { + mutex->owner_ref--; + if (mutex->owner_ref > 0) + return APR_SUCCESS; + } + + if (atomic_add(&mutex->LockCount, -1) > 1) { + if ((stat = release_sem(mutex->Lock)) < B_NO_ERROR) { + atomic_add(&mutex->LockCount, 1); + return stat; + } + } + + mutex->owner = -1; + mutex->owner_ref = 0; + + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_thread_mutex_destroy(apr_thread_mutex_t *mutex) +{ + apr_status_t stat; + if ((stat = _thread_mutex_cleanup(mutex)) == APR_SUCCESS) { + apr_pool_cleanup_kill(mutex->pool, mutex, _thread_mutex_cleanup); + return APR_SUCCESS; + } + return stat; +} + +APR_POOL_IMPLEMENT_ACCESSOR(thread_mutex) + diff --git a/locks/beos/thread_rwlock.c b/locks/beos/thread_rwlock.c new file mode 100644 index 00000000000..a540b445574 --- /dev/null +++ b/locks/beos/thread_rwlock.c @@ -0,0 +1,190 @@ +/* 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. + */ + +/*Read/Write locking implementation based on the MultiLock code from + * Stephen Beaulieu <hippo@be.com> + */ + +#include "apr_arch_thread_rwlock.h" +#include "apr_strings.h" +#include "apr_portable.h" + +#define BIG_NUM 100000 + +static apr_status_t _thread_rw_cleanup(void * data) +{ + apr_thread_rwlock_t *mutex = (apr_thread_rwlock_t*)data; + + if (mutex->ReadCount != 0) { + while (atomic_add(&mutex->ReadCount , -1) > 1){ + release_sem (mutex->Read); + } + } + if (mutex->WriteCount != 0) { + while (atomic_add(&mutex->WriteCount , -1) > 1){ + release_sem (mutex->Write); + } + } + if (mutex->LockCount != 0) { + while (atomic_add(&mutex->LockCount , -1) > 1){ + release_sem (mutex->Lock); + } + } + + delete_sem(mutex->Read); + delete_sem(mutex->Write); + delete_sem(mutex->Lock); + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_thread_rwlock_create(apr_thread_rwlock_t **rwlock, + apr_pool_t *pool) +{ + apr_thread_rwlock_t *new; + + new = (apr_thread_rwlock_t *)apr_pcalloc(pool, sizeof(apr_thread_rwlock_t)); + if (new == NULL){ + return APR_ENOMEM; + } + + new->pool = pool; + /* we need to make 3 locks... */ + new->ReadCount = 0; + new->WriteCount = 0; + new->LockCount = 0; + new->Read = create_sem(0, "APR_ReadLock"); + new->Write = create_sem(0, "APR_WriteLock"); + new->Lock = create_sem(0, "APR_Lock"); + + if (new->Lock < 0 || new->Read < 0 || new->Write < 0) { + _thread_rw_cleanup(new); + return -1; + } + + apr_pool_cleanup_register(new->pool, (void *)new, _thread_rw_cleanup, + apr_pool_cleanup_null); + (*rwlock) = new; + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_thread_rwlock_rdlock(apr_thread_rwlock_t *rwlock) +{ + int32 rv = APR_SUCCESS; + + if (find_thread(NULL) == rwlock->writer) { + /* we're the writer - no problem */ + rwlock->Nested++; + } else { + /* we're not the writer */ + int32 r = atomic_add(&rwlock->ReadCount, 1); + if (r < 0) { + /* Oh dear, writer holds lock, wait for sem */ + rv = acquire_sem_etc(rwlock->Read, 1, B_DO_NOT_RESCHEDULE, + B_INFINITE_TIMEOUT); + } + } + + return rv; +} + +APR_DECLARE(apr_status_t) apr_thread_rwlock_tryrdlock(apr_thread_rwlock_t *rwlock) +{ + return APR_ENOTIMPL; +} + +APR_DECLARE(apr_status_t) apr_thread_rwlock_wrlock(apr_thread_rwlock_t *rwlock) +{ + int rv = APR_SUCCESS; + + if (find_thread(NULL) == rwlock->writer) { + rwlock->Nested++; + } else { + /* we're not the writer... */ + if (atomic_add(&rwlock->LockCount, 1) >= 1) { + /* we're locked - acquire the sem */ + rv = acquire_sem_etc(rwlock->Lock, 1, B_DO_NOT_RESCHEDULE, + B_INFINITE_TIMEOUT); + } + if (rv == APR_SUCCESS) { + /* decrement the ReadCount to a large -ve number so that + * we block on new readers... + */ + int32 readers = atomic_add(&rwlock->ReadCount, -BIG_NUM); + if (readers > 0) { + /* readers are holding the lock */ + rv = acquire_sem_etc(rwlock->Write, readers, B_DO_NOT_RESCHEDULE, + B_INFINITE_TIMEOUT); + } + if (rv == APR_SUCCESS) + rwlock->writer = find_thread(NULL); + } + } + + return rv; +} + +APR_DECLARE(apr_status_t) apr_thread_rwlock_trywrlock(apr_thread_rwlock_t *rwlock) +{ + return APR_ENOTIMPL; +} + +APR_DECLARE(apr_status_t) apr_thread_rwlock_unlock(apr_thread_rwlock_t *rwlock) +{ + apr_status_t rv = APR_SUCCESS; + int32 readers; + + /* we know we hold the lock, so don't check it :) */ + if (find_thread(NULL) == rwlock->writer) { + /* we know we hold the lock, so don't check it :) */ + if (rwlock->Nested > 1) { + /* we're recursively locked */ + rwlock->Nested--; + return APR_SUCCESS; + } + /* OK so we need to release the sem if we have it :) */ + readers = atomic_add(&rwlock->ReadCount, BIG_NUM) + BIG_NUM; + if (readers > 0) { + rv = release_sem_etc(rwlock->Read, readers, B_DO_NOT_RESCHEDULE); + } + if (rv == APR_SUCCESS) { + rwlock->writer = -1; + if (atomic_add(&rwlock->LockCount, -1) > 1) { + rv = release_sem_etc(rwlock->Lock, 1, B_DO_NOT_RESCHEDULE); + } + } + } else { + /* We weren't the Writer, so just release the ReadCount... */ + if (atomic_add(&rwlock->ReadCount, -1) < 0) { + /* we have a writer waiting for the lock, so release it */ + rv = release_sem_etc(rwlock->Write, 1, B_DO_NOT_RESCHEDULE); + } + } + + return rv; +} + +APR_DECLARE(apr_status_t) apr_thread_rwlock_destroy(apr_thread_rwlock_t *rwlock) +{ + apr_status_t stat; + if ((stat = _thread_rw_cleanup(rwlock)) == APR_SUCCESS) { + apr_pool_cleanup_kill(rwlock->pool, rwlock, _thread_rw_cleanup); + return APR_SUCCESS; + } + return stat; +} + +APR_POOL_IMPLEMENT_ACCESSOR(thread_rwlock) + diff --git a/locks/netware/proc_mutex.c b/locks/netware/proc_mutex.c new file mode 100644 index 00000000000..287011b0683 --- /dev/null +++ b/locks/netware/proc_mutex.c @@ -0,0 +1,184 @@ +/* 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_portable.h" +#include "apr_arch_proc_mutex.h" +#include "apr_arch_thread_mutex.h" + +APR_DECLARE(apr_status_t) apr_proc_mutex_create(apr_proc_mutex_t **mutex, + const char *fname, + apr_lockmech_e mech, + apr_pool_t *pool) +{ + apr_status_t ret; + apr_proc_mutex_t *new_mutex; + unsigned int flags = APR_THREAD_MUTEX_DEFAULT; + + *mutex = NULL; + if (mech == APR_LOCK_DEFAULT_TIMED) { + flags |= APR_THREAD_MUTEX_TIMED; + } + else if (mech != APR_LOCK_DEFAULT) { + return APR_ENOTIMPL; + } + + new_mutex = (apr_proc_mutex_t *)apr_pcalloc(pool, sizeof(apr_proc_mutex_t)); + if (new_mutex == NULL) { + return APR_ENOMEM; + } + + new_mutex->pool = pool; + ret = apr_thread_mutex_create(&(new_mutex->mutex), flags, pool); + + if (ret == APR_SUCCESS) + *mutex = new_mutex; + + return ret; +} + +APR_DECLARE(apr_status_t) apr_proc_mutex_child_init(apr_proc_mutex_t **mutex, + const char *fname, + apr_pool_t *pool) +{ + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_proc_mutex_lock(apr_proc_mutex_t *mutex) +{ + if (mutex) + return apr_thread_mutex_lock(mutex->mutex); + return APR_ENOLOCK; +} + +APR_DECLARE(apr_status_t) apr_proc_mutex_trylock(apr_proc_mutex_t *mutex) +{ + if (mutex) + return apr_thread_mutex_trylock(mutex->mutex); + return APR_ENOLOCK; +} + +APR_DECLARE(apr_status_t) apr_proc_mutex_timedlock(apr_proc_mutex_t *mutex, + apr_interval_time_t timeout) +{ + if (mutex) + return apr_thread_mutex_timedlock(mutex->mutex, timeout); + return APR_ENOLOCK; +} + +APR_DECLARE(apr_status_t) apr_proc_mutex_unlock(apr_proc_mutex_t *mutex) +{ + if (mutex) + return apr_thread_mutex_unlock(mutex->mutex); + return APR_ENOLOCK; +} + +APR_DECLARE(apr_status_t) apr_proc_mutex_cleanup(void *mutex) +{ + return apr_proc_mutex_destroy(mutex); +} + +APR_DECLARE(apr_status_t) apr_proc_mutex_destroy(apr_proc_mutex_t *mutex) +{ + if (mutex) + return apr_thread_mutex_destroy(mutex->mutex); + return APR_ENOLOCK; +} + +APR_DECLARE(const char *) apr_proc_mutex_lockfile(apr_proc_mutex_t *mutex) +{ + return NULL; +} + +APR_DECLARE(apr_lockmech_e) apr_proc_mutex_mech(apr_proc_mutex_t *mutex) +{ + return APR_LOCK_DEFAULT; +} + +APR_DECLARE(const char *) apr_proc_mutex_name(apr_proc_mutex_t *mutex) +{ + return "netwarethread"; +} + +APR_DECLARE(const char *) apr_proc_mutex_defname(void) +{ + return "netwarethread"; +} + +APR_PERMS_SET_ENOTIMPL(proc_mutex) + +APR_POOL_IMPLEMENT_ACCESSOR(proc_mutex) + +/* Implement OS-specific accessors defined in apr_portable.h */ + +APR_DECLARE(apr_status_t) apr_os_proc_mutex_get_ex(apr_os_proc_mutex_t *ospmutex, + apr_proc_mutex_t *pmutex, + apr_lockmech_e *mech) +{ + if (!pmutex->mutex) { + return APR_ENOLOCK; + } + + *ospmutex = pmutex->mutex->mutex; + if (mech) { + *mech = APR_LOCK_DEFAULT; + } + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_os_proc_mutex_get(apr_os_proc_mutex_t *ospmutex, + apr_proc_mutex_t *pmutex) +{ + return apr_os_proc_mutex_get_ex(ospmutex, pmutex, NULL); +} + +APR_DECLARE(apr_status_t) apr_os_proc_mutex_put_ex(apr_proc_mutex_t **pmutex, + apr_os_proc_mutex_t *ospmutex, + apr_lockmech_e mech, + int register_cleanup, + apr_pool_t *pool) +{ + if (pool == NULL) { + return APR_ENOPOOL; + } + if (mech != APR_LOCK_DEFAULT) { + return APR_ENOTIMPL; + } + + if ((*pmutex) == NULL) { + (*pmutex) = apr_pcalloc(pool, sizeof(apr_proc_mutex_t)); + (*pmutex)->pool = pool; + } + (*pmutex)->mutex = apr_pcalloc(pool, sizeof(apr_thread_mutex_t)); + (*pmutex)->mutex->mutex = *ospmutex; + (*pmutex)->mutex->pool = pool; + + if (register_cleanup) { + apr_pool_cleanup_register(pool, *pmutex, apr_proc_mutex_cleanup, + apr_pool_cleanup_null); + } + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_os_proc_mutex_put(apr_proc_mutex_t **pmutex, + apr_os_proc_mutex_t *ospmutex, + apr_pool_t *pool) +{ + return apr_os_proc_mutex_put_ex(pmutex, ospmutex, APR_LOCK_DEFAULT, + 0, pool); +} + diff --git a/locks/netware/thread_cond.c b/locks/netware/thread_cond.c new file mode 100644 index 00000000000..432b0d2908b --- /dev/null +++ b/locks/netware/thread_cond.c @@ -0,0 +1,111 @@ +/* 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 <nks/errno.h> + +#include "apr.h" +#include "apr_private.h" +#include "apr_general.h" +#include "apr_strings.h" +#include "apr_arch_thread_mutex.h" +#include "apr_arch_thread_cond.h" +#include "apr_portable.h" + +static apr_status_t thread_cond_cleanup(void *data) +{ + apr_thread_cond_t *cond = (apr_thread_cond_t *)data; + + NXCondFree(cond->cond); + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_thread_cond_create(apr_thread_cond_t **cond, + apr_pool_t *pool) +{ + apr_thread_cond_t *new_cond = NULL; + + new_cond = (apr_thread_cond_t *)apr_pcalloc(pool, sizeof(apr_thread_cond_t)); + + if(new_cond ==NULL) { + return APR_ENOMEM; + } + new_cond->pool = pool; + + new_cond->cond = NXCondAlloc(NULL); + + if(new_cond->cond == NULL) + return APR_ENOMEM; + + apr_pool_cleanup_register(new_cond->pool, new_cond, + (void*)thread_cond_cleanup, + apr_pool_cleanup_null); + *cond = new_cond; + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_thread_cond_wait(apr_thread_cond_t *cond, + apr_thread_mutex_t *mutex) +{ + if (NXCondWait(cond->cond, mutex->mutex) != 0) + return APR_EINTR; + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_thread_cond_timedwait(apr_thread_cond_t *cond, + apr_thread_mutex_t *mutex, + apr_interval_time_t timeout) +{ + int rc; + if (timeout < 0) { + rc = NXCondWait(cond->cond, mutex->mutex); + } + else { + timeout = timeout * 1000 / NXGetSystemTick(); + rc = NXCondTimedWait(cond->cond, mutex->mutex, timeout); + if (rc == NX_ETIMEDOUT) { + return APR_TIMEUP; + } + } + if (rc != 0) { + return APR_EINTR; + } + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_thread_cond_signal(apr_thread_cond_t *cond) +{ + NXCondSignal(cond->cond); + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_thread_cond_broadcast(apr_thread_cond_t *cond) +{ + NXCondBroadcast(cond->cond); + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_thread_cond_destroy(apr_thread_cond_t *cond) +{ + apr_status_t stat; + if ((stat = thread_cond_cleanup(cond)) == APR_SUCCESS) { + apr_pool_cleanup_kill(cond->pool, cond, thread_cond_cleanup); + return APR_SUCCESS; + } + return stat; +} + +APR_POOL_IMPLEMENT_ACCESSOR(thread_cond) + diff --git a/locks/netware/thread_mutex.c b/locks/netware/thread_mutex.c new file mode 100644 index 00000000000..435abebba30 --- /dev/null +++ b/locks/netware/thread_mutex.c @@ -0,0 +1,181 @@ +/* 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_general.h" +#include "apr_strings.h" +#include "apr_arch_thread_mutex.h" +#include "apr_thread_cond.h" +#include "apr_portable.h" + +static apr_status_t thread_mutex_cleanup(void *data) +{ + apr_thread_mutex_t *mutex = (apr_thread_mutex_t *)data; + + NXMutexFree(mutex->mutex); + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_thread_mutex_create(apr_thread_mutex_t **mutex, + unsigned int flags, + apr_pool_t *pool) +{ + apr_thread_mutex_t *new_mutex = NULL; + + /* XXX: Implement _UNNESTED flavor and favor _DEFAULT for performance + */ + if (flags & APR_THREAD_MUTEX_UNNESTED) { + return APR_ENOTIMPL; + } + new_mutex = (apr_thread_mutex_t *)apr_pcalloc(pool, sizeof(apr_thread_mutex_t)); + + if (new_mutex == NULL) { + return APR_ENOMEM; + } + new_mutex->pool = pool; + + new_mutex->mutex = NXMutexAlloc(NX_MUTEX_RECURSIVE, 0, NULL); + + if(new_mutex->mutex == NULL) + return APR_ENOMEM; + + if (flags & APR_THREAD_MUTEX_TIMED) { + apr_status_t rv = apr_thread_cond_create(&new_mutex->cond, pool); + if (rv != APR_SUCCESS) { + NXMutexFree(new_mutex->mutex); + return rv; + } + } + + apr_pool_cleanup_register(new_mutex->pool, new_mutex, + (void*)thread_mutex_cleanup, + apr_pool_cleanup_null); + *mutex = new_mutex; + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_thread_mutex_lock(apr_thread_mutex_t *mutex) +{ + if (mutex->cond) { + apr_status_t rv; + NXLock(mutex->mutex); + if (mutex->locked) { + mutex->num_waiters++; + rv = apr_thread_cond_wait(mutex->cond, mutex); + mutex->num_waiters--; + } + else { + mutex->locked = 1; + rv = APR_SUCCESS; + } + NXUnlock(mutex->mutex); + return rv; + } + + NXLock(mutex->mutex); + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_thread_mutex_trylock(apr_thread_mutex_t *mutex) +{ + if (mutex->cond) { + apr_status_t rv; + NXLock(mutex->mutex); + if (mutex->locked) { + rv = APR_EBUSY; + } + else { + mutex->locked = 1; + rv = APR_SUCCESS; + } + NXUnlock(mutex->mutex); + return rv; + } + + if (!NXTryLock(mutex->mutex)) + return APR_EBUSY; + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_thread_mutex_timedlock(apr_thread_mutex_t *mutex, + apr_interval_time_t timeout) +{ + if (mutex->cond) { + apr_status_t rv = APR_SUCCESS; + + NXLock(mutex->mutex); + if (mutex->locked) { + if (timeout <= 0) { + rv = APR_TIMEUP; + } + else { + mutex->num_waiters++; + do { + rv = apr_thread_cond_timedwait(mutex->cond, mutex, + timeout); + } while (rv == APR_SUCCESS && mutex->locked); + mutex->num_waiters--; + } + } + if (rv == APR_SUCCESS) { + mutex->locked = 1; + } + NXUnlock(mutex->mutex); + return rv; + } + + return APR_ENOTIMPL; +} + +APR_DECLARE(apr_status_t) apr_thread_mutex_unlock(apr_thread_mutex_t *mutex) +{ + apr_status_t rv = APR_SUCCESS; + + if (mutex->cond) { + NXLock(mutex->mutex); + + if (!mutex->locked) { + rv = APR_EINVAL; + } + else if (mutex->num_waiters) { + rv = apr_thread_cond_signal(mutex->cond); + } + if (rv == APR_SUCCESS) { + mutex->locked = 0; + } + } + + NXUnlock(mutex->mutex); + return rv; +} + +APR_DECLARE(apr_status_t) apr_thread_mutex_destroy(apr_thread_mutex_t *mutex) +{ + apr_status_t stat, rv = APR_SUCCESS; + if (mutex->cond) { + rv = apr_thread_cond_destroy(mutex->cond); + mutex->cond = NULL; + } + stat = apr_pool_cleanup_run(mutex->pool, mutex, thread_mutex_cleanup); + if (stat == APR_SUCCESS && rv) { + stat = rv; + } + return stat; +} + +APR_POOL_IMPLEMENT_ACCESSOR(thread_mutex) + diff --git a/locks/netware/thread_rwlock.c b/locks/netware/thread_rwlock.c new file mode 100644 index 00000000000..f971aefd47b --- /dev/null +++ b/locks/netware/thread_rwlock.c @@ -0,0 +1,102 @@ +/* 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_general.h" +#include "apr_strings.h" +#include "apr_arch_thread_rwlock.h" +#include "apr_portable.h" + +static apr_status_t thread_rwlock_cleanup(void *data) +{ + apr_thread_rwlock_t *rwlock = (apr_thread_rwlock_t *)data; + + NXRwLockFree (rwlock->rwlock); + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_thread_rwlock_create(apr_thread_rwlock_t **rwlock, + apr_pool_t *pool) +{ + apr_thread_rwlock_t *new_rwlock = NULL; + + NXHierarchy_t hierarchy = 1; /* for libc NKS NXRwLockAlloc */ + NXLockInfo_t *info; /* for libc NKS NXRwLockAlloc */ + + new_rwlock = (apr_thread_rwlock_t *)apr_pcalloc(pool, sizeof(apr_thread_rwlock_t)); + + if(new_rwlock ==NULL) { + return APR_ENOMEM; + } + new_rwlock->pool = pool; + + info = (NXLockInfo_t *)apr_pcalloc(pool, sizeof(NXLockInfo_t)); + new_rwlock->rwlock = NXRwLockAlloc(hierarchy, info); + if(new_rwlock->rwlock == NULL) + return APR_ENOMEM; + + apr_pool_cleanup_register(new_rwlock->pool, new_rwlock, thread_rwlock_cleanup, + apr_pool_cleanup_null); + *rwlock = new_rwlock; + + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_thread_rwlock_rdlock(apr_thread_rwlock_t *rwlock) +{ + NXRdLock(rwlock->rwlock); + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_thread_rwlock_tryrdlock(apr_thread_rwlock_t *rwlock) +{ + if (!NXTryRdLock(rwlock->rwlock)) + return APR_EBUSY; + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_thread_rwlock_wrlock(apr_thread_rwlock_t *rwlock) +{ + NXWrLock(rwlock->rwlock); + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_thread_rwlock_trywrlock(apr_thread_rwlock_t *rwlock) +{ + if (!NXTryWrLock(rwlock->rwlock)) + return APR_EBUSY; + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_thread_rwlock_unlock(apr_thread_rwlock_t *rwlock) +{ + NXRwUnlock(rwlock->rwlock); + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_thread_rwlock_destroy(apr_thread_rwlock_t *rwlock) +{ + apr_status_t stat; + if ((stat = thread_rwlock_cleanup(rwlock)) == APR_SUCCESS) { + apr_pool_cleanup_kill(rwlock->pool, rwlock, thread_rwlock_cleanup); + return APR_SUCCESS; + } + return stat; +} + +APR_POOL_IMPLEMENT_ACCESSOR(thread_rwlock) + diff --git a/locks/os2/.cvsignore b/locks/os2/.cvsignore deleted file mode 100644 index f3c7a7c5da6..00000000000 --- a/locks/os2/.cvsignore +++ /dev/null @@ -1 +0,0 @@ -Makefile diff --git a/locks/os2/Makefile.in b/locks/os2/Makefile.in deleted file mode 100644 index 9ba454f10f7..00000000000 --- a/locks/os2/Makefile.in +++ /dev/null @@ -1,59 +0,0 @@ -#CFLAGS=$(OPTIM) $(CFLAGS1) $(EXTRA_CFLAGS) -#LIBS=$(EXTRA_LIBS) $(LIBS1) -#INCLUDES=$(INCLUDES1) $(INCLUDES0) $(EXTRA_INCLUDES) -#LDFLAGS=$(LDFLAGS1) $(EXTRA_LDFLAGS) - -CC=@CC@ -RANLIB=@RANLIB@ -CFLAGS=@CFLAGS@ @OPTIM@ -LIBS=@LIBS@ -LDFLAGS=@LDFLAGS@ $(LIBS) -INCDIR=../../inc -INCDIR1=../../include -INCDIR2=../../file_io/os2 -INCLUDES=-I$(INCDIR) -I$(INCDIR1) -I$(INCDIR2) -I. - -LIB=lock.a - -OBJS=locks.o - -.c.o: - $(CC) $(CFLAGS) -c $(INCLUDES) $< - -all: $(LIB) - -clean: - $(RM) -f *.o *.a *.so - -distclean: clean - -$(RM) -f Makefile - -$(OBJS): Makefile - -$(LIB): $(OBJS) - $(RM) -f $@ - $(AR) cr $@ $(OBJS) - $(RANLIB) $@ - -# -# We really don't expect end users to use this rule. It works only with -# gcc, and rebuilds Makefile.tmpl. You have to re-run Configure after -# using it. -# -depend: - cp Makefile.in Makefile.in.bak \ - && sed -ne '1,/^# DO NOT REMOVE/p' Makefile.in > Makefile.new \ - && gcc -MM $(INCLUDES) $(CFLAGS) *.c | sed -e "s%\\\\\(.\)%/\\1%g" >> Makefile.new \ - && sed -e '1,$$s: $(INCDIR)/: $$(INCDIR)/:g' \ - -e '1,$$s: $(INCDIR1)/: $$(INCDIR1)/:g' \ - -e '1,$$s: $(INCDIR2)/: $$(INCDIR2)/:g' \ - -e '1,$$s: $(OSDIR)/: $$(OSDIR)/:g' Makefile.new \ - > Makefile.in \ - && rm Makefile.new - -# DO NOT REMOVE -locks.o: locks.c $(INCDIR1)/apr_general.h $(INCDIR1)/apr.h \ - $(INCDIR1)/apr_errno.h $(INCDIR1)/apr_lib.h \ - $(INCDIR1)/apr_file_io.h $(INCDIR1)/apr_time.h \ - $(INCDIR1)/apr_thread_proc.h locks.h $(INCDIR1)/apr_lock.h \ - $(INCDIR2)/fileio.h $(INCDIR1)/apr_private.h diff --git a/locks/os2/locks.c b/locks/os2/locks.c deleted file mode 100644 index dc288b6c9c5..00000000000 --- a/locks/os2/locks.c +++ /dev/null @@ -1,190 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#include "apr_general.h" -#include "apr_lib.h" -#include "locks.h" -#include "fileio.h" -#include <string.h> -#define INCL_DOS -#include <os2.h> - -#define CurrentTid (lock->tib->tib_ptib2->tib2_ultid) - - -void setup_lock() -{ -} - - - -static ap_status_t lock_cleanup(void *thelock) -{ - ap_lock_t *lock = thelock; - return ap_destroy_lock(lock); -} - - - -ap_status_t ap_create_lock(ap_lock_t **lock, ap_locktype_e type, ap_lockscope_e scope, - const char *fname, ap_pool_t *cont) -{ - ap_lock_t *new; - ULONG rc; - char *semname; - PIB *ppib; - - new = (ap_lock_t *)ap_palloc(cont, sizeof(ap_lock_t)); - new->cntxt = cont; - new->type = type; - new->scope = scope; - new->owner = 0; - new->lock_count = 0; - new->fname = ap_pstrdup(cont, fname); - DosGetInfoBlocks(&(new->tib), &ppib); - - if (fname == NULL) - semname = NULL; - else - semname = ap_pstrcat(cont, "/SEM32/", fname, NULL); - - rc = DosCreateMutexSem(semname, &(new->hMutex), scope == APR_CROSS_PROCESS ? DC_SEM_SHARED : 0, FALSE); - *lock = new; - - if (!rc) - ap_register_cleanup(cont, new, lock_cleanup, ap_null_cleanup); - - return APR_OS2_STATUS(rc); -} - - - -ap_status_t ap_child_init_lock(ap_lock_t **lock, const char *fname, - ap_pool_t *cont) -{ - int rc; - PIB *ppib; - - *lock = (ap_lock_t *)ap_palloc(cont, sizeof(ap_lock_t)); - - if (lock == NULL) - return APR_ENOMEM; - - DosGetInfoBlocks(&((*lock)->tib), &ppib); - (*lock)->owner = 0; - (*lock)->lock_count = 0; - rc = DosOpenMutexSem( (char *)fname, &(*lock)->hMutex ); - - if (!rc) - ap_register_cleanup(cont, *lock, lock_cleanup, ap_null_cleanup); - - return APR_OS2_STATUS(rc); -} - - - -ap_status_t ap_lock(ap_lock_t *lock) -{ - ULONG rc; - - rc = DosRequestMutexSem(lock->hMutex, SEM_INDEFINITE_WAIT); - - if (rc == 0) { - lock->owner = CurrentTid; - lock->lock_count++; - } - - return APR_OS2_STATUS(rc); -} - - - -ap_status_t ap_unlock(ap_lock_t *lock) -{ - ULONG rc; - - if (lock->owner == CurrentTid && lock->lock_count > 0) { - lock->lock_count--; - rc = DosReleaseMutexSem(lock->hMutex); - return APR_OS2_STATUS(rc); - } - - return APR_SUCCESS; -} - - - -ap_status_t ap_destroy_lock(ap_lock_t *lock) -{ - ULONG rc; - ap_status_t stat = APR_SUCCESS; - - if (lock->owner == CurrentTid) { - while (lock->lock_count > 0 && stat == APR_SUCCESS) - stat = ap_unlock(lock); - } - - if (stat != APR_SUCCESS) - return stat; - - if (lock->hMutex == 0) - return APR_SUCCESS; - - rc = DosCloseMutexSem(lock->hMutex); - - if (!rc) - lock->hMutex = 0; - - return APR_OS2_STATUS(rc); -} diff --git a/locks/os2/locks.h b/locks/os2/locks.h deleted file mode 100644 index d416b6b0833..00000000000 --- a/locks/os2/locks.h +++ /dev/null @@ -1,77 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#ifndef LOCKS_H -#define LOCKS_H - -#include "apr_lock.h" -#include "apr_file_io.h" -#define INCL_DOS -#include <os2.h> - -struct ap_lock_t { - ap_pool_t *cntxt; - ap_locktype_e type; - ap_lockscope_e scope; - char *fname; - HMTX hMutex; - TID owner; - int lock_count; - TIB *tib; -}; - -void setup_lock(); - -#endif /* LOCKS_H */ - diff --git a/locks/os2/proc_mutex.c b/locks/os2/proc_mutex.c new file mode 100644 index 00000000000..a86c208b324 --- /dev/null +++ b/locks/os2/proc_mutex.c @@ -0,0 +1,289 @@ +/* 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_general.h" +#include "apr_lib.h" +#include "apr_strings.h" +#include "apr_portable.h" +#include "apr_arch_proc_mutex.h" +#include "apr_arch_file_io.h" +#include <string.h> +#include <stddef.h> + +#define CurrentTid (*_threadid) + +static char *fixed_name(const char *fname, apr_pool_t *pool) +{ + char *semname; + + if (fname == NULL) + semname = NULL; + else { + /* Semaphores don't live in the file system, fix up the name */ + while (*fname == '/' || *fname == '\\') { + fname++; + } + + semname = apr_pstrcat(pool, "/SEM32/", fname, NULL); + + if (semname[8] == ':') { + semname[8] = '$'; + } + } + + return semname; +} + + + +APR_DECLARE(apr_status_t) apr_proc_mutex_cleanup(void *vmutex) +{ + apr_proc_mutex_t *mutex = vmutex; + return apr_proc_mutex_destroy(mutex); +} + +APR_DECLARE(const char *) apr_proc_mutex_lockfile(apr_proc_mutex_t *mutex) +{ + return NULL; +} + +APR_DECLARE(apr_lockmech_e) apr_proc_mutex_mech(apr_proc_mutex_t *mutex) +{ + return APR_LOCK_DEFAULT; +} + +APR_DECLARE(const char *) apr_proc_mutex_name(apr_proc_mutex_t *mutex) +{ + return "os2sem"; +} + +APR_DECLARE(const char *) apr_proc_mutex_defname(void) +{ + return "os2sem"; +} + + +APR_DECLARE(apr_status_t) apr_proc_mutex_create(apr_proc_mutex_t **mutex, + const char *fname, + apr_lockmech_e mech, + apr_pool_t *pool) +{ + apr_proc_mutex_t *new; + ULONG rc; + char *semname; + + if (mech != APR_LOCK_DEFAULT && mech != APR_LOCK_DEFAULT_TIMED) { + return APR_ENOTIMPL; + } + + new = (apr_proc_mutex_t *)apr_palloc(pool, sizeof(apr_proc_mutex_t)); + new->pool = pool; + new->owner = 0; + new->lock_count = 0; + *mutex = new; + + semname = fixed_name(fname, pool); + rc = DosCreateMutexSem(semname, &(new->hMutex), DC_SEM_SHARED, FALSE); + + if (!rc) { + apr_pool_cleanup_register(pool, new, apr_proc_mutex_cleanup, apr_pool_cleanup_null); + } + + return APR_FROM_OS_ERROR(rc); +} + + + +APR_DECLARE(apr_status_t) apr_proc_mutex_child_init(apr_proc_mutex_t **mutex, + const char *fname, + apr_pool_t *pool) +{ + apr_proc_mutex_t *new; + ULONG rc; + char *semname; + + new = (apr_proc_mutex_t *)apr_palloc(pool, sizeof(apr_proc_mutex_t)); + new->pool = pool; + new->owner = 0; + new->lock_count = 0; + + semname = fixed_name(fname, pool); + rc = DosOpenMutexSem(semname, &(new->hMutex)); + *mutex = new; + + if (!rc) { + apr_pool_cleanup_register(pool, new, apr_proc_mutex_cleanup, apr_pool_cleanup_null); + } + + return APR_FROM_OS_ERROR(rc); +} + + + +APR_DECLARE(apr_status_t) apr_proc_mutex_lock(apr_proc_mutex_t *mutex) +{ + ULONG rc = DosRequestMutexSem(mutex->hMutex, SEM_INDEFINITE_WAIT); + + if (rc == 0) { + mutex->owner = CurrentTid; + mutex->lock_count++; + } + + return APR_FROM_OS_ERROR(rc); +} + + + +APR_DECLARE(apr_status_t) apr_proc_mutex_trylock(apr_proc_mutex_t *mutex) +{ + ULONG rc = DosRequestMutexSem(mutex->hMutex, SEM_IMMEDIATE_RETURN); + + if (rc == 0) { + mutex->owner = CurrentTid; + mutex->lock_count++; + } + + return (rc == ERROR_TIMEOUT) ? APR_EBUSY : APR_FROM_OS_ERROR(rc); +} + + + +APR_DECLARE(apr_status_t) apr_proc_mutex_timedlock(apr_proc_mutex_t *mutex, + apr_interval_time_t timeout) +{ + ULONG rc; + + if (timeout <= 0) { + rc = DosRequestMutexSem(mutex->hMutex, SEM_IMMEDIATE_RETURN); + } + else { + rc = DosRequestMutexSem(mutex->hMutex, apr_time_as_msec(timeout)); + } + + if (rc == 0) { + mutex->owner = CurrentTid; + mutex->lock_count++; + } + + return (rc == ERROR_TIMEOUT) ? APR_TIMEUP : APR_FROM_OS_ERROR(rc); +} + + + +APR_DECLARE(apr_status_t) apr_proc_mutex_unlock(apr_proc_mutex_t *mutex) +{ + ULONG rc; + + if (mutex->owner == CurrentTid && mutex->lock_count > 0) { + mutex->lock_count--; + rc = DosReleaseMutexSem(mutex->hMutex); + return APR_FROM_OS_ERROR(rc); + } + + return APR_SUCCESS; +} + + + +APR_DECLARE(apr_status_t) apr_proc_mutex_destroy(apr_proc_mutex_t *mutex) +{ + ULONG rc; + apr_status_t status = APR_SUCCESS; + + if (mutex->owner == CurrentTid) { + while (mutex->lock_count > 0 && status == APR_SUCCESS) { + status = apr_proc_mutex_unlock(mutex); + } + } + + if (status != APR_SUCCESS) { + return status; + } + + if (mutex->hMutex == 0) { + return APR_SUCCESS; + } + + rc = DosCloseMutexSem(mutex->hMutex); + + if (!rc) { + mutex->hMutex = 0; + } + + return APR_FROM_OS_ERROR(rc); +} + +APR_PERMS_SET_ENOTIMPL(proc_mutex) + +APR_POOL_IMPLEMENT_ACCESSOR(proc_mutex) + + + +/* Implement OS-specific accessors defined in apr_portable.h */ + +APR_DECLARE(apr_status_t) apr_os_proc_mutex_get_ex(apr_os_proc_mutex_t *ospmutex, + apr_proc_mutex_t *pmutex, + apr_lockmech_e *mech) +{ + *ospmutex = pmutex->hMutex; + if (mech) { + *mech = APR_LOCK_DEFAULT; + } + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_os_proc_mutex_get(apr_os_proc_mutex_t *ospmutex, + apr_proc_mutex_t *pmutex) +{ + return apr_os_proc_mutex_get_ex(ospmutex, pmutex, NULL); +} + +APR_DECLARE(apr_status_t) apr_os_proc_mutex_put_ex(apr_proc_mutex_t **pmutex, + apr_os_proc_mutex_t *ospmutex, + apr_lockmech_e mech, + int register_cleanup, + apr_pool_t *pool) +{ + apr_proc_mutex_t *new; + if (pool == NULL) { + return APR_ENOPOOL; + } + if (mech != APR_LOCK_DEFAULT && mech != APR_LOCK_DEFAULT_TIMED) { + return APR_ENOTIMPL; + } + + new = (apr_proc_mutex_t *)apr_palloc(pool, sizeof(apr_proc_mutex_t)); + new->pool = pool; + new->owner = 0; + new->lock_count = 0; + new->hMutex = *ospmutex; + *pmutex = new; + + if (register_cleanup) { + apr_pool_cleanup_register(pool, *pmutex, apr_proc_mutex_cleanup, + apr_pool_cleanup_null); + } + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_os_proc_mutex_put(apr_proc_mutex_t **pmutex, + apr_os_proc_mutex_t *ospmutex, + apr_pool_t *pool) +{ + return apr_os_proc_mutex_put_ex(pmutex, ospmutex, APR_LOCK_DEFAULT, + 0, pool); +} + diff --git a/locks/os2/thread_cond.c b/locks/os2/thread_cond.c new file mode 100644 index 00000000000..86dbb8881ad --- /dev/null +++ b/locks/os2/thread_cond.c @@ -0,0 +1,194 @@ +/* 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_general.h" +#include "apr_lib.h" +#include "apr_strings.h" +#include "apr_portable.h" +#include "apr_arch_thread_mutex.h" +#include "apr_arch_thread_cond.h" +#include "apr_arch_file_io.h" +#include <string.h> + +#ifndef DCE_POSTONE +#define DCE_POSTONE 0x0800 /* Post one flag */ +#endif + +static apr_status_t thread_cond_cleanup(void *data) +{ + apr_thread_cond_t *cv = data; + + if (cv->semaphore) { + DosCloseEventSem(cv->semaphore); + } + + if (cv->mutex) { + DosCloseMutexSem(cv->mutex); + } + + return APR_SUCCESS; +} + + + +APR_DECLARE(apr_status_t) apr_thread_cond_create(apr_thread_cond_t **cond, + apr_pool_t *pool) +{ + int rc; + apr_thread_cond_t *cv; + + cv = apr_pcalloc(pool, sizeof(**cond)); + rc = DosCreateEventSem(NULL, &cv->semaphore, DCE_POSTONE, FALSE); + + if (rc == 0) { + rc = DosCreateMutexSem(NULL, &cv->mutex, 0, FALSE); + } + + *cond = cv; + cv->pool = pool; + apr_pool_cleanup_register(cv->pool, cv, thread_cond_cleanup, + apr_pool_cleanup_null); + + return APR_FROM_OS_ERROR(rc); +} + + + +static apr_status_t thread_cond_timedwait(apr_thread_cond_t *cond, + apr_thread_mutex_t *mutex, + ULONG timeout_ms ) +{ + ULONG rc; + apr_status_t rv = APR_SUCCESS; + int wake = FALSE; + unsigned long generation; + + DosRequestMutexSem(cond->mutex, SEM_INDEFINITE_WAIT); + cond->num_waiting++; + generation = cond->generation; + DosReleaseMutexSem(cond->mutex); + + apr_thread_mutex_unlock(mutex); + + do { + rc = DosWaitEventSem(cond->semaphore, timeout_ms); + + DosRequestMutexSem(cond->mutex, SEM_INDEFINITE_WAIT); + + if (cond->num_wake) { + if (cond->generation != generation) { + cond->num_wake--; + cond->num_waiting--; + rv = APR_SUCCESS; + break; + } else { + wake = TRUE; + } + } + else if (rc != 0) { + cond->num_waiting--; + rv = APR_TIMEUP; + break; + } + + DosReleaseMutexSem(cond->mutex); + + if (wake) { + wake = FALSE; + DosPostEventSem(cond->semaphore); + } + } while (1); + + DosReleaseMutexSem(cond->mutex); + apr_thread_mutex_lock(mutex); + return rv; +} + + + +APR_DECLARE(apr_status_t) apr_thread_cond_wait(apr_thread_cond_t *cond, + apr_thread_mutex_t *mutex) +{ + return thread_cond_timedwait(cond, mutex, SEM_INDEFINITE_WAIT); +} + + + +APR_DECLARE(apr_status_t) apr_thread_cond_timedwait(apr_thread_cond_t *cond, + apr_thread_mutex_t *mutex, + apr_interval_time_t timeout) +{ + ULONG timeout_ms = (timeout >= 0) ? apr_time_as_msec(timeout) + : SEM_INDEFINITE_WAIT; + return thread_cond_timedwait(cond, mutex, timeout_ms); +} + + + +APR_DECLARE(apr_status_t) apr_thread_cond_signal(apr_thread_cond_t *cond) +{ + int wake = FALSE; + + DosRequestMutexSem(cond->mutex, SEM_INDEFINITE_WAIT); + + if (cond->num_waiting > cond->num_wake) { + wake = TRUE; + cond->num_wake++; + cond->generation++; + } + + DosReleaseMutexSem(cond->mutex); + + if (wake) { + DosPostEventSem(cond->semaphore); + } + + return APR_SUCCESS; +} + + + +APR_DECLARE(apr_status_t) apr_thread_cond_broadcast(apr_thread_cond_t *cond) +{ + unsigned long num_wake = 0; + + DosRequestMutexSem(cond->mutex, SEM_INDEFINITE_WAIT); + + if (cond->num_waiting > cond->num_wake) { + num_wake = cond->num_waiting - cond->num_wake; + cond->num_wake = cond->num_waiting; + cond->generation++; + } + + DosReleaseMutexSem(cond->mutex); + + for (; num_wake; num_wake--) { + DosPostEventSem(cond->semaphore); + } + + return APR_SUCCESS; +} + + + +APR_DECLARE(apr_status_t) apr_thread_cond_destroy(apr_thread_cond_t *cond) +{ + return apr_pool_cleanup_run(cond->pool, cond, thread_cond_cleanup); +} + + + +APR_POOL_IMPLEMENT_ACCESSOR(thread_cond) diff --git a/locks/os2/thread_mutex.c b/locks/os2/thread_mutex.c new file mode 100644 index 00000000000..884004ce2de --- /dev/null +++ b/locks/os2/thread_mutex.c @@ -0,0 +1,120 @@ +/* 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_general.h" +#include "apr_lib.h" +#include "apr_strings.h" +#include "apr_portable.h" +#include "apr_arch_thread_mutex.h" +#include "apr_arch_file_io.h" +#include <string.h> +#include <stddef.h> + +static apr_status_t thread_mutex_cleanup(void *themutex) +{ + apr_thread_mutex_t *mutex = themutex; + return apr_thread_mutex_destroy(mutex); +} + + + +/* XXX: Need to respect APR_THREAD_MUTEX_[UN]NESTED flags argument + * or return APR_ENOTIMPL!!! + */ +APR_DECLARE(apr_status_t) apr_thread_mutex_create(apr_thread_mutex_t **mutex, + unsigned int flags, + apr_pool_t *pool) +{ + apr_thread_mutex_t *new_mutex; + ULONG rc; + + new_mutex = (apr_thread_mutex_t *)apr_palloc(pool, sizeof(apr_thread_mutex_t)); + new_mutex->pool = pool; + + rc = DosCreateMutexSem(NULL, &(new_mutex->hMutex), 0, FALSE); + *mutex = new_mutex; + + if (!rc) + apr_pool_cleanup_register(pool, new_mutex, thread_mutex_cleanup, apr_pool_cleanup_null); + + return APR_FROM_OS_ERROR(rc); +} + + + +APR_DECLARE(apr_status_t) apr_thread_mutex_lock(apr_thread_mutex_t *mutex) +{ + ULONG rc = DosRequestMutexSem(mutex->hMutex, SEM_INDEFINITE_WAIT); + return APR_FROM_OS_ERROR(rc); +} + + + +APR_DECLARE(apr_status_t) apr_thread_mutex_trylock(apr_thread_mutex_t *mutex) +{ + ULONG rc = DosRequestMutexSem(mutex->hMutex, SEM_IMMEDIATE_RETURN); + + return (rc == ERROR_TIMEOUT) ? APR_EBUSY : APR_FROM_OS_ERROR(rc); +} + + + +APR_DECLARE(apr_status_t) apr_thread_mutex_timedlock(apr_thread_mutex_t *mutex, + apr_interval_time_t timeout) +{ + ULONG rc; + + if (timeout <= 0) { + rc = DosRequestMutexSem(mutex->hMutex, SEM_IMMEDIATE_RETURN); + } + else { + rc = DosRequestMutexSem(mutex->hMutex, apr_time_as_msec(timeout)); + } + + return (rc == ERROR_TIMEOUT) ? APR_TIMEUP : APR_FROM_OS_ERROR(rc); +} + + + +APR_DECLARE(apr_status_t) apr_thread_mutex_unlock(apr_thread_mutex_t *mutex) +{ + ULONG rc = DosReleaseMutexSem(mutex->hMutex); + return APR_FROM_OS_ERROR(rc); +} + + + +APR_DECLARE(apr_status_t) apr_thread_mutex_destroy(apr_thread_mutex_t *mutex) +{ + ULONG rc; + + if (mutex->hMutex == 0) + return APR_SUCCESS; + + while (DosReleaseMutexSem(mutex->hMutex) == 0); + + rc = DosCloseMutexSem(mutex->hMutex); + + if (!rc) { + mutex->hMutex = 0; + return APR_SUCCESS; + } + + return APR_FROM_OS_ERROR(rc); +} + +APR_POOL_IMPLEMENT_ACCESSOR(thread_mutex) + diff --git a/locks/os2/thread_rwlock.c b/locks/os2/thread_rwlock.c new file mode 100644 index 00000000000..195a56bda3e --- /dev/null +++ b/locks/os2/thread_rwlock.c @@ -0,0 +1,200 @@ +/* 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_general.h" +#include "apr_lib.h" +#include "apr_strings.h" +#include "apr_portable.h" +#include "apr_arch_thread_rwlock.h" +#include "apr_arch_file_io.h" +#include <string.h> + +static apr_status_t thread_rwlock_cleanup(void *therwlock) +{ + apr_thread_rwlock_t *rwlock = therwlock; + return apr_thread_rwlock_destroy(rwlock); +} + + + +APR_DECLARE(apr_status_t) apr_thread_rwlock_create(apr_thread_rwlock_t **rwlock, + apr_pool_t *pool) +{ + apr_thread_rwlock_t *new_rwlock; + ULONG rc; + + new_rwlock = (apr_thread_rwlock_t *)apr_palloc(pool, sizeof(apr_thread_rwlock_t)); + new_rwlock->pool = pool; + new_rwlock->readers = 0; + + rc = DosCreateMutexSem(NULL, &(new_rwlock->write_lock), 0, FALSE); + + if (rc) + return APR_FROM_OS_ERROR(rc); + + rc = DosCreateEventSem(NULL, &(new_rwlock->read_done), 0, FALSE); + + if (rc) + return APR_FROM_OS_ERROR(rc); + + *rwlock = new_rwlock; + + if (!rc) + apr_pool_cleanup_register(pool, new_rwlock, thread_rwlock_cleanup, + apr_pool_cleanup_null); + + return APR_FROM_OS_ERROR(rc); +} + + + +APR_DECLARE(apr_status_t) apr_thread_rwlock_rdlock(apr_thread_rwlock_t *rwlock) +{ + ULONG rc, posts; + + rc = DosRequestMutexSem(rwlock->write_lock, SEM_INDEFINITE_WAIT); + + if (rc) + return APR_FROM_OS_ERROR(rc); + + /* We've successfully acquired the writer mutex so we can't be locked + * for write which means it's ok to add a reader lock. The writer mutex + * doubles as race condition protection for the readers counter. + */ + rwlock->readers++; + DosResetEventSem(rwlock->read_done, &posts); + rc = DosReleaseMutexSem(rwlock->write_lock); + return APR_FROM_OS_ERROR(rc); +} + + + +APR_DECLARE(apr_status_t) apr_thread_rwlock_tryrdlock(apr_thread_rwlock_t *rwlock) +{ + /* As above but with different wait time */ + ULONG rc, posts; + + rc = DosRequestMutexSem(rwlock->write_lock, SEM_IMMEDIATE_RETURN); + + if (rc) + return APR_FROM_OS_ERROR(rc); + + rwlock->readers++; + DosResetEventSem(rwlock->read_done, &posts); + rc = DosReleaseMutexSem(rwlock->write_lock); + return APR_FROM_OS_ERROR(rc); +} + + + +APR_DECLARE(apr_status_t) apr_thread_rwlock_wrlock(apr_thread_rwlock_t *rwlock) +{ + ULONG rc; + + rc = DosRequestMutexSem(rwlock->write_lock, SEM_INDEFINITE_WAIT); + + if (rc) + return APR_FROM_OS_ERROR(rc); + + /* We've got the writer lock but we have to wait for all readers to + * unlock before it's ok to use it + */ + + if (rwlock->readers) { + rc = DosWaitEventSem(rwlock->read_done, SEM_INDEFINITE_WAIT); + + if (rc) + DosReleaseMutexSem(rwlock->write_lock); + } + + return APR_FROM_OS_ERROR(rc); +} + + + +APR_DECLARE(apr_status_t) apr_thread_rwlock_trywrlock(apr_thread_rwlock_t *rwlock) +{ + ULONG rc; + + rc = DosRequestMutexSem(rwlock->write_lock, SEM_IMMEDIATE_RETURN); + + if (rc) + return APR_FROM_OS_ERROR(rc); + + /* We've got the writer lock but we have to wait for all readers to + * unlock before it's ok to use it + */ + + if (rwlock->readers) { + /* There are readers active, give up */ + DosReleaseMutexSem(rwlock->write_lock); + rc = ERROR_TIMEOUT; + } + + return APR_FROM_OS_ERROR(rc); +} + + + +APR_DECLARE(apr_status_t) apr_thread_rwlock_unlock(apr_thread_rwlock_t *rwlock) +{ + ULONG rc; + + /* First, guess that we're unlocking a writer */ + rc = DosReleaseMutexSem(rwlock->write_lock); + + if (rc == ERROR_NOT_OWNER) { + /* Nope, we must have a read lock */ + if (rwlock->readers) { + DosEnterCritSec(); + rwlock->readers--; + + if (rwlock->readers == 0) { + DosPostEventSem(rwlock->read_done); + } + + DosExitCritSec(); + rc = 0; + } + } + + return APR_FROM_OS_ERROR(rc); +} + + + +APR_DECLARE(apr_status_t) apr_thread_rwlock_destroy(apr_thread_rwlock_t *rwlock) +{ + ULONG rc; + + if (rwlock->write_lock == 0) + return APR_SUCCESS; + + while (DosReleaseMutexSem(rwlock->write_lock) == 0); + + rc = DosCloseMutexSem(rwlock->write_lock); + + if (!rc) { + rwlock->write_lock = 0; + DosCloseEventSem(rwlock->read_done); + return APR_SUCCESS; + } + + return APR_FROM_OS_ERROR(rc); +} + +APR_POOL_IMPLEMENT_ACCESSOR(thread_rwlock) + diff --git a/locks/unix/.cvsignore b/locks/unix/.cvsignore deleted file mode 100644 index f3c7a7c5da6..00000000000 --- a/locks/unix/.cvsignore +++ /dev/null @@ -1 +0,0 @@ -Makefile diff --git a/locks/unix/Makefile.in b/locks/unix/Makefile.in deleted file mode 100644 index 80bd8da69fc..00000000000 --- a/locks/unix/Makefile.in +++ /dev/null @@ -1,70 +0,0 @@ -#CFLAGS=$(OPTIM) $(CFLAGS1) $(EXTRA_CFLAGS) -#LIBS=$(EXTRA_LIBS) $(LIBS1) -#INCLUDES=$(INCLUDES1) $(INCLUDES0) $(EXTRA_INCLUDES) -#LDFLAGS=$(LDFLAGS1) $(EXTRA_LDFLAGS) - -RM=@RM@ -CC=@CC@ -RANLIB=@RANLIB@ -CFLAGS=@CFLAGS@ @OPTIM@ -LIBS=@LIBS@ -LDFLAGS=@LDFLAGS@ $(LIBS) -INCDIR1=../../include -INCDIR2=../../file_io/unix -INCLUDES=-I$(INCDIR1) -I$(INCDIR2) -I. - -#LIB=liblock.a - -OBJS=locks.o \ - crossproc.o \ - intraproc.o - -.c.o: - $(CC) $(CFLAGS) -c $(INCLUDES) $< - -all: $(OBJS) - -clean: - $(RM) -f *.o *.a *.so - -distclean: clean - -$(RM) -f Makefile - -$(OBJS): Makefile - -#$(LIB): $(OBJS) -# $(RM) -f $@ -# $(AR) cr $@ $(OBJS) -# $(RANLIB) $@ - -# -# We really don't expect end users to use this rule. It works only with -# gcc, and rebuilds Makefile.tmpl. You have to re-run Configure after -# using it. -# -depend: - cp Makefile.in Makefile.in.bak \ - && sed -ne '1,/^# DO NOT REMOVE/p' Makefile.in > Makefile.new \ - && gcc -MM $(INCLUDES) $(CFLAGS) *.c >> Makefile.new \ - && sed -e '1,$$s: $(INCDIR)/: $$(INCDIR)/:g' \ - -e '1,$$s: $(OSDIR)/: $$(OSDIR)/:g' Makefile.new \ - > Makefile.in \ - && rm Makefile.new - -# DO NOT REMOVE -crossproc.o: crossproc.c locks.h ../../include/apr_private.h \ - ../../include/apr_general.h ../../include/apr.h \ - ../../include/apr_errno.h ../../include/apr_lib.h \ - ../../include/apr_file_io.h ../../include/apr_time.h \ - ../../include/apr_thread_proc.h ../../include/apr_lock.h -intraproc.o: intraproc.c locks.h ../../include/apr_private.h \ - ../../include/apr_general.h ../../include/apr.h \ - ../../include/apr_errno.h ../../include/apr_lib.h \ - ../../include/apr_file_io.h ../../include/apr_time.h \ - ../../include/apr_thread_proc.h ../../include/apr_lock.h -locks.o: locks.c locks.h ../../include/apr_private.h \ - ../../include/apr_general.h ../../include/apr.h \ - ../../include/apr_errno.h ../../include/apr_lib.h \ - ../../include/apr_file_io.h ../../include/apr_time.h \ - ../../include/apr_thread_proc.h ../../include/apr_lock.h \ - ../../include/apr_portable.h ../../include/apr_network_io.h diff --git a/locks/unix/crossproc.c b/locks/unix/crossproc.c deleted file mode 100644 index cddd80f4a36..00000000000 --- a/locks/unix/crossproc.c +++ /dev/null @@ -1,403 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#include "locks.h" - -#if defined (USE_SYSVSEM_SERIALIZE) - -static struct sembuf op_on; -static struct sembuf op_off; - -void ap_unix_setup_lock(void) -{ - op_on.sem_num = 0; - op_on.sem_op = -1; - op_on.sem_flg = SEM_UNDO; - op_off.sem_num = 0; - op_off.sem_op = 1; - op_off.sem_flg = SEM_UNDO; -} - -static ap_status_t lock_cleanup(void *lock_) -{ - ap_lock_t *lock=lock_; - union semun ick; - - if (lock->interproc != -1) { - ick.val = 0; - semctl(lock->interproc, 0, IPC_RMID, ick); - } - return APR_SUCCESS; -} - -ap_status_t ap_unix_create_inter_lock(ap_lock_t *new) -{ - union semun ick; - - new->interproc = semget(IPC_PRIVATE, 1, IPC_CREAT | 0600); - - if (new->interproc < 0) { - lock_cleanup(new); - return errno; - } - ick.val = 1; - if (semctl(new->interproc, 0, SETVAL, ick) < 0) { - lock_cleanup(new); - return errno; - } - new->curr_locked = 0; - ap_register_cleanup(new->cntxt, (void *)new, lock_cleanup, ap_null_cleanup); - return APR_SUCCESS; -} - -ap_status_t ap_unix_lock_inter(ap_lock_t *lock) -{ - lock->curr_locked = 1; - if (semop(lock->interproc, &op_on, 1) < 0) { - return errno; - } - return APR_SUCCESS; -} - -ap_status_t ap_unix_unlock_inter(ap_lock_t *lock) -{ - if (semop(lock->interproc, &op_off, 1) < 0) { - return errno; - } - lock->curr_locked = 0; - return APR_SUCCESS; -} - -ap_status_t ap_unix_destroy_inter_lock(ap_lock_t *lock) -{ - ap_status_t stat; - - if ((stat = lock_cleanup(lock)) == APR_SUCCESS) { - ap_kill_cleanup(lock->cntxt, lock, lock_cleanup); - return APR_SUCCESS; - } - return stat; -} - -ap_status_t ap_unix_child_init_lock(ap_lock_t **lock, ap_pool_t *cont, char *fname) -{ - return APR_SUCCESS; -} - -#elif defined (USE_PROC_PTHREAD_SERIALIZE) - -void ap_unix_setup_lock(void) -{ -} - -static ap_status_t lock_cleanup(void *lock_) -{ - ap_lock_t *lock=lock_; - - if (lock->curr_locked == 1) { - if (pthread_mutex_unlock(lock->interproc)) { - return errno; - } - if (munmap((caddr_t)lock->interproc, sizeof(pthread_mutex_t))){ - return errno; - } - } - return APR_SUCCESS; -} - -ap_status_t ap_unix_create_inter_lock(ap_lock_t *new) -{ - ap_status_t stat; - int fd; - pthread_mutexattr_t mattr; - - fd = open("/dev/zero", O_RDWR); - if (fd < 0) { - return errno; - } - - new->interproc = (pthread_mutex_t *)mmap((caddr_t) 0, - sizeof(pthread_mutex_t), - PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - if (new->interproc == (pthread_mutex_t *) (caddr_t) -1) { - return errno; - } - close(fd); - if ((stat = pthread_mutexattr_init(&mattr))) { - lock_cleanup(new); - return stat; - } - if ((stat = pthread_mutexattr_setpshared(&mattr, - PTHREAD_PROCESS_SHARED))) { - lock_cleanup(new); - return stat; - } - - if ((stat = pthread_mutex_init(new->interproc, &mattr))) { - lock_cleanup(new); - return stat; - } - - if ((stat = pthread_mutexattr_destroy(&mattr))) { - lock_cleanup(new); - return stat; - } - - new->curr_locked = 0; - ap_register_cleanup(new->cntxt, (void *)new, lock_cleanup, ap_null_cleanup); - return APR_SUCCESS; -} - -ap_status_t ap_unix_lock_inter(ap_lock_t *lock) -{ - ap_status_t stat; - lock->curr_locked = 1; - if (stat = pthread_mutex_lock(lock->interproc)) { - return stat; - } - return APR_SUCCESS; -} - -ap_status_t ap_unix_unlock_inter(ap_lock_t *lock) -{ - ap_status_t stat; - - if (stat = pthread_mutex_unlock(lock->interproc)) { - return stat; - } - lock->curr_locked = 0; - return APR_SUCCESS; -} - -ap_status_t ap_unix_destroy_inter_lock(ap_lock_t *lock) -{ - ap_status_t stat; - if ((stat = lock_cleanup(lock)) == APR_SUCCESS) { - ap_kill_cleanup(lock->cntxt, lock, lock_cleanup); - return APR_SUCCESS; - } - return stat; -} - -ap_status_t ap_unix_child_init_lock(ap_lock_t **lock, ap_pool_t *cont, char *fname) -{ - return APR_SUCCESS; -} - -#elif defined (USE_FCNTL_SERIALIZE) - -static struct flock lock_it; -static struct flock unlock_it; - -void ap_unix_setup_lock(void) -{ - lock_it.l_whence = SEEK_SET; /* from current point */ - lock_it.l_start = 0; /* -"- */ - lock_it.l_len = 0; /* until end of file */ - lock_it.l_type = F_WRLCK; /* set exclusive/write lock */ - lock_it.l_pid = 0; /* pid not actually interesting */ - unlock_it.l_whence = SEEK_SET; /* from current point */ - unlock_it.l_start = 0; /* -"- */ - unlock_it.l_len = 0; /* until end of file */ - unlock_it.l_type = F_UNLCK; /* set exclusive/write lock */ - unlock_it.l_pid = 0; /* pid not actually interesting */ -} - -static ap_status_t lock_cleanup(void *lock_) -{ - ap_lock_t *lock=lock_; - - if (lock->curr_locked == 1) { - if (fcntl(lock->interproc, F_SETLKW, &unlock_it) < 0) { - return errno; - } - lock->curr_locked=0; - } - return APR_SUCCESS; -} - -ap_status_t ap_unix_create_inter_lock(ap_lock_t *new) -{ - new->interproc = open(new->fname, O_CREAT | O_WRONLY | O_EXCL, 0644); - - if (new->interproc < 0) { - lock_cleanup(new); - return errno; - } - - new->curr_locked=0; - unlink(new->fname); - ap_register_cleanup(new->cntxt, new, lock_cleanup, ap_null_cleanup); - return APR_SUCCESS; -} - -ap_status_t ap_unix_lock_inter(ap_lock_t *lock) -{ - lock->curr_locked=1; - if (fcntl(lock->interproc, F_SETLKW, &lock_it) < 0) { - return errno; - } - return APR_SUCCESS; -} - -ap_status_t ap_unix_unlock_inter(ap_lock_t *lock) -{ - if (fcntl(lock->interproc, F_SETLKW, &unlock_it) < 0) { - return errno; - } - lock->curr_locked=0; - return APR_SUCCESS; -} - -ap_status_t ap_unix_destroy_inter_lock(ap_lock_t *lock) -{ - ap_status_t stat; - if ((stat = lock_cleanup(lock)) == APR_SUCCESS) { - ap_kill_cleanup(lock->cntxt, lock, lock_cleanup); - return APR_SUCCESS; - } - return stat; -} - -ap_status_t ap_unix_child_init_lock(ap_lock_t **lock, ap_pool_t *cont, - const char *fname) -{ - return APR_SUCCESS; -} - -#elif defined (USE_FLOCK_SERIALIZE) - -void ap_unix_setup_lock(void) -{ -} - -static ap_status_t lock_cleanup(void *lock_) -{ - ap_lock_t *lock=lock_; - - if (lock->curr_locked == 1) { - if (flock(lock->interproc, LOCK_UN) < 0) { - return errno; - } - lock->curr_locked = 0; - } - unlink(lock->fname); - return APR_SUCCESS; -} - -ap_status_t ap_unix_create_inter_lock(ap_lock_t *new) -{ - new->interproc = open(new->fname, O_CREAT | O_WRONLY | O_EXCL, 0600); - - if (new->interproc < 0) { - lock_cleanup(new); - return errno; - } - new->curr_locked = 0; - ap_register_cleanup(new->cntxt, (void *)new, lock_cleanup, ap_null_cleanup); - return APR_SUCCESS; -} - -ap_status_t ap_unix_lock_inter(ap_lock_t *lock) -{ - lock->curr_locked = 1; - if (flock(lock->interproc, LOCK_EX) < 0) { - return errno; - } - return APR_SUCCESS; -} - -ap_status_t ap_unix_unlock_inter(ap_lock_t *lock) -{ - if (flock(lock->interproc, LOCK_UN) < 0) { - return errno; - } - lock->curr_locked = 0; - return APR_SUCCESS; -} - -ap_status_t ap_unix_destroy_inter_lock(ap_lock_t *lock) -{ - ap_status_t stat; - if ((stat = lock_cleanup(lock)) == APR_SUCCESS) { - ap_kill_cleanup(lock->cntxt, lock, lock_cleanup); - return APR_SUCCESS; - } - return stat; -} - -ap_status_t ap_unix_child_init_lock(ap_lock_t **lock, ap_pool_t *cont, - const char *fname) -{ - ap_lock_t *new; - - new = (ap_lock_t *)ap_palloc(cont, sizeof(ap_lock_t)); - - new->fname = ap_pstrdup(cont, fname); - new->interproc = open(new->fname, O_CREAT | O_WRONLY | O_EXCL, 0600); - if (new->interproc == -1) { - destroy_inter_lock(new); - return errno; - } - return APR_SUCCESS; -} - -#else -/* No inter-process mutex on this platform. Use at your own risk */ -#define create_inter_lock(x, y) -#define lock_inter(x, y) -#define unlock_inter(x, y) -#define destroy_inter_lock(x, y) -#define child_init_lock(x, y, z) -#endif diff --git a/locks/unix/global_mutex.c b/locks/unix/global_mutex.c new file mode 100644 index 00000000000..22592060d2f --- /dev/null +++ b/locks/unix/global_mutex.c @@ -0,0 +1,241 @@ +/* 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_arch_global_mutex.h" +#include "apr_proc_mutex.h" +#include "apr_thread_mutex.h" +#include "apr_portable.h" + +static apr_status_t global_mutex_cleanup(void *data) +{ + apr_global_mutex_t *m = (apr_global_mutex_t *)data; + apr_status_t rv; + + rv = apr_proc_mutex_destroy(m->proc_mutex); + +#if APR_HAS_THREADS + if (m->thread_mutex) { + if (rv != APR_SUCCESS) { + (void)apr_thread_mutex_destroy(m->thread_mutex); + } + else { + rv = apr_thread_mutex_destroy(m->thread_mutex); + } + } +#endif /* APR_HAS_THREADS */ + + return rv; +} + +APR_DECLARE(apr_status_t) apr_global_mutex_create(apr_global_mutex_t **mutex, + const char *fname, + apr_lockmech_e mech, + apr_pool_t *pool) +{ + apr_status_t rv; + apr_global_mutex_t *m; + + m = (apr_global_mutex_t *)apr_palloc(pool, sizeof(*m)); + m->pool = pool; + + rv = apr_proc_mutex_create(&m->proc_mutex, fname, mech, m->pool); + if (rv != APR_SUCCESS) { + return rv; + } + +#if APR_HAS_THREADS + if (m->proc_mutex->meth->flags & APR_PROCESS_LOCK_MECH_IS_GLOBAL) { + m->thread_mutex = NULL; /* We don't need a thread lock. */ + } + else { + rv = apr_thread_mutex_create(&m->thread_mutex, + APR_THREAD_MUTEX_DEFAULT, m->pool); + if (rv != APR_SUCCESS) { + rv = apr_proc_mutex_destroy(m->proc_mutex); + return rv; + } + } +#endif /* APR_HAS_THREADS */ + + apr_pool_cleanup_register(m->pool, (void *)m, + global_mutex_cleanup, apr_pool_cleanup_null); + *mutex = m; + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_global_mutex_child_init( + apr_global_mutex_t **mutex, + const char *fname, + apr_pool_t *pool) +{ + apr_status_t rv; + + rv = apr_proc_mutex_child_init(&((*mutex)->proc_mutex), fname, pool); + return rv; +} + +APR_DECLARE(apr_status_t) apr_global_mutex_lock(apr_global_mutex_t *mutex) +{ + apr_status_t rv; + +#if APR_HAS_THREADS + if (mutex->thread_mutex) { + rv = apr_thread_mutex_lock(mutex->thread_mutex); + if (rv != APR_SUCCESS) { + return rv; + } + } +#endif /* APR_HAS_THREADS */ + + rv = apr_proc_mutex_lock(mutex->proc_mutex); + +#if APR_HAS_THREADS + if (rv != APR_SUCCESS) { + if (mutex->thread_mutex) { + (void)apr_thread_mutex_unlock(mutex->thread_mutex); + } + } +#endif /* APR_HAS_THREADS */ + + return rv; +} + +APR_DECLARE(apr_status_t) apr_global_mutex_trylock(apr_global_mutex_t *mutex) +{ + apr_status_t rv; + +#if APR_HAS_THREADS + if (mutex->thread_mutex) { + rv = apr_thread_mutex_trylock(mutex->thread_mutex); + if (rv != APR_SUCCESS) { + return rv; + } + } +#endif /* APR_HAS_THREADS */ + + rv = apr_proc_mutex_trylock(mutex->proc_mutex); + +#if APR_HAS_THREADS + if (rv != APR_SUCCESS) { + if (mutex->thread_mutex) { + (void)apr_thread_mutex_unlock(mutex->thread_mutex); + } + } +#endif /* APR_HAS_THREADS */ + + return rv; +} + +APR_DECLARE(apr_status_t) apr_global_mutex_timedlock(apr_global_mutex_t *mutex, + apr_interval_time_t timeout) +{ + apr_status_t rv; + +#if APR_HAS_THREADS + if (mutex->thread_mutex) { + apr_time_t expiry = 0; + if (timeout > 0) { + expiry = apr_time_now() + timeout; + } + rv = apr_thread_mutex_timedlock(mutex->thread_mutex, timeout); + if (rv != APR_SUCCESS) { + return rv; + } + if (expiry) { + timeout = expiry - apr_time_now(); + if (timeout < 0) { + timeout = 0; + } + } + } +#endif /* APR_HAS_THREADS */ + + rv = apr_proc_mutex_timedlock(mutex->proc_mutex, timeout); + +#if APR_HAS_THREADS + if (rv != APR_SUCCESS) { + if (mutex->thread_mutex) { + (void)apr_thread_mutex_unlock(mutex->thread_mutex); + } + } +#endif /* APR_HAS_THREADS */ + + return rv; +} + +APR_DECLARE(apr_status_t) apr_global_mutex_unlock(apr_global_mutex_t *mutex) +{ + apr_status_t rv; + + rv = apr_proc_mutex_unlock(mutex->proc_mutex); +#if APR_HAS_THREADS + if (mutex->thread_mutex) { + if (rv != APR_SUCCESS) { + (void)apr_thread_mutex_unlock(mutex->thread_mutex); + } + else { + rv = apr_thread_mutex_unlock(mutex->thread_mutex); + } + } +#endif /* APR_HAS_THREADS */ + return rv; +} + +APR_DECLARE(apr_status_t) apr_os_global_mutex_get(apr_os_global_mutex_t *ospmutex, + apr_global_mutex_t *pmutex) +{ + ospmutex->pool = pmutex->pool; + ospmutex->proc_mutex = pmutex->proc_mutex; +#if APR_HAS_THREADS + ospmutex->thread_mutex = pmutex->thread_mutex; +#endif + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_global_mutex_destroy(apr_global_mutex_t *mutex) +{ + return apr_pool_cleanup_run(mutex->pool, mutex, global_mutex_cleanup); +} + +APR_DECLARE(const char *) apr_global_mutex_lockfile(apr_global_mutex_t *mutex) +{ + return apr_proc_mutex_lockfile(mutex->proc_mutex); +} + +APR_DECLARE(apr_lockmech_e) apr_global_mutex_mech(apr_global_mutex_t *mutex) +{ + return apr_proc_mutex_mech(mutex->proc_mutex); +} + +APR_DECLARE(const char *) apr_global_mutex_name(apr_global_mutex_t *mutex) +{ + return apr_proc_mutex_name(mutex->proc_mutex); +} + +APR_PERMS_SET_IMPLEMENT(global_mutex) +{ + apr_status_t rv; + apr_global_mutex_t *mutex = (apr_global_mutex_t *)theglobal_mutex; + + rv = APR_PERMS_SET_FN(proc_mutex)(mutex->proc_mutex, perms, uid, gid); + return rv; +} + +APR_POOL_IMPLEMENT_ACCESSOR(global_mutex) + diff --git a/locks/unix/intraproc.c b/locks/unix/intraproc.c deleted file mode 100644 index feb2c52c62f..00000000000 --- a/locks/unix/intraproc.c +++ /dev/null @@ -1,121 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#include "locks.h" - -#if APR_HAS_THREADS - -#if defined(USE_PTHREAD_SERIALIZE) - -static ap_status_t lock_intra_cleanup(void *data) -{ - ap_lock_t *lock = (ap_lock_t *) data; - return pthread_mutex_unlock(lock->intraproc); -} - -ap_status_t ap_unix_create_intra_lock(ap_lock_t *new) -{ - ap_status_t stat; - pthread_mutexattr_t mattr; - - new->intraproc = (pthread_mutex_t *)ap_palloc(new->cntxt, - sizeof(pthread_mutex_t)); - if (new->intraproc == NULL ) { - return errno; - } - if ((stat = pthread_mutexattr_init(&mattr))) { - lock_intra_cleanup(new); - return stat; - } - - if ((stat = pthread_mutex_init(new->intraproc, &mattr))) { - lock_intra_cleanup(new); - return stat; - } - - if ((stat = pthread_mutexattr_destroy(&mattr))) { - lock_intra_cleanup(new); - return stat; - } - - new->curr_locked = 0; - ap_register_cleanup(new->cntxt, (void *)new, lock_intra_cleanup, - ap_null_cleanup); - return APR_SUCCESS; -} - -ap_status_t ap_unix_lock_intra(ap_lock_t *lock) -{ - return pthread_mutex_lock(lock->intraproc); -} - -ap_status_t ap_unix_unlock_intra(ap_lock_t *lock) -{ - ap_status_t status; - - status = pthread_mutex_unlock(lock->intraproc); - return status; -} - -ap_status_t ap_unix_destroy_intra_lock(ap_lock_t *lock) -{ - ap_status_t stat; - if ((stat = lock_intra_cleanup(lock)) == APR_SUCCESS) { - ap_kill_cleanup(lock->cntxt, lock, lock_intra_cleanup); - return APR_SUCCESS; - } - return stat; -} -#endif -#endif diff --git a/locks/unix/locks.c b/locks/unix/locks.c deleted file mode 100644 index 2a648654c78..00000000000 --- a/locks/unix/locks.c +++ /dev/null @@ -1,230 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#include "locks.h" -#include "apr_portable.h" - -ap_status_t ap_create_lock(ap_lock_t **lock, ap_locktype_e type, - ap_lockscope_e scope, const char *fname, - ap_pool_t *cont) -{ - ap_lock_t *new; - ap_status_t stat; - - new = (ap_lock_t *)ap_palloc(cont, sizeof(ap_lock_t)); - - new->cntxt = cont; - new->type = type; - new->scope = scope; -#if defined(USE_FCNTL_SERIALIZE) || defined(USE_FLOCK_SERIALIZE) - /* file-based serialization primitives */ - if (scope != APR_INTRAPROCESS) { - if (fname != NULL) { - new->fname = ap_pstrdup(cont, fname); - } - else { - new->fname = ap_pstrdup(cont, tempnam(NULL, NULL)); - unlink(new->fname); - } - } -#endif - - if (scope != APR_CROSS_PROCESS) { -#if APR_HAS_THREADS - if ((stat = ap_unix_create_intra_lock(new)) != APR_SUCCESS) { - return stat; - } -#else - return APR_ENOTIMPL; -#endif - } - if (scope != APR_INTRAPROCESS) { - if ((stat = ap_unix_create_inter_lock(new)) != APR_SUCCESS) { - return stat; - } - } - *lock = new; - return APR_SUCCESS; -} - -ap_status_t ap_lock(ap_lock_t *lock) -{ - ap_status_t stat; - if (lock->scope != APR_CROSS_PROCESS) { -#if APR_HAS_THREADS - if ((stat = ap_unix_lock_intra(lock)) != APR_SUCCESS) { - return stat; - } -#else - return APR_ENOTIMPL; -#endif - } - if (lock->scope != APR_INTRAPROCESS) { - if ((stat = ap_unix_lock_inter(lock)) != APR_SUCCESS) { - return stat; - } - } - return APR_SUCCESS; -} - -ap_status_t ap_unlock(ap_lock_t *lock) -{ - ap_status_t stat; - - if (lock->scope != APR_CROSS_PROCESS) { -#if APR_HAS_THREADS - if ((stat = ap_unix_unlock_intra(lock)) != APR_SUCCESS) { - return stat; - } -#else - return APR_ENOTIMPL; -#endif - } - if (lock->scope != APR_INTRAPROCESS) { - if ((stat = ap_unix_unlock_inter(lock)) != APR_SUCCESS) { - return stat; - } - } - return APR_SUCCESS; -} - -ap_status_t ap_destroy_lock(ap_lock_t *lock) -{ - ap_status_t stat; - if (lock->scope != APR_CROSS_PROCESS) { -#if APR_HAS_THREADS - if ((stat = ap_unix_destroy_intra_lock(lock)) != APR_SUCCESS) { - return stat; - } -#else - return APR_ENOTIMPL; -#endif - } - if (lock->scope != APR_INTRAPROCESS) { - if ((stat = ap_unix_destroy_inter_lock(lock)) != APR_SUCCESS) { - return stat; - } - } - return APR_SUCCESS; -} - -ap_status_t ap_child_init_lock(ap_lock_t **lock, const char *fname, - ap_pool_t *cont) -{ - ap_status_t stat; - if ((*lock)->scope != APR_CROSS_PROCESS) { - if ((stat = ap_unix_child_init_lock(lock, cont, fname)) != APR_SUCCESS) { - return stat; - } - } - return APR_SUCCESS; -} - -ap_status_t ap_get_lockdata(ap_lock_t *lock, char *key, void *data) -{ - if (lock != NULL) { - return ap_get_userdata(data, key, lock->cntxt); - } - else { - data = NULL; - return APR_ENOLOCK; - } -} - -ap_status_t ap_set_lockdata(ap_lock_t *lock, void *data, char *key, - ap_status_t (*cleanup) (void *)) -{ - if (lock != NULL) { - return ap_set_userdata(data, key, cleanup, lock->cntxt); - } - else { - data = NULL; - return APR_ENOLOCK; - } -} - -ap_status_t ap_get_os_lock(ap_os_lock_t *oslock, ap_lock_t *lock) -{ - if (lock == NULL) { - return APR_ENOLOCK; - } - oslock->crossproc = lock->interproc; -#if APR_HAS_THREADS -#if USE_PTHREAD_SERIALIZE - oslock->intraproc = lock->intraproc; -#endif -#endif - - return APR_SUCCESS; -} - -ap_status_t ap_put_os_lock(ap_lock_t **lock, ap_os_lock_t *thelock, - ap_pool_t *cont) -{ - if (cont == NULL) { - return APR_ENOPOOL; - } - if ((*lock) == NULL) { - (*lock) = (ap_lock_t *)ap_palloc(cont, sizeof(ap_lock_t)); - (*lock)->cntxt = cont; - } - (*lock)->interproc = thelock->crossproc; -#if APR_HAS_THREADS -#if defined (USE_PTHREAD_SERIALIZE) - (*lock)->intraproc = thelock->intraproc; -#endif -#endif - return APR_SUCCESS; -} - diff --git a/locks/unix/locks.h b/locks/unix/locks.h deleted file mode 100644 index f6d37100d5e..00000000000 --- a/locks/unix/locks.h +++ /dev/null @@ -1,157 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#ifndef LOCKS_H -#define LOCKS_H - -#include "apr_private.h" -#include "apr_general.h" -#include "apr_lib.h" -#include "apr_lock.h" - -/* System headers required by Locks library */ -#if HAVE_UNISTD_H -#include <unistd.h> -#endif -#if HAVE_STRING_H -#include <string.h> -#endif -#if HAVE_USLOCKS_H -#include <uslocks.h> -#endif -#if HAVE_SYS_TYPES_H -#include <sys/types.h> -#endif -#if HAVE_SYS_IPC_H -#include <sys/ipc.h> -#endif -#if HAVE_SYS_SEM_H -#include <sys/sem.h> -#endif -#if HAVE_SYS_FILE_H -#include <sys/file.h> -#endif -#if HAVE_STDIO_H -#include <stdio.h> -#endif -#if HAVE_FCNTL_H -#include <fcntl.h> -#endif -#if HAVE_SYS_MMAN_H -#include <sys/mman.h> -#endif - -#if APR_HAS_THREADS -#if HAVE_PTHREAD_H -#include <pthread.h> -#endif -#endif -/* End System Headers */ - -#if !APR_HAVE_UNION_SEMUN && APR_USE_SYSVSEM_SERIALIZE -/* it makes no sense, but this isn't defined on solaris */ -union semun { - long val; - struct semid_ds *buf; - ushort *array; -}; -#endif - -struct ap_lock_t { - ap_pool_t *cntxt; - ap_locktype_e type; - ap_lockscope_e scope; - int curr_locked; - char *fname; -#if USE_SYSVSEM_SERIALIZE - int interproc; -#elif USE_FCNTL_SERIALIZE - int interproc; -#elif USE_PROC_PTHREAD_SERIALIZE - pthread_mutex_t *interproc; -#elif USE_FLOCK_SERIALIZE - int interproc; -#else - /* No Interprocess serialization. Too bad. */ -#endif -#if APR_HAS_THREADS - /* APR doesn't have threads, no sense in having an thread lock mechanism. - */ -#if USE_PTHREAD_SERIALIZE - pthread_mutex_t *intraproc; -#endif -#endif - /* At some point, we should do a scope for both inter and intra process - * locking here. Something like pthread_mutex with PTHREAD_PROCESS_SHARED - */ -}; - -#if APR_HAS_THREADS -ap_status_t ap_unix_create_intra_lock(struct ap_lock_t *new); -ap_status_t ap_unix_lock_intra(struct ap_lock_t *lock); -ap_status_t ap_unix_unlock_intra(struct ap_lock_t *lock); -ap_status_t ap_unix_destroy_intra_lock(struct ap_lock_t *lock); -#endif - -void ap_unix_setup_lock(void); -ap_status_t ap_unix_create_inter_lock(struct ap_lock_t *new); -ap_status_t ap_unix_lock_inter(struct ap_lock_t *lock); -ap_status_t ap_unix_unlock_inter(struct ap_lock_t *lock); -ap_status_t ap_unix_destroy_inter_lock(struct ap_lock_t *lock); - -ap_status_t ap_unix_child_init_lock(struct ap_lock_t **lock, ap_pool_t *cont, - const char *fname); - -#endif /* LOCKS_H */ - diff --git a/locks/unix/proc_mutex.c b/locks/unix/proc_mutex.c new file mode 100644 index 00000000000..a8002c6bd4b --- /dev/null +++ b/locks/unix/proc_mutex.c @@ -0,0 +1,1669 @@ +/* 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_arch_proc_mutex.h" +#include "apr_arch_file_io.h" /* for apr_mkstemp() */ +#include "apr_md5.h" /* for apr_md5() */ +#include "apr_atomic.h" + +APR_DECLARE(apr_status_t) apr_proc_mutex_destroy(apr_proc_mutex_t *mutex) +{ + apr_status_t rv = apr_proc_mutex_cleanup(mutex); + if (rv == APR_SUCCESS) { + apr_pool_cleanup_kill(mutex->pool, mutex, apr_proc_mutex_cleanup); + } + return rv; +} + +#if APR_HAS_POSIXSEM_SERIALIZE || APR_HAS_FCNTL_SERIALIZE || \ + APR_HAS_SYSVSEM_SERIALIZE +static apr_status_t proc_mutex_no_child_init(apr_proc_mutex_t **mutex, + apr_pool_t *cont, + const char *fname) +{ + return APR_SUCCESS; +} +#endif + +#if APR_HAS_POSIXSEM_SERIALIZE || APR_HAS_PROC_PTHREAD_SERIALIZE +static apr_status_t proc_mutex_no_perms_set(apr_proc_mutex_t *mutex, + apr_fileperms_t perms, + apr_uid_t uid, + apr_gid_t gid) +{ + return APR_ENOTIMPL; +} +#endif + +#if APR_HAS_FCNTL_SERIALIZE \ + || APR_HAS_FLOCK_SERIALIZE \ + || (APR_HAS_SYSVSEM_SERIALIZE \ + && !defined(HAVE_SEMTIMEDOP)) \ + || (APR_HAS_POSIXSEM_SERIALIZE \ + && !defined(HAVE_SEM_TIMEDWAIT)) \ + || (APR_HAS_PROC_PTHREAD_SERIALIZE \ + && !defined(HAVE_PTHREAD_MUTEX_TIMEDLOCK) \ + && !defined(HAVE_PTHREAD_CONDATTR_SETPSHARED)) +static apr_status_t proc_mutex_spinsleep_timedacquire(apr_proc_mutex_t *mutex, + apr_interval_time_t timeout) +{ +#define SLEEP_TIME apr_time_from_msec(10) + apr_status_t rv; + for (;;) { + rv = apr_proc_mutex_trylock(mutex); + if (!APR_STATUS_IS_EBUSY(rv)) { + if (rv == APR_SUCCESS) { + mutex->curr_locked = 1; + } + break; + } + if (timeout <= 0) { + rv = APR_TIMEUP; + break; + } + if (timeout > SLEEP_TIME) { + apr_sleep(SLEEP_TIME); + timeout -= SLEEP_TIME; + } + else { + apr_sleep(timeout); + timeout = 0; + } + } + return rv; +} +#endif + +#if APR_HAS_POSIXSEM_SERIALIZE + +#ifndef SEM_FAILED +#define SEM_FAILED (-1) +#endif + +static apr_status_t proc_mutex_posix_cleanup(void *mutex_) +{ + apr_proc_mutex_t *mutex = mutex_; + + if (sem_close(mutex->os.psem_interproc) < 0) { + return errno; + } + + return APR_SUCCESS; +} + +static apr_status_t proc_mutex_posix_create(apr_proc_mutex_t *new_mutex, + const char *fname) +{ + #define APR_POSIXSEM_NAME_MAX 30 + #define APR_POSIXSEM_NAME_MIN 13 + sem_t *psem; + char semname[APR_MD5_DIGESTSIZE * 2 + 2]; + + /* + * This bogusness is to follow what appears to be the + * lowest common denominator in Posix semaphore naming: + * - start with '/' + * - be at most 14 chars + * - be unique and not match anything on the filesystem + * + * Because of this, we use fname to generate an md5 hex checksum + * and use that as the name of the semaphore. If no filename was + * given, we create one based on the time. We tuck the name + * away, since it might be useful for debugging. + * + * To make this as robust as possible, we initially try something + * larger (and hopefully more unique) and gracefully fail down to the + * LCD above. + * + * NOTE: Darwin (Mac OS X) seems to be the most restrictive + * implementation. Versions previous to Darwin 6.2 had the 14 + * char limit, but later rev's allow up to 31 characters. + * + */ + if (fname) { + unsigned char digest[APR_MD5_DIGESTSIZE]; /* note dependency on semname here */ + const char *hex = "0123456789abcdef"; + char *p = semname; + int i; + apr_md5(digest, fname, strlen(fname)); + *p++ = '/'; /* must start with /, right? */ + for (i = 0; i < sizeof(digest); i++) { + *p++ = hex[digest[i] >> 4]; + *p++ = hex[digest[i] & 0xF]; + } + semname[APR_POSIXSEM_NAME_MAX] = '\0'; + } else { + apr_time_t now; + unsigned long sec; + unsigned long usec; + now = apr_time_now(); + sec = apr_time_sec(now); + usec = apr_time_usec(now); + apr_snprintf(semname, sizeof(semname), "/ApR.%lxZ%lx", sec, usec); + } + do { + psem = sem_open(semname, O_CREAT | O_EXCL, 0644, 1); + } while (psem == (sem_t *)SEM_FAILED && errno == EINTR); + if (psem == (sem_t *)SEM_FAILED) { + if (errno == ENAMETOOLONG) { + /* Oh well, good try */ + semname[APR_POSIXSEM_NAME_MIN] = '\0'; + } else { + return errno; + } + do { + psem = sem_open(semname, O_CREAT | O_EXCL, 0644, 1); + } while (psem == (sem_t *)SEM_FAILED && errno == EINTR); + } + + if (psem == (sem_t *)SEM_FAILED) { + return errno; + } + /* Ahhh. The joys of Posix sems. Predelete it... */ + sem_unlink(semname); + new_mutex->os.psem_interproc = psem; + new_mutex->fname = apr_pstrdup(new_mutex->pool, semname); + apr_pool_cleanup_register(new_mutex->pool, (void *)new_mutex, + apr_proc_mutex_cleanup, + apr_pool_cleanup_null); + return APR_SUCCESS; +} + +static apr_status_t proc_mutex_posix_acquire(apr_proc_mutex_t *mutex) +{ + int rc; + + do { + rc = sem_wait(mutex->os.psem_interproc); + } while (rc < 0 && errno == EINTR); + if (rc < 0) { + return errno; + } + mutex->curr_locked = 1; + return APR_SUCCESS; +} + +static apr_status_t proc_mutex_posix_tryacquire(apr_proc_mutex_t *mutex) +{ + int rc; + + do { + rc = sem_trywait(mutex->os.psem_interproc); + } while (rc < 0 && errno == EINTR); + if (rc < 0) { + if (errno == EAGAIN) { + return APR_EBUSY; + } + return errno; + } + mutex->curr_locked = 1; + return APR_SUCCESS; +} + +#if defined(HAVE_SEM_TIMEDWAIT) +static apr_status_t proc_mutex_posix_timedacquire(apr_proc_mutex_t *mutex, + apr_interval_time_t timeout) +{ + if (timeout <= 0) { + apr_status_t rv = proc_mutex_posix_tryacquire(mutex); + return (rv == APR_EBUSY) ? APR_TIMEUP : rv; + } + else { + int rc; + struct timespec abstime; + + timeout += apr_time_now(); + abstime.tv_sec = apr_time_sec(timeout); + abstime.tv_nsec = apr_time_usec(timeout) * 1000; /* nanoseconds */ + + do { + rc = sem_timedwait(mutex->os.psem_interproc, &abstime); + } while (rc < 0 && errno == EINTR); + if (rc < 0) { + if (errno == ETIMEDOUT) { + return APR_TIMEUP; + } + return errno; + } + } + mutex->curr_locked = 1; + return APR_SUCCESS; +} +#endif + +static apr_status_t proc_mutex_posix_release(apr_proc_mutex_t *mutex) +{ + mutex->curr_locked = 0; + if (sem_post(mutex->os.psem_interproc) < 0) { + /* any failure is probably fatal, so no big deal to leave + * ->curr_locked at 0. */ + return errno; + } + return APR_SUCCESS; +} + +static const apr_proc_mutex_unix_lock_methods_t mutex_posixsem_methods = +{ +#if APR_PROCESS_LOCK_IS_GLOBAL || !APR_HAS_THREADS || defined(POSIXSEM_IS_GLOBAL) + APR_PROCESS_LOCK_MECH_IS_GLOBAL, +#else + 0, +#endif + proc_mutex_posix_create, + proc_mutex_posix_acquire, + proc_mutex_posix_tryacquire, +#if defined(HAVE_SEM_TIMEDWAIT) + proc_mutex_posix_timedacquire, +#else + proc_mutex_spinsleep_timedacquire, +#endif + proc_mutex_posix_release, + proc_mutex_posix_cleanup, + proc_mutex_no_child_init, + proc_mutex_no_perms_set, + APR_LOCK_POSIXSEM, + "posixsem" +}; + +#endif /* Posix sem implementation */ + +#if APR_HAS_SYSVSEM_SERIALIZE + +static struct sembuf proc_mutex_op_on; +static struct sembuf proc_mutex_op_try; +static struct sembuf proc_mutex_op_off; + +static void proc_mutex_sysv_setup(void) +{ + proc_mutex_op_on.sem_num = 0; + proc_mutex_op_on.sem_op = -1; + proc_mutex_op_on.sem_flg = SEM_UNDO; + proc_mutex_op_try.sem_num = 0; + proc_mutex_op_try.sem_op = -1; + proc_mutex_op_try.sem_flg = SEM_UNDO | IPC_NOWAIT; + proc_mutex_op_off.sem_num = 0; + proc_mutex_op_off.sem_op = 1; + proc_mutex_op_off.sem_flg = SEM_UNDO; +} + +static apr_status_t proc_mutex_sysv_cleanup(void *mutex_) +{ + apr_proc_mutex_t *mutex=mutex_; + union semun ick; + + if (mutex->os.crossproc != -1) { + ick.val = 0; + semctl(mutex->os.crossproc, 0, IPC_RMID, ick); + } + return APR_SUCCESS; +} + +static apr_status_t proc_mutex_sysv_create(apr_proc_mutex_t *new_mutex, + const char *fname) +{ + union semun ick; + apr_status_t rv; + + new_mutex->os.crossproc = semget(IPC_PRIVATE, 1, IPC_CREAT | 0600); + if (new_mutex->os.crossproc == -1) { + rv = errno; + proc_mutex_sysv_cleanup(new_mutex); + return rv; + } + ick.val = 1; + if (semctl(new_mutex->os.crossproc, 0, SETVAL, ick) < 0) { + rv = errno; + proc_mutex_sysv_cleanup(new_mutex); + new_mutex->os.crossproc = -1; + return rv; + } + new_mutex->curr_locked = 0; + apr_pool_cleanup_register(new_mutex->pool, + (void *)new_mutex, apr_proc_mutex_cleanup, + apr_pool_cleanup_null); + return APR_SUCCESS; +} + +static apr_status_t proc_mutex_sysv_acquire(apr_proc_mutex_t *mutex) +{ + int rc; + + do { + rc = semop(mutex->os.crossproc, &proc_mutex_op_on, 1); + } while (rc < 0 && errno == EINTR); + if (rc < 0) { + return errno; + } + mutex->curr_locked = 1; + return APR_SUCCESS; +} + +static apr_status_t proc_mutex_sysv_tryacquire(apr_proc_mutex_t *mutex) +{ + int rc; + + do { + rc = semop(mutex->os.crossproc, &proc_mutex_op_try, 1); + } while (rc < 0 && errno == EINTR); + if (rc < 0) { + if (errno == EAGAIN) { + return APR_EBUSY; + } + return errno; + } + mutex->curr_locked = 1; + return APR_SUCCESS; +} + +#if defined(HAVE_SEMTIMEDOP) +static apr_status_t proc_mutex_sysv_timedacquire(apr_proc_mutex_t *mutex, + apr_interval_time_t timeout) +{ + if (timeout <= 0) { + apr_status_t rv = proc_mutex_sysv_tryacquire(mutex); + return (rv == APR_EBUSY) ? APR_TIMEUP : rv; + } + else { + int rc; + struct timespec reltime; + + reltime.tv_sec = apr_time_sec(timeout); + reltime.tv_nsec = apr_time_usec(timeout) * 1000; /* nanoseconds */ + + do { + rc = semtimedop(mutex->os.crossproc, &proc_mutex_op_on, 1, + &reltime); + } while (rc < 0 && errno == EINTR); + if (rc < 0) { + if (errno == EAGAIN) { + return APR_TIMEUP; + } + return errno; + } + } + mutex->curr_locked = 1; + return APR_SUCCESS; +} +#endif + +static apr_status_t proc_mutex_sysv_release(apr_proc_mutex_t *mutex) +{ + int rc; + + mutex->curr_locked = 0; + do { + rc = semop(mutex->os.crossproc, &proc_mutex_op_off, 1); + } while (rc < 0 && errno == EINTR); + if (rc < 0) { + return errno; + } + return APR_SUCCESS; +} + +static apr_status_t proc_mutex_sysv_perms_set(apr_proc_mutex_t *mutex, + apr_fileperms_t perms, + apr_uid_t uid, + apr_gid_t gid) +{ + + union semun ick; + struct semid_ds buf; + buf.sem_perm.uid = uid; + buf.sem_perm.gid = gid; + buf.sem_perm.mode = apr_unix_perms2mode(perms); + ick.buf = &buf; + if (semctl(mutex->os.crossproc, 0, IPC_SET, ick) < 0) { + return errno; + } + return APR_SUCCESS; +} + +static const apr_proc_mutex_unix_lock_methods_t mutex_sysv_methods = +{ +#if APR_PROCESS_LOCK_IS_GLOBAL || !APR_HAS_THREADS || defined(SYSVSEM_IS_GLOBAL) + APR_PROCESS_LOCK_MECH_IS_GLOBAL, +#else + 0, +#endif + proc_mutex_sysv_create, + proc_mutex_sysv_acquire, + proc_mutex_sysv_tryacquire, +#if defined(HAVE_SEMTIMEDOP) + proc_mutex_sysv_timedacquire, +#else + proc_mutex_spinsleep_timedacquire, +#endif + proc_mutex_sysv_release, + proc_mutex_sysv_cleanup, + proc_mutex_no_child_init, + proc_mutex_sysv_perms_set, + APR_LOCK_SYSVSEM, + "sysvsem" +}; + +#endif /* SysV sem implementation */ + +#if APR_HAS_PROC_PTHREAD_SERIALIZE + +#ifndef APR_USE_PROC_PTHREAD_MUTEX_COND +#define APR_USE_PROC_PTHREAD_MUTEX_COND \ + (defined(HAVE_PTHREAD_CONDATTR_SETPSHARED) \ + && !defined(HAVE_PTHREAD_MUTEX_TIMEDLOCK)) +#endif + +/* The mmap()ed pthread_interproc is the native pthread_mutex_t followed + * by a refcounter to track children using it. We want to avoid calling + * pthread_mutex_destroy() on the shared mutex area while it is in use by + * another process, because this may mark the shared pthread_mutex_t as + * invalid for everyone, including forked children (unlike "sysvsem" for + * example), causing unexpected errors or deadlocks (PR 49504). So the + * last process (parent or child) referencing the mutex will effectively + * destroy it. + */ +typedef struct { +#define proc_pthread_cast(m) \ + ((proc_pthread_mutex_t *)(m)->os.pthread_interproc) + pthread_mutex_t mutex; +#define proc_pthread_mutex(m) \ + (proc_pthread_cast(m)->mutex) +#if APR_USE_PROC_PTHREAD_MUTEX_COND + pthread_cond_t cond; +#define proc_pthread_mutex_cond(m) \ + (proc_pthread_cast(m)->cond) + apr_int32_t cond_locked; +#define proc_pthread_mutex_cond_locked(m) \ + (proc_pthread_cast(m)->cond_locked) + apr_uint32_t cond_num_waiters; +#define proc_pthread_mutex_cond_num_waiters(m) \ + (proc_pthread_cast(m)->cond_num_waiters) +#define proc_pthread_mutex_is_cond(m) \ + ((m)->pthread_refcounting && proc_pthread_mutex_cond_locked(m) != -1) +#endif /* APR_USE_PROC_PTHREAD_MUTEX_COND */ + apr_uint32_t refcount; +#define proc_pthread_mutex_refcount(m) \ + (proc_pthread_cast(m)->refcount) +} proc_pthread_mutex_t; + + +static APR_INLINE int proc_pthread_mutex_inc(apr_proc_mutex_t *mutex) +{ + if (mutex->pthread_refcounting) { + apr_atomic_inc32(&proc_pthread_mutex_refcount(mutex)); + return 1; + } + return 0; +} + +static APR_INLINE int proc_pthread_mutex_dec(apr_proc_mutex_t *mutex) +{ + if (mutex->pthread_refcounting) { + return apr_atomic_dec32(&proc_pthread_mutex_refcount(mutex)); + } + return 0; +} + +static apr_status_t proc_pthread_mutex_unref(void *mutex_) +{ + apr_proc_mutex_t *mutex=mutex_; + apr_status_t rv; + +#if APR_USE_PROC_PTHREAD_MUTEX_COND + if (proc_pthread_mutex_is_cond(mutex)) { + mutex->curr_locked = 0; + } + else +#endif /* APR_USE_PROC_PTHREAD_MUTEX_COND */ + if (mutex->curr_locked == 1) { + if ((rv = pthread_mutex_unlock(&proc_pthread_mutex(mutex)))) { +#ifdef HAVE_ZOS_PTHREADS + rv = errno; +#endif + return rv; + } + } + if (!proc_pthread_mutex_dec(mutex)) { +#if APR_USE_PROC_PTHREAD_MUTEX_COND + if (proc_pthread_mutex_is_cond(mutex) && + (rv = pthread_cond_destroy(&proc_pthread_mutex_cond(mutex)))) { +#ifdef HAVE_ZOS_PTHREADS + rv = errno; +#endif + return rv; + } +#endif /* APR_USE_PROC_PTHREAD_MUTEX_COND */ + + if ((rv = pthread_mutex_destroy(&proc_pthread_mutex(mutex)))) { +#ifdef HAVE_ZOS_PTHREADS + rv = errno; +#endif + return rv; + } + } + return APR_SUCCESS; +} + +static apr_status_t proc_mutex_pthread_cleanup(void *mutex_) +{ + apr_proc_mutex_t *mutex=mutex_; + apr_status_t rv; + + /* curr_locked is set to -1 until the mutex has been created */ + if (mutex->curr_locked != -1) { + if ((rv = proc_pthread_mutex_unref(mutex))) { + return rv; + } + } + if (munmap(mutex->os.pthread_interproc, sizeof(proc_pthread_mutex_t))) { + return errno; + } + return APR_SUCCESS; +} + +static apr_status_t proc_mutex_pthread_create(apr_proc_mutex_t *new_mutex, + const char *fname) +{ + apr_status_t rv; + int fd; + pthread_mutexattr_t mattr; + + fd = open("/dev/zero", O_RDWR); + if (fd < 0) { + return errno; + } + + new_mutex->os.pthread_interproc = mmap(NULL, sizeof(proc_pthread_mutex_t), + PROT_READ | PROT_WRITE, MAP_SHARED, + fd, 0); + if (new_mutex->os.pthread_interproc == MAP_FAILED) { + new_mutex->os.pthread_interproc = NULL; + rv = errno; + close(fd); + return rv; + } + close(fd); + + new_mutex->pthread_refcounting = 1; + new_mutex->curr_locked = -1; /* until the mutex has been created */ +#if APR_USE_PROC_PTHREAD_MUTEX_COND + proc_pthread_mutex_cond_locked(new_mutex) = -1; +#endif + + if ((rv = pthread_mutexattr_init(&mattr))) { +#ifdef HAVE_ZOS_PTHREADS + rv = errno; +#endif + proc_mutex_pthread_cleanup(new_mutex); + return rv; + } + if ((rv = pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED))) { +#ifdef HAVE_ZOS_PTHREADS + rv = errno; +#endif + proc_mutex_pthread_cleanup(new_mutex); + pthread_mutexattr_destroy(&mattr); + return rv; + } + +#ifdef HAVE_PTHREAD_MUTEX_ROBUST + if ((rv = pthread_mutexattr_setrobust_np(&mattr, + PTHREAD_MUTEX_ROBUST_NP))) { +#ifdef HAVE_ZOS_PTHREADS + rv = errno; +#endif + proc_mutex_pthread_cleanup(new_mutex); + pthread_mutexattr_destroy(&mattr); + return rv; + } + if ((rv = pthread_mutexattr_setprotocol(&mattr, PTHREAD_PRIO_INHERIT))) { +#ifdef HAVE_ZOS_PTHREADS + rv = errno; +#endif + proc_mutex_pthread_cleanup(new_mutex); + pthread_mutexattr_destroy(&mattr); + return rv; + } +#endif /* HAVE_PTHREAD_MUTEX_ROBUST */ + + if ((rv = pthread_mutex_init(&proc_pthread_mutex(new_mutex), &mattr))) { +#ifdef HAVE_ZOS_PTHREADS + rv = errno; +#endif + proc_mutex_pthread_cleanup(new_mutex); + pthread_mutexattr_destroy(&mattr); + return rv; + } + + proc_pthread_mutex_refcount(new_mutex) = 1; /* first/parent reference */ + new_mutex->curr_locked = 0; /* mutex created now */ + + if ((rv = pthread_mutexattr_destroy(&mattr))) { +#ifdef HAVE_ZOS_PTHREADS + rv = errno; +#endif + proc_mutex_pthread_cleanup(new_mutex); + return rv; + } + + apr_pool_cleanup_register(new_mutex->pool, + (void *)new_mutex, + apr_proc_mutex_cleanup, + apr_pool_cleanup_null); + return APR_SUCCESS; +} + +static apr_status_t proc_mutex_pthread_child_init(apr_proc_mutex_t **mutex, + apr_pool_t *pool, + const char *fname) +{ + (*mutex)->curr_locked = 0; + if (proc_pthread_mutex_inc(*mutex)) { + apr_pool_cleanup_register(pool, *mutex, proc_pthread_mutex_unref, + apr_pool_cleanup_null); + } + return APR_SUCCESS; +} + +static apr_status_t proc_mutex_pthread_acquire_ex(apr_proc_mutex_t *mutex, + apr_interval_time_t timeout) +{ + apr_status_t rv; + +#if APR_USE_PROC_PTHREAD_MUTEX_COND + if (proc_pthread_mutex_is_cond(mutex)) { + if ((rv = pthread_mutex_lock(&proc_pthread_mutex(mutex)))) { +#ifdef HAVE_ZOS_PTHREADS + rv = errno; +#endif +#ifdef HAVE_PTHREAD_MUTEX_ROBUST + /* Okay, our owner died. Let's try to make it consistent again. */ + if (rv == EOWNERDEAD) { + proc_pthread_mutex_dec(mutex); + pthread_mutex_consistent_np(&proc_pthread_mutex(mutex)); + } + else +#endif + return rv; + } + + if (!proc_pthread_mutex_cond_locked(mutex)) { + rv = APR_SUCCESS; + } + else if (!timeout) { + rv = APR_TIMEUP; + } + else { + struct timespec abstime; + + if (timeout > 0) { + timeout += apr_time_now(); + abstime.tv_sec = apr_time_sec(timeout); + abstime.tv_nsec = apr_time_usec(timeout) * 1000; /* nanoseconds */ + } + + proc_pthread_mutex_cond_num_waiters(mutex)++; + do { + if (timeout < 0) { + rv = pthread_cond_wait(&proc_pthread_mutex_cond(mutex), + &proc_pthread_mutex(mutex)); + if (rv) { +#ifdef HAVE_ZOS_PTHREADS + rv = errno; +#endif + break; + } + } + else { + rv = pthread_cond_timedwait(&proc_pthread_mutex_cond(mutex), + &proc_pthread_mutex(mutex), + &abstime); + if (rv) { +#ifdef HAVE_ZOS_PTHREADS + rv = errno; +#endif + if (rv == ETIMEDOUT) { + rv = APR_TIMEUP; + } + break; + } + } + } while (proc_pthread_mutex_cond_locked(mutex)); + proc_pthread_mutex_cond_num_waiters(mutex)--; + } + if (rv != APR_SUCCESS) { + pthread_mutex_unlock(&proc_pthread_mutex(mutex)); + return rv; + } + + proc_pthread_mutex_cond_locked(mutex) = 1; + + rv = pthread_mutex_unlock(&proc_pthread_mutex(mutex)); + if (rv) { +#ifdef HAVE_ZOS_PTHREADS + rv = errno; +#endif + return rv; + } + } + else +#endif /* APR_USE_PROC_PTHREAD_MUTEX_COND */ + { + if (timeout < 0) { + rv = pthread_mutex_lock(&proc_pthread_mutex(mutex)); + if (rv) { +#ifdef HAVE_ZOS_PTHREADS + rv = errno; +#endif + } + } + else if (!timeout) { + rv = pthread_mutex_trylock(&proc_pthread_mutex(mutex)); + if (rv) { +#ifdef HAVE_ZOS_PTHREADS + rv = errno; +#endif + if (rv == EBUSY) { + return APR_TIMEUP; + } + } + } + else +#if defined(HAVE_PTHREAD_MUTEX_TIMEDLOCK) + { + struct timespec abstime; + + timeout += apr_time_now(); + abstime.tv_sec = apr_time_sec(timeout); + abstime.tv_nsec = apr_time_usec(timeout) * 1000; /* nanoseconds */ + + rv = pthread_mutex_timedlock(&proc_pthread_mutex(mutex), &abstime); + if (rv) { +#ifdef HAVE_ZOS_PTHREADS + rv = errno; +#endif + if (rv == ETIMEDOUT) { + return APR_TIMEUP; + } + } + } + if (rv) { +#ifdef HAVE_PTHREAD_MUTEX_ROBUST + /* Okay, our owner died. Let's try to make it consistent again. */ + if (rv == EOWNERDEAD) { + proc_pthread_mutex_dec(mutex); + pthread_mutex_consistent_np(&proc_pthread_mutex(mutex)); + } + else +#endif + return rv; + } +#else /* !HAVE_PTHREAD_MUTEX_TIMEDLOCK */ + return proc_mutex_spinsleep_timedacquire(mutex, timeout); +#endif + } + + mutex->curr_locked = 1; + return APR_SUCCESS; +} + +static apr_status_t proc_mutex_pthread_acquire(apr_proc_mutex_t *mutex) +{ + return proc_mutex_pthread_acquire_ex(mutex, -1); +} + +static apr_status_t proc_mutex_pthread_tryacquire(apr_proc_mutex_t *mutex) +{ + apr_status_t rv = proc_mutex_pthread_acquire_ex(mutex, 0); + return (rv == APR_TIMEUP) ? APR_EBUSY : rv; +} + +static apr_status_t proc_mutex_pthread_timedacquire(apr_proc_mutex_t *mutex, + apr_interval_time_t timeout) +{ + return proc_mutex_pthread_acquire_ex(mutex, (timeout <= 0) ? 0 : timeout); +} + +static apr_status_t proc_mutex_pthread_release(apr_proc_mutex_t *mutex) +{ + apr_status_t rv; + +#if APR_USE_PROC_PTHREAD_MUTEX_COND + if (proc_pthread_mutex_is_cond(mutex)) { + if ((rv = pthread_mutex_lock(&proc_pthread_mutex(mutex)))) { +#ifdef HAVE_ZOS_PTHREADS + rv = errno; +#endif +#ifdef HAVE_PTHREAD_MUTEX_ROBUST + /* Okay, our owner died. Let's try to make it consistent again. */ + if (rv == EOWNERDEAD) { + proc_pthread_mutex_dec(mutex); + pthread_mutex_consistent_np(&proc_pthread_mutex(mutex)); + } + else +#endif + return rv; + } + + if (!proc_pthread_mutex_cond_locked(mutex)) { + rv = APR_EINVAL; + } + else if (!proc_pthread_mutex_cond_num_waiters(mutex)) { + rv = APR_SUCCESS; + } + else { + rv = pthread_cond_signal(&proc_pthread_mutex_cond(mutex)); +#ifdef HAVE_ZOS_PTHREADS + if (rv) { + rv = errno; + } +#endif + } + if (rv != APR_SUCCESS) { + pthread_mutex_unlock(&proc_pthread_mutex(mutex)); + return rv; + } + + proc_pthread_mutex_cond_locked(mutex) = 0; + } +#endif /* APR_USE_PROC_PTHREAD_MUTEX_COND */ + + mutex->curr_locked = 0; + if ((rv = pthread_mutex_unlock(&proc_pthread_mutex(mutex)))) { +#ifdef HAVE_ZOS_PTHREADS + rv = errno; +#endif + return rv; + } + + return APR_SUCCESS; +} + +static const apr_proc_mutex_unix_lock_methods_t mutex_proc_pthread_methods = +{ + APR_PROCESS_LOCK_MECH_IS_GLOBAL, + proc_mutex_pthread_create, + proc_mutex_pthread_acquire, + proc_mutex_pthread_tryacquire, + proc_mutex_pthread_timedacquire, + proc_mutex_pthread_release, + proc_mutex_pthread_cleanup, + proc_mutex_pthread_child_init, + proc_mutex_no_perms_set, + APR_LOCK_PROC_PTHREAD, + "pthread" +}; + +#if APR_USE_PROC_PTHREAD_MUTEX_COND +static apr_status_t proc_mutex_pthread_cond_create(apr_proc_mutex_t *new_mutex, + const char *fname) +{ + apr_status_t rv; + pthread_condattr_t cattr; + + rv = proc_mutex_pthread_create(new_mutex, fname); + if (rv != APR_SUCCESS) { + return rv; + } + + if ((rv = pthread_condattr_init(&cattr))) { +#ifdef HAVE_ZOS_PTHREADS + rv = errno; +#endif + apr_pool_cleanup_run(new_mutex->pool, new_mutex, + apr_proc_mutex_cleanup); + return rv; + } + if ((rv = pthread_condattr_setpshared(&cattr, PTHREAD_PROCESS_SHARED))) { +#ifdef HAVE_ZOS_PTHREADS + rv = errno; +#endif + pthread_condattr_destroy(&cattr); + apr_pool_cleanup_run(new_mutex->pool, new_mutex, + apr_proc_mutex_cleanup); + return rv; + } + if ((rv = pthread_cond_init(&proc_pthread_mutex_cond(new_mutex), + &cattr))) { +#ifdef HAVE_ZOS_PTHREADS + rv = errno; +#endif + pthread_condattr_destroy(&cattr); + apr_pool_cleanup_run(new_mutex->pool, new_mutex, + apr_proc_mutex_cleanup); + return rv; + } + pthread_condattr_destroy(&cattr); + + proc_pthread_mutex_cond_locked(new_mutex) = 0; + proc_pthread_mutex_cond_num_waiters(new_mutex) = 0; + + return APR_SUCCESS; +} + +static const apr_proc_mutex_unix_lock_methods_t mutex_proc_pthread_cond_methods = +{ + APR_PROCESS_LOCK_MECH_IS_GLOBAL, + proc_mutex_pthread_cond_create, + proc_mutex_pthread_acquire, + proc_mutex_pthread_tryacquire, + proc_mutex_pthread_timedacquire, + proc_mutex_pthread_release, + proc_mutex_pthread_cleanup, + proc_mutex_pthread_child_init, + proc_mutex_no_perms_set, + APR_LOCK_PROC_PTHREAD, + "pthread" +}; +#endif + +#endif + +#if APR_HAS_FCNTL_SERIALIZE + +static struct flock proc_mutex_lock_it; +static struct flock proc_mutex_unlock_it; + +static apr_status_t proc_mutex_fcntl_release(apr_proc_mutex_t *); + +static void proc_mutex_fcntl_setup(void) +{ + proc_mutex_lock_it.l_whence = SEEK_SET; /* from current point */ + proc_mutex_lock_it.l_start = 0; /* -"- */ + proc_mutex_lock_it.l_len = 0; /* until end of file */ + proc_mutex_lock_it.l_type = F_WRLCK; /* set exclusive/write lock */ + proc_mutex_lock_it.l_pid = 0; /* pid not actually interesting */ + proc_mutex_unlock_it.l_whence = SEEK_SET; /* from current point */ + proc_mutex_unlock_it.l_start = 0; /* -"- */ + proc_mutex_unlock_it.l_len = 0; /* until end of file */ + proc_mutex_unlock_it.l_type = F_UNLCK; /* set exclusive/write lock */ + proc_mutex_unlock_it.l_pid = 0; /* pid not actually interesting */ +} + +static apr_status_t proc_mutex_fcntl_cleanup(void *mutex_) +{ + apr_status_t status = APR_SUCCESS; + apr_proc_mutex_t *mutex=mutex_; + + if (mutex->curr_locked == 1) { + status = proc_mutex_fcntl_release(mutex); + if (status != APR_SUCCESS) + return status; + } + + if (mutex->interproc) { + status = apr_file_close(mutex->interproc); + } + if (!mutex->interproc_closing + && mutex->os.crossproc != -1 + && close(mutex->os.crossproc) == -1 + && status == APR_SUCCESS) { + status = errno; + } + return status; +} + +static apr_status_t proc_mutex_fcntl_create(apr_proc_mutex_t *new_mutex, + const char *fname) +{ + int rv; + + if (fname) { + new_mutex->fname = apr_pstrdup(new_mutex->pool, fname); + rv = apr_file_open(&new_mutex->interproc, new_mutex->fname, + APR_FOPEN_CREATE | APR_FOPEN_WRITE | APR_FOPEN_EXCL, + APR_FPROT_UREAD | APR_FPROT_UWRITE | APR_FPROT_GREAD | APR_FPROT_WREAD, + new_mutex->pool); + } + else { + new_mutex->fname = apr_pstrdup(new_mutex->pool, "/tmp/aprXXXXXX"); + rv = apr_file_mktemp(&new_mutex->interproc, new_mutex->fname, + APR_FOPEN_CREATE | APR_FOPEN_WRITE | APR_FOPEN_EXCL, + new_mutex->pool); + } + + if (rv != APR_SUCCESS) { + return rv; + } + + new_mutex->os.crossproc = new_mutex->interproc->filedes; + new_mutex->interproc_closing = 1; + new_mutex->curr_locked = 0; + unlink(new_mutex->fname); + apr_pool_cleanup_register(new_mutex->pool, + (void*)new_mutex, + apr_proc_mutex_cleanup, + apr_pool_cleanup_null); + return APR_SUCCESS; +} + +static apr_status_t proc_mutex_fcntl_acquire(apr_proc_mutex_t *mutex) +{ + int rc; + + do { + rc = fcntl(mutex->os.crossproc, F_SETLKW, &proc_mutex_lock_it); + } while (rc < 0 && errno == EINTR); + if (rc < 0) { + return errno; + } + mutex->curr_locked=1; + return APR_SUCCESS; +} + +static apr_status_t proc_mutex_fcntl_tryacquire(apr_proc_mutex_t *mutex) +{ + int rc; + + do { + rc = fcntl(mutex->os.crossproc, F_SETLK, &proc_mutex_lock_it); + } while (rc < 0 && errno == EINTR); + if (rc < 0) { +#if FCNTL_TRYACQUIRE_EACCES + if (errno == EACCES) { +#else + if (errno == EAGAIN) { +#endif + return APR_EBUSY; + } + return errno; + } + mutex->curr_locked = 1; + return APR_SUCCESS; +} + +static apr_status_t proc_mutex_fcntl_release(apr_proc_mutex_t *mutex) +{ + int rc; + + mutex->curr_locked=0; + do { + rc = fcntl(mutex->os.crossproc, F_SETLKW, &proc_mutex_unlock_it); + } while (rc < 0 && errno == EINTR); + if (rc < 0) { + return errno; + } + return APR_SUCCESS; +} + +static apr_status_t proc_mutex_fcntl_perms_set(apr_proc_mutex_t *mutex, + apr_fileperms_t perms, + apr_uid_t uid, + apr_gid_t gid) +{ + + if (mutex->fname) { + if (!(perms & APR_FPROT_GSETID)) + gid = -1; + if (fchown(mutex->os.crossproc, uid, gid) < 0) { + return errno; + } + } + return APR_SUCCESS; +} + +static const apr_proc_mutex_unix_lock_methods_t mutex_fcntl_methods = +{ +#if APR_PROCESS_LOCK_IS_GLOBAL || !APR_HAS_THREADS || defined(FCNTL_IS_GLOBAL) + APR_PROCESS_LOCK_MECH_IS_GLOBAL, +#else + 0, +#endif + proc_mutex_fcntl_create, + proc_mutex_fcntl_acquire, + proc_mutex_fcntl_tryacquire, + proc_mutex_spinsleep_timedacquire, + proc_mutex_fcntl_release, + proc_mutex_fcntl_cleanup, + proc_mutex_no_child_init, + proc_mutex_fcntl_perms_set, + APR_LOCK_FCNTL, + "fcntl" +}; + +#endif /* fcntl implementation */ + +#if APR_HAS_FLOCK_SERIALIZE + +static apr_status_t proc_mutex_flock_release(apr_proc_mutex_t *); + +static apr_status_t proc_mutex_flock_cleanup(void *mutex_) +{ + apr_status_t status = APR_SUCCESS; + apr_proc_mutex_t *mutex=mutex_; + + if (mutex->curr_locked == 1) { + status = proc_mutex_flock_release(mutex); + if (status != APR_SUCCESS) + return status; + } + if (mutex->interproc) { /* if it was opened properly */ + status = apr_file_close(mutex->interproc); + } + if (!mutex->interproc_closing + && mutex->os.crossproc != -1 + && close(mutex->os.crossproc) == -1 + && status == APR_SUCCESS) { + status = errno; + } + if (mutex->fname) { + unlink(mutex->fname); + } + return status; +} + +static apr_status_t proc_mutex_flock_create(apr_proc_mutex_t *new_mutex, + const char *fname) +{ + int rv; + + if (fname) { + new_mutex->fname = apr_pstrdup(new_mutex->pool, fname); + rv = apr_file_open(&new_mutex->interproc, new_mutex->fname, + APR_FOPEN_CREATE | APR_FOPEN_WRITE | APR_FOPEN_EXCL, + APR_FPROT_UREAD | APR_FPROT_UWRITE, + new_mutex->pool); + } + else { + new_mutex->fname = apr_pstrdup(new_mutex->pool, "/tmp/aprXXXXXX"); + rv = apr_file_mktemp(&new_mutex->interproc, new_mutex->fname, + APR_FOPEN_CREATE | APR_FOPEN_WRITE | APR_FOPEN_EXCL, + new_mutex->pool); + } + + if (rv != APR_SUCCESS) { + proc_mutex_flock_cleanup(new_mutex); + return rv; + } + + new_mutex->os.crossproc = new_mutex->interproc->filedes; + new_mutex->interproc_closing = 1; + new_mutex->curr_locked = 0; + apr_pool_cleanup_register(new_mutex->pool, (void *)new_mutex, + apr_proc_mutex_cleanup, + apr_pool_cleanup_null); + return APR_SUCCESS; +} + +static apr_status_t proc_mutex_flock_acquire(apr_proc_mutex_t *mutex) +{ + int rc; + + do { + rc = flock(mutex->os.crossproc, LOCK_EX); + } while (rc < 0 && errno == EINTR); + if (rc < 0) { + return errno; + } + mutex->curr_locked = 1; + return APR_SUCCESS; +} + +static apr_status_t proc_mutex_flock_tryacquire(apr_proc_mutex_t *mutex) +{ + int rc; + + do { + rc = flock(mutex->os.crossproc, LOCK_EX | LOCK_NB); + } while (rc < 0 && errno == EINTR); + if (rc < 0) { + if (errno == EWOULDBLOCK || errno == EAGAIN) { + return APR_EBUSY; + } + return errno; + } + mutex->curr_locked = 1; + return APR_SUCCESS; +} + +static apr_status_t proc_mutex_flock_release(apr_proc_mutex_t *mutex) +{ + int rc; + + mutex->curr_locked = 0; + do { + rc = flock(mutex->os.crossproc, LOCK_UN); + } while (rc < 0 && errno == EINTR); + if (rc < 0) { + return errno; + } + return APR_SUCCESS; +} + +static apr_status_t proc_mutex_flock_child_init(apr_proc_mutex_t **mutex, + apr_pool_t *pool, + const char *fname) +{ + apr_proc_mutex_t *new_mutex; + int rv; + + if (!fname) { + fname = (*mutex)->fname; + if (!fname) { + return APR_SUCCESS; + } + } + + new_mutex = (apr_proc_mutex_t *)apr_pmemdup(pool, *mutex, + sizeof(apr_proc_mutex_t)); + new_mutex->pool = pool; + new_mutex->fname = apr_pstrdup(pool, fname); + rv = apr_file_open(&new_mutex->interproc, new_mutex->fname, + APR_FOPEN_WRITE, 0, new_mutex->pool); + if (rv != APR_SUCCESS) { + return rv; + } + new_mutex->os.crossproc = new_mutex->interproc->filedes; + new_mutex->interproc_closing = 1; + + *mutex = new_mutex; + return APR_SUCCESS; +} + +static apr_status_t proc_mutex_flock_perms_set(apr_proc_mutex_t *mutex, + apr_fileperms_t perms, + apr_uid_t uid, + apr_gid_t gid) +{ + + if (mutex->fname) { + if (!(perms & APR_FPROT_GSETID)) + gid = -1; + if (fchown(mutex->os.crossproc, uid, gid) < 0) { + return errno; + } + } + return APR_SUCCESS; +} + +static const apr_proc_mutex_unix_lock_methods_t mutex_flock_methods = +{ +#if APR_PROCESS_LOCK_IS_GLOBAL || !APR_HAS_THREADS || defined(FLOCK_IS_GLOBAL) + APR_PROCESS_LOCK_MECH_IS_GLOBAL, +#else + 0, +#endif + proc_mutex_flock_create, + proc_mutex_flock_acquire, + proc_mutex_flock_tryacquire, + proc_mutex_spinsleep_timedacquire, + proc_mutex_flock_release, + proc_mutex_flock_cleanup, + proc_mutex_flock_child_init, + proc_mutex_flock_perms_set, + APR_LOCK_FLOCK, + "flock" +}; + +#endif /* flock implementation */ + +void apr_proc_mutex_unix_setup_lock(void) +{ + /* setup only needed for sysvsem and fnctl */ +#if APR_HAS_SYSVSEM_SERIALIZE + proc_mutex_sysv_setup(); +#endif +#if APR_HAS_FCNTL_SERIALIZE + proc_mutex_fcntl_setup(); +#endif +} + +static apr_status_t proc_mutex_choose_method(apr_proc_mutex_t *new_mutex, + apr_lockmech_e mech, + apr_os_proc_mutex_t *ospmutex) +{ +#if APR_HAS_PROC_PTHREAD_SERIALIZE + new_mutex->os.pthread_interproc = NULL; +#endif +#if APR_HAS_POSIXSEM_SERIALIZE + new_mutex->os.psem_interproc = NULL; +#endif +#if APR_HAS_SYSVSEM_SERIALIZE || APR_HAS_FCNTL_SERIALIZE || APR_HAS_FLOCK_SERIALIZE + new_mutex->os.crossproc = -1; + +#if APR_HAS_FCNTL_SERIALIZE || APR_HAS_FLOCK_SERIALIZE + new_mutex->interproc = NULL; + new_mutex->interproc_closing = 0; +#endif +#endif + + switch (mech) { + case APR_LOCK_FCNTL: +#if APR_HAS_FCNTL_SERIALIZE + new_mutex->meth = &mutex_fcntl_methods; + if (ospmutex) { + if (ospmutex->crossproc == -1) { + return APR_EINVAL; + } + new_mutex->os.crossproc = ospmutex->crossproc; + } +#else + return APR_ENOTIMPL; +#endif + break; + case APR_LOCK_FLOCK: +#if APR_HAS_FLOCK_SERIALIZE + new_mutex->meth = &mutex_flock_methods; + if (ospmutex) { + if (ospmutex->crossproc == -1) { + return APR_EINVAL; + } + new_mutex->os.crossproc = ospmutex->crossproc; + } +#else + return APR_ENOTIMPL; +#endif + break; + case APR_LOCK_SYSVSEM: +#if APR_HAS_SYSVSEM_SERIALIZE + new_mutex->meth = &mutex_sysv_methods; + if (ospmutex) { + if (ospmutex->crossproc == -1) { + return APR_EINVAL; + } + new_mutex->os.crossproc = ospmutex->crossproc; + } +#else + return APR_ENOTIMPL; +#endif + break; + case APR_LOCK_POSIXSEM: +#if APR_HAS_POSIXSEM_SERIALIZE + new_mutex->meth = &mutex_posixsem_methods; + if (ospmutex) { + if (ospmutex->psem_interproc == NULL) { + return APR_EINVAL; + } + new_mutex->os.psem_interproc = ospmutex->psem_interproc; + } +#else + return APR_ENOTIMPL; +#endif + break; + case APR_LOCK_PROC_PTHREAD: +#if APR_HAS_PROC_PTHREAD_SERIALIZE + new_mutex->meth = &mutex_proc_pthread_methods; + if (ospmutex) { + if (ospmutex->pthread_interproc == NULL) { + return APR_EINVAL; + } + new_mutex->os.pthread_interproc = ospmutex->pthread_interproc; + } +#else + return APR_ENOTIMPL; +#endif + break; + case APR_LOCK_DEFAULT_TIMED: +#if APR_HAS_PROC_PTHREAD_SERIALIZE \ + && (APR_USE_PROC_PTHREAD_MUTEX_COND \ + || defined(HAVE_PTHREAD_MUTEX_TIMEDLOCK)) \ + && defined(HAVE_PTHREAD_MUTEX_ROBUST) +#if APR_USE_PROC_PTHREAD_MUTEX_COND + new_mutex->meth = &mutex_proc_pthread_cond_methods; +#else + new_mutex->meth = &mutex_proc_pthread_methods; +#endif + if (ospmutex) { + if (ospmutex->pthread_interproc == NULL) { + return APR_EINVAL; + } + new_mutex->os.pthread_interproc = ospmutex->pthread_interproc; + } + break; +#elif APR_HAS_SYSVSEM_SERIALIZE && defined(HAVE_SEMTIMEDOP) + new_mutex->meth = &mutex_sysv_methods; + if (ospmutex) { + if (ospmutex->crossproc == -1) { + return APR_EINVAL; + } + new_mutex->os.crossproc = ospmutex->crossproc; + } + break; +#elif APR_HAS_POSIXSEM_SERIALIZE && defined(HAVE_SEM_TIMEDWAIT) + new_mutex->meth = &mutex_posixsem_methods; + if (ospmutex) { + if (ospmutex->psem_interproc == NULL) { + return APR_EINVAL; + } + new_mutex->os.psem_interproc = ospmutex->psem_interproc; + } + break; +#endif + /* fall trough */ + case APR_LOCK_DEFAULT: +#if APR_USE_FLOCK_SERIALIZE + new_mutex->meth = &mutex_flock_methods; + if (ospmutex) { + if (ospmutex->crossproc == -1) { + return APR_EINVAL; + } + new_mutex->os.crossproc = ospmutex->crossproc; + } +#elif APR_USE_SYSVSEM_SERIALIZE + new_mutex->meth = &mutex_sysv_methods; + if (ospmutex) { + if (ospmutex->crossproc == -1) { + return APR_EINVAL; + } + new_mutex->os.crossproc = ospmutex->crossproc; + } +#elif APR_USE_FCNTL_SERIALIZE + new_mutex->meth = &mutex_fcntl_methods; + if (ospmutex) { + if (ospmutex->crossproc == -1) { + return APR_EINVAL; + } + new_mutex->os.crossproc = ospmutex->crossproc; + } +#elif APR_USE_PROC_PTHREAD_SERIALIZE + new_mutex->meth = &mutex_proc_pthread_methods; + if (ospmutex) { + if (ospmutex->pthread_interproc == NULL) { + return APR_EINVAL; + } + new_mutex->os.pthread_interproc = ospmutex->pthread_interproc; + } +#elif APR_USE_POSIXSEM_SERIALIZE + new_mutex->meth = &mutex_posixsem_methods; + if (ospmutex) { + if (ospmutex->psem_interproc == NULL) { + return APR_EINVAL; + } + new_mutex->os.psem_interproc = ospmutex->psem_interproc; + } +#else + return APR_ENOTIMPL; +#endif + break; + default: + return APR_ENOTIMPL; + } + return APR_SUCCESS; +} + +APR_DECLARE(const char *) apr_proc_mutex_defname(void) +{ + apr_status_t rv; + apr_proc_mutex_t mutex; + + if ((rv = proc_mutex_choose_method(&mutex, APR_LOCK_DEFAULT, + NULL)) != APR_SUCCESS) { + return "unknown"; + } + + return apr_proc_mutex_name(&mutex); +} + +static apr_status_t proc_mutex_create(apr_proc_mutex_t *new_mutex, apr_lockmech_e mech, const char *fname) +{ + apr_status_t rv; + + if ((rv = proc_mutex_choose_method(new_mutex, mech, + NULL)) != APR_SUCCESS) { + return rv; + } + + if ((rv = new_mutex->meth->create(new_mutex, fname)) != APR_SUCCESS) { + return rv; + } + + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_proc_mutex_create(apr_proc_mutex_t **mutex, + const char *fname, + apr_lockmech_e mech, + apr_pool_t *pool) +{ + apr_proc_mutex_t *new_mutex; + apr_status_t rv; + + new_mutex = apr_pcalloc(pool, sizeof(apr_proc_mutex_t)); + new_mutex->pool = pool; + + if ((rv = proc_mutex_create(new_mutex, mech, fname)) != APR_SUCCESS) + return rv; + + *mutex = new_mutex; + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_proc_mutex_child_init(apr_proc_mutex_t **mutex, + const char *fname, + apr_pool_t *pool) +{ + return (*mutex)->meth->child_init(mutex, pool, fname); +} + +APR_DECLARE(apr_status_t) apr_proc_mutex_lock(apr_proc_mutex_t *mutex) +{ + return mutex->meth->acquire(mutex); +} + +APR_DECLARE(apr_status_t) apr_proc_mutex_trylock(apr_proc_mutex_t *mutex) +{ + return mutex->meth->tryacquire(mutex); +} + +APR_DECLARE(apr_status_t) apr_proc_mutex_timedlock(apr_proc_mutex_t *mutex, + apr_interval_time_t timeout) +{ + return mutex->meth->timedacquire(mutex, timeout); +} + +APR_DECLARE(apr_status_t) apr_proc_mutex_unlock(apr_proc_mutex_t *mutex) +{ + return mutex->meth->release(mutex); +} + +APR_DECLARE(apr_status_t) apr_proc_mutex_cleanup(void *mutex) +{ + return ((apr_proc_mutex_t *)mutex)->meth->cleanup(mutex); +} + +APR_DECLARE(apr_lockmech_e) apr_proc_mutex_mech(apr_proc_mutex_t *mutex) +{ + return mutex->meth->mech; +} + +APR_DECLARE(const char *) apr_proc_mutex_name(apr_proc_mutex_t *mutex) +{ + return mutex->meth->name; +} + +APR_DECLARE(const char *) apr_proc_mutex_lockfile(apr_proc_mutex_t *mutex) +{ + /* POSIX sems use the fname field but don't use a file, + * so be careful. */ +#if APR_HAS_FLOCK_SERIALIZE + if (mutex->meth == &mutex_flock_methods) { + return mutex->fname; + } +#endif +#if APR_HAS_FCNTL_SERIALIZE + if (mutex->meth == &mutex_fcntl_methods) { + return mutex->fname; + } +#endif + return NULL; +} + +APR_PERMS_SET_IMPLEMENT(proc_mutex) +{ + apr_proc_mutex_t *mutex = (apr_proc_mutex_t *)theproc_mutex; + return mutex->meth->perms_set(mutex, perms, uid, gid); +} + +APR_POOL_IMPLEMENT_ACCESSOR(proc_mutex) + +/* Implement OS-specific accessors defined in apr_portable.h */ + +APR_DECLARE(apr_status_t) apr_os_proc_mutex_get_ex(apr_os_proc_mutex_t *ospmutex, + apr_proc_mutex_t *pmutex, + apr_lockmech_e *mech) +{ + *ospmutex = pmutex->os; + if (mech) { + *mech = pmutex->meth->mech; + } + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_os_proc_mutex_get(apr_os_proc_mutex_t *ospmutex, + apr_proc_mutex_t *pmutex) +{ + return apr_os_proc_mutex_get_ex(ospmutex, pmutex, NULL); +} + +APR_DECLARE(apr_status_t) apr_os_proc_mutex_put_ex(apr_proc_mutex_t **pmutex, + apr_os_proc_mutex_t *ospmutex, + apr_lockmech_e mech, + int register_cleanup, + apr_pool_t *pool) +{ + apr_status_t rv; + if (pool == NULL) { + return APR_ENOPOOL; + } + + if ((*pmutex) == NULL) { + (*pmutex) = (apr_proc_mutex_t *)apr_pcalloc(pool, + sizeof(apr_proc_mutex_t)); + (*pmutex)->pool = pool; + } + rv = proc_mutex_choose_method(*pmutex, mech, ospmutex); +#if APR_HAS_FCNTL_SERIALIZE || APR_HAS_FLOCK_SERIALIZE + if (rv == APR_SUCCESS) { + rv = apr_os_file_put(&(*pmutex)->interproc, &(*pmutex)->os.crossproc, + 0, pool); + } +#endif + + if (rv == APR_SUCCESS && register_cleanup) { + apr_pool_cleanup_register(pool, *pmutex, apr_proc_mutex_cleanup, + apr_pool_cleanup_null); + } + return rv; +} + +APR_DECLARE(apr_status_t) apr_os_proc_mutex_put(apr_proc_mutex_t **pmutex, + apr_os_proc_mutex_t *ospmutex, + apr_pool_t *pool) +{ + return apr_os_proc_mutex_put_ex(pmutex, ospmutex, APR_LOCK_DEFAULT, + 0, pool); +} + diff --git a/locks/unix/thread_cond.c b/locks/unix/thread_cond.c new file mode 100644 index 00000000000..3c8e3170a0d --- /dev/null +++ b/locks/unix/thread_cond.c @@ -0,0 +1,145 @@ +/* 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" + +#if APR_HAS_THREADS + +#include "apr_arch_thread_mutex.h" +#include "apr_arch_thread_cond.h" + +static apr_status_t thread_cond_cleanup(void *data) +{ + apr_thread_cond_t *cond = (apr_thread_cond_t *)data; + apr_status_t rv; + + rv = pthread_cond_destroy(&cond->cond); +#ifdef HAVE_ZOS_PTHREADS + if (rv) { + rv = errno; + } +#endif + return rv; +} + +APR_DECLARE(apr_status_t) apr_thread_cond_create(apr_thread_cond_t **cond, + apr_pool_t *pool) +{ + apr_thread_cond_t *new_cond; + apr_status_t rv; + + new_cond = apr_palloc(pool, sizeof(apr_thread_cond_t)); + + new_cond->pool = pool; + + if ((rv = pthread_cond_init(&new_cond->cond, NULL))) { +#ifdef HAVE_ZOS_PTHREADS + rv = errno; +#endif + return rv; + } + + apr_pool_cleanup_register(new_cond->pool, + (void *)new_cond, thread_cond_cleanup, + apr_pool_cleanup_null); + + *cond = new_cond; + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_thread_cond_wait(apr_thread_cond_t *cond, + apr_thread_mutex_t *mutex) +{ + apr_status_t rv; + + rv = pthread_cond_wait(&cond->cond, &mutex->mutex); +#ifdef HAVE_ZOS_PTHREADS + if (rv) { + rv = errno; + } +#endif + return rv; +} + +APR_DECLARE(apr_status_t) apr_thread_cond_timedwait(apr_thread_cond_t *cond, + apr_thread_mutex_t *mutex, + apr_interval_time_t timeout) +{ + apr_status_t rv; + if (timeout < 0) { + rv = pthread_cond_wait(&cond->cond, &mutex->mutex); +#ifdef HAVE_ZOS_PTHREADS + if (rv) { + rv = errno; + } +#endif + } + else { + apr_time_t then; + struct timespec abstime; + + then = apr_time_now() + timeout; + abstime.tv_sec = apr_time_sec(then); + abstime.tv_nsec = apr_time_usec(then) * 1000; /* nanoseconds */ + + rv = pthread_cond_timedwait(&cond->cond, &mutex->mutex, &abstime); +#ifdef HAVE_ZOS_PTHREADS + if (rv) { + rv = errno; + } +#endif + if (ETIMEDOUT == rv) { + return APR_TIMEUP; + } + } + return rv; +} + + +APR_DECLARE(apr_status_t) apr_thread_cond_signal(apr_thread_cond_t *cond) +{ + apr_status_t rv; + + rv = pthread_cond_signal(&cond->cond); +#ifdef HAVE_ZOS_PTHREADS + if (rv) { + rv = errno; + } +#endif + return rv; +} + +APR_DECLARE(apr_status_t) apr_thread_cond_broadcast(apr_thread_cond_t *cond) +{ + apr_status_t rv; + + rv = pthread_cond_broadcast(&cond->cond); +#ifdef HAVE_ZOS_PTHREADS + if (rv) { + rv = errno; + } +#endif + return rv; +} + +APR_DECLARE(apr_status_t) apr_thread_cond_destroy(apr_thread_cond_t *cond) +{ + return apr_pool_cleanup_run(cond->pool, cond, thread_cond_cleanup); +} + +APR_POOL_IMPLEMENT_ACCESSOR(thread_cond) + +#endif /* APR_HAS_THREADS */ diff --git a/locks/unix/thread_mutex.c b/locks/unix/thread_mutex.c new file mode 100644 index 00000000000..f027c791f2e --- /dev/null +++ b/locks/unix/thread_mutex.c @@ -0,0 +1,332 @@ +/* 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_thread_mutex.h" +#define APR_WANT_MEMFUNC +#include "apr_want.h" + +#if APR_HAS_THREADS + +static apr_status_t thread_mutex_cleanup(void *data) +{ + apr_thread_mutex_t *mutex = data; + apr_status_t rv; + + rv = pthread_mutex_destroy(&mutex->mutex); +#ifdef HAVE_ZOS_PTHREADS + if (rv) { + rv = errno; + } +#endif + return rv; +} + +APR_DECLARE(apr_status_t) apr_thread_mutex_create(apr_thread_mutex_t **mutex, + unsigned int flags, + apr_pool_t *pool) +{ + apr_thread_mutex_t *new_mutex; + apr_status_t rv; + +#ifndef HAVE_PTHREAD_MUTEX_RECURSIVE + if (flags & APR_THREAD_MUTEX_NESTED) { + return APR_ENOTIMPL; + } +#endif + + new_mutex = apr_pcalloc(pool, sizeof(apr_thread_mutex_t)); + new_mutex->pool = pool; + +#ifdef HAVE_PTHREAD_MUTEX_RECURSIVE + if (flags & APR_THREAD_MUTEX_NESTED) { + pthread_mutexattr_t mattr; + + rv = pthread_mutexattr_init(&mattr); + if (rv) return rv; + + rv = pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_RECURSIVE); + if (rv) { + pthread_mutexattr_destroy(&mattr); + return rv; + } + + rv = pthread_mutex_init(&new_mutex->mutex, &mattr); + + pthread_mutexattr_destroy(&mattr); + } else +#endif + rv = pthread_mutex_init(&new_mutex->mutex, NULL); + + if (rv) { +#ifdef HAVE_ZOS_PTHREADS + rv = errno; +#endif + return rv; + } + +#ifndef HAVE_PTHREAD_MUTEX_TIMEDLOCK + if (flags & APR_THREAD_MUTEX_TIMED) { + rv = apr_thread_cond_create(&new_mutex->cond, pool); + if (rv) { +#ifdef HAVE_ZOS_PTHREADS + rv = errno; +#endif + pthread_mutex_destroy(&new_mutex->mutex); + return rv; + } + } +#endif + + apr_pool_cleanup_register(new_mutex->pool, + new_mutex, thread_mutex_cleanup, + apr_pool_cleanup_null); + + *mutex = new_mutex; + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_thread_mutex_lock(apr_thread_mutex_t *mutex) +{ + apr_status_t rv; + + if (mutex->cond) { + apr_status_t rv2; + + rv = pthread_mutex_lock(&mutex->mutex); + if (rv) { +#ifdef HAVE_ZOS_PTHREADS + rv = errno; +#endif + return rv; + } + + if (mutex->locked) { + mutex->num_waiters++; + rv = apr_thread_cond_wait(mutex->cond, mutex); + mutex->num_waiters--; + } + else { + mutex->locked = 1; + } + + rv2 = pthread_mutex_unlock(&mutex->mutex); + if (rv2 && !rv) { +#ifdef HAVE_ZOS_PTHREADS + rv = errno; +#else + rv = rv2; +#endif + } + + return rv; + } + + rv = pthread_mutex_lock(&mutex->mutex); +#ifdef HAVE_ZOS_PTHREADS + if (rv) { + rv = errno; + } +#endif + + return rv; +} + +APR_DECLARE(apr_status_t) apr_thread_mutex_trylock(apr_thread_mutex_t *mutex) +{ + apr_status_t rv; + + if (mutex->cond) { + apr_status_t rv2; + + rv = pthread_mutex_lock(&mutex->mutex); + if (rv) { +#ifdef HAVE_ZOS_PTHREADS + rv = errno; +#endif + return rv; + } + + if (mutex->locked) { + rv = APR_EBUSY; + } + else { + mutex->locked = 1; + } + + rv2 = pthread_mutex_unlock(&mutex->mutex); + if (rv2) { +#ifdef HAVE_ZOS_PTHREADS + rv = errno; +#else + rv = rv2; +#endif + } + + return rv; + } + + rv = pthread_mutex_trylock(&mutex->mutex); + if (rv) { +#ifdef HAVE_ZOS_PTHREADS + rv = errno; +#endif + return (rv == EBUSY) ? APR_EBUSY : rv; + } + + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_thread_mutex_timedlock(apr_thread_mutex_t *mutex, + apr_interval_time_t timeout) +{ + apr_status_t rv = APR_ENOTIMPL; + +#ifdef HAVE_PTHREAD_MUTEX_TIMEDLOCK + if (timeout <= 0) { + rv = pthread_mutex_trylock(&mutex->mutex); + if (rv) { +#ifdef HAVE_ZOS_PTHREADS + rv = errno; +#endif + if (rv == EBUSY) { + rv = APR_TIMEUP; + } + } + } + else { + struct timespec abstime; + + timeout += apr_time_now(); + abstime.tv_sec = apr_time_sec(timeout); + abstime.tv_nsec = apr_time_usec(timeout) * 1000; /* nanoseconds */ + + rv = pthread_mutex_timedlock(&mutex->mutex, &abstime); + if (rv) { +#ifdef HAVE_ZOS_PTHREADS + rv = errno; +#endif + if (rv == ETIMEDOUT) { + rv = APR_TIMEUP; + } + } + } + +#else /* HAVE_PTHREAD_MUTEX_TIMEDLOCK */ + + if (mutex->cond) { + rv = pthread_mutex_lock(&mutex->mutex); + if (rv) { +#ifdef HAVE_ZOS_PTHREADS + rv = errno; +#endif + return rv; + } + + if (mutex->locked) { + if (timeout <= 0) { + rv = APR_TIMEUP; + } + else { + mutex->num_waiters++; + do { + rv = apr_thread_cond_timedwait(mutex->cond, mutex, + timeout); + if (rv) { +#ifdef HAVE_ZOS_PTHREADS + rv = errno; +#endif + break; + } + } while (mutex->locked); + mutex->num_waiters--; + } + if (rv) { + pthread_mutex_unlock(&mutex->mutex); + return rv; + } + } + + mutex->locked = 1; + + rv = pthread_mutex_unlock(&mutex->mutex); + if (rv) { +#ifdef HAVE_ZOS_PTHREADS + rv = errno; +#endif + return rv; + } + } + +#endif /* HAVE_PTHREAD_MUTEX_TIMEDLOCK */ + + return rv; +} + +APR_DECLARE(apr_status_t) apr_thread_mutex_unlock(apr_thread_mutex_t *mutex) +{ + apr_status_t status; + + if (mutex->cond) { + status = pthread_mutex_lock(&mutex->mutex); + if (status) { +#ifdef HAVE_ZOS_PTHREADS + status = errno; +#endif + return status; + } + + if (!mutex->locked) { + status = APR_EINVAL; + } + else if (mutex->num_waiters) { + status = apr_thread_cond_signal(mutex->cond); + } + if (status) { + pthread_mutex_unlock(&mutex->mutex); + return status; + } + + mutex->locked = 0; + } + + status = pthread_mutex_unlock(&mutex->mutex); +#ifdef HAVE_ZOS_PTHREADS + if (status) { + status = errno; + } +#endif + + return status; +} + +APR_DECLARE(apr_status_t) apr_thread_mutex_destroy(apr_thread_mutex_t *mutex) +{ + apr_status_t rv, rv2 = APR_SUCCESS; + + if (mutex->cond) { + rv2 = apr_thread_cond_destroy(mutex->cond); + } + rv = apr_pool_cleanup_run(mutex->pool, mutex, thread_mutex_cleanup); + if (rv == APR_SUCCESS) { + rv = rv2; + } + + return rv; +} + +APR_POOL_IMPLEMENT_ACCESSOR(thread_mutex) + +#endif /* APR_HAS_THREADS */ diff --git a/locks/unix/thread_rwlock.c b/locks/unix/thread_rwlock.c new file mode 100644 index 00000000000..0f8b7a79ff7 --- /dev/null +++ b/locks/unix/thread_rwlock.c @@ -0,0 +1,181 @@ +/* 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_thread_rwlock.h" +#include "apr_private.h" + +#if APR_HAS_THREADS + +#ifdef HAVE_PTHREAD_RWLOCKS + +/* The rwlock must be initialized but not locked by any thread when + * cleanup is called. */ +static apr_status_t thread_rwlock_cleanup(void *data) +{ + apr_thread_rwlock_t *rwlock = (apr_thread_rwlock_t *)data; + apr_status_t stat; + + stat = pthread_rwlock_destroy(&rwlock->rwlock); +#ifdef HAVE_ZOS_PTHREADS + if (stat) { + stat = errno; + } +#endif + return stat; +} + +APR_DECLARE(apr_status_t) apr_thread_rwlock_create(apr_thread_rwlock_t **rwlock, + apr_pool_t *pool) +{ + apr_thread_rwlock_t *new_rwlock; + apr_status_t stat; + + new_rwlock = apr_palloc(pool, sizeof(apr_thread_rwlock_t)); + new_rwlock->pool = pool; + + if ((stat = pthread_rwlock_init(&new_rwlock->rwlock, NULL))) { +#ifdef HAVE_ZOS_PTHREADS + stat = errno; +#endif + return stat; + } + + apr_pool_cleanup_register(new_rwlock->pool, + (void *)new_rwlock, thread_rwlock_cleanup, + apr_pool_cleanup_null); + + *rwlock = new_rwlock; + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_thread_rwlock_rdlock(apr_thread_rwlock_t *rwlock) +{ + apr_status_t stat; + + stat = pthread_rwlock_rdlock(&rwlock->rwlock); +#ifdef HAVE_ZOS_PTHREADS + if (stat) { + stat = errno; + } +#endif + return stat; +} + +APR_DECLARE(apr_status_t) apr_thread_rwlock_tryrdlock(apr_thread_rwlock_t *rwlock) +{ + apr_status_t stat; + + stat = pthread_rwlock_tryrdlock(&rwlock->rwlock); +#ifdef HAVE_ZOS_PTHREADS + if (stat) { + stat = errno; + } +#endif + /* Normalize the return code. */ + if (stat == EBUSY) + stat = APR_EBUSY; + return stat; +} + +APR_DECLARE(apr_status_t) apr_thread_rwlock_wrlock(apr_thread_rwlock_t *rwlock) +{ + apr_status_t stat; + + stat = pthread_rwlock_wrlock(&rwlock->rwlock); +#ifdef HAVE_ZOS_PTHREADS + if (stat) { + stat = errno; + } +#endif + return stat; +} + +APR_DECLARE(apr_status_t) apr_thread_rwlock_trywrlock(apr_thread_rwlock_t *rwlock) +{ + apr_status_t stat; + + stat = pthread_rwlock_trywrlock(&rwlock->rwlock); +#ifdef HAVE_ZOS_PTHREADS + if (stat) { + stat = errno; + } +#endif + /* Normalize the return code. */ + if (stat == EBUSY) + stat = APR_EBUSY; + return stat; +} + +APR_DECLARE(apr_status_t) apr_thread_rwlock_unlock(apr_thread_rwlock_t *rwlock) +{ + apr_status_t stat; + + stat = pthread_rwlock_unlock(&rwlock->rwlock); +#ifdef HAVE_ZOS_PTHREADS + if (stat) { + stat = errno; + } +#endif + return stat; +} + +APR_DECLARE(apr_status_t) apr_thread_rwlock_destroy(apr_thread_rwlock_t *rwlock) +{ + return apr_pool_cleanup_run(rwlock->pool, rwlock, thread_rwlock_cleanup); +} + +#else /* HAVE_PTHREAD_RWLOCKS */ + +APR_DECLARE(apr_status_t) apr_thread_rwlock_create(apr_thread_rwlock_t **rwlock, + apr_pool_t *pool) +{ + return APR_ENOTIMPL; +} + +APR_DECLARE(apr_status_t) apr_thread_rwlock_rdlock(apr_thread_rwlock_t *rwlock) +{ + return APR_ENOTIMPL; +} + +APR_DECLARE(apr_status_t) apr_thread_rwlock_tryrdlock(apr_thread_rwlock_t *rwlock) +{ + return APR_ENOTIMPL; +} + +APR_DECLARE(apr_status_t) apr_thread_rwlock_wrlock(apr_thread_rwlock_t *rwlock) +{ + return APR_ENOTIMPL; +} + +APR_DECLARE(apr_status_t) apr_thread_rwlock_trywrlock(apr_thread_rwlock_t *rwlock) +{ + return APR_ENOTIMPL; +} + +APR_DECLARE(apr_status_t) apr_thread_rwlock_unlock(apr_thread_rwlock_t *rwlock) +{ + return APR_ENOTIMPL; +} + +APR_DECLARE(apr_status_t) apr_thread_rwlock_destroy(apr_thread_rwlock_t *rwlock) +{ + return APR_ENOTIMPL; +} + +#endif /* HAVE_PTHREAD_RWLOCKS */ +APR_POOL_IMPLEMENT_ACCESSOR(thread_rwlock) + +#endif /* APR_HAS_THREADS */ diff --git a/locks/win32/locks.c b/locks/win32/locks.c deleted file mode 100644 index a9031a05d47..00000000000 --- a/locks/win32/locks.c +++ /dev/null @@ -1,201 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#include "apr_general.h" -#include "apr_lib.h" -#include "locks.h" -#include "apr_portable.h" - -ap_status_t ap_create_lock(ap_lock_t **lock, ap_locktype_e type, - ap_lockscope_e scope, const char *fname, - ap_pool_t *cont) -{ - ap_lock_t *newlock; - SECURITY_ATTRIBUTES sec; - - newlock = (ap_lock_t *)ap_palloc(cont, sizeof(ap_lock_t)); - - newlock->cntxt = cont; - /* ToDo: How to handle the case when no context is available? - * How to cleanup the storage properly? - */ - newlock->fname = ap_pstrdup(cont, fname); - newlock->type = type; - newlock->scope = scope; - sec.nLength = sizeof(SECURITY_ATTRIBUTES); - sec.lpSecurityDescriptor = NULL; - - if (scope == APR_CROSS_PROCESS || scope == APR_LOCKALL) { - sec.bInheritHandle = TRUE; - } - else { - sec.bInheritHandle = FALSE; - } - - if (scope == APR_INTRAPROCESS) { - InitializeCriticalSection(&newlock->section); - } else { - newlock->mutex = CreateMutex(&sec, FALSE, fname); - } - *lock = newlock; - return APR_SUCCESS; -} - -ap_status_t ap_child_init_lock(ap_lock_t **lock, const char *fname, - ap_pool_t *cont) -{ - /* This routine should not be called (and OpenMutex will fail if called) - * on a INTRAPROCESS lock - */ - (*lock) = (ap_lock_t *)ap_palloc(cont, sizeof(ap_lock_t)); - - if ((*lock) == NULL) { - return APR_ENOMEM; - } - (*lock)->fname = ap_pstrdup(cont, fname); - (*lock)->mutex = OpenMutex(MUTEX_ALL_ACCESS, TRUE, fname); - - if ((*lock)->mutex == NULL) { - return APR_EEXIST; - } - return APR_SUCCESS; -} - -ap_status_t ap_lock(ap_lock_t *lock) -{ - DWORD rv; - if (lock->scope == APR_INTRAPROCESS) { - EnterCriticalSection(&lock->section); - return APR_SUCCESS; - } else { - rv = WaitForSingleObject(lock->mutex, INFINITE); - - if (rv == WAIT_OBJECT_0 || rv == WAIT_ABANDONED) { - return APR_SUCCESS; - } - } - return GetLastError(); -} - -ap_status_t ap_unlock(ap_lock_t *lock) -{ - if (lock->scope == APR_INTRAPROCESS) { - LeaveCriticalSection(&lock->section); - return APR_SUCCESS; - } else { - if (ReleaseMutex(lock->mutex) == 0) { - return APR_EEXIST; - } - } - return APR_SUCCESS; -} - -ap_status_t ap_destroy_lock(ap_lock_t *lock) -{ - if (lock->scope == APR_INTRAPROCESS) { - DeleteCriticalSection(&lock->section); - return APR_SUCCESS; - } else { - if (CloseHandle(lock->mutex) == 0) { - return APR_EEXIST; - } - } - return APR_SUCCESS; -} - -ap_status_t ap_get_lockdata(ap_lock_t *lock, char *key, void *data) -{ - if (lock != NULL) { - return ap_get_userdata(data, key, lock->cntxt); - } - else { - data = NULL; - return APR_ENOLOCK; - } -} - -ap_status_t ap_set_lockdata(ap_lock_t *lock, void *data, char *key, - ap_status_t (*cleanup) (void *)) -{ - if (lock != NULL) { - return ap_set_userdata(data, key, cleanup, lock->cntxt); - } - else { - data = NULL; - return APR_ENOLOCK; - } -} - -ap_status_t ap_get_os_lock(ap_os_lock_t *thelock, ap_lock_t *lock) -{ - if (lock == NULL) { - return APR_ENOFILE; - } - thelock = &(lock->mutex); - return APR_SUCCESS; -} - -ap_status_t ap_put_os_lock(ap_lock_t **lock, ap_os_lock_t *thelock, - ap_pool_t *cont) -{ - if (cont == NULL) { - return APR_ENOPOOL; - } - if ((*lock) == NULL) { - (*lock) = (ap_lock_t *)ap_palloc(cont, sizeof(ap_lock_t)); - (*lock)->cntxt = cont; - } - (*lock)->mutex = *thelock; - return APR_SUCCESS; -} diff --git a/locks/win32/locks.h b/locks/win32/locks.h deleted file mode 100644 index 602c2eb673f..00000000000 --- a/locks/win32/locks.h +++ /dev/null @@ -1,70 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#ifndef LOCKS_H -#define LOCKS_H - -#include "apr_lock.h" - -struct ap_lock_t { - ap_pool_t *cntxt; - ap_locktype_e type; - ap_lockscope_e scope; - HANDLE mutex; - CRITICAL_SECTION section; - char *fname; -}; - -#endif /* LOCKS_H */ - diff --git a/locks/win32/proc_mutex.c b/locks/win32/proc_mutex.c new file mode 100644 index 00000000000..e132e20a2e3 --- /dev/null +++ b/locks/win32/proc_mutex.c @@ -0,0 +1,301 @@ +/* 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_general.h" +#include "apr_strings.h" +#include "apr_portable.h" +#include "apr_arch_file_io.h" +#include "apr_arch_proc_mutex.h" +#include "apr_arch_misc.h" + +static apr_status_t proc_mutex_cleanup(void *mutex_) +{ + apr_proc_mutex_t *mutex = mutex_; + + if (mutex->handle) { + if (CloseHandle(mutex->handle) == 0) { + return apr_get_os_error(); + } + } + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_proc_mutex_create(apr_proc_mutex_t **mutex, + const char *fname, + apr_lockmech_e mech, + apr_pool_t *pool) +{ + HANDLE hMutex; + void *mutexkey; + + if (mech != APR_LOCK_DEFAULT && mech != APR_LOCK_DEFAULT_TIMED) { + return APR_ENOTIMPL; + } + + /* res_name_from_filename turns fname into a pseduo-name + * without slashes or backslashes, and prepends the \global + * prefix on Win2K and later + */ + if (fname) { + mutexkey = res_name_from_filename(fname, 1, pool); + } + else { + mutexkey = NULL; + } + +#if APR_HAS_UNICODE_FS + IF_WIN_OS_IS_UNICODE + { + hMutex = CreateMutexW(NULL, FALSE, mutexkey); + } +#endif +#if APR_HAS_ANSI_FS + ELSE_WIN_OS_IS_ANSI + { + hMutex = CreateMutexA(NULL, FALSE, mutexkey); + } +#endif + + if (!hMutex) { + return apr_get_os_error(); + } + + *mutex = (apr_proc_mutex_t *)apr_palloc(pool, sizeof(apr_proc_mutex_t)); + (*mutex)->pool = pool; + (*mutex)->handle = hMutex; + (*mutex)->fname = fname; + apr_pool_cleanup_register((*mutex)->pool, *mutex, + proc_mutex_cleanup, apr_pool_cleanup_null); + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_proc_mutex_child_init(apr_proc_mutex_t **mutex, + const char *fname, + apr_pool_t *pool) +{ + HANDLE hMutex; + void *mutexkey; + + if (!fname) { + /* Reinitializing unnamed mutexes is a noop in the Unix code. */ + return APR_SUCCESS; + } + + /* res_name_from_filename turns file into a pseudo-name + * without slashes or backslashes, and prepends the \global + * prefix on Win2K and later + */ + mutexkey = res_name_from_filename(fname, 1, pool); + +#if defined(_WIN32_WCE) + hMutex = CreateMutex(NULL, FALSE, mutexkey); + if (hMutex && ERROR_ALREADY_EXISTS != GetLastError()) { + CloseHandle(hMutex); + hMutex = NULL; + SetLastError(ERROR_FILE_NOT_FOUND); + } +#else +#if APR_HAS_UNICODE_FS + IF_WIN_OS_IS_UNICODE + { + hMutex = OpenMutexW(MUTEX_ALL_ACCESS, FALSE, mutexkey); + } +#endif +#if APR_HAS_ANSI_FS + ELSE_WIN_OS_IS_ANSI + { + hMutex = OpenMutexA(MUTEX_ALL_ACCESS, FALSE, mutexkey); + } +#endif +#endif + + if (!hMutex) { + return apr_get_os_error(); + } + + *mutex = (apr_proc_mutex_t *)apr_palloc(pool, sizeof(apr_proc_mutex_t)); + (*mutex)->pool = pool; + (*mutex)->handle = hMutex; + (*mutex)->fname = fname; + apr_pool_cleanup_register((*mutex)->pool, *mutex, + proc_mutex_cleanup, apr_pool_cleanup_null); + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_proc_mutex_lock(apr_proc_mutex_t *mutex) +{ + DWORD rv; + + rv = WaitForSingleObject(mutex->handle, INFINITE); + + if (rv == WAIT_OBJECT_0 || rv == WAIT_ABANDONED) { + return APR_SUCCESS; + } + return apr_get_os_error(); +} + +APR_DECLARE(apr_status_t) apr_proc_mutex_trylock(apr_proc_mutex_t *mutex) +{ + DWORD rv; + + rv = WaitForSingleObject(mutex->handle, 0); + + if (rv == WAIT_OBJECT_0 || rv == WAIT_ABANDONED) { + return APR_SUCCESS; + } + else if (rv == WAIT_TIMEOUT) { + return APR_EBUSY; + } + return apr_get_os_error(); +} + +APR_DECLARE(apr_status_t) apr_proc_mutex_timedlock(apr_proc_mutex_t *mutex, + apr_interval_time_t timeout) +{ + DWORD rv, timeout_ms = 0; + apr_interval_time_t t = timeout; + + do { + if (t > 0) { + /* Given timeout is 64bit usecs whereas Windows timeouts are + * 32bit msecs and below INFINITE (2^32 - 1), so we may need + * multiple timed out waits... + */ + if (t > apr_time_from_msec(INFINITE - 1)) { + timeout_ms = INFINITE - 1; + t -= apr_time_from_msec(INFINITE - 1); + } + else { + timeout_ms = (DWORD)apr_time_as_msec(t); + t = 0; + } + } + rv = WaitForSingleObject(mutex->handle, timeout_ms); + } while (rv == WAIT_TIMEOUT && t > 0); + + if (rv == WAIT_TIMEOUT) { + return APR_TIMEUP; + } + if (rv == WAIT_OBJECT_0 || rv == WAIT_ABANDONED) { + return APR_SUCCESS; + } + return apr_get_os_error(); +} + +APR_DECLARE(apr_status_t) apr_proc_mutex_unlock(apr_proc_mutex_t *mutex) +{ + if (ReleaseMutex(mutex->handle) == 0) { + return apr_get_os_error(); + } + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_proc_mutex_destroy(apr_proc_mutex_t *mutex) +{ + apr_status_t stat; + + stat = proc_mutex_cleanup(mutex); + if (stat == APR_SUCCESS) { + apr_pool_cleanup_kill(mutex->pool, mutex, proc_mutex_cleanup); + } + return stat; +} + +APR_DECLARE(apr_status_t) apr_proc_mutex_cleanup(void *mutex) +{ + return apr_proc_mutex_destroy((apr_proc_mutex_t *)mutex); +} + +APR_DECLARE(const char *) apr_proc_mutex_lockfile(apr_proc_mutex_t *mutex) +{ + return mutex->fname; +} + +APR_DECLARE(apr_lockmech_e) apr_proc_mutex_mech(apr_proc_mutex_t *mutex) +{ + return APR_LOCK_DEFAULT; +} + +APR_DECLARE(const char *) apr_proc_mutex_name(apr_proc_mutex_t *mutex) +{ + return apr_proc_mutex_defname(); +} + +APR_DECLARE(const char *) apr_proc_mutex_defname(void) +{ + return "win32mutex"; +} + +APR_PERMS_SET_ENOTIMPL(proc_mutex) + +APR_POOL_IMPLEMENT_ACCESSOR(proc_mutex) + +/* Implement OS-specific accessors defined in apr_portable.h */ + +APR_DECLARE(apr_status_t) apr_os_proc_mutex_get_ex(apr_os_proc_mutex_t *ospmutex, + apr_proc_mutex_t *pmutex, + apr_lockmech_e *mech) +{ + *ospmutex = pmutex->handle; + if (mech) { + *mech = APR_LOCK_DEFAULT; + } + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_os_proc_mutex_get(apr_os_proc_mutex_t *ospmutex, + apr_proc_mutex_t *pmutex) +{ + return apr_os_proc_mutex_get_ex(ospmutex, pmutex, NULL); +} + +APR_DECLARE(apr_status_t) apr_os_proc_mutex_put_ex(apr_proc_mutex_t **pmutex, + apr_os_proc_mutex_t *ospmutex, + apr_lockmech_e mech, + int register_cleanup, + apr_pool_t *pool) +{ + if (pool == NULL) { + return APR_ENOPOOL; + } + if (mech != APR_LOCK_DEFAULT && mech != APR_LOCK_DEFAULT_TIMED) { + return APR_ENOTIMPL; + } + + if ((*pmutex) == NULL) { + (*pmutex) = (apr_proc_mutex_t *)apr_palloc(pool, + sizeof(apr_proc_mutex_t)); + (*pmutex)->pool = pool; + } + (*pmutex)->handle = *ospmutex; + + if (register_cleanup) { + apr_pool_cleanup_register(pool, *pmutex, proc_mutex_cleanup, + apr_pool_cleanup_null); + } + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_os_proc_mutex_put(apr_proc_mutex_t **pmutex, + apr_os_proc_mutex_t *ospmutex, + apr_pool_t *pool) +{ + return apr_os_proc_mutex_put_ex(pmutex, ospmutex, APR_LOCK_DEFAULT, + 0, pool); +} + diff --git a/locks/win32/thread_cond.c b/locks/win32/thread_cond.c new file mode 100644 index 00000000000..d22567a88e0 --- /dev/null +++ b/locks/win32/thread_cond.c @@ -0,0 +1,188 @@ +/* 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_general.h" +#include "apr_strings.h" +#include "apr_arch_thread_mutex.h" +#include "apr_arch_thread_cond.h" +#include "apr_portable.h" + +#include <limits.h> + +static apr_status_t thread_cond_cleanup(void *data) +{ + apr_thread_cond_t *cond = data; + CloseHandle(cond->semaphore); + DeleteCriticalSection(&cond->csection); + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_thread_cond_create(apr_thread_cond_t **cond, + apr_pool_t *pool) +{ + apr_thread_cond_t *cv; + + cv = apr_pcalloc(pool, sizeof(**cond)); + if (cv == NULL) { + return APR_ENOMEM; + } + + cv->semaphore = CreateSemaphore(NULL, 0, LONG_MAX, NULL); + if (cv->semaphore == NULL) { + return apr_get_os_error(); + } + + *cond = cv; + cv->pool = pool; + InitializeCriticalSection(&cv->csection); + apr_pool_cleanup_register(cv->pool, cv, thread_cond_cleanup, + apr_pool_cleanup_null); + + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_thread_cond_destroy(apr_thread_cond_t *cond) +{ + return apr_pool_cleanup_run(cond->pool, cond, thread_cond_cleanup); +} + +static APR_INLINE apr_status_t thread_cond_timedwait(apr_thread_cond_t *cond, + apr_thread_mutex_t *mutex, + apr_interval_time_t timeout) +{ + DWORD res; + apr_status_t rv; + unsigned int wake = 0; + unsigned long generation; + DWORD timeout_ms = 0; + + EnterCriticalSection(&cond->csection); + cond->num_waiting++; + generation = cond->generation; + LeaveCriticalSection(&cond->csection); + + apr_thread_mutex_unlock(mutex); + + do { + apr_interval_time_t t = timeout; + + do { + if (t < 0) { + timeout_ms = INFINITE; + } + else if (t > 0) { + /* Given timeout is 64bit usecs whereas Windows timeouts are + * 32bit msecs and below INFINITE (2^32 - 1), so we may need + * multiple timed out waits... + */ + if (t > apr_time_from_msec(INFINITE - 1)) { + timeout_ms = INFINITE - 1; + t -= apr_time_from_msec(INFINITE - 1); + } + else { + timeout_ms = (DWORD)apr_time_as_msec(t); + t = 0; + } + } + res = WaitForSingleObject(mutex->handle, timeout_ms); + } while (res == WAIT_TIMEOUT && t > 0); + + EnterCriticalSection(&cond->csection); + + if (cond->num_wake) { + if (cond->generation != generation) { + cond->num_wake--; + cond->num_waiting--; + rv = APR_SUCCESS; + break; + } else { + wake = 1; + } + } + else if (res != WAIT_OBJECT_0) { + cond->num_waiting--; + rv = APR_TIMEUP; + break; + } + + LeaveCriticalSection(&cond->csection); + + if (wake) { + wake = 0; + ReleaseSemaphore(cond->semaphore, 1, NULL); + } + } while (1); + + LeaveCriticalSection(&cond->csection); + apr_thread_mutex_lock(mutex); + + return rv; +} + +APR_DECLARE(apr_status_t) apr_thread_cond_wait(apr_thread_cond_t *cond, + apr_thread_mutex_t *mutex) +{ + return thread_cond_timedwait(cond, mutex, (apr_interval_time_t)-1); +} + +APR_DECLARE(apr_status_t) apr_thread_cond_timedwait(apr_thread_cond_t *cond, + apr_thread_mutex_t *mutex, + apr_interval_time_t timeout) +{ + return thread_cond_timedwait(cond, mutex, timeout); +} + +APR_DECLARE(apr_status_t) apr_thread_cond_signal(apr_thread_cond_t *cond) +{ + unsigned int wake = 0; + + EnterCriticalSection(&cond->csection); + if (cond->num_waiting > cond->num_wake) { + wake = 1; + cond->num_wake++; + cond->generation++; + } + LeaveCriticalSection(&cond->csection); + + if (wake) { + ReleaseSemaphore(cond->semaphore, 1, NULL); + } + + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_thread_cond_broadcast(apr_thread_cond_t *cond) +{ + unsigned long num_wake = 0; + + EnterCriticalSection(&cond->csection); + if (cond->num_waiting > cond->num_wake) { + num_wake = cond->num_waiting - cond->num_wake; + cond->num_wake = cond->num_waiting; + cond->generation++; + } + LeaveCriticalSection(&cond->csection); + + if (num_wake) { + ReleaseSemaphore(cond->semaphore, num_wake, NULL); + } + + return APR_SUCCESS; +} + +APR_POOL_IMPLEMENT_ACCESSOR(thread_cond) diff --git a/locks/win32/thread_mutex.c b/locks/win32/thread_mutex.c new file mode 100644 index 00000000000..f19152495f6 --- /dev/null +++ b/locks/win32/thread_mutex.c @@ -0,0 +1,175 @@ +/* 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_general.h" +#include "apr_strings.h" +#include "apr_arch_thread_mutex.h" +#include "apr_thread_mutex.h" +#include "apr_portable.h" +#include "apr_arch_misc.h" + +static apr_status_t thread_mutex_cleanup(void *data) +{ + apr_thread_mutex_t *lock = data; + + if (lock->type == thread_mutex_critical_section) { + lock->type = -1; + DeleteCriticalSection(&lock->section); + } + else { + if (!CloseHandle(lock->handle)) { + return apr_get_os_error(); + } + } + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_thread_mutex_create(apr_thread_mutex_t **mutex, + unsigned int flags, + apr_pool_t *pool) +{ + (*mutex) = (apr_thread_mutex_t *)apr_palloc(pool, sizeof(**mutex)); + + (*mutex)->pool = pool; + + if (flags & APR_THREAD_MUTEX_UNNESTED) { + /* Use an auto-reset signaled event, ready to accept one + * waiting thread. + */ + (*mutex)->type = thread_mutex_unnested_event; + (*mutex)->handle = CreateEvent(NULL, FALSE, TRUE, NULL); + } + else if (flags & APR_THREAD_MUTEX_TIMED) { + (*mutex)->type = thread_mutex_nested_mutex; + (*mutex)->handle = CreateMutex(NULL, FALSE, NULL); + } + else { +#if APR_HAS_UNICODE_FS + /* Critical Sections are terrific, performance-wise, on NT. + * On Win9x, we cannot 'try' on a critical section, so we + * use a [slower] mutex object, instead. + */ + IF_WIN_OS_IS_UNICODE { + InitializeCriticalSection(&(*mutex)->section); + (*mutex)->type = thread_mutex_critical_section; + (*mutex)->handle = NULL; + } +#endif +#if APR_HAS_ANSI_FS + ELSE_WIN_OS_IS_ANSI { + (*mutex)->type = thread_mutex_nested_mutex; + (*mutex)->handle = CreateMutex(NULL, FALSE, NULL); + + } +#endif + } + + apr_pool_cleanup_register((*mutex)->pool, (*mutex), thread_mutex_cleanup, + apr_pool_cleanup_null); + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_thread_mutex_lock(apr_thread_mutex_t *mutex) +{ + if (mutex->type == thread_mutex_critical_section) { + EnterCriticalSection(&mutex->section); + } + else { + DWORD rv = WaitForSingleObject(mutex->handle, INFINITE); + if ((rv != WAIT_OBJECT_0) && (rv != WAIT_ABANDONED)) { + return (rv == WAIT_TIMEOUT) ? APR_EBUSY : apr_get_os_error(); + } + } + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_thread_mutex_trylock(apr_thread_mutex_t *mutex) +{ + if (mutex->type == thread_mutex_critical_section) { + if (!TryEnterCriticalSection(&mutex->section)) { + return APR_EBUSY; + } + } + else { + DWORD rv = WaitForSingleObject(mutex->handle, 0); + if ((rv != WAIT_OBJECT_0) && (rv != WAIT_ABANDONED)) { + return (rv == WAIT_TIMEOUT) ? APR_EBUSY : apr_get_os_error(); + } + } + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_thread_mutex_timedlock(apr_thread_mutex_t *mutex, + apr_interval_time_t timeout) +{ + if (mutex->type != thread_mutex_critical_section) { + DWORD rv, timeout_ms = 0; + apr_interval_time_t t = timeout; + + do { + if (t > 0) { + /* Given timeout is 64bit usecs whereas Windows timeouts are + * 32bit msecs and below INFINITE (2^32 - 1), so we may need + * multiple timed out waits... + */ + if (t > apr_time_from_msec(INFINITE - 1)) { + timeout_ms = INFINITE - 1; + t -= apr_time_from_msec(INFINITE - 1); + } + else { + timeout_ms = (DWORD)apr_time_as_msec(t); + t = 0; + } + } + rv = WaitForSingleObject(mutex->handle, timeout_ms); + } while (rv == WAIT_TIMEOUT && t > 0); + + if ((rv != WAIT_OBJECT_0) && (rv != WAIT_ABANDONED)) { + return (rv == WAIT_TIMEOUT) ? APR_TIMEUP : apr_get_os_error(); + } + return APR_SUCCESS; + } + + return APR_ENOTIMPL; +} + +APR_DECLARE(apr_status_t) apr_thread_mutex_unlock(apr_thread_mutex_t *mutex) +{ + if (mutex->type == thread_mutex_critical_section) { + LeaveCriticalSection(&mutex->section); + } + else if (mutex->type == thread_mutex_unnested_event) { + if (!SetEvent(mutex->handle)) { + return apr_get_os_error(); + } + } + else if (mutex->type == thread_mutex_nested_mutex) { + if (!ReleaseMutex(mutex->handle)) { + return apr_get_os_error(); + } + } + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_thread_mutex_destroy(apr_thread_mutex_t *mutex) +{ + return apr_pool_cleanup_run(mutex->pool, mutex, thread_mutex_cleanup); +} + +APR_POOL_IMPLEMENT_ACCESSOR(thread_mutex) + diff --git a/locks/win32/thread_rwlock.c b/locks/win32/thread_rwlock.c new file mode 100644 index 00000000000..fd9d579f158 --- /dev/null +++ b/locks/win32/thread_rwlock.c @@ -0,0 +1,165 @@ +/* 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_general.h" +#include "apr_strings.h" +#include "apr_arch_thread_rwlock.h" +#include "apr_portable.h" + +static apr_status_t thread_rwlock_cleanup(void *data) +{ + apr_thread_rwlock_t *rwlock = data; + + if (! CloseHandle(rwlock->read_event)) + return apr_get_os_error(); + + if (! CloseHandle(rwlock->write_mutex)) + return apr_get_os_error(); + + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t)apr_thread_rwlock_create(apr_thread_rwlock_t **rwlock, + apr_pool_t *pool) +{ + *rwlock = apr_palloc(pool, sizeof(**rwlock)); + + (*rwlock)->pool = pool; + (*rwlock)->readers = 0; + + if (! ((*rwlock)->read_event = CreateEvent(NULL, TRUE, FALSE, NULL))) { + *rwlock = NULL; + return apr_get_os_error(); + } + + if (! ((*rwlock)->write_mutex = CreateMutex(NULL, FALSE, NULL))) { + CloseHandle((*rwlock)->read_event); + *rwlock = NULL; + return apr_get_os_error(); + } + + apr_pool_cleanup_register(pool, *rwlock, thread_rwlock_cleanup, + apr_pool_cleanup_null); + + return APR_SUCCESS; +} + +static apr_status_t apr_thread_rwlock_rdlock_core(apr_thread_rwlock_t *rwlock, + DWORD milliseconds) +{ + DWORD code = WaitForSingleObject(rwlock->write_mutex, milliseconds); + + if (code == WAIT_FAILED || code == WAIT_TIMEOUT) + return APR_FROM_OS_ERROR(code); + + /* We've successfully acquired the writer mutex, we can't be locked + * for write, so it's OK to add the reader lock. The writer mutex + * doubles as race condition protection for the readers counter. + */ + InterlockedIncrement(&rwlock->readers); + + if (! ResetEvent(rwlock->read_event)) + return apr_get_os_error(); + + if (! ReleaseMutex(rwlock->write_mutex)) + return apr_get_os_error(); + + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_thread_rwlock_rdlock(apr_thread_rwlock_t *rwlock) +{ + return apr_thread_rwlock_rdlock_core(rwlock, INFINITE); +} + +APR_DECLARE(apr_status_t) +apr_thread_rwlock_tryrdlock(apr_thread_rwlock_t *rwlock) +{ + return apr_thread_rwlock_rdlock_core(rwlock, 0); +} + +static apr_status_t +apr_thread_rwlock_wrlock_core(apr_thread_rwlock_t *rwlock, DWORD milliseconds) +{ + DWORD code = WaitForSingleObject(rwlock->write_mutex, milliseconds); + + if (code == WAIT_FAILED || code == WAIT_TIMEOUT) + return APR_FROM_OS_ERROR(code); + + /* We've got the writer lock but we have to wait for all readers to + * unlock before it's ok to use it. + */ + if (rwlock->readers) { + /* Must wait for readers to finish before returning, unless this + * is an trywrlock (milliseconds == 0): + */ + code = milliseconds + ? WaitForSingleObject(rwlock->read_event, milliseconds) + : WAIT_TIMEOUT; + + if (code == WAIT_FAILED || code == WAIT_TIMEOUT) { + /* Unable to wait for readers to finish, release write lock: */ + if (! ReleaseMutex(rwlock->write_mutex)) + return apr_get_os_error(); + + return APR_FROM_OS_ERROR(code); + } + } + + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_thread_rwlock_wrlock(apr_thread_rwlock_t *rwlock) +{ + return apr_thread_rwlock_wrlock_core(rwlock, INFINITE); +} + +APR_DECLARE(apr_status_t)apr_thread_rwlock_trywrlock(apr_thread_rwlock_t *rwlock) +{ + return apr_thread_rwlock_wrlock_core(rwlock, 0); +} + +APR_DECLARE(apr_status_t) apr_thread_rwlock_unlock(apr_thread_rwlock_t *rwlock) +{ + apr_status_t rv = 0; + + /* First, guess that we're unlocking a writer */ + if (! ReleaseMutex(rwlock->write_mutex)) + rv = apr_get_os_error(); + + if (rv == APR_FROM_OS_ERROR(ERROR_NOT_OWNER)) { + /* Nope, we must have a read lock */ + if (rwlock->readers && + ! InterlockedDecrement(&rwlock->readers) && + ! SetEvent(rwlock->read_event)) { + rv = apr_get_os_error(); + } + else { + rv = 0; + } + } + + return rv; +} + +APR_DECLARE(apr_status_t) apr_thread_rwlock_destroy(apr_thread_rwlock_t *rwlock) +{ + return apr_pool_cleanup_run(rwlock->pool, rwlock, thread_rwlock_cleanup); +} + +APR_POOL_IMPLEMENT_ACCESSOR(thread_rwlock) diff --git a/memcache/apr_memcache.c b/memcache/apr_memcache.c new file mode 100644 index 00000000000..cfaf5db92d6 --- /dev/null +++ b/memcache/apr_memcache.c @@ -0,0 +1,1728 @@ +/* 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_memcache.h" +#include "apr_poll.h" +#include "apr_version.h" +#include <stdlib.h> + +#define BUFFER_SIZE 512 +struct apr_memcache_conn_t +{ + char *buffer; + apr_size_t blen; + apr_pool_t *p; + apr_pool_t *tp; + apr_socket_t *sock; + apr_bucket_brigade *bb; + apr_bucket_brigade *tb; + apr_memcache_server_t *ms; +}; + +/* Strings for Client Commands */ + +#define MC_EOL "\r\n" +#define MC_EOL_LEN (sizeof(MC_EOL)-1) + +#define MC_WS " " +#define MC_WS_LEN (sizeof(MC_WS)-1) + +#define MC_GET "get " +#define MC_GET_LEN (sizeof(MC_GET)-1) + +#define MC_SET "set " +#define MC_SET_LEN (sizeof(MC_SET)-1) + +#define MC_ADD "add " +#define MC_ADD_LEN (sizeof(MC_ADD)-1) + +#define MC_REPLACE "replace " +#define MC_REPLACE_LEN (sizeof(MC_REPLACE)-1) + +#define MC_DELETE "delete " +#define MC_DELETE_LEN (sizeof(MC_DELETE)-1) + +#define MC_INCR "incr " +#define MC_INCR_LEN (sizeof(MC_INCR)-1) + +#define MC_DECR "decr " +#define MC_DECR_LEN (sizeof(MC_DECR)-1) + +#define MC_VERSION "version" +#define MC_VERSION_LEN (sizeof(MC_VERSION)-1) + +#define MC_STATS "stats" +#define MC_STATS_LEN (sizeof(MC_STATS)-1) + +#define MC_QUIT "quit" +#define MC_QUIT_LEN (sizeof(MC_QUIT)-1) + +/* Strings for Server Replies */ + +#define MS_STORED "STORED" +#define MS_STORED_LEN (sizeof(MS_STORED)-1) + +#define MS_NOT_STORED "NOT_STORED" +#define MS_NOT_STORED_LEN (sizeof(MS_NOT_STORED)-1) + +#define MS_DELETED "DELETED" +#define MS_DELETED_LEN (sizeof(MS_DELETED)-1) + +#define MS_NOT_FOUND "NOT_FOUND" +#define MS_NOT_FOUND_LEN (sizeof(MS_NOT_FOUND)-1) + +#define MS_VALUE "VALUE" +#define MS_VALUE_LEN (sizeof(MS_VALUE)-1) + +#define MS_ERROR "ERROR" +#define MS_ERROR_LEN (sizeof(MS_ERROR)-1) + +#define MS_VERSION "VERSION" +#define MS_VERSION_LEN (sizeof(MS_VERSION)-1) + +#define MS_STAT "STAT" +#define MS_STAT_LEN (sizeof(MS_STAT)-1) + +#define MS_END "END" +#define MS_END_LEN (sizeof(MS_END)-1) + +/** Server and Query Structure for a multiple get */ +struct cache_server_query_t { + apr_memcache_server_t* ms; + apr_memcache_conn_t* conn; + struct iovec* query_vec; + apr_int32_t query_vec_count; +}; + +#define MULT_GET_TIMEOUT 50000 + +static apr_status_t make_server_dead(apr_memcache_t *mc, apr_memcache_server_t *ms) +{ +#if APR_HAS_THREADS + apr_thread_mutex_lock(ms->lock); +#endif + ms->status = APR_MC_SERVER_DEAD; + ms->btime = apr_time_now(); +#if APR_HAS_THREADS + apr_thread_mutex_unlock(ms->lock); +#endif + return APR_SUCCESS; +} + +static apr_status_t make_server_live(apr_memcache_t *mc, apr_memcache_server_t *ms) +{ + ms->status = APR_MC_SERVER_LIVE; + return APR_SUCCESS; +} + + +APR_DECLARE(apr_status_t) apr_memcache_add_server(apr_memcache_t *mc, apr_memcache_server_t *ms) +{ + apr_status_t rv = APR_SUCCESS; + + if(mc->ntotal >= mc->nalloc) { + return APR_ENOMEM; + } + + mc->live_servers[mc->ntotal] = ms; + mc->ntotal++; + make_server_live(mc, ms); + return rv; +} + +static apr_status_t mc_version_ping(apr_memcache_server_t *ms); + +APR_DECLARE(apr_memcache_server_t *) +apr_memcache_find_server_hash(apr_memcache_t *mc, const apr_uint32_t hash) +{ + if (mc->server_func) { + return mc->server_func(mc->server_baton, mc, hash); + } + else { + return apr_memcache_find_server_hash_default(NULL, mc, hash); + } +} + +APR_DECLARE(apr_memcache_server_t *) +apr_memcache_find_server_hash_default(void *baton, apr_memcache_t *mc, + const apr_uint32_t hash) +{ + apr_memcache_server_t *ms = NULL; + apr_uint32_t h = hash ? hash : 1; + apr_uint32_t i = 0; + apr_time_t curtime = 0; + + if(mc->ntotal == 0) { + return NULL; + } + + do { + ms = mc->live_servers[h % mc->ntotal]; + if(ms->status == APR_MC_SERVER_LIVE) { + break; + } + else { + if (curtime == 0) { + curtime = apr_time_now(); + } +#if APR_HAS_THREADS + apr_thread_mutex_lock(ms->lock); +#endif + /* Try the dead server, every 5 seconds */ + if (curtime - ms->btime > apr_time_from_sec(5)) { + ms->btime = curtime; + if (mc_version_ping(ms) == APR_SUCCESS) { + make_server_live(mc, ms); +#if APR_HAS_THREADS + apr_thread_mutex_unlock(ms->lock); +#endif + break; + } + } +#if APR_HAS_THREADS + apr_thread_mutex_unlock(ms->lock); +#endif + } + h++; + i++; + } while(i < mc->ntotal); + + if (i == mc->ntotal) { + ms = NULL; + } + + return ms; +} + +APR_DECLARE(apr_memcache_server_t *) apr_memcache_find_server(apr_memcache_t *mc, const char *host, apr_port_t port) +{ + int i; + + for (i = 0; i < mc->ntotal; i++) { + if (strcmp(mc->live_servers[i]->host, host) == 0 + && mc->live_servers[i]->port == port) { + + return mc->live_servers[i]; + } + } + + return NULL; +} + +static apr_status_t ms_find_conn(apr_memcache_server_t *ms, apr_memcache_conn_t **conn) +{ + apr_status_t rv; + apr_bucket_alloc_t *balloc; + apr_bucket *e; + +#if APR_HAS_THREADS + rv = apr_reslist_acquire(ms->conns, (void **)conn); +#else + *conn = ms->conn; + rv = APR_SUCCESS; +#endif + + if (rv != APR_SUCCESS) { + return rv; + } + + balloc = apr_bucket_alloc_create((*conn)->tp); + (*conn)->bb = apr_brigade_create((*conn)->tp, balloc); + (*conn)->tb = apr_brigade_create((*conn)->tp, balloc); + + e = apr_bucket_socket_create((*conn)->sock, balloc); + APR_BRIGADE_INSERT_TAIL((*conn)->bb, e); + + return rv; +} + +static apr_status_t ms_bad_conn(apr_memcache_server_t *ms, apr_memcache_conn_t *conn) +{ +#if APR_HAS_THREADS + return apr_reslist_invalidate(ms->conns, conn); +#else + return APR_SUCCESS; +#endif +} + +static apr_status_t ms_release_conn(apr_memcache_server_t *ms, apr_memcache_conn_t *conn) +{ + apr_pool_clear(conn->tp); +#if APR_HAS_THREADS + return apr_reslist_release(ms->conns, conn); +#else + return APR_SUCCESS; +#endif +} + +APR_DECLARE(apr_status_t) apr_memcache_enable_server(apr_memcache_t *mc, apr_memcache_server_t *ms) +{ + apr_status_t rv = APR_SUCCESS; + + if (ms->status == APR_MC_SERVER_LIVE) { + return rv; + } + + rv = make_server_live(mc, ms); + return rv; +} + +APR_DECLARE(apr_status_t) apr_memcache_disable_server(apr_memcache_t *mc, apr_memcache_server_t *ms) +{ + return make_server_dead(mc, ms); +} + +static apr_status_t conn_connect(apr_memcache_conn_t *conn) +{ + apr_status_t rv = APR_SUCCESS; + apr_sockaddr_t *sa; +#if APR_HAVE_SOCKADDR_UN + apr_int32_t family = conn->ms->host[0] != '/' ? APR_INET : APR_UNIX; +#else + apr_int32_t family = APR_INET; +#endif + + rv = apr_sockaddr_info_get(&sa, conn->ms->host, family, conn->ms->port, 0, conn->p); + if (rv != APR_SUCCESS) { + return rv; + } + + rv = apr_socket_timeout_set(conn->sock, 1 * APR_USEC_PER_SEC); + if (rv != APR_SUCCESS) { + return rv; + } + + rv = apr_socket_connect(conn->sock, sa); + if (rv != APR_SUCCESS) { + return rv; + } + + rv = apr_socket_timeout_set(conn->sock, -1); + if (rv != APR_SUCCESS) { + return rv; + } + + return rv; +} + + +static apr_status_t +mc_conn_construct(void **conn_, void *params, apr_pool_t *pool) +{ + apr_status_t rv = APR_SUCCESS; + apr_memcache_conn_t *conn; + apr_pool_t *np; + apr_pool_t *tp; + apr_memcache_server_t *ms = params; +#if APR_HAVE_SOCKADDR_UN + apr_int32_t family = ms->host[0] != '/' ? APR_INET : APR_UNIX; +#else + apr_int32_t family = APR_INET; +#endif + + rv = apr_pool_create(&np, pool); + if (rv != APR_SUCCESS) { + return rv; + } + + rv = apr_pool_create(&tp, np); + if (rv != APR_SUCCESS) { + apr_pool_destroy(np); + return rv; + } + + conn = apr_palloc(np, sizeof( apr_memcache_conn_t )); + + conn->p = np; + conn->tp = tp; + + rv = apr_socket_create(&conn->sock, family, SOCK_STREAM, 0, np); + + if (rv != APR_SUCCESS) { + apr_pool_destroy(np); + return rv; + } + + conn->buffer = apr_palloc(conn->p, BUFFER_SIZE + 1); + conn->blen = 0; + conn->ms = ms; + + rv = conn_connect(conn); + if (rv != APR_SUCCESS) { + apr_pool_destroy(np); + } + else { + *conn_ = conn; + } + + return rv; +} + +#if APR_HAS_THREADS +static apr_status_t +mc_conn_destruct(void *conn_, void *params, apr_pool_t *pool) +{ + apr_memcache_conn_t *conn = (apr_memcache_conn_t*)conn_; + struct iovec vec[2]; + apr_size_t written; + + /* send a quit message to the memcached server to be nice about it. */ + vec[0].iov_base = MC_QUIT; + vec[0].iov_len = MC_QUIT_LEN; + + vec[1].iov_base = MC_EOL; + vec[1].iov_len = MC_EOL_LEN; + + /* Return values not checked, since we just want to make it go away. */ + apr_socket_sendv(conn->sock, vec, 2, &written); + apr_socket_close(conn->sock); + + apr_pool_destroy(conn->p); + + return APR_SUCCESS; +} +#endif + +APR_DECLARE(apr_status_t) apr_memcache_server_create(apr_pool_t *p, + const char *host, apr_port_t port, + apr_uint32_t min, apr_uint32_t smax, + apr_uint32_t max, apr_uint32_t ttl, + apr_memcache_server_t **ms) +{ + apr_status_t rv = APR_SUCCESS; + apr_memcache_server_t *server; + apr_pool_t *np; + + rv = apr_pool_create(&np, p); + if (rv != APR_SUCCESS) { + return rv; + } + + server = apr_palloc(np, sizeof(apr_memcache_server_t)); + + server->p = np; + server->host = apr_pstrdup(np, host); + server->port = port; + server->status = APR_MC_SERVER_DEAD; +#if APR_HAS_THREADS + rv = apr_thread_mutex_create(&server->lock, APR_THREAD_MUTEX_DEFAULT, np); + if (rv != APR_SUCCESS) { + return rv; + } + + rv = apr_reslist_create(&server->conns, + min, /* hard minimum */ + smax, /* soft maximum */ + max, /* hard maximum */ + ttl, /* Time to live */ + mc_conn_construct, /* Make a New Connection */ + mc_conn_destruct, /* Kill Old Connection */ + server, np); + if (rv != APR_SUCCESS) { + return rv; + } + + apr_reslist_cleanup_order_set(server->conns, APR_RESLIST_CLEANUP_FIRST); +#else + rv = mc_conn_construct((void**)&(server->conn), server, np); + if (rv != APR_SUCCESS) { + return rv; + } +#endif + + *ms = server; + + return rv; +} + +APR_DECLARE(apr_status_t) apr_memcache_create(apr_pool_t *p, + apr_uint16_t max_servers, apr_uint32_t flags, + apr_memcache_t **memcache) +{ + apr_status_t rv = APR_SUCCESS; + apr_memcache_t *mc; + + mc = apr_palloc(p, sizeof(apr_memcache_t)); + mc->p = p; + mc->nalloc = max_servers; + mc->ntotal = 0; + mc->live_servers = apr_palloc(p, mc->nalloc * sizeof(struct apr_memcache_server_t *)); + mc->hash_func = NULL; + mc->hash_baton = NULL; + mc->server_func = NULL; + mc->server_baton = NULL; + *memcache = mc; + return rv; +} + + +/* The crc32 functions and data was originally written by Spencer + * Garrett <srg@quick.com> and was gleaned from the PostgreSQL source + * tree via the files contrib/ltree/crc32.[ch] and from FreeBSD at + * src/usr.bin/cksum/crc32.c. + */ + +static const apr_uint32_t crc32tab[256] = { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, + 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, + 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, + 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, + 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, + 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, + 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, + 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, + 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, + 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, + 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, + 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, + 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, + 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, + 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, + 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, + 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, + 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, + 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, + 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, + 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, + 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, + 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, + 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, + 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, + 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, + 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, + 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, + 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, + 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, + 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, + 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, + 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, + 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, + 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, + 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, + 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, + 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, + 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, + 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, + 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, + 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, + 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, + 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, + 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, + 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, + 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, + 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d, +}; + +APR_DECLARE(apr_uint32_t) apr_memcache_hash_crc32(void *baton, + const char *data, + const apr_size_t data_len) +{ + apr_uint32_t i; + apr_uint32_t crc; + crc = ~0; + + for (i = 0; i < data_len; i++) + crc = (crc >> 8) ^ crc32tab[(crc ^ (data[i])) & 0xff]; + + return ~crc; +} + +APR_DECLARE(apr_uint32_t) apr_memcache_hash_default(void *baton, + const char *data, + const apr_size_t data_len) +{ + /* The default Perl Client doesn't actually use just crc32 -- it shifts it again + * like this.... + */ + return ((apr_memcache_hash_crc32(baton, data, data_len) >> 16) & 0x7fff); +} + +APR_DECLARE(apr_uint32_t) apr_memcache_hash(apr_memcache_t *mc, + const char *data, + const apr_size_t data_len) +{ + if (mc->hash_func) { + return mc->hash_func(mc->hash_baton, data, data_len); + } + else { + return apr_memcache_hash_default(NULL, data, data_len); + } +} + +static apr_status_t get_server_line(apr_memcache_conn_t *conn) +{ + apr_size_t bsize = BUFFER_SIZE; + apr_status_t rv = APR_SUCCESS; + + rv = apr_brigade_split_line(conn->tb, conn->bb, APR_BLOCK_READ, BUFFER_SIZE); + + if (rv != APR_SUCCESS) { + return rv; + } + + rv = apr_brigade_flatten(conn->tb, conn->buffer, &bsize); + + if (rv != APR_SUCCESS) { + return rv; + } + + conn->blen = bsize; + conn->buffer[bsize] = '\0'; + + return apr_brigade_cleanup(conn->tb); +} + +static apr_status_t storage_cmd_write(apr_memcache_t *mc, + char *cmd, + const apr_size_t cmd_size, + const char *key, + char *data, + const apr_size_t data_size, + apr_uint32_t timeout, + apr_uint16_t flags) +{ + apr_uint32_t hash; + apr_memcache_server_t *ms; + apr_memcache_conn_t *conn; + apr_status_t rv; + apr_size_t written; + struct iovec vec[5]; + apr_size_t klen; + + apr_size_t key_size = strlen(key); + + hash = apr_memcache_hash(mc, key, key_size); + + ms = apr_memcache_find_server_hash(mc, hash); + + if (ms == NULL) + return APR_NOTFOUND; + + rv = ms_find_conn(ms, &conn); + + if (rv != APR_SUCCESS) { + apr_memcache_disable_server(mc, ms); + return rv; + } + + /* <command name> <key> <flags> <exptime> <bytes>\r\n<data>\r\n */ + + vec[0].iov_base = cmd; + vec[0].iov_len = cmd_size; + + vec[1].iov_base = (void*)key; + vec[1].iov_len = key_size; + + klen = apr_snprintf(conn->buffer, BUFFER_SIZE, " %u %u %" APR_SIZE_T_FMT " " MC_EOL, + flags, timeout, data_size); + + vec[2].iov_base = conn->buffer; + vec[2].iov_len = klen; + + vec[3].iov_base = data; + vec[3].iov_len = data_size; + + vec[4].iov_base = MC_EOL; + vec[4].iov_len = MC_EOL_LEN; + + rv = apr_socket_sendv(conn->sock, vec, 5, &written); + + if (rv != APR_SUCCESS) { + ms_bad_conn(ms, conn); + apr_memcache_disable_server(mc, ms); + return rv; + } + + rv = get_server_line(conn); + + if (rv != APR_SUCCESS) { + ms_bad_conn(ms, conn); + apr_memcache_disable_server(mc, ms); + return rv; + } + + if (strcmp(conn->buffer, MS_STORED MC_EOL) == 0) { + rv = APR_SUCCESS; + } + else if (strcmp(conn->buffer, MS_NOT_STORED MC_EOL) == 0) { + rv = APR_EEXIST; + } + else { + rv = APR_EGENERAL; + } + + ms_release_conn(ms, conn); + + return rv; +} + +APR_DECLARE(apr_status_t) +apr_memcache_set(apr_memcache_t *mc, + const char *key, + char *data, + const apr_size_t data_size, + apr_uint32_t timeout, + apr_uint16_t flags) +{ + return storage_cmd_write(mc, + MC_SET, MC_SET_LEN, + key, + data, data_size, + timeout, flags); +} + +APR_DECLARE(apr_status_t) +apr_memcache_add(apr_memcache_t *mc, + const char *key, + char *data, + const apr_size_t data_size, + apr_uint32_t timeout, + apr_uint16_t flags) +{ + return storage_cmd_write(mc, + MC_ADD, MC_ADD_LEN, + key, + data, data_size, + timeout, flags); +} + +APR_DECLARE(apr_status_t) +apr_memcache_replace(apr_memcache_t *mc, + const char *key, + char *data, + const apr_size_t data_size, + apr_uint32_t timeout, + apr_uint16_t flags) +{ + return storage_cmd_write(mc, + MC_REPLACE, MC_REPLACE_LEN, + key, + data, data_size, + timeout, flags); + +} + +/* + * Parses a decimal size from size_str, returning the value in *size. + * Returns 1 if parsing was successful, 0 if parsing failed. + */ +static int parse_size(const char *size_str, apr_size_t *size) +{ + char *endptr; + long size_as_long; + + errno = 0; + size_as_long = strtol(size_str, &endptr, 10); + if ((size_as_long < 0) || (errno != 0) || (endptr == size_str) || + (endptr[0] != ' ' && (endptr[0] != '\r' || endptr[1] != '\n'))) { + return 0; + } + + *size = (unsigned long)size_as_long; + return 1; +} + +APR_DECLARE(apr_status_t) +apr_memcache_getp(apr_memcache_t *mc, + apr_pool_t *p, + const char *key, + char **baton, + apr_size_t *new_length, + apr_uint16_t *flags_) +{ + apr_status_t rv; + apr_memcache_server_t *ms; + apr_memcache_conn_t *conn; + apr_uint32_t hash; + apr_size_t written; + apr_size_t klen = strlen(key); + struct iovec vec[3]; + + hash = apr_memcache_hash(mc, key, klen); + ms = apr_memcache_find_server_hash(mc, hash); + if (ms == NULL) + return APR_NOTFOUND; + + rv = ms_find_conn(ms, &conn); + + if (rv != APR_SUCCESS) { + apr_memcache_disable_server(mc, ms); + return rv; + } + + /* get <key>[ <key>[...]]\r\n */ + vec[0].iov_base = MC_GET; + vec[0].iov_len = MC_GET_LEN; + + vec[1].iov_base = (void*)key; + vec[1].iov_len = klen; + + vec[2].iov_base = MC_EOL; + vec[2].iov_len = MC_EOL_LEN; + + rv = apr_socket_sendv(conn->sock, vec, 3, &written); + + if (rv != APR_SUCCESS) { + ms_bad_conn(ms, conn); + apr_memcache_disable_server(mc, ms); + return rv; + } + + rv = get_server_line(conn); + if (rv != APR_SUCCESS) { + ms_bad_conn(ms, conn); + apr_memcache_disable_server(mc, ms); + return rv; + } + + if (strncmp(MS_VALUE, conn->buffer, MS_VALUE_LEN) == 0) { + char *flags; + char *length; + char *last; + apr_size_t len = 0; + + apr_strtok(conn->buffer, " ", &last); + apr_strtok(NULL, " ", &last); + flags = apr_strtok(NULL, " ", &last); + + if (flags_) { + *flags_ = atoi(flags); + } + + length = apr_strtok(NULL, " ", &last); + if (!length || !parse_size(length, &len)) { + ms_bad_conn(ms, conn); + apr_memcache_disable_server(mc, ms); + return APR_EGENERAL; + } + else { + apr_bucket_brigade *bbb; + apr_bucket *e; + + /* eat the trailing \r\n */ + rv = apr_brigade_partition(conn->bb, len+2, &e); + if (rv != APR_SUCCESS) { + ms_bad_conn(ms, conn); + apr_memcache_disable_server(mc, ms); + return rv; + } + + bbb = apr_brigade_split(conn->bb, e); + + rv = apr_brigade_pflatten(conn->bb, baton, &len, p); + if (rv != APR_SUCCESS) { + ms_bad_conn(ms, conn); + return rv; + } + + rv = apr_brigade_destroy(conn->bb); + if (rv != APR_SUCCESS) { + ms_bad_conn(ms, conn); + return rv; + } + + conn->bb = bbb; + + *new_length = len - 2; + (*baton)[*new_length] = '\0'; + } + + rv = get_server_line(conn); + if (rv != APR_SUCCESS) { + ms_bad_conn(ms, conn); + apr_memcache_disable_server(mc, ms); + return rv; + } + + if (strncmp(MS_END, conn->buffer, MS_END_LEN) != 0) { + ms_bad_conn(ms, conn); + apr_memcache_disable_server(mc, ms); + return APR_EGENERAL; + } + } + else if (strncmp(MS_END, conn->buffer, MS_END_LEN) == 0) { + rv = APR_NOTFOUND; + } + else { + ms_bad_conn(ms, conn); + apr_memcache_disable_server(mc, ms); + return APR_EGENERAL; + } + + ms_release_conn(ms, conn); + + return rv; +} + +APR_DECLARE(apr_status_t) +apr_memcache_delete(apr_memcache_t *mc, + const char *key, + apr_uint32_t timeout) +{ + apr_status_t rv; + apr_memcache_server_t *ms; + apr_memcache_conn_t *conn; + apr_uint32_t hash; + apr_size_t written; + struct iovec vec[3]; + apr_size_t klen = strlen(key); + + hash = apr_memcache_hash(mc, key, klen); + ms = apr_memcache_find_server_hash(mc, hash); + if (ms == NULL) + return APR_NOTFOUND; + + rv = ms_find_conn(ms, &conn); + + if (rv != APR_SUCCESS) { + apr_memcache_disable_server(mc, ms); + return rv; + } + + /* delete <key> <time>\r\n */ + vec[0].iov_base = MC_DELETE; + vec[0].iov_len = MC_DELETE_LEN; + + vec[1].iov_base = (void*)key; + vec[1].iov_len = klen; + + klen = apr_snprintf(conn->buffer, BUFFER_SIZE, " %u" MC_EOL, timeout); + + vec[2].iov_base = conn->buffer; + vec[2].iov_len = klen; + + rv = apr_socket_sendv(conn->sock, vec, 3, &written); + + if (rv != APR_SUCCESS) { + ms_bad_conn(ms, conn); + apr_memcache_disable_server(mc, ms); + return rv; + } + + rv = get_server_line(conn); + if (rv != APR_SUCCESS) { + ms_bad_conn(ms, conn); + apr_memcache_disable_server(mc, ms); + return rv; + } + + if (strncmp(MS_DELETED, conn->buffer, MS_DELETED_LEN) == 0) { + rv = APR_SUCCESS; + } + else if (strncmp(MS_NOT_FOUND, conn->buffer, MS_NOT_FOUND_LEN) == 0) { + rv = APR_NOTFOUND; + } + else { + rv = APR_EGENERAL; + } + + ms_release_conn(ms, conn); + + return rv; +} + +static apr_status_t num_cmd_write(apr_memcache_t *mc, + char *cmd, + const apr_uint32_t cmd_size, + const char *key, + const apr_int32_t inc, + apr_uint32_t *new_value) +{ + apr_status_t rv; + apr_memcache_server_t *ms; + apr_memcache_conn_t *conn; + apr_uint32_t hash; + apr_size_t written; + struct iovec vec[3]; + apr_size_t klen = strlen(key); + + hash = apr_memcache_hash(mc, key, klen); + ms = apr_memcache_find_server_hash(mc, hash); + if (ms == NULL) + return APR_NOTFOUND; + + rv = ms_find_conn(ms, &conn); + + if (rv != APR_SUCCESS) { + apr_memcache_disable_server(mc, ms); + return rv; + } + + /* <cmd> <key> <value>\r\n */ + vec[0].iov_base = cmd; + vec[0].iov_len = cmd_size; + + vec[1].iov_base = (void*)key; + vec[1].iov_len = klen; + + klen = apr_snprintf(conn->buffer, BUFFER_SIZE, " %u" MC_EOL, inc); + + vec[2].iov_base = conn->buffer; + vec[2].iov_len = klen; + + rv = apr_socket_sendv(conn->sock, vec, 3, &written); + + if (rv != APR_SUCCESS) { + ms_bad_conn(ms, conn); + apr_memcache_disable_server(mc, ms); + return rv; + } + + rv = get_server_line(conn); + if (rv != APR_SUCCESS) { + ms_bad_conn(ms, conn); + apr_memcache_disable_server(mc, ms); + return rv; + } + + if (strncmp(MS_ERROR, conn->buffer, MS_ERROR_LEN) == 0) { + rv = APR_EGENERAL; + } + else if (strncmp(MS_NOT_FOUND, conn->buffer, MS_NOT_FOUND_LEN) == 0) { + rv = APR_NOTFOUND; + } + else { + if (new_value) { + *new_value = atoi(conn->buffer); + } + rv = APR_SUCCESS; + } + + ms_release_conn(ms, conn); + + return rv; +} + +APR_DECLARE(apr_status_t) +apr_memcache_incr(apr_memcache_t *mc, + const char *key, + apr_int32_t inc, + apr_uint32_t *new_value) +{ + return num_cmd_write(mc, + MC_INCR, + MC_INCR_LEN, + key, + inc, + new_value); +} + + +APR_DECLARE(apr_status_t) +apr_memcache_decr(apr_memcache_t *mc, + const char *key, + apr_int32_t inc, + apr_uint32_t *new_value) +{ + return num_cmd_write(mc, + MC_DECR, + MC_DECR_LEN, + key, + inc, + new_value); +} + + + +APR_DECLARE(apr_status_t) +apr_memcache_version(apr_memcache_server_t *ms, + apr_pool_t *p, + char **baton) +{ + apr_status_t rv; + apr_memcache_conn_t *conn; + apr_size_t written; + struct iovec vec[2]; + + rv = ms_find_conn(ms, &conn); + + if (rv != APR_SUCCESS) { + return rv; + } + + /* version\r\n */ + vec[0].iov_base = MC_VERSION; + vec[0].iov_len = MC_VERSION_LEN; + + vec[1].iov_base = MC_EOL; + vec[1].iov_len = MC_EOL_LEN; + + rv = apr_socket_sendv(conn->sock, vec, 2, &written); + + if (rv != APR_SUCCESS) { + ms_bad_conn(ms, conn); + return rv; + } + + rv = get_server_line(conn); + if (rv != APR_SUCCESS) { + ms_bad_conn(ms, conn); + return rv; + } + + if (strncmp(MS_VERSION, conn->buffer, MS_VERSION_LEN) == 0) { + *baton = apr_pstrmemdup(p, conn->buffer+MS_VERSION_LEN+1, + conn->blen - MS_VERSION_LEN - 2); + rv = APR_SUCCESS; + } + else { + rv = APR_EGENERAL; + } + + ms_release_conn(ms, conn); + + return rv; +} + +apr_status_t mc_version_ping(apr_memcache_server_t *ms) +{ + apr_status_t rv; + apr_size_t written; + struct iovec vec[2]; + apr_memcache_conn_t *conn; + + rv = ms_find_conn(ms, &conn); + + if (rv != APR_SUCCESS) { + return rv; + } + + /* version\r\n */ + vec[0].iov_base = MC_VERSION; + vec[0].iov_len = MC_VERSION_LEN; + + vec[1].iov_base = MC_EOL; + vec[1].iov_len = MC_EOL_LEN; + + rv = apr_socket_sendv(conn->sock, vec, 2, &written); + + if (rv != APR_SUCCESS) { + ms_bad_conn(ms, conn); + return rv; + } + + rv = get_server_line(conn); + ms_release_conn(ms, conn); + return rv; +} + + +APR_DECLARE(void) +apr_memcache_add_multget_key(apr_pool_t *data_pool, + const char* key, + apr_hash_t **values) +{ + apr_memcache_value_t* value; + apr_size_t klen = strlen(key); + + /* create the value hash if need be */ + if (!*values) { + *values = apr_hash_make(data_pool); + } + + /* init key and add it to the value hash */ + value = apr_pcalloc(data_pool, sizeof(apr_memcache_value_t)); + + value->status = APR_NOTFOUND; + value->key = apr_pstrdup(data_pool, key); + + apr_hash_set(*values, value->key, klen, value); +} + +static void mget_conn_result(int serverup, + int connup, + apr_status_t rv, + apr_memcache_t *mc, + apr_memcache_server_t *ms, + apr_memcache_conn_t *conn, + struct cache_server_query_t *server_query, + apr_hash_t *values, + apr_hash_t *server_queries) +{ + apr_int32_t j; + apr_memcache_value_t* value; + + apr_hash_set(server_queries, &ms, sizeof(ms), NULL); + + if (connup) { + ms_release_conn(ms, conn); + } else { + ms_bad_conn(ms, conn); + + if (!serverup) { + apr_memcache_disable_server(mc, ms); + } + } + + for (j = 1; j < server_query->query_vec_count ; j+=2) { + if (server_query->query_vec[j].iov_base) { + value = apr_hash_get(values, server_query->query_vec[j].iov_base, + strlen(server_query->query_vec[j].iov_base)); + + if (value->status == APR_NOTFOUND) { + value->status = rv; + } + } + } +} + +APR_DECLARE(apr_status_t) +apr_memcache_multgetp(apr_memcache_t *mc, + apr_pool_t *temp_pool, + apr_pool_t *data_pool, + apr_hash_t *values) +{ + apr_status_t rv; + apr_memcache_server_t* ms; + apr_memcache_conn_t* conn; + apr_uint32_t hash; + apr_size_t written; + apr_size_t klen; + + apr_memcache_value_t* value; + apr_hash_index_t* value_hash_index; + + /* this is a little over aggresive, but beats multiple loops + * to figure out how long each vector needs to be per-server. + */ + apr_int32_t veclen = 2 + 2 * apr_hash_count(values) - 1; /* get <key>[<space><key>...]\r\n */ + apr_int32_t i, j; + apr_int32_t queries_sent; + apr_int32_t queries_recvd; + + apr_hash_t * server_queries = apr_hash_make(temp_pool); + struct cache_server_query_t* server_query; + apr_hash_index_t * query_hash_index; + + apr_pollset_t* pollset; + const apr_pollfd_t* activefds; + apr_pollfd_t* pollfds; + + + /* build all the queries */ + value_hash_index = apr_hash_first(temp_pool, values); + while (value_hash_index) { + void *v; + apr_hash_this(value_hash_index, NULL, NULL, &v); + value = v; + value_hash_index = apr_hash_next(value_hash_index); + klen = strlen(value->key); + + hash = apr_memcache_hash(mc, value->key, klen); + ms = apr_memcache_find_server_hash(mc, hash); + if (ms == NULL) { + continue; + } + + server_query = apr_hash_get(server_queries, &ms, sizeof(ms)); + + if (!server_query) { + rv = ms_find_conn(ms, &conn); + + if (rv != APR_SUCCESS) { + apr_memcache_disable_server(mc, ms); + value->status = rv; + continue; + } + + server_query = apr_pcalloc(temp_pool,sizeof(struct cache_server_query_t)); + + apr_hash_set(server_queries, &ms, sizeof(ms), server_query); + + server_query->ms = ms; + server_query->conn = conn; + server_query->query_vec = apr_pcalloc(temp_pool, sizeof(struct iovec)*veclen); + + /* set up the first key */ + server_query->query_vec[0].iov_base = MC_GET; + server_query->query_vec[0].iov_len = MC_GET_LEN; + + server_query->query_vec[1].iov_base = (void*)(value->key); + server_query->query_vec[1].iov_len = klen; + + server_query->query_vec[2].iov_base = MC_EOL; + server_query->query_vec[2].iov_len = MC_EOL_LEN; + + server_query->query_vec_count = 3; + } + else { + j = server_query->query_vec_count - 1; + + server_query->query_vec[j].iov_base = MC_WS; + server_query->query_vec[j].iov_len = MC_WS_LEN; + j++; + + server_query->query_vec[j].iov_base = (void*)(value->key); + server_query->query_vec[j].iov_len = klen; + j++; + + server_query->query_vec[j].iov_base = MC_EOL; + server_query->query_vec[j].iov_len = MC_EOL_LEN; + j++; + + server_query->query_vec_count = j; + } + } + + /* create polling structures */ + pollfds = apr_pcalloc(temp_pool, apr_hash_count(server_queries) * sizeof(apr_pollfd_t)); + + rv = apr_pollset_create(&pollset, apr_hash_count(server_queries), temp_pool, + APR_POLLSET_NOCOPY); + + if (rv != APR_SUCCESS) { + query_hash_index = apr_hash_first(temp_pool, server_queries); + + while (query_hash_index) { + void *v; + apr_hash_this(query_hash_index, NULL, NULL, &v); + server_query = v; + query_hash_index = apr_hash_next(query_hash_index); + + mget_conn_result(TRUE, TRUE, rv, mc, server_query->ms, server_query->conn, + server_query, values, server_queries); + } + + return rv; + } + + /* send all the queries */ + queries_sent = 0; + query_hash_index = apr_hash_first(temp_pool, server_queries); + + while (query_hash_index) { + void *v; + apr_hash_this(query_hash_index, NULL, NULL, &v); + server_query = v; + query_hash_index = apr_hash_next(query_hash_index); + + conn = server_query->conn; + ms = server_query->ms; + + for (i = 0, rv = APR_SUCCESS; i < veclen && rv == APR_SUCCESS; i += APR_MAX_IOVEC_SIZE) { + rv = apr_socket_sendv(conn->sock, &(server_query->query_vec[i]), + veclen-i>APR_MAX_IOVEC_SIZE ? APR_MAX_IOVEC_SIZE : veclen-i , &written); + } + + if (rv != APR_SUCCESS) { + mget_conn_result(FALSE, FALSE, rv, mc, ms, conn, + server_query, values, server_queries); + continue; + } + + pollfds[queries_sent].desc_type = APR_POLL_SOCKET; + pollfds[queries_sent].reqevents = APR_POLLIN; + pollfds[queries_sent].p = temp_pool; + pollfds[queries_sent].desc.s = conn->sock; + pollfds[queries_sent].client_data = (void *)server_query; + apr_pollset_add (pollset, &pollfds[queries_sent]); + + queries_sent++; + } + + while (queries_sent) { + rv = apr_pollset_poll(pollset, MULT_GET_TIMEOUT, &queries_recvd, &activefds); + + if (rv != APR_SUCCESS) { + /* timeout */ + queries_sent = 0; + continue; + } + for (i = 0; i < queries_recvd; i++) { + server_query = activefds[i].client_data; + conn = server_query->conn; + ms = server_query->ms; + + rv = get_server_line(conn); + + if (rv != APR_SUCCESS) { + apr_pollset_remove (pollset, &activefds[i]); + mget_conn_result(FALSE, FALSE, rv, mc, ms, conn, + server_query, values, server_queries); + queries_sent--; + continue; + } + + if (strncmp(MS_VALUE, conn->buffer, MS_VALUE_LEN) == 0) { + char *key; + char *flags; + char *length; + char *last; + char *data; + apr_size_t len = 0; + apr_bucket *e = NULL; + + apr_strtok(conn->buffer, " ", &last); /* just the VALUE, ignore */ + key = apr_strtok(NULL, " ", &last); + flags = apr_strtok(NULL, " ", &last); + length = apr_strtok(NULL, " ", &last); + + if (!length || !parse_size(length, &len)) { + rv = APR_EGENERAL; + } + else { + /* eat the trailing \r\n */ + rv = apr_brigade_partition(conn->bb, len+2, &e); + } + if (rv != APR_SUCCESS) { + apr_pollset_remove (pollset, &activefds[i]); + mget_conn_result(TRUE, FALSE, rv, mc, ms, conn, + server_query, values, server_queries); + queries_sent--; + continue; + } + + value = apr_hash_get(values, key, strlen(key)); + if (value) { + apr_bucket_brigade *bbb; + + bbb = apr_brigade_split(conn->bb, e); + + rv = apr_brigade_pflatten(conn->bb, &data, &len, data_pool); + if (rv != APR_SUCCESS) { + apr_pollset_remove (pollset, &activefds[i]); + mget_conn_result(TRUE, FALSE, rv, mc, ms, conn, + server_query, values, server_queries); + queries_sent--; + continue; + } + + rv = apr_brigade_destroy(conn->bb); + if (rv != APR_SUCCESS) { + apr_pollset_remove (pollset, &activefds[i]); + mget_conn_result(TRUE, FALSE, rv, mc, ms, conn, + server_query, values, server_queries); + queries_sent--; + continue; + } + + conn->bb = bbb; + + value->len = len - 2; + data[value->len] = '\0'; + value->data = data; + + value->status = rv; + value->flags = atoi(flags); + + /* stay on the server */ + i--; + } + else { + /* Server Sent back a key I didn't ask for or my + * hash is corrupt */ + rv = APR_EGENERAL; + } + } + else if (strncmp(MS_END, conn->buffer, MS_END_LEN) == 0) { + /* this connection is done */ + apr_pollset_remove (pollset, &activefds[i]); + ms_release_conn(ms, conn); + apr_hash_set(server_queries, &ms, sizeof(ms), NULL); + queries_sent--; + } + else { + /* unknown reply? */ + rv = APR_EGENERAL; + } + if (rv != APR_SUCCESS) { + apr_pollset_remove (pollset, &activefds[i]); + mget_conn_result(TRUE, FALSE, rv, mc, ms, conn, + server_query, values, server_queries); + queries_sent--; + } + } /* /for */ + } /* /while */ + + query_hash_index = apr_hash_first(temp_pool, server_queries); + while (query_hash_index) { + void *v; + apr_hash_this(query_hash_index, NULL, NULL, &v); + server_query = v; + query_hash_index = apr_hash_next(query_hash_index); + + conn = server_query->conn; + ms = server_query->ms; + + mget_conn_result(TRUE, (rv == APR_SUCCESS), rv, mc, ms, conn, + server_query, values, server_queries); + continue; + } + + apr_pollset_destroy(pollset); + apr_pool_clear(temp_pool); + return APR_SUCCESS; + +} + + + +/** + * Define all of the strings for stats + */ + +#define STAT_pid MS_STAT " pid " +#define STAT_pid_LEN (sizeof(STAT_pid)-1) + +#define STAT_uptime MS_STAT " uptime " +#define STAT_uptime_LEN (sizeof(STAT_uptime)-1) + +#define STAT_time MS_STAT " time " +#define STAT_time_LEN (sizeof(STAT_time)-1) + +#define STAT_version MS_STAT " version " +#define STAT_version_LEN (sizeof(STAT_version)-1) + +#define STAT_pointer_size MS_STAT " pointer_size " +#define STAT_pointer_size_LEN (sizeof(STAT_pointer_size)-1) + +#define STAT_rusage_user MS_STAT " rusage_user " +#define STAT_rusage_user_LEN (sizeof(STAT_rusage_user)-1) + +#define STAT_rusage_system MS_STAT " rusage_system " +#define STAT_rusage_system_LEN (sizeof(STAT_rusage_system)-1) + +#define STAT_curr_items MS_STAT " curr_items " +#define STAT_curr_items_LEN (sizeof(STAT_curr_items)-1) + +#define STAT_total_items MS_STAT " total_items " +#define STAT_total_items_LEN (sizeof(STAT_total_items)-1) + +#define STAT_bytes MS_STAT " bytes " +#define STAT_bytes_LEN (sizeof(STAT_bytes)-1) + +#define STAT_curr_connections MS_STAT " curr_connections " +#define STAT_curr_connections_LEN (sizeof(STAT_curr_connections)-1) + +#define STAT_total_connections MS_STAT " total_connections " +#define STAT_total_connections_LEN (sizeof(STAT_total_connections)-1) + +#define STAT_connection_structures MS_STAT " connection_structures " +#define STAT_connection_structures_LEN (sizeof(STAT_connection_structures)-1) + +#define STAT_cmd_get MS_STAT " cmd_get " +#define STAT_cmd_get_LEN (sizeof(STAT_cmd_get)-1) + +#define STAT_cmd_set MS_STAT " cmd_set " +#define STAT_cmd_set_LEN (sizeof(STAT_cmd_set)-1) + +#define STAT_get_hits MS_STAT " get_hits " +#define STAT_get_hits_LEN (sizeof(STAT_get_hits)-1) + +#define STAT_get_misses MS_STAT " get_misses " +#define STAT_get_misses_LEN (sizeof(STAT_get_misses)-1) + +#define STAT_evictions MS_STAT " evictions " +#define STAT_evictions_LEN (sizeof(STAT_evictions)-1) + +#define STAT_bytes_read MS_STAT " bytes_read " +#define STAT_bytes_read_LEN (sizeof(STAT_bytes_read)-1) + +#define STAT_bytes_written MS_STAT " bytes_written " +#define STAT_bytes_written_LEN (sizeof(STAT_bytes_written)-1) + +#define STAT_limit_maxbytes MS_STAT " limit_maxbytes " +#define STAT_limit_maxbytes_LEN (sizeof(STAT_limit_maxbytes)-1) + +#define STAT_threads MS_STAT " threads " +#define STAT_threads_LEN (sizeof(STAT_threads)-1) + +static const char *stat_read_string(apr_pool_t *p, char *buf, apr_size_t len) +{ + /* remove trailing \r\n and null char */ + return apr_pstrmemdup(p, buf, len-2); +} + +static apr_uint32_t stat_read_uint32(apr_pool_t *p, char *buf, apr_size_t len) +{ + buf[len-2] = '\0'; + return atoi(buf); +} + +static apr_uint64_t stat_read_uint64(apr_pool_t *p, char *buf, apr_size_t len) +{ + buf[len-2] = '\0'; + return apr_atoi64(buf); +} + +static apr_time_t stat_read_time(apr_pool_t *p, char *buf, apr_size_t len) +{ + buf[len-2] = '\0'; + return apr_time_from_sec(atoi(buf)); +} + +static apr_time_t stat_read_rtime(apr_pool_t *p, char *buf, apr_size_t len) +{ + char *tok; + char *secs; + char *usecs; + const char *sep = ":."; + + buf[len-2] = '\0'; + + secs = apr_strtok(buf, sep, &tok); + usecs = apr_strtok(NULL, sep, &tok); + if (secs && usecs) { + return apr_time_make(atoi(secs), atoi(usecs)); + } + else { + return apr_time_make(0, 0); + } +} + +/** + * I got tired of Typing. Meh. + * + * TODO: Convert it to static tables to make it cooler. + */ + +#define mc_stat_cmp(name) \ + strncmp(STAT_ ## name, conn->buffer, STAT_ ## name ## _LEN) == 0 + +#define mc_stat_str(name) \ + stat_read_string(p, conn->buffer + name, \ + conn->blen - name) + +#define mc_stat_uint32(name) \ + stat_read_uint32(p, conn->buffer + name, \ + conn->blen - name) + +#define mc_stat_uint64(name) \ + stat_read_uint64(p, conn->buffer + name, \ + conn->blen - name) + +#define mc_stat_time(name) \ + stat_read_time(p, conn->buffer + name, \ + conn->blen - name) + +#define mc_stat_rtime(name) \ + stat_read_rtime(p, conn->buffer + name, \ + conn->blen - name) + + +#define mc_do_stat(name, type) \ + if (mc_stat_cmp(name)) { \ + stats-> name = mc_stat_ ## type ((STAT_ ## name ## _LEN)); \ + } + +static void update_stats(apr_pool_t *p, apr_memcache_conn_t *conn, + apr_memcache_stats_t *stats) +{ + + mc_do_stat(version, str) + else mc_do_stat(pid, uint32) + else mc_do_stat(uptime, uint32) + else mc_do_stat(pointer_size, uint32) + else mc_do_stat(time, time) + else mc_do_stat(rusage_user, rtime) + else mc_do_stat(rusage_system, rtime) + else mc_do_stat(curr_items, uint32) + else mc_do_stat(total_items, uint32) + else mc_do_stat(bytes, uint64) + else mc_do_stat(curr_connections, uint32) + else mc_do_stat(total_connections, uint32) + else mc_do_stat(connection_structures, uint32) + else mc_do_stat(cmd_get, uint32) + else mc_do_stat(cmd_set, uint32) + else mc_do_stat(get_hits, uint32) + else mc_do_stat(get_misses, uint32) + else mc_do_stat(evictions, uint64) + else mc_do_stat(bytes_read, uint64) + else mc_do_stat(bytes_written, uint64) + else mc_do_stat(limit_maxbytes, uint32) + else mc_do_stat(threads, uint32) +} + +APR_DECLARE(apr_status_t) +apr_memcache_stats(apr_memcache_server_t *ms, + apr_pool_t *p, + apr_memcache_stats_t **stats) +{ + apr_memcache_stats_t *ret; + apr_status_t rv; + apr_memcache_conn_t *conn; + apr_size_t written; + struct iovec vec[2]; + + rv = ms_find_conn(ms, &conn); + + if (rv != APR_SUCCESS) { + return rv; + } + + /* version\r\n */ + vec[0].iov_base = MC_STATS; + vec[0].iov_len = MC_STATS_LEN; + + vec[1].iov_base = MC_EOL; + vec[1].iov_len = MC_EOL_LEN; + + rv = apr_socket_sendv(conn->sock, vec, 2, &written); + + if (rv != APR_SUCCESS) { + ms_bad_conn(ms, conn); + return rv; + } + + ret = apr_pcalloc(p, sizeof(apr_memcache_stats_t)); + + do { + rv = get_server_line(conn); + if (rv != APR_SUCCESS) { + ms_bad_conn(ms, conn); + return rv; + } + + if (strncmp(MS_END, conn->buffer, MS_END_LEN) == 0) { + rv = APR_SUCCESS; + break; + } + else if (strncmp(MS_STAT, conn->buffer, MS_STAT_LEN) == 0) { + update_stats(p, conn, ret); + continue; + } + else { + rv = APR_EGENERAL; + break; + } + + } while(1); + + ms_release_conn(ms, conn); + + if (stats) { + *stats = ret; + } + + return rv; +} + diff --git a/memory/unix/apr_pools.c b/memory/unix/apr_pools.c index 0d853a730ab..5fa7da1b5be 100644 --- a/memory/unix/apr_pools.c +++ b/memory/unix/apr_pools.c @@ -1,1280 +1,2746 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -/* - * Resource allocation code... the code here is responsible for making - * sure that nothing leaks. - * - * rst --- 4/95 --- 6/95 + * 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_atomic.h" #include "apr_portable.h" /* for get_os_proc */ +#include "apr_strings.h" #include "apr_general.h" #include "apr_pools.h" +#include "apr_allocator.h" #include "apr_lib.h" -#include "apr_lock.h" -#include "misc.h" - -#ifdef HAVE_SYS_STAT_H -#include <sys/stat.h> +#include "apr_thread_mutex.h" +#include "apr_hash.h" +#include "apr_time.h" +#include "apr_support.h" +#define APR_WANT_MEMFUNC +#include "apr_want.h" +#include "apr_env.h" + +#if APR_HAVE_STDLIB_H +#include <stdlib.h> /* for malloc, free and abort */ #endif -#ifdef HAVE_SYS_SIGNAL_H -#include <sys/signal.h> -#endif -#ifdef HAVE_SIGNAL_H -#include <signal.h> -#endif -#ifdef HAVE_SYS_WAIT_H -#include <sys/wait.h> -#endif -#ifdef HAVE_SYS_TYPES_H -#include <sys/types.h> + +#if APR_HAVE_UNISTD_H +#include <unistd.h> /* for getpid and sysconf */ #endif -#ifdef HAVE_UNISTD_H -#include <unistd.h> + +#if APR_ALLOCATOR_GUARD_PAGES && !APR_ALLOCATOR_USES_MMAP +#define APR_ALLOCATOR_USES_MMAP 1 #endif -#ifdef HAVE_FCNTL_H -#include <fcntl.h> + +#if APR_ALLOCATOR_USES_MMAP +#include <sys/mman.h> #endif -#ifdef HAVE_STDLIB_H -#include <stdlib.h> +#if HAVE_VALGRIND +#define REDZONE APR_ALIGN_DEFAULT(8) +int apr_running_on_valgrind = 0; #endif -#ifdef HAVE_MALLOC_H -#include <malloc.h> + +#if APR_POOL_CONCURRENCY_CHECK && !APR_HAS_THREADS +#error pool-concurrency-check does not make sense without threads #endif + /* - * Debugging support: Define this to enable code which helps detect re-use - * of freed memory and other such nonsense. - * - * The theory is simple. The FILL_BYTE (0xa5) is written over all malloc'd - * memory as we receive it, and is written over everything that we free up - * during a clear_pool. We check that blocks on the free list always - * have the FILL_BYTE in them, and we check during palloc() that the bytes - * still have FILL_BYTE in them. If you ever see garbage URLs or whatnot - * containing lots of 0xa5s then you know something used data that's been - * freed or uninitialized. + * Magic numbers */ -/* #define ALLOC_DEBUG */ /* - * Debugging support: If defined all allocations will be done with - * malloc and free()d appropriately at the end. This is intended to be - * used with something like Electric Fence or Purify to help detect - * memory problems. Note that if you're using efence then you should also - * add in ALLOC_DEBUG. But don't add in ALLOC_DEBUG if you're using Purify - * because ALLOC_DEBUG would hide all the uninitialized read errors that - * Purify can diagnose. + * Recycle up to MAX_INDEX in slots, larger indexes go to the + * sink slot at MAX_INDEX, and allocate at least MIN_ALLOC + * bytes (2^order boundaries/pages). */ -/* #define ALLOC_USE_MALLOC */ +#define MAX_INDEX 20 +#define MAX_ORDER 9 +static unsigned int min_order = 1; +#define MIN_ALLOC (BOUNDARY_SIZE << min_order) /* - * Pool debugging support: This is intended to detect cases where the - * wrong pool is used when assigning data to an object in another pool. - * In particular, it causes the table_{set,add,merge}n routines to check - * that their arguments are safe for the ap_table_t they're being placed in. - * It currently only works with the unix multiprocess model, but could - * be extended to others. + * Determines the boundary/page size. */ -/* #define POOL_DEBUG */ +#if defined(_SC_PAGESIZE) || defined(WIN32) +static unsigned int boundary_index; +static unsigned int boundary_size; +#define BOUNDARY_INDEX boundary_index +#define BOUNDARY_SIZE boundary_size +#else /* Assume 4K pages */ +#define BOUNDARY_INDEX 12 +#define BOUNDARY_SIZE (1 << BOUNDARY_INDEX) +#endif -/* - * Provide diagnostic information about make_table() calls which are - * possibly too small. This requires a recent gcc which supports - * __builtin_return_address(). The error_log output will be a - * message such as: - * table_push: ap_table_t created by 0x804d874 hit limit of 10 - * Use "l *0x804d874" to find the source that corresponds to. It - * indicates that a ap_table_t allocated by a call at that address has - * possibly too small an initial ap_table_t size guess. +#if APR_ALLOCATOR_GUARD_PAGES +#if defined(_SC_PAGESIZE) +#define GUARDPAGE_SIZE boundary_size +#else +#error Cannot determine page size +#endif /* _SC_PAGESIZE */ +#else +#define GUARDPAGE_SIZE 0 +#endif /* APR_ALLOCATOR_GUARD_PAGES */ + +/* + * Timing constants for killing subprocesses + * There is a total 3-second delay between sending a SIGINT + * and sending of the final SIGKILL. + * TIMEOUT_INTERVAL should be set to TIMEOUT_USECS / 64 + * for the exponetial timeout alogrithm. */ -/* #define MAKE_TABLE_PROFILE */ +#define TIMEOUT_USECS 3000000 +#define TIMEOUT_INTERVAL 46875 /* - * Provide some statistics on the cost of allocations. It requires a - * bit of an understanding of how alloc.c works. + * Allocator + * + * @note The max_free_index and current_free_index fields are not really + * indices, but quantities of BOUNDARY_SIZE big memory blocks. */ -/* #define ALLOC_STATS */ - -#ifdef POOL_DEBUG -#ifdef ALLOC_USE_MALLOC -#error "sorry, no support for ALLOC_USE_MALLOC and POOL_DEBUG at the same time" -#endif /* ALLOC_USE_MALLOC */ - -#ifdef MULTITHREAD -# error "sorry, no support for MULTITHREAD and POOL_DEBUG at the same time" -#endif /* MULTITHREAD */ -#endif /* POOL_DEBUG */ - -#ifdef ALLOC_USE_MALLOC -#undef BLOCK_MINFREE -#undef BLOCK_MINALLOC -#define BLOCK_MINFREE 0 -#define BLOCK_MINALLOC 0 -#endif /* ALLOC_USE_MALLOC */ +struct apr_allocator_t { + /** largest used index into free[], always < MAX_INDEX */ + apr_size_t max_index; + /** Total size (in BOUNDARY_SIZE multiples) of unused memory before + * blocks are given back. @see apr_allocator_max_free_set(). + * @note Initialized to APR_ALLOCATOR_MAX_FREE_UNLIMITED, + * which means to never give back blocks. + */ + apr_size_t max_free_index; + /** + * Memory size (in BOUNDARY_SIZE multiples) that currently must be freed + * before blocks are given back. Range: 0..max_free_index + */ + apr_size_t current_free_index; +#if APR_HAS_THREADS + apr_thread_mutex_t *mutex; +#endif /* APR_HAS_THREADS */ + apr_pool_t *owner; + /** + * Lists of free nodes. Slot MAX_INDEX is used for oversized nodes, + * and the slots 0..MAX_INDEX-1 contain nodes of sizes + * (i+1) * BOUNDARY_SIZE. Example for BOUNDARY_INDEX == 12: + * slot 0: size 4096 + * slot 1: size 8192 + * slot 2: size 12288 + * ... + * slot 19: size 81920 + * slot 20: nodes larger than 81920 + */ + apr_memnode_t *free[MAX_INDEX + 1]; +}; -#define AP_SLACK_LOW 1 -#define AP_SLACK_HIGH 2 +#define SIZEOF_ALLOCATOR_T APR_ALIGN_DEFAULT(sizeof(apr_allocator_t)) -/***************************************************************** - * - * Managing free storage blocks... +/* + * Allocator */ -union align { - /* - * Types which are likely to have the longest RELEVANT alignment - * restrictions... - */ +static APR_INLINE +void allocator_lock(apr_allocator_t *allocator) +{ +#if APR_HAS_THREADS + if (allocator->mutex) + apr_thread_mutex_lock(allocator->mutex); +#endif /* APR_HAS_THREADS */ +} - char *cp; - void (*f) (void); - long l; - FILE *fp; - double d; -}; +static APR_INLINE +void allocator_unlock(apr_allocator_t *allocator) +{ +#if APR_HAS_THREADS + if (allocator->mutex) + apr_thread_mutex_unlock(allocator->mutex); +#endif /* APR_HAS_THREADS */ +} -#define CLICK_SZ (sizeof(union align)) +APR_DECLARE(apr_status_t) apr_allocator_create(apr_allocator_t **allocator) +{ + apr_allocator_t *new_allocator; -union block_hdr { - union align a; + *allocator = NULL; - /* Actual header... */ + if ((new_allocator = malloc(SIZEOF_ALLOCATOR_T)) == NULL) + return APR_ENOMEM; - struct { - char *endp; - union block_hdr *next; - char *first_avail; -#ifdef POOL_DEBUG - union block_hdr *global_next; - ap_pool_t *owning_pool; -#endif /* POOL_DEBUG */ - } h; -}; + memset(new_allocator, 0, SIZEOF_ALLOCATOR_T); + new_allocator->max_free_index = APR_ALLOCATOR_MAX_FREE_UNLIMITED; -#define APR_ABORT(conditional, retcode, func, str) \ - if (conditional) { \ - if ((func) == NULL) { \ - return NULL; \ - } \ - else { \ - fprintf(stderr, "%s", str); \ - (*(func))(retcode); \ - } \ - } + *allocator = new_allocator; -/* - * Static cells for managing our internal synchronisation. - */ -static union block_hdr *block_freelist = NULL; + return APR_SUCCESS; +} -#if APR_HAS_THREADS -static ap_lock_t *alloc_mutex; -static ap_lock_t *spawn_mutex; +APR_DECLARE(void) apr_allocator_destroy(apr_allocator_t *allocator) +{ + apr_size_t index; + apr_memnode_t *node, **ref; + + for (index = 0; index <= MAX_INDEX; index++) { + ref = &allocator->free[index]; + while ((node = *ref) != NULL) { + *ref = node->next; +#if APR_ALLOCATOR_USES_MMAP + munmap((char *)node - GUARDPAGE_SIZE, + 2 * GUARDPAGE_SIZE + ((node->index+1) << BOUNDARY_INDEX)); +#else + free(node); #endif + } + } -#ifdef POOL_DEBUG -static char *known_stack_point; -static int stack_direction; -static union block_hdr *global_block_list; -#define FREE_POOL ((ap_pool_t *)(-1)) -#endif /* POOL_DEBUG */ - -#ifdef ALLOC_STATS -static unsigned long long num_free_blocks_calls; -static unsigned long long num_blocks_freed; -static unsigned max_blocks_in_one_free; -static unsigned num_malloc_calls; -static unsigned num_malloc_bytes; -#endif /* ALLOC_STATS */ + free(allocator); +} -#ifdef ALLOC_DEBUG -#define FILL_BYTE ((char)(0xa5)) -#define debug_fill(ptr,size) ((void)memset((ptr), FILL_BYTE, (size))) +#if APR_HAS_THREADS +APR_DECLARE(void) apr_allocator_mutex_set(apr_allocator_t *allocator, + apr_thread_mutex_t *mutex) +{ + allocator->mutex = mutex; +} -static APR_INLINE void debug_verify_filled(const char *ptr, const char *endp, - const char *error_msg) +APR_DECLARE(apr_thread_mutex_t *) apr_allocator_mutex_get( + apr_allocator_t *allocator) { - for ( ; ptr < endp; ++ptr) { - if (*ptr != FILL_BYTE) { - fputs(error_msg, stderr); - abort(); - exit(1); - } - } + return allocator->mutex; } +#endif /* APR_HAS_THREADS */ -#else /* ALLOC_DEBUG */ -#define debug_fill(a,b) -#define debug_verify_filled(a,b,c) -#endif /* ALLOC_DEBUG */ +APR_DECLARE(void) apr_allocator_owner_set(apr_allocator_t *allocator, + apr_pool_t *pool) +{ + allocator->owner = pool; +} -/* - * Get a completely new block from the system pool. Note that we rely on - * malloc() to provide aligned memory. - */ +APR_DECLARE(apr_pool_t *) apr_allocator_owner_get(apr_allocator_t *allocator) +{ + return allocator->owner; +} -static union block_hdr *malloc_block(int size, int (*apr_abort)(int retcode)) +APR_DECLARE(void) apr_allocator_max_free_set(apr_allocator_t *allocator, + apr_size_t in_size) { - union block_hdr *blok; + apr_size_t max_free_index; + apr_size_t size = in_size; -#ifdef ALLOC_DEBUG - /* make some room at the end which we'll fill and expect to be - * always filled - */ - size += CLICK_SZ; -#endif /* ALLOC_DEBUG */ + allocator_lock(allocator); -#ifdef ALLOC_STATS - ++num_malloc_calls; - num_malloc_bytes += size + sizeof(union block_hdr); -#endif /* ALLOC_STATS */ + max_free_index = APR_ALIGN(size, BOUNDARY_SIZE) >> BOUNDARY_INDEX; + allocator->current_free_index += max_free_index; + allocator->current_free_index -= allocator->max_free_index; + allocator->max_free_index = max_free_index; + if (allocator->current_free_index > max_free_index) + allocator->current_free_index = max_free_index; - blok = (union block_hdr *) malloc(size + sizeof(union block_hdr)); - APR_ABORT(blok == NULL, APR_ENOMEM, apr_abort, - "Ouch! malloc failed in malloc_block()\n"); - debug_fill(blok, size + sizeof(union block_hdr)); - blok->h.next = NULL; - blok->h.first_avail = (char *) (blok + 1); - blok->h.endp = size + blok->h.first_avail; + allocator_unlock(allocator); +} -#ifdef ALLOC_DEBUG - blok->h.endp -= CLICK_SZ; -#endif /* ALLOC_DEBUG */ +static APR_INLINE +apr_size_t allocator_align(apr_size_t in_size) +{ + apr_size_t size = in_size; -#ifdef POOL_DEBUG - blok->h.global_next = global_block_list; - global_block_list = blok; - blok->h.owning_pool = NULL; -#endif /* POOL_DEBUG */ + /* Round up the block size to the next boundary, but always + * allocate at least a certain size (MIN_ALLOC). + */ + size = APR_ALIGN(size + APR_MEMNODE_T_SIZE, BOUNDARY_SIZE); + if (size < in_size) { + return 0; + } + if (size < MIN_ALLOC) { + size = MIN_ALLOC; + } - return blok; + return size; } - - -#if defined(ALLOC_DEBUG) && !defined(ALLOC_USE_MALLOC) -static void chk_on_blk_list(union block_hdr *blok, union block_hdr *free_blk) +APR_DECLARE(apr_size_t) apr_allocator_align(apr_allocator_t *allocator, + apr_size_t size) { - debug_verify_filled(blok->h.endp, blok->h.endp + CLICK_SZ, - "Ouch! Someone trounced the padding " - "at the end of a block!\n"); - while (free_blk) { - if (free_blk == blok) { - fprintf(stderr, "Ouch! Freeing free block\n"); - abort(); - exit(1); - } - free_blk = free_blk->h.next; - } + (void)allocator; + return allocator_align(size); } -#else /* defined(ALLOC_DEBUG) && !defined(ALLOC_USE_MALLOC) */ -#define chk_on_blk_list(_x, _y) -#endif /* defined(ALLOC_DEBUG) && !defined(ALLOC_USE_MALLOC) */ - -/* Free a chain of blocks --- must be called with alarms blocked. */ -static void free_blocks(union block_hdr *blok) +static APR_INLINE +apr_memnode_t *allocator_alloc(apr_allocator_t *allocator, apr_size_t in_size) { -#ifdef ALLOC_USE_MALLOC - union block_hdr *next; + apr_memnode_t *node, **ref; + apr_size_t max_index, upper_index; + apr_size_t size, i, index; - for ( ; blok; blok = next) { - next = blok->h.next; - free(blok); + /* Round up the block size to the next boundary, but always + * allocate at least a certain size (MIN_ALLOC). + */ + size = allocator_align(in_size); + if (!size) { + return NULL; } -#else /* ALLOC_USE_MALLOC */ -#ifdef ALLOC_STATS - unsigned num_blocks; -#endif /* ALLOC_STATS */ + /* Find the index for this node size by + * dividing its size by the boundary size + */ + index = (size >> BOUNDARY_INDEX) - 1; + + if (index > APR_UINT32_MAX) { + return NULL; + } - /* - * First, put new blocks at the head of the free list --- - * we'll eventually bash the 'next' pointer of the last block - * in the chain to point to the free blocks we already had. + /* First see if there are any nodes in the area we know + * our node will fit into. */ + if (index <= allocator->max_index) { + allocator_lock(allocator); + + /* Walk the free list to see if there are + * any nodes on it of the requested size + * + * If there is no exact match, look for nodes + * of up to twice the requested size, so we + * won't unnecessarily allocate more memory + * nor waste too much of what we have. + * + * NOTE: an optimization would be to check + * allocator->free[index] first and if no + * node is present, directly use + * allocator->free[max_index]. This seems + * like overkill though and could cause + * memory waste. + */ + max_index = allocator->max_index; + upper_index = 2 * index < max_index ? 2 * index : max_index; + ref = &allocator->free[index]; + i = index; + while (*ref == NULL && i < upper_index) { + ref++; + i++; + } - union block_hdr *old_free_list; + if ((node = *ref) != NULL) { + /* If we have found a node and it doesn't have any + * nodes waiting in line behind it _and_ we are on + * the highest available index, find the new highest + * available index + */ + if ((*ref = node->next) == NULL && i >= max_index) { + do { + ref--; + max_index--; + } + while (*ref == NULL && max_index); - if (blok == NULL) { - return; /* Sanity check --- freeing empty pool? */ - } + allocator->max_index = max_index; + } -#if APR_HAS_THREADS - ap_lock(alloc_mutex); -#endif - old_free_list = block_freelist; - block_freelist = blok; + allocator->current_free_index += node->index + 1; + if (allocator->current_free_index > allocator->max_free_index) + allocator->current_free_index = allocator->max_free_index; - /* - * Next, adjust first_avail pointers of each block --- have to do it - * sooner or later, and it simplifies the search in new_block to do it - * now. + allocator_unlock(allocator); + + goto have_node; + } + + allocator_unlock(allocator); + } + + /* If we found nothing, seek the sink (at index MAX_INDEX), if + * it is not empty. */ + else if (allocator->free[MAX_INDEX]) { + allocator_lock(allocator); -#ifdef ALLOC_STATS - num_blocks = 1; -#endif /* ALLOC_STATS */ + /* Walk the free list to see if there are + * any nodes on it of the requested size + */ + ref = &allocator->free[MAX_INDEX]; + while ((node = *ref) != NULL && index > node->index) + ref = &node->next; - while (blok->h.next != NULL) { + if (node) { + *ref = node->next; -#ifdef ALLOC_STATS - ++num_blocks; -#endif /* ALLOC_STATS */ + allocator->current_free_index += node->index + 1; + if (allocator->current_free_index > allocator->max_free_index) + allocator->current_free_index = allocator->max_free_index; - chk_on_blk_list(blok, old_free_list); - blok->h.first_avail = (char *) (blok + 1); - debug_fill(blok->h.first_avail, blok->h.endp - blok->h.first_avail); -#ifdef POOL_DEBUG - blok->h.owning_pool = FREE_POOL; -#endif /* POOL_DEBUG */ - blok = blok->h.next; - } + allocator_unlock(allocator); - chk_on_blk_list(blok, old_free_list); - blok->h.first_avail = (char *) (blok + 1); - debug_fill(blok->h.first_avail, blok->h.endp - blok->h.first_avail); -#ifdef POOL_DEBUG - blok->h.owning_pool = FREE_POOL; -#endif /* POOL_DEBUG */ + goto have_node; + } - /* Finally, reset next pointer to get the old free blocks back */ + allocator_unlock(allocator); + } - blok->h.next = old_free_list; + /* If we haven't got a suitable node, malloc a new one + * and initialize it. + */ +#if APR_ALLOCATOR_GUARD_PAGES + if ((node = mmap(NULL, size + 2 * GUARDPAGE_SIZE, PROT_NONE, + MAP_PRIVATE|MAP_ANON, -1, 0)) == MAP_FAILED) +#elif APR_ALLOCATOR_USES_MMAP + if ((node = mmap(NULL, size, PROT_READ|PROT_WRITE, + MAP_PRIVATE|MAP_ANON, -1, 0)) == MAP_FAILED) +#else + if ((node = malloc(size)) == NULL) +#endif + return NULL; -#ifdef ALLOC_STATS - if (num_blocks > max_blocks_in_one_free) { - max_blocks_in_one_free = num_blocks; +#if APR_ALLOCATOR_GUARD_PAGES + node = (apr_memnode_t *)((char *)node + GUARDPAGE_SIZE); + if (mprotect(node, size, PROT_READ|PROT_WRITE) != 0) { + munmap((char *)node - GUARDPAGE_SIZE, size + 2 * GUARDPAGE_SIZE); + return NULL; } - ++num_free_blocks_calls; - num_blocks_freed += num_blocks; -#endif /* ALLOC_STATS */ +#endif + node->index = index; + node->endp = (char *)node + size; -#if APR_HAS_THREADS - ap_unlock(alloc_mutex); -#endif /* APR_HAS_THREADS */ -#endif /* ALLOC_USE_MALLOC */ -} +have_node: + node->next = NULL; + node->first_avail = (char *)node + APR_MEMNODE_T_SIZE; -/* - * Get a new block, from our own free list if possible, from the system - * if necessary. Must be called with alarms blocked. - */ + APR_VALGRIND_UNDEFINED(node->first_avail, size - APR_MEMNODE_T_SIZE); + + return node; +} -static union block_hdr *new_block(int min_size, int (*apr_abort)(int retcode)) +static APR_INLINE +void allocator_free(apr_allocator_t *allocator, apr_memnode_t *node) { - union block_hdr **lastptr = &block_freelist; - union block_hdr *blok = block_freelist; + apr_memnode_t *next, *freelist = NULL; + apr_size_t index, max_index; + apr_size_t max_free_index, current_free_index; + + allocator_lock(allocator); - /* First, see if we have anything of the required size - * on the free list... + max_index = allocator->max_index; + max_free_index = allocator->max_free_index; + current_free_index = allocator->current_free_index; + + /* Walk the list of submitted nodes and free them one by one, + * shoving them in the right 'size' buckets as we go. */ + do { + next = node->next; + index = node->index; - while (blok != NULL) { - if (min_size + BLOCK_MINFREE <= blok->h.endp - blok->h.first_avail) { - *lastptr = blok->h.next; - blok->h.next = NULL; - debug_verify_filled(blok->h.first_avail, blok->h.endp, - "Ouch! Someone trounced a block " - "on the free list!\n"); - return blok; - } - else { - lastptr = &blok->h.next; - blok = blok->h.next; - } - } + APR_VALGRIND_NOACCESS((char *)node + APR_MEMNODE_T_SIZE, + (node->index+1) << BOUNDARY_INDEX); + + if (max_free_index != APR_ALLOCATOR_MAX_FREE_UNLIMITED + && index + 1 > current_free_index) { + node->next = freelist; + freelist = node; + } + else if (index < MAX_INDEX) { + /* Add the node to the appropriate 'size' bucket. Adjust + * the max_index when appropriate. + */ + if ((node->next = allocator->free[index]) == NULL + && index > max_index) { + max_index = index; + } + allocator->free[index] = node; + if (current_free_index >= index + 1) + current_free_index -= index + 1; + else + current_free_index = 0; + } + else { + /* This node is too large to keep in a specific size bucket, + * just add it to the sink (at index MAX_INDEX). + */ + node->next = allocator->free[MAX_INDEX]; + allocator->free[MAX_INDEX] = node; + if (current_free_index >= index + 1) + current_free_index -= index + 1; + else + current_free_index = 0; + } + } while ((node = next) != NULL); - /* Nope. */ + allocator->max_index = max_index; + allocator->current_free_index = current_free_index; - min_size += BLOCK_MINFREE; - blok = malloc_block((min_size > BLOCK_MINALLOC) - ? min_size : BLOCK_MINALLOC, apr_abort); - return blok; + allocator_unlock(allocator); + + while (freelist != NULL) { + node = freelist; + freelist = node->next; +#if APR_ALLOCATOR_USES_MMAP + munmap((char *)node - GUARDPAGE_SIZE, + 2 * GUARDPAGE_SIZE + ((node->index+1) << BOUNDARY_INDEX)); +#else + free(node); +#endif + } } +APR_DECLARE(apr_memnode_t *) apr_allocator_alloc(apr_allocator_t *allocator, + apr_size_t size) +{ + return allocator_alloc(allocator, size); +} -/* Accounting */ +APR_DECLARE(void) apr_allocator_free(apr_allocator_t *allocator, + apr_memnode_t *node) +{ + allocator_free(allocator, node); +} -static long bytes_in_block_list(union block_hdr *blok) +APR_DECLARE(apr_size_t) apr_allocator_page_size(void) { - long size = 0; + return boundary_size; +} - while (blok) { - size += blok->h.endp - (char *) (blok + 1); - blok = blok->h.next; +APR_DECLARE(apr_status_t) apr_allocator_min_order_set(unsigned int order) +{ + if (order > MAX_ORDER) { + return APR_EINVAL; } - - return size; + min_order = order; + return APR_SUCCESS; } -/***************************************************************** - * - * Pool internals and management... - * NB that subprocesses are not handled by the generic cleanup code, - * basically because we don't want cleanups for multiple subprocesses - * to result in multiple three-second pauses. +/* + * Debug level */ -struct process_chain; -struct cleanup; +#define APR_POOL_DEBUG_GENERAL 0x01 +#define APR_POOL_DEBUG_VERBOSE 0x02 +#define APR_POOL_DEBUG_LIFETIME 0x04 +#define APR_POOL_DEBUG_OWNER 0x08 +#define APR_POOL_DEBUG_VERBOSE_ALLOC 0x10 -static void run_cleanups(struct cleanup *c); -static void free_proc_chain(struct process_chain *p); +#define APR_POOL_DEBUG_VERBOSE_ALL (APR_POOL_DEBUG_VERBOSE \ + | APR_POOL_DEBUG_VERBOSE_ALLOC) -static ap_pool_t *permanent_pool; -/* Each pool structure is allocated in the start of its own first block, - * so we need to know how many bytes that is (once properly aligned...). - * This also means that when a pool's sub-pool is destroyed, the storage - * associated with it is *completely* gone, so we have to make sure it - * gets taken off the parent's sub-pool list... +/* + * Structures */ -#define POOL_HDR_CLICKS (1 + ((sizeof(struct ap_pool_t) - 1) / CLICK_SZ)) -#define POOL_HDR_BYTES (POOL_HDR_CLICKS * CLICK_SZ) +typedef struct cleanup_t cleanup_t; -API_EXPORT(ap_pool_t *) ap_make_sub_pool(ap_pool_t *p, int (*apr_abort)(int retcode)) -{ - union block_hdr *blok; - ap_pool_t *new_pool; +/** A list of processes */ +struct process_chain { + /** The process ID */ + apr_proc_t *proc; + apr_kill_conditions_e kill_how; + /** The next process in the list */ + struct process_chain *next; +}; - ap_block_alarms(); -#if APR_HAS_THREADS - ap_lock(alloc_mutex); -#endif +#if APR_POOL_DEBUG - blok = new_block(POOL_HDR_BYTES, apr_abort); - new_pool = (ap_pool_t *) blok->h.first_avail; - blok->h.first_avail += POOL_HDR_BYTES; -#ifdef POOL_DEBUG - blok->h.owning_pool = new_pool; -#endif +typedef struct debug_node_t debug_node_t; + +struct debug_node_t { + debug_node_t *next; + apr_size_t index; + void *beginp[64]; + void *endp[64]; +}; - memset((char *) new_pool, '\0', sizeof(struct ap_pool_t)); - new_pool->free_first_avail = blok->h.first_avail; - new_pool->first = new_pool->last = blok; +#define SIZEOF_DEBUG_NODE_T APR_ALIGN_DEFAULT(sizeof(debug_node_t)) - if (p) { - new_pool->parent = p; - new_pool->sub_next = p->sub_pools; - if (new_pool->sub_next) { - new_pool->sub_next->sub_prev = new_pool; - } - p->sub_pools = new_pool; - } - else { - permanent_pool = new_pool; - } +#endif /* APR_POOL_DEBUG */ +/* The ref field in the apr_pool_t struct holds a + * pointer to the pointer referencing this pool. + * It is used for parent, child, sibling management. + * Look at apr_pool_create_ex() and apr_pool_destroy() + * to see how it is used. + */ +struct apr_pool_t { + apr_pool_t *parent; + apr_pool_t *child; + apr_pool_t *sibling; + apr_pool_t **ref; + cleanup_t *cleanups; + cleanup_t *free_cleanups; + apr_allocator_t *allocator; + struct process_chain *subprocesses; + apr_abortfunc_t abort_fn; + apr_hash_t *user_data; + const char *tag; + +#if !APR_POOL_DEBUG + apr_memnode_t *active; + apr_memnode_t *self; /* The node containing the pool itself */ + char *self_first_avail; + +#else /* APR_POOL_DEBUG */ + apr_pool_t *joined; /* the caller has guaranteed that this pool + * will survive as long as ->joined */ + debug_node_t *nodes; + const char *file_line; + apr_uint32_t creation_flags; + unsigned int stat_alloc; + unsigned int stat_total_alloc; + unsigned int stat_clear; #if APR_HAS_THREADS - ap_unlock(alloc_mutex); -#endif - ap_unblock_alarms(); + apr_os_thread_t owner; + apr_thread_mutex_t *mutex; +#endif /* APR_HAS_THREADS */ +#endif /* APR_POOL_DEBUG */ +#ifdef NETWARE + apr_os_proc_t owner_proc; +#endif /* defined(NETWARE) */ + cleanup_t *pre_cleanups; +#if APR_POOL_CONCURRENCY_CHECK + +#define IDLE 0 +#define IN_USE 1 +#define DESTROYED 2 + volatile apr_uint32_t in_use; + apr_os_thread_t in_use_by; +#endif /* APR_POOL_CONCURRENCY_CHECK */ +}; - return new_pool; -} +#define SIZEOF_POOL_T APR_ALIGN_DEFAULT(sizeof(apr_pool_t)) -#ifdef POOL_DEBUG -static void stack_var_init(char *s) -{ - char t; - if (s < &t) { - stack_direction = 1; /* stack grows up */ - } - else { - stack_direction = -1; /* stack grows down */ - } -} -#endif +/* + * Variables + */ + +static apr_byte_t apr_pools_initialized = 0; +static apr_pool_t *global_pool = NULL; -#ifdef ALLOC_STATS -static void dump_stats(void) +#if !APR_POOL_DEBUG +static apr_allocator_t *global_allocator = NULL; +#endif /* !APR_POOL_DEBUG */ + +#if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) +static apr_file_t *file_stderr = NULL; +static apr_status_t apr_pool_cleanup_file_stderr(void *data) { - fprintf(stderr, - "alloc_stats: [%d] #free_blocks %llu #blocks %llu max " - "%u #malloc %u #bytes %u\n", - (int) getpid(), - num_free_blocks_calls, - num_blocks_freed, - max_blocks_in_one_free, - num_malloc_calls, - num_malloc_bytes); + file_stderr = NULL; + return APR_SUCCESS; } -#endif -/***************************************************************** - * - * Managing generic cleanups. +#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) */ + +/* + * Local functions */ -struct cleanup { - void *data; - ap_status_t (*plain_cleanup) (void *); - ap_status_t (*child_cleanup) (void *); - struct cleanup *next; -}; +static void run_cleanups(cleanup_t **c); +static void free_proc_chain(struct process_chain *procs); + +#if APR_POOL_DEBUG +static void pool_destroy_debug(apr_pool_t *pool, const char *file_line); +#endif -static void * ap_pool_palloc(ap_pool_t *a, int reqsize, int (*apr_abort)(int retcode)); +#if !APR_POOL_DEBUG +/* + * Initialization + */ -#if 0 -static void ap_register_pool_cleanup(struct ap_pool_t *p, void *data, - ap_status_t (*plain_cleanup) (void *), - ap_status_t (*child_cleanup) (void *)) +APR_DECLARE(apr_status_t) apr_pool_initialize(void) { - struct cleanup *c; + apr_status_t rv; - if (p != NULL) { - c = (struct cleanup *) ap_pool_palloc(p, sizeof(struct cleanup), NULL); - c->data = data; - c->plain_cleanup = plain_cleanup; - c->child_cleanup = child_cleanup; - c->next = p->cleanups; - p->cleanups = c; + if (apr_pools_initialized++) + return APR_SUCCESS; + +#if HAVE_VALGRIND + apr_running_on_valgrind = RUNNING_ON_VALGRIND; +#endif + +#if defined(_SC_PAGESIZE) + boundary_size = sysconf(_SC_PAGESIZE); +#elif defined(WIN32) + { + SYSTEM_INFO si; + GetSystemInfo(&si); + boundary_size = si.dwPageSize; } -} #endif + boundary_index = 12; + while ( (1 << boundary_index) < boundary_size) + boundary_index++; + boundary_size = (1 << boundary_index); + + if ((rv = apr_allocator_create(&global_allocator)) != APR_SUCCESS) { + apr_pools_initialized = 0; + return rv; + } -API_EXPORT(void) ap_register_cleanup(ap_pool_t *p, void *data, - ap_status_t (*plain_cleanup) (void *), - ap_status_t (*child_cleanup) (void *)) -{ - struct cleanup *c; + if ((rv = apr_pool_create_ex(&global_pool, NULL, NULL, + global_allocator)) != APR_SUCCESS) { + apr_allocator_destroy(global_allocator); + global_allocator = NULL; + apr_pools_initialized = 0; + return rv; + } - if (p != NULL) { - c = (struct cleanup *) ap_palloc(p, sizeof(struct cleanup)); - c->data = data; - c->plain_cleanup = plain_cleanup; - c->child_cleanup = child_cleanup; - c->next = p->cleanups; - p->cleanups = c; + apr_pool_tag(global_pool, "apr_global_pool"); + + /* This has to happen here because mutexes might be backed by + * atomics. It used to be snug and safe in apr_initialize(). + * + * Warning: apr_atomic_init() must always be called, by any + * means possible, from apr_initialize(). + */ + if ((rv = apr_atomic_init(global_pool)) != APR_SUCCESS) { + return rv; } -} -API_EXPORT(void) ap_kill_cleanup(ap_pool_t *p, void *data, - ap_status_t (*cleanup) (void *)) -{ - struct cleanup *c; - struct cleanup **lastp; +#if APR_HAS_THREADS + { + apr_thread_mutex_t *mutex; - if (p == NULL) - return; - c = p->cleanups; - lastp = &p->cleanups; - while (c) { - if (c->data == data && c->plain_cleanup == cleanup) { - *lastp = c->next; - break; + if ((rv = apr_thread_mutex_create(&mutex, + APR_THREAD_MUTEX_DEFAULT, + global_pool)) != APR_SUCCESS) { + return rv; } - lastp = &c->next; - c = c->next; + apr_allocator_mutex_set(global_allocator, mutex); } -} +#endif /* APR_HAS_THREADS */ -API_EXPORT(void) ap_run_cleanup(ap_pool_t *p, void *data, - ap_status_t (*cleanup) (void *)) -{ - ap_block_alarms(); /* Run cleanup only once! */ - (*cleanup) (data); - ap_kill_cleanup(p, data, cleanup); - ap_unblock_alarms(); -} + apr_allocator_owner_set(global_allocator, global_pool); -static void run_cleanups(struct cleanup *c) -{ - while (c) { - (*c->plain_cleanup) (c->data); - c = c->next; - } + return APR_SUCCESS; } -static void run_child_cleanups(struct cleanup *c) +APR_DECLARE(void) apr_pool_terminate(void) { - while (c) { - (*c->child_cleanup) (c->data); - c = c->next; - } -} + if (!apr_pools_initialized) + return; -static void cleanup_pool_for_exec(ap_pool_t *p) -{ - run_child_cleanups(p->cleanups); - p->cleanups = NULL; + if (--apr_pools_initialized) + return; - for (p = p->sub_pools; p; p = p->sub_next) { - cleanup_pool_for_exec(p); - } -} + apr_pool_destroy(global_pool); /* This will also destroy the mutex */ + global_pool = NULL; -API_EXPORT(void) ap_cleanup_for_exec(void) -{ -#if !defined(WIN32) && !defined(OS2) - /* - * Don't need to do anything on NT or OS/2, because I - * am actually going to spawn the new process - not - * exec it. All handles that are not inheritable, will - * be automajically closed. The only problem is with - * file handles that are open, but there isn't much - * I can do about that (except if the child decides - * to go out and close them - */ - ap_block_alarms(); - cleanup_pool_for_exec(permanent_pool); - ap_unblock_alarms(); -#endif /* ndef WIN32 */ + global_allocator = NULL; } -API_EXPORT_NONSTD(ap_status_t) ap_null_cleanup(void *data) -{ - /* do nothing cleanup routine */ - return APR_SUCCESS; -} -ap_status_t ap_init_alloc(void) -{ -#if APR_HAS_THREADS - ap_status_t status; -#endif -#ifdef POOL_DEBUG - char s; +/* Node list management helper macros; list_insert() inserts 'node' + * before 'point'. */ +#define list_insert(node, point) do { \ + node->ref = point->ref; \ + *node->ref = node; \ + node->next = point; \ + point->ref = &node->next; \ +} while (0) - known_stack_point = &s; - stack_var_init(&s); -#endif -#if APR_HAS_THREADS - status = ap_create_lock(&alloc_mutex, APR_MUTEX, APR_INTRAPROCESS, - NULL, NULL); - if (status != APR_SUCCESS) { - ap_destroy_lock(alloc_mutex); - return status; - } - status = ap_create_lock(&spawn_mutex, APR_MUTEX, APR_INTRAPROCESS, - NULL, NULL); - if (status != APR_SUCCESS) { - ap_destroy_lock(spawn_mutex); - return status; - } -#endif +/* list_remove() removes 'node' from its list. */ +#define list_remove(node) do { \ + *node->ref = node->next; \ + node->next->ref = node->ref; \ +} while (0) -#ifdef ALLOC_STATS - atexit(dump_stats); -#endif +/* Returns the amount of free space in the given node. */ +#define node_free_space(node_) ((apr_size_t)(node_->endp - node_->first_avail)) - return APR_SUCCESS; -} +/* + * Helpers to mark pool as in-use/free. Used for finding thread-unsafe + * concurrent accesses from different threads. + */ +#if APR_POOL_CONCURRENCY_CHECK -void ap_term_alloc(void) +static const char * const in_use_string[] = { "idle", "in use", "destroyed" }; + +static void pool_concurrency_abort(apr_pool_t *pool, apr_uint32_t new, apr_uint32_t old) { -#if APR_HAS_THREADS - ap_destroy_lock(alloc_mutex); - ap_destroy_lock(spawn_mutex); -#endif + fprintf(stderr, "pool concurrency check: pool %p(%s), thread cur %lx " + "in use by %lx, state %s -> %s \n", + pool, pool->tag, (unsigned long)apr_os_thread_current(), + (unsigned long)pool->in_use_by, + in_use_string[old], in_use_string[new]); + abort(); } -/* We only want to lock the mutex if we are being called from ap_clear_pool. - * This is because if we also call this function from ap_destroy_real_pool, - * which also locks the same mutex, and recursive locks aren't portable. - * This way, we are garaunteed that we only lock this mutex once when calling - * either one of these functions. - */ -API_EXPORT(void) ap_clear_pool(ap_pool_t *a) +static APR_INLINE void pool_concurrency_set_used(apr_pool_t *pool) { - ap_block_alarms(); + apr_uint32_t old; - while (a->sub_pools) { - ap_destroy_pool(a->sub_pools); - } - /* - * Don't hold the mutex during cleanups. - */ - run_cleanups(a->cleanups); - a->cleanups = NULL; - free_proc_chain(a->subprocesses); - a->subprocesses = NULL; - free_blocks(a->first->h.next); - a->first->h.next = NULL; - - a->last = a->first; - a->first->h.first_avail = a->free_first_avail; - debug_fill(a->first->h.first_avail, - a->first->h.endp - a->first->h.first_avail); - -#ifdef ALLOC_USE_MALLOC - { - void *c, *n; + old = apr_atomic_cas32(&pool->in_use, IN_USE, IDLE); - for (c = a->allocation_list; c; c = n) { - n = *(void **)c; - free(c); - } - a->allocation_list = NULL; - } -#endif + if (old != IDLE) + pool_concurrency_abort(pool, IN_USE, old); - ap_unblock_alarms(); + pool->in_use_by = apr_os_thread_current(); } -API_EXPORT(void) ap_destroy_pool(ap_pool_t *a) +static APR_INLINE void pool_concurrency_set_idle(apr_pool_t *pool) { - ap_block_alarms(); - ap_clear_pool(a); -#if APR_HAS_THREADS - ap_lock(alloc_mutex); -#endif + apr_uint32_t old; - if (a->parent) { - if (a->parent->sub_pools == a) { - a->parent->sub_pools = a->sub_next; - } - if (a->sub_prev) { - a->sub_prev->sub_next = a->sub_next; - } - if (a->sub_next) { - a->sub_next->sub_prev = a->sub_prev; - } - } -#if APR_HAS_THREADS - ap_unlock(alloc_mutex); -#endif - free_blocks(a->first); - ap_unblock_alarms(); + old = apr_atomic_cas32(&pool->in_use, IDLE, IN_USE); + + if (old != IN_USE) + pool_concurrency_abort(pool, IDLE, old); } -API_EXPORT(long) ap_bytes_in_pool(ap_pool_t *p) +static APR_INLINE void pool_concurrency_init(apr_pool_t *pool) { - return bytes_in_block_list(p->first); + pool->in_use = IDLE; } -API_EXPORT(long) ap_bytes_in_free_blocks(void) + +static APR_INLINE void pool_concurrency_set_destroyed(apr_pool_t *pool) +{ + apr_uint32_t old; + + old = apr_atomic_cas32(&pool->in_use, DESTROYED, IDLE); + + if (old != IDLE) + pool_concurrency_abort(pool, DESTROYED, old); + pool->in_use_by = apr_os_thread_current(); +} +#else +static APR_INLINE void pool_concurrency_init(apr_pool_t *pool) { } +static APR_INLINE void pool_concurrency_set_used(apr_pool_t *pool) { } +static APR_INLINE void pool_concurrency_set_idle(apr_pool_t *pool) { } +static APR_INLINE void pool_concurrency_set_destroyed(apr_pool_t *pool) { } +#endif /* APR_POOL_CONCURRENCY_CHECK */ + +/* + * Memory allocation + */ + +APR_DECLARE(void *) apr_palloc(apr_pool_t *pool, apr_size_t in_size) +{ + apr_memnode_t *active, *node; + void *mem; + apr_size_t size, free_index; + + pool_concurrency_set_used(pool); + size = APR_ALIGN_DEFAULT(in_size); +#if HAVE_VALGRIND + if (apr_running_on_valgrind) + size += 2 * REDZONE; +#endif + if (size < in_size) { + pool_concurrency_set_idle(pool); + if (pool->abort_fn) + pool->abort_fn(APR_ENOMEM); + + return NULL; + } + active = pool->active; + + /* If the active node has enough bytes left, use it. */ + if (size <= node_free_space(active)) { + mem = active->first_avail; + active->first_avail += size; + goto have_mem; + } + + node = active->next; + if (size <= node_free_space(node)) { + list_remove(node); + } + else { + if ((node = allocator_alloc(pool->allocator, size)) == NULL) { + pool_concurrency_set_idle(pool); + if (pool->abort_fn) + pool->abort_fn(APR_ENOMEM); + + return NULL; + } + } + + node->free_index = 0; + + mem = node->first_avail; + node->first_avail += size; + + list_insert(node, active); + + pool->active = node; + + free_index = (APR_ALIGN(active->endp - active->first_avail + 1, + BOUNDARY_SIZE) - BOUNDARY_SIZE) >> BOUNDARY_INDEX; + + active->free_index = free_index; + node = active->next; + if (free_index >= node->free_index) + goto have_mem; + + do { + node = node->next; + } + while (free_index < node->free_index); + + list_remove(active); + list_insert(active, node); + +have_mem: +#if HAVE_VALGRIND + if (!apr_running_on_valgrind) { + pool_concurrency_set_idle(pool); + return mem; + } + else { + mem = (char *)mem + REDZONE; + VALGRIND_MEMPOOL_ALLOC(pool, mem, in_size); + pool_concurrency_set_idle(pool); + return mem; + } +#else + pool_concurrency_set_idle(pool); + return mem; +#endif +} + +/* Provide an implementation of apr_pcalloc for backward compatibility + * with code built before apr_pcalloc was a macro + */ + +#ifdef apr_pcalloc +#undef apr_pcalloc +#endif + +APR_DECLARE(void *) apr_pcalloc(apr_pool_t *pool, apr_size_t size); +APR_DECLARE(void *) apr_pcalloc(apr_pool_t *pool, apr_size_t size) +{ + void *mem; + + if ((mem = apr_palloc(pool, size)) != NULL) { + memset(mem, 0, size); + } + + return mem; +} + + +/* + * Pool creation/destruction + */ + +APR_DECLARE(void) apr_pool_clear(apr_pool_t *pool) +{ + apr_memnode_t *active; + + /* Run pre destroy cleanups */ + run_cleanups(&pool->pre_cleanups); + + pool_concurrency_set_used(pool); + pool->pre_cleanups = NULL; + pool_concurrency_set_idle(pool); + + /* Destroy the subpools. The subpools will detach themselves from + * this pool thus this loop is safe and easy. + */ + while (pool->child) + apr_pool_destroy(pool->child); + + /* Run cleanups */ + run_cleanups(&pool->cleanups); + + pool_concurrency_set_used(pool); + pool->cleanups = NULL; + pool->free_cleanups = NULL; + + /* Free subprocesses */ + free_proc_chain(pool->subprocesses); + pool->subprocesses = NULL; + + /* Clear the user data. */ + pool->user_data = NULL; + + /* Find the node attached to the pool structure, reset it, make + * it the active node and free the rest of the nodes. + */ + active = pool->active = pool->self; + active->first_avail = pool->self_first_avail; + + APR_IF_VALGRIND(VALGRIND_MEMPOOL_TRIM(pool, pool, 1)); + + if (active->next == active) { + pool_concurrency_set_idle(pool); + return; + } + + *active->ref = NULL; + allocator_free(pool->allocator, active->next); + active->next = active; + active->ref = &active->next; + + pool_concurrency_set_idle(pool); +} + +APR_DECLARE(void) apr_pool_destroy(apr_pool_t *pool) +{ + apr_memnode_t *active; + apr_allocator_t *allocator; + + /* Run pre destroy cleanups */ + run_cleanups(&pool->pre_cleanups); + + pool_concurrency_set_used(pool); + pool->pre_cleanups = NULL; + pool_concurrency_set_idle(pool); + + /* Destroy the subpools. The subpools will detach themselve from + * this pool thus this loop is safe and easy. + */ + while (pool->child) + apr_pool_destroy(pool->child); + + /* Run cleanups */ + run_cleanups(&pool->cleanups); + pool_concurrency_set_destroyed(pool); + + /* Free subprocesses */ + free_proc_chain(pool->subprocesses); + + /* Remove the pool from the parents child list */ + if (pool->parent) { +#if APR_HAS_THREADS + apr_thread_mutex_t *mutex; + + if ((mutex = apr_allocator_mutex_get(pool->parent->allocator)) != NULL) + apr_thread_mutex_lock(mutex); +#endif /* APR_HAS_THREADS */ + + if ((*pool->ref = pool->sibling) != NULL) + pool->sibling->ref = pool->ref; + +#if APR_HAS_THREADS + if (mutex) + apr_thread_mutex_unlock(mutex); +#endif /* APR_HAS_THREADS */ + } + + /* Find the block attached to the pool structure. Save a copy of the + * allocator pointer, because the pool struct soon will be no more. + */ + allocator = pool->allocator; + active = pool->self; + *active->ref = NULL; + +#if APR_HAS_THREADS + if (apr_allocator_owner_get(allocator) == pool) { + /* Make sure to remove the lock, since it is highly likely to + * be invalid now. + */ + apr_allocator_mutex_set(allocator, NULL); + } +#endif /* APR_HAS_THREADS */ + + /* Free all the nodes in the pool (including the node holding the + * pool struct), by giving them back to the allocator. + */ + allocator_free(allocator, active); + + /* If this pool happens to be the owner of the allocator, free + * everything in the allocator (that includes the pool struct + * and the allocator). Don't worry about destroying the optional mutex + * in the allocator, it will have been destroyed by the cleanup function. + */ + if (apr_allocator_owner_get(allocator) == pool) { + apr_allocator_destroy(allocator); + } + APR_IF_VALGRIND(VALGRIND_DESTROY_MEMPOOL(pool)); +} + +APR_DECLARE(apr_status_t) apr_pool_create_ex(apr_pool_t **newpool, + apr_pool_t *parent, + apr_abortfunc_t abort_fn, + apr_allocator_t *allocator) +{ + apr_pool_t *pool; + apr_memnode_t *node; + + *newpool = NULL; + + if (!parent) + parent = global_pool; + + /* parent will always be non-NULL here except the first time a + * pool is created, in which case allocator is guaranteed to be + * non-NULL. */ + + if (!abort_fn && parent) + abort_fn = parent->abort_fn; + + if (allocator == NULL) + allocator = parent->allocator; + + if ((node = allocator_alloc(allocator, + MIN_ALLOC - APR_MEMNODE_T_SIZE)) == NULL) { + if (abort_fn) + abort_fn(APR_ENOMEM); + + return APR_ENOMEM; + } + + node->next = node; + node->ref = &node->next; + +#if HAVE_VALGRIND + if (!apr_running_on_valgrind) { + pool = (apr_pool_t *)node->first_avail; + pool->self_first_avail = (char *)pool + SIZEOF_POOL_T; + } + else { + pool = (apr_pool_t *)(node->first_avail + REDZONE); + pool->self_first_avail = (char *)pool + SIZEOF_POOL_T + 2 * REDZONE; + VALGRIND_MAKE_MEM_NOACCESS(pool->self_first_avail, + node->endp - pool->self_first_avail); + VALGRIND_CREATE_MEMPOOL(pool, REDZONE, 0); + } +#else + pool = (apr_pool_t *)node->first_avail; + pool->self_first_avail = (char *)pool + SIZEOF_POOL_T; +#endif + node->first_avail = pool->self_first_avail; + + pool->allocator = allocator; + pool->active = pool->self = node; + pool->abort_fn = abort_fn; + pool->child = NULL; + pool->cleanups = NULL; + pool->free_cleanups = NULL; + pool->pre_cleanups = NULL; + pool->subprocesses = NULL; + pool->user_data = NULL; + pool->tag = NULL; + +#ifdef NETWARE + pool->owner_proc = (apr_os_proc_t)getnlmhandle(); +#endif /* defined(NETWARE) */ + + if ((pool->parent = parent) != NULL) { +#if APR_HAS_THREADS + apr_thread_mutex_t *mutex; + + if ((mutex = apr_allocator_mutex_get(parent->allocator)) != NULL) + apr_thread_mutex_lock(mutex); +#endif /* APR_HAS_THREADS */ + + if ((pool->sibling = parent->child) != NULL) + pool->sibling->ref = &pool->sibling; + + parent->child = pool; + pool->ref = &parent->child; + +#if APR_HAS_THREADS + if (mutex) + apr_thread_mutex_unlock(mutex); +#endif /* APR_HAS_THREADS */ + } + else { + pool->sibling = NULL; + pool->ref = NULL; + } + + pool_concurrency_init(pool); + + *newpool = pool; + + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_pool_create_unmanaged_ex(apr_pool_t **newpool, + apr_abortfunc_t abort_fn, + apr_allocator_t *allocator) +{ + apr_pool_t *pool; + apr_memnode_t *node; + apr_allocator_t *pool_allocator; + + *newpool = NULL; + + if (!apr_pools_initialized) + return APR_ENOPOOL; + if ((pool_allocator = allocator) == NULL) { + if (apr_allocator_create(&pool_allocator) != APR_SUCCESS) { + if (abort_fn) + abort_fn(APR_ENOMEM); + + return APR_ENOMEM; + } + if ((node = allocator_alloc(pool_allocator, + MIN_ALLOC - APR_MEMNODE_T_SIZE)) == NULL) { + if (abort_fn) + abort_fn(APR_ENOMEM); + + return APR_ENOMEM; + } + } + else if ((node = allocator_alloc(pool_allocator, + MIN_ALLOC - APR_MEMNODE_T_SIZE)) == NULL) { + if (abort_fn) + abort_fn(APR_ENOMEM); + + return APR_ENOMEM; + } + + node->next = node; + node->ref = &node->next; + + pool = (apr_pool_t *)node->first_avail; + node->first_avail = pool->self_first_avail = (char *)pool + SIZEOF_POOL_T; + + pool->allocator = pool_allocator; + pool->active = pool->self = node; + pool->abort_fn = abort_fn; + pool->child = NULL; + pool->cleanups = NULL; + pool->free_cleanups = NULL; + pool->pre_cleanups = NULL; + pool->subprocesses = NULL; + pool->user_data = NULL; + pool->tag = NULL; + pool->parent = NULL; + pool->sibling = NULL; + pool->ref = NULL; + +#ifdef NETWARE + pool->owner_proc = (apr_os_proc_t)getnlmhandle(); +#endif /* defined(NETWARE) */ + if (!allocator) + pool_allocator->owner = pool; + + pool_concurrency_init(pool); + *newpool = pool; + + return APR_SUCCESS; +} + +/* + * "Print" functions + */ + +/* + * apr_psprintf is implemented by writing directly into the current + * block of the pool, starting right at first_avail. If there's + * insufficient room, then a new block is allocated and the earlier + * output is copied over. The new block isn't linked into the pool + * until all the output is done. + * + * Note that this is completely safe because nothing else can + * allocate in this apr_pool_t while apr_psprintf is running. alarms are + * blocked, and the only thing outside of apr_pools.c that's invoked + * is apr_vformatter -- which was purposefully written to be + * self-contained with no callouts. + */ + +struct psprintf_data { + apr_vformatter_buff_t vbuff; + apr_memnode_t *node; + apr_pool_t *pool; + apr_byte_t got_a_new_node; + apr_memnode_t *free; +}; + +#define APR_PSPRINTF_MIN_STRINGSIZE 32 + +static int psprintf_flush(apr_vformatter_buff_t *vbuff) +{ + struct psprintf_data *ps = (struct psprintf_data *)vbuff; + apr_memnode_t *node, *active; + apr_size_t cur_len, size; + char *strp; + apr_pool_t *pool; + apr_size_t free_index; + + pool = ps->pool; + active = ps->node; + strp = ps->vbuff.curpos; + cur_len = strp - active->first_avail; + size = cur_len << 1; + + /* Make sure that we don't try to use a block that has less + * than APR_PSPRINTF_MIN_STRINGSIZE bytes left in it. This + * also catches the case where size == 0, which would result + * in reusing a block that can't even hold the NUL byte. + */ + if (size < APR_PSPRINTF_MIN_STRINGSIZE) + size = APR_PSPRINTF_MIN_STRINGSIZE; + + node = active->next; + if (!ps->got_a_new_node && size <= node_free_space(node)) { + + list_remove(node); + list_insert(node, active); + + node->free_index = 0; + + pool->active = node; + + free_index = (APR_ALIGN(active->endp - active->first_avail + 1, + BOUNDARY_SIZE) - BOUNDARY_SIZE) >> BOUNDARY_INDEX; + + active->free_index = free_index; + node = active->next; + if (free_index < node->free_index) { + do { + node = node->next; + } + while (free_index < node->free_index); + + list_remove(active); + list_insert(active, node); + } + + node = pool->active; + } + else { + if ((node = allocator_alloc(pool->allocator, size)) == NULL) + return -1; + + if (ps->got_a_new_node) { + active->next = ps->free; + ps->free = active; + } + + ps->got_a_new_node = 1; + } + + APR_VALGRIND_UNDEFINED(node->first_avail, + node->endp - node->first_avail); + memcpy(node->first_avail, active->first_avail, cur_len); + APR_VALGRIND_NOACCESS(active->first_avail, + active->endp - active->first_avail); + + ps->node = node; + ps->vbuff.curpos = node->first_avail + cur_len; + ps->vbuff.endpos = node->endp - 1; /* Save a byte for NUL terminator */ + + return 0; +} + +#if HAVE_VALGRIND +static int add_redzone(int (*flush_func)(apr_vformatter_buff_t *b), + struct psprintf_data *ps) +{ + apr_size_t len = ps->vbuff.curpos - ps->node->first_avail + REDZONE; + + while (ps->vbuff.curpos - ps->node->first_avail < len) { + if (ps->vbuff.endpos - ps->node->first_avail >= len) + ps->vbuff.curpos = ps->node->first_avail + len; + else + ps->vbuff.curpos = ps->vbuff.endpos; + + /* + * Prevent valgrind from complaining when psprintf_flush() + * does a memcpy(). The VALGRIND_MEMPOOL_ALLOC() will reset + * the redzone to NOACCESS. + */ + if (ps->vbuff.curpos != ps->node->first_avail) + VALGRIND_MAKE_MEM_DEFINED(ps->node->first_avail, + ps->vbuff.curpos - ps->node->first_avail); + if (ps->vbuff.curpos == ps->vbuff.endpos) { + if (psprintf_flush(&ps->vbuff) == -1) + return -1; + } + } + return 0; +} +#endif + +APR_DECLARE(char *) apr_pvsprintf(apr_pool_t *pool, const char *fmt, va_list ap) +{ + struct psprintf_data ps; + char *strp; + apr_size_t size; + apr_memnode_t *active, *node; + apr_size_t free_index; + + pool_concurrency_set_used(pool); + ps.node = active = pool->active; + ps.pool = pool; + ps.vbuff.curpos = ps.node->first_avail; + + /* Save a byte for the NUL terminator */ + ps.vbuff.endpos = ps.node->endp - 1; + ps.got_a_new_node = 0; + ps.free = NULL; + + /* Make sure that the first node passed to apr_vformatter has at least + * room to hold the NUL terminator. + */ + if (ps.node->first_avail == ps.node->endp) { + if (psprintf_flush(&ps.vbuff) == -1) + goto error; + } +#if HAVE_VALGRIND + if (apr_running_on_valgrind) { + if (add_redzone(psprintf_flush, &ps) == -1) + goto error; + if (!ps.got_a_new_node) { + /* psprintf_flush() has not been called, allow access to our node */ + VALGRIND_MAKE_MEM_UNDEFINED(ps.vbuff.curpos, + ps.node->endp - ps.vbuff.curpos); + } + } +#endif /* HAVE_VALGRIND */ + + if (apr_vformatter(psprintf_flush, &ps.vbuff, fmt, ap) == -1) + goto error; + + *ps.vbuff.curpos++ = '\0'; + +#if HAVE_VALGRIND + if (!apr_running_on_valgrind) { + strp = ps.node->first_avail; + } + else { + if (add_redzone(psprintf_flush, &ps) == -1) + goto error; + if (ps.node->endp != ps.vbuff.curpos) + APR_VALGRIND_NOACCESS(ps.vbuff.curpos, + ps.node->endp - ps.vbuff.curpos); + strp = ps.node->first_avail + REDZONE; + size = ps.vbuff.curpos - strp; + VALGRIND_MEMPOOL_ALLOC(pool, strp, size); + VALGRIND_MAKE_MEM_DEFINED(strp, size); + } +#else + strp = ps.node->first_avail; +#endif + + size = ps.vbuff.curpos - ps.node->first_avail; + size = APR_ALIGN_DEFAULT(size); + ps.node->first_avail += size; + + if (ps.free) + allocator_free(pool->allocator, ps.free); + + /* + * Link the node in if it's a new one + */ + if (!ps.got_a_new_node) { + pool_concurrency_set_idle(pool); + return strp; + } + + active = pool->active; + node = ps.node; + + node->free_index = 0; + + list_insert(node, active); + + pool->active = node; + + free_index = (APR_ALIGN(active->endp - active->first_avail + 1, + BOUNDARY_SIZE) - BOUNDARY_SIZE) >> BOUNDARY_INDEX; + + active->free_index = free_index; + node = active->next; + + if (free_index >= node->free_index) { + pool_concurrency_set_idle(pool); + return strp; + } + + do { + node = node->next; + } + while (free_index < node->free_index); + + list_remove(active); + list_insert(active, node); + + pool_concurrency_set_idle(pool); + return strp; + +error: + pool_concurrency_set_idle(pool); + if (pool->abort_fn) + pool->abort_fn(APR_ENOMEM); + if (ps.got_a_new_node) { + ps.node->next = ps.free; + allocator_free(pool->allocator, ps.node); + } + APR_VALGRIND_NOACCESS(pool->active->first_avail, + pool->active->endp - pool->active->first_avail); + return NULL; +} + + +#else /* APR_POOL_DEBUG */ +/* + * Debug helper functions + */ + + +/* + * Walk the pool tree rooted at pool, depth first. When fn returns + * anything other than 0, abort the traversal and return the value + * returned by fn. + */ +static int apr_pool_walk_tree(apr_pool_t *pool, + int (*fn)(apr_pool_t *pool, void *data), + void *data) +{ + int rv; + apr_pool_t *child; + + rv = fn(pool, data); + if (rv) + return rv; + +#if APR_HAS_THREADS + if (pool->mutex) { + apr_thread_mutex_lock(pool->mutex); + } +#endif /* APR_HAS_THREADS */ + + child = pool->child; + while (child) { + rv = apr_pool_walk_tree(child, fn, data); + if (rv) + break; + + child = child->sibling; + } + +#if APR_HAS_THREADS + if (pool->mutex) { + apr_thread_mutex_unlock(pool->mutex); + } +#endif /* APR_HAS_THREADS */ + + return rv; +} + +#if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) +static void apr_pool_log_event(apr_pool_t *pool, const char *event, + const char *file_line, int deref) +{ + if (file_stderr) { + if (deref) { + apr_file_printf(file_stderr, + "POOL DEBUG: " + "[%lu" +#if APR_HAS_THREADS + "/%lu" +#endif /* APR_HAS_THREADS */ + "] " + "%7s " + "(%10lu/%10lu/%10lu) " + "0x%pp \"%s\" " + "<%s> " + "0x%pp " + "(%u/%u/%u) " + "\n", + (unsigned long)getpid(), +#if APR_HAS_THREADS + (unsigned long)apr_os_thread_current(), +#endif /* APR_HAS_THREADS */ + event, + (unsigned long)apr_pool_num_bytes(pool, 0), + (unsigned long)apr_pool_num_bytes(pool, 1), + (unsigned long)apr_pool_num_bytes(global_pool, 1), + pool, pool->tag, + file_line, + pool->parent, + pool->stat_alloc, pool->stat_total_alloc, pool->stat_clear); + } + else { + apr_file_printf(file_stderr, + "POOL DEBUG: " + "[%lu" +#if APR_HAS_THREADS + "/%lu" +#endif /* APR_HAS_THREADS */ + "] " + "%7s " + " " + "0x%pp " + "<%s> " + "\n", + (unsigned long)getpid(), +#if APR_HAS_THREADS + (unsigned long)apr_os_thread_current(), +#endif /* APR_HAS_THREADS */ + event, + pool, + file_line); + } + } +} +#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) */ + +#if (APR_POOL_DEBUG & APR_POOL_DEBUG_LIFETIME) +static int pool_is_child_of(apr_pool_t *parent, void *data) +{ + apr_pool_t *pool = (apr_pool_t *)data; + + return (pool == parent); +} + +static int apr_pool_is_child_of(apr_pool_t *pool, apr_pool_t *parent) +{ + if (parent == NULL) + return 0; + + return apr_pool_walk_tree(parent, pool_is_child_of, pool); +} +#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_LIFETIME) */ + +static void apr_pool_check_lifetime(apr_pool_t *pool) +{ + /* Rule of thumb: use of the global pool is always + * ok, since the only user is apr_pools.c. Unless + * people have searched for the top level parent and + * started to use that... + */ + if (pool == global_pool || global_pool == NULL) + return; + + /* Lifetime + * This basically checks to see if the pool being used is still + * a relative to the global pool. If not it was previously + * destroyed, in which case we abort(). + */ +#if (APR_POOL_DEBUG & APR_POOL_DEBUG_LIFETIME) + if (!apr_pool_is_child_of(pool, global_pool)) { +#if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) + apr_pool_log_event(pool, "LIFE", + __FILE__ ":apr_pool_integrity check [lifetime]", 0); +#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) */ + abort(); + } +#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_LIFETIME) */ +} + +static void apr_pool_check_owner(apr_pool_t *pool) +{ +#if (APR_POOL_DEBUG & APR_POOL_DEBUG_OWNER) +#if APR_HAS_THREADS + if (!apr_os_thread_equal(pool->owner, apr_os_thread_current())) { +#if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) + apr_pool_log_event(pool, "THREAD", + __FILE__ ":apr_pool_integrity check [owner]", 0); +#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) */ + abort(); + } +#endif /* APR_HAS_THREADS */ +#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_OWNER) */ +} + +static void apr_pool_check_integrity(apr_pool_t *pool) +{ + apr_pool_check_lifetime(pool); + apr_pool_check_owner(pool); +} + +APR_DECLARE(void) apr_pool_owner_set(apr_pool_t *pool, apr_uint32_t flags) +{ +#if APR_HAS_THREADS && (APR_POOL_DEBUG & APR_POOL_DEBUG_OWNER) + pool->owner = apr_os_thread_current(); +#endif +} + +/* + * Initialization (debug) + */ + +APR_DECLARE(apr_status_t) apr_pool_initialize(void) +{ + apr_status_t rv; +#if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) + char *logpath; + apr_file_t *debug_log = NULL; +#endif + + if (apr_pools_initialized++) + return APR_SUCCESS; + +#if defined(_SC_PAGESIZE) + boundary_size = sysconf(_SC_PAGESIZE); +#elif defined(WIN32) + { + SYSTEM_INFO si; + GetSystemInfo(&si); + boundary_size = si.dwPageSize; + } +#endif + boundary_index = 12; + while ( (1 << boundary_index) < boundary_size) + boundary_index++; + boundary_size = (1 << boundary_index); + + /* Since the debug code works a bit differently then the + * regular pools code, we ask for a lock here. The regular + * pools code has got this lock embedded in the global + * allocator, a concept unknown to debug mode. + */ + if ((rv = apr_pool_create_ex(&global_pool, NULL, NULL, + NULL)) != APR_SUCCESS) { + return rv; + } + + apr_pool_tag(global_pool, "APR global pool"); + + apr_pools_initialized = 1; + + /* This has to happen here because mutexes might be backed by + * atomics. It used to be snug and safe in apr_initialize(). + */ + if ((rv = apr_atomic_init(global_pool)) != APR_SUCCESS) { + return rv; + } + +#if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) + rv = apr_env_get(&logpath, "APR_POOL_DEBUG_LOG", global_pool); + + /* Don't pass file_stderr directly to apr_file_open() here, since + * apr_file_open() can call back to apr_pool_log_event() and that + * may attempt to use then then non-NULL but partially set up file + * object. */ + if (rv == APR_SUCCESS) { + apr_file_open(&debug_log, logpath, + APR_FOPEN_APPEND|APR_FOPEN_WRITE|APR_FOPEN_CREATE, + APR_FPROT_OS_DEFAULT, global_pool); + } + else { + apr_file_open_stderr(&debug_log, global_pool); + } + + /* debug_log is now a file handle. */ + file_stderr = debug_log; + + if (file_stderr) { + apr_file_printf(file_stderr, + "POOL DEBUG: [PID" +#if APR_HAS_THREADS + "/TID" +#endif /* APR_HAS_THREADS */ + "] ACTION (SIZE /POOL SIZE /TOTAL SIZE) " + "POOL \"TAG\" <__FILE__:__LINE__> PARENT (ALLOCS/TOTAL ALLOCS/CLEARS)\n"); + + apr_pool_log_event(global_pool, "GLOBAL", __FILE__ ":apr_pool_initialize", 0); + + /* Add a cleanup handler that sets the debug log file handle + * to NULL, otherwise we'll try to log the global pool + * destruction event with predictably disastrous results. */ + apr_pool_cleanup_register(global_pool, NULL, + apr_pool_cleanup_file_stderr, + apr_pool_cleanup_null); + } +#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) */ + + return APR_SUCCESS; +} + +APR_DECLARE(void) apr_pool_terminate(void) +{ + if (!apr_pools_initialized) + return; + + if (--apr_pools_initialized) + return; + + apr_pool_destroy(global_pool); /* This will also destroy the mutex */ + global_pool = NULL; + +#if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) + file_stderr = NULL; +#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) */ +} + + +/* + * Memory allocation (debug) + */ + +static void *pool_alloc(apr_pool_t *pool, apr_size_t size) +{ + debug_node_t *node; + void *mem; + + if ((mem = malloc(size)) == NULL) { + if (pool->abort_fn) + pool->abort_fn(APR_ENOMEM); + + return NULL; + } + + node = pool->nodes; + if (node == NULL || node->index == 64) { + if ((node = malloc(SIZEOF_DEBUG_NODE_T)) == NULL) { + free(mem); + if (pool->abort_fn) + pool->abort_fn(APR_ENOMEM); + + return NULL; + } + + memset(node, 0, SIZEOF_DEBUG_NODE_T); + + node->next = pool->nodes; + pool->nodes = node; + node->index = 0; + } + + node->beginp[node->index] = mem; + node->endp[node->index] = (char *)mem + size; + node->index++; + + pool->stat_alloc++; + pool->stat_total_alloc++; + + return mem; +} + +APR_DECLARE(void *) apr_palloc_debug(apr_pool_t *pool, apr_size_t size, + const char *file_line) +{ + void *mem; + + apr_pool_check_integrity(pool); + + mem = pool_alloc(pool, size); + +#if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALLOC) + apr_pool_log_event(pool, "PALLOC", file_line, 1); +#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALLOC) */ + + return mem; +} + +APR_DECLARE(void *) apr_pcalloc_debug(apr_pool_t *pool, apr_size_t size, + const char *file_line) +{ + void *mem; + + apr_pool_check_integrity(pool); + + mem = pool_alloc(pool, size); + memset(mem, 0, size); + +#if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALLOC) + apr_pool_log_event(pool, "PCALLOC", file_line, 1); +#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALLOC) */ + + return mem; +} + + +/* + * Pool creation/destruction (debug) + */ + +#define POOL_POISON_BYTE 'A' + +static void pool_clear_debug(apr_pool_t *pool, const char *file_line) +{ + debug_node_t *node; + apr_size_t index; + + /* Run pre destroy cleanups */ + run_cleanups(&pool->pre_cleanups); + pool->pre_cleanups = NULL; + + /* + * Now that we have given the pre cleanups the chance to kill of any + * threads using the pool, the owner must be correct. + */ + apr_pool_check_owner(pool); + + /* Destroy the subpools. The subpools will detach themselves from + * this pool thus this loop is safe and easy. + */ + while (pool->child) + pool_destroy_debug(pool->child, file_line); + + /* Run cleanups */ + run_cleanups(&pool->cleanups); + pool->free_cleanups = NULL; + pool->cleanups = NULL; + + /* If new child pools showed up, this is a reason to raise a flag */ + if (pool->child) + abort(); + + /* Free subprocesses */ + free_proc_chain(pool->subprocesses); + pool->subprocesses = NULL; + + /* Clear the user data. */ + pool->user_data = NULL; + + /* Free the blocks, scribbling over them first to help highlight + * use-after-free issues. */ + while ((node = pool->nodes) != NULL) { + pool->nodes = node->next; + + for (index = 0; index < node->index; index++) { + memset(node->beginp[index], POOL_POISON_BYTE, + (char *)node->endp[index] - (char *)node->beginp[index]); + free(node->beginp[index]); + } + + memset(node, POOL_POISON_BYTE, SIZEOF_DEBUG_NODE_T); + free(node); + } + + pool->stat_alloc = 0; + pool->stat_clear++; +} + +APR_DECLARE(void) apr_pool_clear_debug(apr_pool_t *pool, + const char *file_line) +{ +#if APR_HAS_THREADS + apr_thread_mutex_t *mutex = NULL; +#endif + + apr_pool_check_lifetime(pool); + +#if APR_HAS_THREADS + if (pool->parent != NULL) + mutex = pool->parent->mutex; + + /* Lock the parent mutex before clearing so that if we have our + * own mutex it won't be accessed by apr_pool_walk_tree after + * it has been destroyed. + */ + if (mutex != NULL && mutex != pool->mutex) { + apr_thread_mutex_lock(mutex); + } +#endif + + pool_clear_debug(pool, file_line); + +#if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE) + apr_pool_log_event(pool, "CLEAR", file_line, 1); +#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE) */ + +#if APR_HAS_THREADS + /* If we had our own mutex, it will have been destroyed by + * the registered cleanups. Recreate the mutex. Unlock + * the mutex we obtained above. + */ + if (mutex != pool->mutex) { + /* + * Prevent apr_palloc() in apr_thread_mutex_create() from trying to + * use the destroyed mutex. + */ + pool->mutex = NULL; + (void)apr_thread_mutex_create(&pool->mutex, + APR_THREAD_MUTEX_NESTED, pool); + + if (mutex != NULL) + (void)apr_thread_mutex_unlock(mutex); + } +#endif /* APR_HAS_THREADS */ +} + +static void pool_destroy_debug(apr_pool_t *pool, const char *file_line) +{ + apr_pool_check_lifetime(pool); + + pool_clear_debug(pool, file_line); + +#if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE) + apr_pool_log_event(pool, "DESTROY", file_line, 1); +#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE) */ + + /* Remove the pool from the parents child list */ + if (pool->parent) { +#if APR_HAS_THREADS + apr_thread_mutex_t *mutex; + + if ((mutex = pool->parent->mutex) != NULL) + apr_thread_mutex_lock(mutex); +#endif /* APR_HAS_THREADS */ + + if ((*pool->ref = pool->sibling) != NULL) + pool->sibling->ref = pool->ref; + +#if APR_HAS_THREADS + if (mutex) + apr_thread_mutex_unlock(mutex); +#endif /* APR_HAS_THREADS */ + } + + if (pool->allocator != NULL + && apr_allocator_owner_get(pool->allocator) == pool) { + apr_allocator_destroy(pool->allocator); + } + + /* Free the pool itself */ + free(pool); +} + +APR_DECLARE(void) apr_pool_destroy_debug(apr_pool_t *pool, + const char *file_line) +{ + if (pool->joined) { + /* Joined pools must not be explicitly destroyed; the caller + * has broken the guarantee. */ +#if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) + apr_pool_log_event(pool, "LIFE", + __FILE__ ":apr_pool_destroy abort on joined", 0); +#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) */ + + abort(); + } + pool_destroy_debug(pool, file_line); +} + +APR_DECLARE(apr_status_t) apr_pool_create_ex_debug(apr_pool_t **newpool, + apr_pool_t *parent, + apr_abortfunc_t abort_fn, + apr_allocator_t *allocator, + const char *file_line) +{ + apr_pool_t *pool; + + *newpool = NULL; + + if (!parent) { + parent = global_pool; + } + else { + apr_pool_check_lifetime(parent); + + if (!allocator) + allocator = parent->allocator; + } + + if (!abort_fn && parent) + abort_fn = parent->abort_fn; + + if ((pool = malloc(SIZEOF_POOL_T)) == NULL) { + if (abort_fn) + abort_fn(APR_ENOMEM); + + return APR_ENOMEM; + } + + memset(pool, 0, SIZEOF_POOL_T); + + pool->allocator = allocator; + pool->abort_fn = abort_fn; + pool->tag = file_line; + pool->file_line = file_line; + + if ((pool->parent = parent) != NULL) { +#if APR_HAS_THREADS + if (parent->mutex) + apr_thread_mutex_lock(parent->mutex); +#endif /* APR_HAS_THREADS */ + if ((pool->sibling = parent->child) != NULL) + pool->sibling->ref = &pool->sibling; + + parent->child = pool; + pool->ref = &parent->child; + +#if APR_HAS_THREADS + if (parent->mutex) + apr_thread_mutex_unlock(parent->mutex); +#endif /* APR_HAS_THREADS */ + } + else { + pool->sibling = NULL; + pool->ref = NULL; + } + +#if APR_HAS_THREADS + pool->owner = apr_os_thread_current(); +#endif /* APR_HAS_THREADS */ +#ifdef NETWARE + pool->owner_proc = (apr_os_proc_t)getnlmhandle(); +#endif /* defined(NETWARE) */ + +#if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE) + apr_pool_log_event(pool, "CREATE", file_line, 1); +#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE) */ + + if (parent == NULL || parent->allocator != allocator) { +#if APR_HAS_THREADS + apr_status_t rv; + + /* No matter what the creation flags say, always create + * a lock. Without it integrity_check and apr_pool_num_bytes + * blow up (because they traverse pools child lists that + * possibly belong to another thread, in combination with + * the pool having no lock). However, this might actually + * hide problems like creating a child pool of a pool + * belonging to another thread. + */ + if ((rv = apr_thread_mutex_create(&pool->mutex, + APR_THREAD_MUTEX_NESTED, pool)) != APR_SUCCESS) { + free(pool); + return rv; + } +#endif /* APR_HAS_THREADS */ + } + else { +#if APR_HAS_THREADS + if (parent) + pool->mutex = parent->mutex; +#endif /* APR_HAS_THREADS */ + } + + *newpool = pool; + + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_pool_create_unmanaged_ex_debug(apr_pool_t **newpool, + apr_abortfunc_t abort_fn, + apr_allocator_t *allocator, + const char *file_line) +{ + apr_pool_t *pool; + apr_allocator_t *pool_allocator; + + *newpool = NULL; + + if ((pool = malloc(SIZEOF_POOL_T)) == NULL) { + if (abort_fn) + abort_fn(APR_ENOMEM); + + return APR_ENOMEM; + } + + memset(pool, 0, SIZEOF_POOL_T); + + pool->abort_fn = abort_fn; + pool->tag = file_line; + pool->file_line = file_line; + +#if APR_HAS_THREADS + pool->owner = apr_os_thread_current(); +#endif /* APR_HAS_THREADS */ +#ifdef NETWARE + pool->owner_proc = (apr_os_proc_t)getnlmhandle(); +#endif /* defined(NETWARE) */ + + if ((pool_allocator = allocator) == NULL) { + apr_status_t rv; + if ((rv = apr_allocator_create(&pool_allocator)) != APR_SUCCESS) { + if (abort_fn) + abort_fn(rv); + return rv; + } + pool_allocator->owner = pool; + } + pool->allocator = pool_allocator; + +#if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE) + apr_pool_log_event(pool, "CREATEU", file_line, 1); +#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE) */ + + if (pool->allocator != allocator) { +#if APR_HAS_THREADS + apr_status_t rv; + + /* No matter what the creation flags say, always create + * a lock. Without it integrity_check and apr_pool_num_bytes + * blow up (because they traverse pools child lists that + * possibly belong to another thread, in combination with + * the pool having no lock). However, this might actually + * hide problems like creating a child pool of a pool + * belonging to another thread. + */ + if ((rv = apr_thread_mutex_create(&pool->mutex, + APR_THREAD_MUTEX_NESTED, pool)) != APR_SUCCESS) { + free(pool); + return rv; + } +#endif /* APR_HAS_THREADS */ + } + + *newpool = pool; + + return APR_SUCCESS; +} + +/* + * "Print" functions (debug) + */ + +struct psprintf_data { + apr_vformatter_buff_t vbuff; + char *mem; + apr_size_t size; +}; + +static int psprintf_flush(apr_vformatter_buff_t *vbuff) +{ + struct psprintf_data *ps = (struct psprintf_data *)vbuff; + apr_size_t size; + + size = ps->vbuff.curpos - ps->mem; + + ps->size <<= 1; + if ((ps->mem = realloc(ps->mem, ps->size)) == NULL) + return -1; + + ps->vbuff.curpos = ps->mem + size; + ps->vbuff.endpos = ps->mem + ps->size - 1; + + return 0; +} + +APR_DECLARE(char *) apr_pvsprintf(apr_pool_t *pool, const char *fmt, va_list ap) +{ + struct psprintf_data ps; + debug_node_t *node; + + apr_pool_check_integrity(pool); + + ps.size = 64; + ps.mem = malloc(ps.size); + ps.vbuff.curpos = ps.mem; + + /* Save a byte for the NUL terminator */ + ps.vbuff.endpos = ps.mem + ps.size - 1; + + if (apr_vformatter(psprintf_flush, &ps.vbuff, fmt, ap) == -1) { + if (pool->abort_fn) + pool->abort_fn(APR_ENOMEM); + + return NULL; + } + + *ps.vbuff.curpos++ = '\0'; + + /* + * Link the node in + */ + node = pool->nodes; + if (node == NULL || node->index == 64) { + if ((node = malloc(SIZEOF_DEBUG_NODE_T)) == NULL) { + if (pool->abort_fn) + pool->abort_fn(APR_ENOMEM); + + return NULL; + } + + node->next = pool->nodes; + pool->nodes = node; + node->index = 0; + } + + node->beginp[node->index] = ps.mem; + node->endp[node->index] = ps.mem + ps.size; + node->index++; + + return ps.mem; +} + + +/* + * Debug functions + */ + +APR_DECLARE(void) apr_pool_join(apr_pool_t *p, apr_pool_t *sub) +{ +#if APR_POOL_DEBUG + if (sub->parent != p) { + abort(); + } + sub->joined = p; +#endif +} + +static int pool_find(apr_pool_t *pool, void *data) +{ + void **pmem = (void **)data; + debug_node_t *node; + apr_size_t index; + + node = pool->nodes; + + while (node) { + for (index = 0; index < node->index; index++) { + if (node->beginp[index] <= *pmem + && node->endp[index] > *pmem) { + *pmem = pool; + return 1; + } + } + + node = node->next; + } + + return 0; +} + +APR_DECLARE(apr_pool_t *) apr_pool_find(const void *mem) +{ + void *pool = (void *)mem; + + if (apr_pool_walk_tree(global_pool, pool_find, &pool)) + return pool; + + return NULL; +} + +static int pool_num_bytes(apr_pool_t *pool, void *data) +{ + apr_size_t *psize = (apr_size_t *)data; + debug_node_t *node; + apr_size_t index; + + node = pool->nodes; + + while (node) { + for (index = 0; index < node->index; index++) { + *psize += (char *)node->endp[index] - (char *)node->beginp[index]; + } + + node = node->next; + } + + return 0; +} + +APR_DECLARE(apr_size_t) apr_pool_num_bytes(apr_pool_t *pool, int recurse) +{ + apr_size_t size = 0; + + if (!recurse) { + pool_num_bytes(pool, &size); + + return size; + } + + apr_pool_walk_tree(pool, pool_num_bytes, &size); + + return size; +} + +APR_DECLARE(void) apr_pool_lock(apr_pool_t *pool, int flag) { - return bytes_in_block_list(block_freelist); } -/***************************************************************** - * POOL_DEBUG support - */ -#ifdef POOL_DEBUG +#endif /* !APR_POOL_DEBUG */ + +#ifdef NETWARE +void netware_pool_proc_cleanup () +{ + apr_pool_t *pool = global_pool->child; + apr_os_proc_t owner_proc = (apr_os_proc_t)getnlmhandle(); + + while (pool) { + if (pool->owner_proc == owner_proc) { + apr_pool_destroy (pool); + pool = global_pool->child; + } + else { + pool = pool->sibling; + } + } + return; +} +#endif /* defined(NETWARE) */ + -/* the unix linker defines this symbol as the last byte + 1 of - * the executable... so it includes TEXT, BSS, and DATA +/* + * "Print" functions (common) */ -extern char _end; -/* is ptr in the range [lo,hi) */ -#define is_ptr_in_range(ptr, lo, hi) \ - (((unsigned long)(ptr) - (unsigned long)(lo)) \ - < (unsigned long)(hi) - (unsigned long)(lo)) +APR_DECLARE_NONSTD(char *) apr_psprintf(apr_pool_t *p, const char *fmt, ...) +{ + va_list ap; + char *res; + + va_start(ap, fmt); + res = apr_pvsprintf(p, fmt, ap); + va_end(ap); + return res; +} -/* Find the pool that ts belongs to, return NULL if it doesn't - * belong to any pool. +/* + * Pool Properties */ -API_EXPORT(ap_pool_t *) ap_find_pool(const void *ts, int (apr_abort)(int retcode)) + +APR_DECLARE(void) apr_pool_abort_set(apr_abortfunc_t abort_fn, + apr_pool_t *pool) { - const char *s = ts; - union block_hdr **pb; - union block_hdr *b; + pool->abort_fn = abort_fn; +} - /* short-circuit stuff which is in TEXT, BSS, or DATA */ - if (is_ptr_in_range(s, 0, &_end)) { - return NULL; - } - /* consider stuff on the stack to also be in the NULL pool... - * XXX: there's cases where we don't want to assume this - */ - APR_ABORT((stack_direction == -1 && - is_ptr_in_range(s, &ts, known_stack_point)) || - (stack_direction == 1 && - is_ptr_in_range(s, known_stack_point, &ts)), 1, apr_abort, - "Ouch! find_pool() called on pointer in a free block\n"); - ap_block_alarms(); - /* search the global_block_list */ - for (pb = &global_block_list; *pb; pb = &b->h.global_next) { - b = *pb; - if (is_ptr_in_range(s, b, b->h.endp)) { - if (b->h.owning_pool == FREE_POOL) { - abort(); - exit(1); - } - if (b != global_block_list) { - /* - * promote b to front of list, this is a hack to speed - * up the lookup - */ - *pb = b->h.global_next; - b->h.global_next = global_block_list; - global_block_list = b; - } - ap_unblock_alarms(); - return b->h.owning_pool; - } - } - ap_unblock_alarms(); - return NULL; +APR_DECLARE(apr_abortfunc_t) apr_pool_abort_get(apr_pool_t *pool) +{ + return pool->abort_fn; +} + +APR_DECLARE(apr_pool_t *) apr_pool_parent_get(apr_pool_t *pool) +{ +#ifdef NETWARE + /* On NetWare, don't return the global_pool, return the application pool + as the top most pool */ + if (pool->parent == global_pool) + return pool; + else +#endif + return pool->parent; +} + +APR_DECLARE(apr_allocator_t *) apr_pool_allocator_get(apr_pool_t *pool) +{ + return pool->allocator; } -/* return TRUE iff a is an ancestor of b +/* return TRUE if a is an ancestor of b * NULL is considered an ancestor of all pools */ -API_EXPORT(int) ap_pool_is_ancestor(ap_pool_t *a, ap_pool_t *b) +APR_DECLARE(int) apr_pool_is_ancestor(apr_pool_t *a, apr_pool_t *b) { - if (a == NULL) { - return 1; - } + if (a == NULL) + return 1; + +#if APR_POOL_DEBUG + /* Find the pool with the longest lifetime guaranteed by the + * caller: */ while (a->joined) { - a = a->joined; + a = a->joined; } +#endif + while (b) { - if (a == b) { - return 1; - } - b = b->parent; + if (a == b) + return 1; + + b = b->parent; } + return 0; } -/* - * All blocks belonging to sub will be changed to point to p - * instead. This is a guarantee by the caller that sub will not - * be destroyed before p is. - */ -API_EXPORT(void) ap_pool_join(ap_pool_t *p, ap_pool_t *sub, - int (*apr_abort)(int retcode)) +APR_DECLARE(void) apr_pool_tag(apr_pool_t *pool, const char *tag) { - union block_hdr *b; + pool->tag = tag; +} - /* We could handle more general cases... but this is it for now. */ - APR_ABORT(sub->parent != p, 1, apr_abort, - "pool_join: p is not a parent of sub\n"); - ap_block_alarms(); - while (p->joined) { - p = p->joined; - } - sub->joined = p; - for (b = global_block_list; b; b = b->h.global_next) { - if (b->h.owning_pool == sub) { - b->h.owning_pool = p; - } - } - ap_unblock_alarms(); +APR_DECLARE(const char *) apr_pool_get_tag(apr_pool_t *pool) +{ + return pool->tag; } -#endif -/***************************************************************** - * - * Allocating stuff... +/* + * User data management */ -void * ap_palloc(ap_pool_t *a, int reqsize) +APR_DECLARE(apr_status_t) apr_pool_userdata_set(const void *data, const char *key, + apr_status_t (*cleanup) (void *), + apr_pool_t *pool) { -#ifdef ALLOC_USE_MALLOC - int size = reqsize + CLICK_SZ; - void *ptr; +#if APR_POOL_DEBUG + apr_pool_check_integrity(pool); +#endif /* APR_POOL_DEBUG */ - if (a == NULL) { - return malloc(reqsize); - } - ap_block_alarms(); - if (c == NULL) { - return malloc(reqsize); + if (pool->user_data == NULL) + pool->user_data = apr_hash_make(pool); + + if (apr_hash_get(pool->user_data, key, APR_HASH_KEY_STRING) == NULL) { + char *new_key = apr_pstrdup(pool, key); + apr_hash_set(pool->user_data, new_key, APR_HASH_KEY_STRING, data); } - ptr = malloc(size); - if (ptr == NULL) { - fputs("Ouch! Out of memory!\n", stderr); - exit(1); + else { + apr_hash_set(pool->user_data, key, APR_HASH_KEY_STRING, data); } - debug_fill(ptr, size); /* might as well get uninitialized protection */ - *(void **)ptr = a->allocation_list; - a->allocation_list = ptr; - ap_unblock_alarms(); - return (char *)ptr + CLICK_SZ; -#else - - /* - * Round up requested size to an even number of alignment units - * (core clicks) - */ - int nclicks; - int size; - /* First, see if we have space in the block most recently - * allocated to this pool - */ + if (cleanup) + apr_pool_cleanup_register(pool, data, cleanup, cleanup); - union block_hdr *blok; - char *first_avail; - char *new_first_avail; + return APR_SUCCESS; +} - if (a == NULL) { - return malloc(reqsize); - } +APR_DECLARE(apr_status_t) apr_pool_userdata_setn(const void *data, + const char *key, + apr_status_t (*cleanup)(void *), + apr_pool_t *pool) +{ +#if APR_POOL_DEBUG + apr_pool_check_integrity(pool); +#endif /* APR_POOL_DEBUG */ - nclicks = 1 + ((reqsize - 1) / CLICK_SZ); - size = nclicks * CLICK_SZ; + if (pool->user_data == NULL) + pool->user_data = apr_hash_make(pool); - /* First, see if we have space in the block most recently - * allocated to this pool - */ + apr_hash_set(pool->user_data, key, APR_HASH_KEY_STRING, data); - blok = a->last; - first_avail = blok->h.first_avail; + if (cleanup) + apr_pool_cleanup_register(pool, data, cleanup, cleanup); - if (reqsize <= 0) { - return NULL; - } + return APR_SUCCESS; +} - new_first_avail = first_avail + size; +APR_DECLARE(apr_status_t) apr_pool_userdata_get(void **data, const char *key, + apr_pool_t *pool) +{ +#if APR_POOL_DEBUG + apr_pool_check_integrity(pool); +#endif /* APR_POOL_DEBUG */ - if (new_first_avail <= blok->h.endp) { - debug_verify_filled(first_avail, blok->h.endp, - "Ouch! Someone trounced past the end " - "of their allocation!\n"); - blok->h.first_avail = new_first_avail; - return (void *) first_avail; + if (pool->user_data == NULL) { + *data = NULL; + } + else { + *data = apr_hash_get(pool->user_data, key, APR_HASH_KEY_STRING); } - /* Nope --- get a new one that's guaranteed to be big enough */ + return APR_SUCCESS; +} - ap_block_alarms(); -#if APR_HAS_THREADS - ap_lock(alloc_mutex); -#endif +/* + * Cleanup + */ - blok = new_block(size, a->apr_abort); - a->last->h.next = blok; - a->last = blok; -#ifdef POOL_DEBUG - blok->h.owning_pool = a; -#endif +struct cleanup_t { + struct cleanup_t *next; + const void *data; + apr_status_t (*plain_cleanup_fn)(void *data); + apr_status_t (*child_cleanup_fn)(void *data); +}; -#if APR_HAS_THREADS - ap_unlock(alloc_mutex); -#endif +APR_DECLARE(void) apr_pool_cleanup_register(apr_pool_t *p, const void *data, + apr_status_t (*plain_cleanup_fn)(void *data), + apr_status_t (*child_cleanup_fn)(void *data)) +{ + cleanup_t *c; - ap_unblock_alarms(); +#if APR_POOL_DEBUG + apr_pool_check_integrity(p); - first_avail = blok->h.first_avail; - blok->h.first_avail += size; + if (!p || !plain_cleanup_fn || !child_cleanup_fn) { + abort(); + } +#endif /* APR_POOL_DEBUG */ - return (void *) first_avail; -#endif + if (p != NULL) { + if (p->free_cleanups) { + /* reuse a cleanup structure */ + c = p->free_cleanups; + p->free_cleanups = c->next; + } else { + c = apr_palloc(p, sizeof(cleanup_t)); + } + c->data = data; + c->plain_cleanup_fn = plain_cleanup_fn; + c->child_cleanup_fn = child_cleanup_fn; + c->next = p->cleanups; + p->cleanups = c; + } } -API_EXPORT(void *) ap_pcalloc(ap_pool_t *a, int size) +APR_DECLARE(void) apr_pool_pre_cleanup_register(apr_pool_t *p, const void *data, + apr_status_t (*plain_cleanup_fn)(void *data)) { - void *res = ap_palloc(a, size); - memset(res, '\0', size); - return res; -} + cleanup_t *c; -API_EXPORT(char *) ap_pstrdup(ap_pool_t *a, const char *s) -{ - char *res; - size_t len; +#if APR_POOL_DEBUG + apr_pool_check_integrity(p); +#endif /* APR_POOL_DEBUG */ - if (s == NULL) { - return NULL; + if (p != NULL) { + if (p->free_cleanups) { + /* reuse a cleanup structure */ + c = p->free_cleanups; + p->free_cleanups = c->next; + } else { + c = apr_palloc(p, sizeof(cleanup_t)); + } + c->data = data; + c->plain_cleanup_fn = plain_cleanup_fn; + c->next = p->pre_cleanups; + p->pre_cleanups = c; } - len = strlen(s) + 1; - res = ap_palloc(a, len); - memcpy(res, s, len); - return res; } -API_EXPORT(char *) ap_pstrndup(ap_pool_t *a, const char *s, int n) +APR_DECLARE(void) apr_pool_cleanup_kill(apr_pool_t *p, const void *data, + apr_status_t (*cleanup_fn)(void *)) { - char *res; + cleanup_t *c, **lastp; - if (s == NULL) { - return NULL; - } - res = ap_palloc(a, n + 1); - memcpy(res, s, n); - res[n] = '\0'; - return res; -} +#if APR_POOL_DEBUG + apr_pool_check_integrity(p); +#endif /* APR_POOL_DEBUG */ -API_EXPORT_NONSTD(char *) ap_pstrcat(ap_pool_t *a, ...) -{ - char *cp, *argp, *res; + if (p == NULL) + return; + + c = p->cleanups; + lastp = &p->cleanups; + while (c) { +#if APR_POOL_DEBUG + /* Some cheap loop detection to catch a corrupt list: */ + if (c == c->next + || (c->next && c == c->next->next) + || (c->next && c->next->next && c == c->next->next->next)) { + abort(); + } +#endif + + if (c->data == data && c->plain_cleanup_fn == cleanup_fn) { + *lastp = c->next; + /* move to freelist */ + c->next = p->free_cleanups; + p->free_cleanups = c; + break; + } - /* Pass one --- find length of required string */ + lastp = &c->next; + c = c->next; + } - int len = 0; - va_list adummy; + /* Remove any pre-cleanup as well */ + c = p->pre_cleanups; + lastp = &p->pre_cleanups; + while (c) { +#if APR_POOL_DEBUG + /* Some cheap loop detection to catch a corrupt list: */ + if (c == c->next + || (c->next && c == c->next->next) + || (c->next && c->next->next && c == c->next->next->next)) { + abort(); + } +#endif - va_start(adummy, a); + if (c->data == data && c->plain_cleanup_fn == cleanup_fn) { + *lastp = c->next; + /* move to freelist */ + c->next = p->free_cleanups; + p->free_cleanups = c; + break; + } - while ((cp = va_arg(adummy, char *)) != NULL) { - len += strlen(cp); + lastp = &c->next; + c = c->next; } - va_end(adummy); +} - /* Allocate the required string */ +APR_DECLARE(void) apr_pool_child_cleanup_set(apr_pool_t *p, const void *data, + apr_status_t (*plain_cleanup_fn)(void *), + apr_status_t (*child_cleanup_fn)(void *)) +{ + cleanup_t *c; - res = (char *) ap_palloc(a, len + 1); - cp = res; - *cp = '\0'; +#if APR_POOL_DEBUG + apr_pool_check_integrity(p); +#endif /* APR_POOL_DEBUG */ - /* Pass two --- copy the argument strings into the result space */ + if (p == NULL) + return; - va_start(adummy, a); + c = p->cleanups; + while (c) { + if (c->data == data && c->plain_cleanup_fn == plain_cleanup_fn) { + c->child_cleanup_fn = child_cleanup_fn; + break; + } - while ((argp = va_arg(adummy, char *)) != NULL) { - strcpy(cp, argp); - cp += strlen(argp); + c = c->next; } +} - va_end(adummy); +APR_DECLARE(apr_status_t) apr_pool_cleanup_run(apr_pool_t *p, void *data, + apr_status_t (*cleanup_fn)(void *)) +{ + apr_pool_cleanup_kill(p, data, cleanup_fn); + return (*cleanup_fn)(data); +} - /* Return the result string */ +static void run_cleanups(cleanup_t **cref) +{ + cleanup_t *c = *cref; - return res; + while (c) { + *cref = c->next; + (*c->plain_cleanup_fn)((void *)c->data); + c = *cref; + } } -/* - * ap_psprintf is implemented by writing directly into the current - * block of the pool, starting right at first_avail. If there's - * insufficient room, then a new block is allocated and the earlier - * output is copied over. The new block isn't linked into the pool - * until all the output is done. - * - * Note that this is completely safe because nothing else can - * allocate in this ap_pool_t while ap_psprintf is running. alarms are - * blocked, and the only thing outside of alloc.c that's invoked - * is ap_vformatter -- which was purposefully written to be - * self-contained with no callouts. - */ - -struct psprintf_data { - ap_vformatter_buff_t vbuff; -#ifdef ALLOC_USE_MALLOC - char *base; -#else - union block_hdr *blok; - int got_a_new_block; -#endif -}; +#if !defined(WIN32) && !defined(OS2) -static int psprintf_flush(ap_vformatter_buff_t *vbuff) +static void run_child_cleanups(cleanup_t **cref) { - struct psprintf_data *ps = (struct psprintf_data *)vbuff; -#ifdef ALLOC_USE_MALLOC - int size; - char *ptr; - - size = (char *)ps->vbuff.curpos - ps->base; - ptr = realloc(ps->base, 2*size); - if (ptr == NULL) { - fputs("Ouch! Out of memory!\n", stderr); - exit(1); - } - ps->base = ptr; - ps->vbuff.curpos = ptr + size; - ps->vbuff.endpos = ptr + 2*size - 1; - return 0; -#else - union block_hdr *blok; - union block_hdr *nblok; - size_t cur_len; - char *strp; - - blok = ps->blok; - strp = ps->vbuff.curpos; - cur_len = strp - blok->h.first_avail; + cleanup_t *c = *cref; - /* must try another blok */ -#if APR_HAS_THREADS - ap_lock(alloc_mutex); -#endif - nblok = new_block(2 * cur_len, NULL); -#if APR_HAS_THREADS - ap_unlock(alloc_mutex); -#endif - memcpy(nblok->h.first_avail, blok->h.first_avail, cur_len); - ps->vbuff.curpos = nblok->h.first_avail + cur_len; - /* save a byte for the NUL terminator */ - ps->vbuff.endpos = nblok->h.endp - 1; - - /* did we allocate the current blok? if so free it up */ - if (ps->got_a_new_block) { - debug_fill(blok->h.first_avail, blok->h.endp - blok->h.first_avail); -#if APR_HAS_THREADS - ap_lock(alloc_mutex); -#endif - blok->h.next = block_freelist; - block_freelist = blok; -#if APR_HAS_THREADS - ap_unlock(alloc_mutex); -#endif + while (c) { + *cref = c->next; + (*c->child_cleanup_fn)((void *)c->data); + c = *cref; } - ps->blok = nblok; - ps->got_a_new_block = 1; - /* note that we've deliberately not linked the new block onto - * the pool yet... because we may need to flush again later, and - * we'd have to spend more effort trying to unlink the block. - */ - return 0; -#endif } -API_EXPORT(char *) ap_pvsprintf(ap_pool_t *p, const char *fmt, va_list ap) +static void cleanup_pool_for_exec(apr_pool_t *p) { -#ifdef ALLOC_USE_MALLOC - struct psprintf_data ps; - void *ptr; - - ap_block_alarms(); - ps.base = malloc(512); - if (ps.base == NULL) { - fputs("Ouch! Out of memory!\n", stderr); - exit(1); - } - /* need room at beginning for allocation_list */ - ps.vbuff.curpos = ps.base + CLICK_SZ; - ps.vbuff.endpos = ps.base + 511; - ap_vformatter(psprintf_flush, &ps.vbuff, fmt, ap); - *ps.vbuff.curpos++ = '\0'; - ptr = ps.base; - /* shrink */ - ptr = realloc(ptr, (char *)ps.vbuff.curpos - (char *)ptr); - if (ptr == NULL) { - fputs("Ouch! Out of memory!\n", stderr); - exit(1); - } - *(void **)ptr = p->allocation_list; - p->allocation_list = ptr; - ap_unblock_alarms(); - return (char *)ptr + CLICK_SZ; -#else - struct psprintf_data ps; - char *strp; - int size; - - ap_block_alarms(); - ps.blok = p->last; - ps.vbuff.curpos = ps.blok->h.first_avail; - ps.vbuff.endpos = ps.blok->h.endp - 1; /* save one for NUL */ - ps.got_a_new_block = 0; - - ap_vformatter(psprintf_flush, &ps.vbuff, fmt, ap); - - strp = ps.vbuff.curpos; - *strp++ = '\0'; - - size = strp - ps.blok->h.first_avail; - size = (1 + ((size - 1) / CLICK_SZ)) * CLICK_SZ; - strp = ps.blok->h.first_avail; /* save away result pointer */ - ps.blok->h.first_avail += size; - - /* have to link the block in if it's a new one */ - if (ps.got_a_new_block) { - p->last->h.next = ps.blok; - p->last = ps.blok; -#ifdef POOL_DEBUG - ps.blok->h.owning_pool = p; -#endif - } - ap_unblock_alarms(); + run_child_cleanups(&p->cleanups); - return strp; -#endif + for (p = p->child; p; p = p->sibling) + cleanup_pool_for_exec(p); } -API_EXPORT_NONSTD(char *) ap_psprintf(ap_pool_t *p, const char *fmt, ...) +APR_DECLARE(void) apr_pool_cleanup_for_exec(void) { - va_list ap; - char *res; + cleanup_pool_for_exec(global_pool); +} - va_start(ap, fmt); - res = ap_pvsprintf(p, fmt, ap); - va_end(ap); - return res; +#else /* !defined(WIN32) && !defined(OS2) */ + +APR_DECLARE(void) apr_pool_cleanup_for_exec(void) +{ + /* + * Don't need to do anything on NT or OS/2, because + * these platforms will spawn the new process - not + * fork for exec. All handles that are not inheritable, + * will be automajically closed. The only problem is + * with file handles that are open, but there isn't + * much that can be done about that (except if the + * child decides to go out and close them, or the + * developer quits opening them shared) + */ + return; } +#endif /* !defined(WIN32) && !defined(OS2) */ -/***************************************************************** - * - * More grotty system stuff... subprocesses. Frump. These don't use - * the generic cleanup interface because I don't want multiple - * subprocesses to result in multiple three-second pauses; the - * subprocesses have to be "freed" all at once. If someone comes - * along with another resource they want to allocate which has the - * same property, we might want to fold support for that into the - * generic interface, but for now, it's a special case - */ +APR_DECLARE_NONSTD(apr_status_t) apr_pool_cleanup_null(void *data) +{ + /* do nothing cleanup routine */ + return APR_SUCCESS; +} -API_EXPORT(void) ap_note_subprocess(ap_pool_t *a, ap_proc_t *pid, - enum kill_conditions how) +/* Subprocesses don't use the generic cleanup interface because + * we don't want multiple subprocesses to result in multiple + * three-second pauses; the subprocesses have to be "freed" all + * at once. If other resources are introduced with the same property, + * we might want to fold support for that into the generic interface. + * For now, it's a special case. + */ +APR_DECLARE(void) apr_pool_note_subprocess(apr_pool_t *pool, apr_proc_t *proc, + apr_kill_conditions_e how) { - struct process_chain *new = - (struct process_chain *) ap_palloc(a, sizeof(struct process_chain)); + struct process_chain *pc = apr_palloc(pool, sizeof(struct process_chain)); - new->pid = pid; - new->kill_how = how; - new->next = a->subprocesses; - a->subprocesses = new; + pc->proc = proc; + pc->kill_how = how; + pc->next = pool->subprocesses; + pool->subprocesses = pc; } static void free_proc_chain(struct process_chain *procs) @@ -1283,12 +2749,12 @@ static void free_proc_chain(struct process_chain *procs) * whatever it was we're cleaning up now. This may involve killing * some of them off... */ - struct process_chain *p; + struct process_chain *pc; int need_timeout = 0; + apr_time_t timeout_interval; - if (procs == NULL) { - return; /* No work. Whew! */ - } + if (!procs) + return; /* No work. Whew! */ /* First, check to see if we need to do the SIGTERM, sleep, SIGKILL * dance with any of the processes we're cleaning up. If we've got @@ -1299,66 +2765,190 @@ static void free_proc_chain(struct process_chain *procs) #ifndef NEED_WAITPID /* Pick up all defunct processes */ - for (p = procs; p; p = p->next) { - if (ap_wait_proc(p->pid, APR_NOWAIT) == APR_CHILD_DONE) { - p->kill_how = kill_never; - } + for (pc = procs; pc; pc = pc->next) { + if (apr_proc_wait(pc->proc, NULL, NULL, APR_NOWAIT) != APR_CHILD_NOTDONE) + pc->kill_how = APR_KILL_NEVER; } -#endif +#endif /* !defined(NEED_WAITPID) */ - for (p = procs; p; p = p->next) { - if ((p->kill_how == kill_after_timeout) - || (p->kill_how == kill_only_once)) { + for (pc = procs; pc; pc = pc->next) { +#ifndef WIN32 + if ((pc->kill_how == APR_KILL_AFTER_TIMEOUT) + || (pc->kill_how == APR_KILL_ONLY_ONCE)) { /* * Subprocess may be dead already. Only need the timeout if not. - * Note: ap_kill on Windows is TerminateProcess(), which is + * Note: apr_proc_kill on Windows is TerminateProcess(), which is * similar to a SIGKILL, so always give the process a timeout * under Windows before killing it. */ -#ifdef WIN32 + if (apr_proc_kill(pc->proc, SIGTERM) == APR_SUCCESS) + need_timeout = 1; + } + else if (pc->kill_how == APR_KILL_ALWAYS) { +#else /* WIN32 knows only one fast, clean method of killing processes today */ + if (pc->kill_how != APR_KILL_NEVER) { need_timeout = 1; -#else - if (ap_kill(p->pid, APR_SIGTERM) == APR_SUCCESS) { - need_timeout = 1; - } + pc->kill_how = APR_KILL_ALWAYS; #endif - } - else if (p->kill_how == kill_always) { - ap_kill(p->pid, APR_SIGKILL); - } + apr_proc_kill(pc->proc, SIGKILL); + } } - /* Sleep only if we have to... */ + /* Sleep only if we have to. The sleep algorithm grows + * by a factor of two on each iteration. TIMEOUT_INTERVAL + * is equal to TIMEOUT_USECS / 64. + */ if (need_timeout) { - sleep(3); + timeout_interval = TIMEOUT_INTERVAL; + apr_sleep(timeout_interval); + + do { + /* check the status of the subprocesses */ + need_timeout = 0; + for (pc = procs; pc; pc = pc->next) { + if (pc->kill_how == APR_KILL_AFTER_TIMEOUT) { + if (apr_proc_wait(pc->proc, NULL, NULL, APR_NOWAIT) + == APR_CHILD_NOTDONE) + need_timeout = 1; /* subprocess is still active */ + else + pc->kill_how = APR_KILL_NEVER; /* subprocess has exited */ + } + } + if (need_timeout) { + if (timeout_interval >= TIMEOUT_USECS) { + break; + } + apr_sleep(timeout_interval); + timeout_interval *= 2; + } + } while (need_timeout); } /* OK, the scripts we just timed out for have had a chance to clean up * --- now, just get rid of them, and also clean up the system accounting * goop... */ - for (p = procs; p; p = p->next) { - if (p->kill_how == kill_after_timeout) { - ap_kill(p->pid, APR_SIGKILL); - } - } -#ifdef WIN32 - /* - * Do we need an APR function to clean-up a proc_t? - */ - { - PROCESS_INFORMATION pi; - for (p = procs; p; p = p->next) { - ap_get_os_proc(&pi, p->pid); - CloseHandle(pi.hProcess); - } + for (pc = procs; pc; pc = pc->next) { + if (pc->kill_how == APR_KILL_AFTER_TIMEOUT) + apr_proc_kill(pc->proc, SIGKILL); } -#endif /* WIN32 */ /* Now wait for all the signaled processes to die */ - for (p = procs; p; p = p->next) { - if (p->kill_how != kill_never) { - (void) ap_wait_proc(p->pid, APR_WAIT); - } + for (pc = procs; pc; pc = pc->next) { + if (pc->kill_how != APR_KILL_NEVER) + (void)apr_proc_wait(pc->proc, NULL, NULL, APR_WAIT); } } + + +/* + * Pool creation/destruction stubs, for people who are running + * mixed release/debug enviroments. + */ + +#if !APR_POOL_DEBUG +APR_DECLARE(void *) apr_palloc_debug(apr_pool_t *pool, apr_size_t size, + const char *file_line) +{ + return apr_palloc(pool, size); +} + +APR_DECLARE(void *) apr_pcalloc_debug(apr_pool_t *pool, apr_size_t size, + const char *file_line) +{ + return apr_pcalloc(pool, size); +} + +APR_DECLARE(void) apr_pool_clear_debug(apr_pool_t *pool, + const char *file_line) +{ + apr_pool_clear(pool); +} + +APR_DECLARE(void) apr_pool_destroy_debug(apr_pool_t *pool, + const char *file_line) +{ + apr_pool_destroy(pool); +} + +APR_DECLARE(apr_status_t) apr_pool_create_ex_debug(apr_pool_t **newpool, + apr_pool_t *parent, + apr_abortfunc_t abort_fn, + apr_allocator_t *allocator, + const char *file_line) +{ + return apr_pool_create_ex(newpool, parent, abort_fn, allocator); +} + +APR_DECLARE(apr_status_t) apr_pool_create_unmanaged_ex_debug(apr_pool_t **newpool, + apr_abortfunc_t abort_fn, + apr_allocator_t *allocator, + const char *file_line) +{ + return apr_pool_create_unmanaged_ex(newpool, abort_fn, allocator); +} + +#else /* APR_POOL_DEBUG */ + +#undef apr_palloc +APR_DECLARE(void *) apr_palloc(apr_pool_t *pool, apr_size_t size); + +APR_DECLARE(void *) apr_palloc(apr_pool_t *pool, apr_size_t size) +{ + return apr_palloc_debug(pool, size, "undefined"); +} + +#undef apr_pcalloc +APR_DECLARE(void *) apr_pcalloc(apr_pool_t *pool, apr_size_t size); + +APR_DECLARE(void *) apr_pcalloc(apr_pool_t *pool, apr_size_t size) +{ + return apr_pcalloc_debug(pool, size, "undefined"); +} + +#undef apr_pool_clear +APR_DECLARE(void) apr_pool_clear(apr_pool_t *pool); + +APR_DECLARE(void) apr_pool_clear(apr_pool_t *pool) +{ + apr_pool_clear_debug(pool, "undefined"); +} + +#undef apr_pool_destroy +APR_DECLARE(void) apr_pool_destroy(apr_pool_t *pool); + +APR_DECLARE(void) apr_pool_destroy(apr_pool_t *pool) +{ + apr_pool_destroy_debug(pool, "undefined"); +} + +#undef apr_pool_create_ex +APR_DECLARE(apr_status_t) apr_pool_create_ex(apr_pool_t **newpool, + apr_pool_t *parent, + apr_abortfunc_t abort_fn, + apr_allocator_t *allocator); + +APR_DECLARE(apr_status_t) apr_pool_create_ex(apr_pool_t **newpool, + apr_pool_t *parent, + apr_abortfunc_t abort_fn, + apr_allocator_t *allocator) +{ + return apr_pool_create_ex_debug(newpool, parent, + abort_fn, allocator, + "undefined"); +} + +#undef apr_pool_create_unmanaged_ex +APR_DECLARE(apr_status_t) apr_pool_create_unmanaged_ex(apr_pool_t **newpool, + apr_abortfunc_t abort_fn, + apr_allocator_t *allocator); + +APR_DECLARE(apr_status_t) apr_pool_create_unmanaged_ex(apr_pool_t **newpool, + apr_abortfunc_t abort_fn, + apr_allocator_t *allocator) +{ + return apr_pool_create_unmanaged_ex_debug(newpool, abort_fn, + allocator, "undefined"); +} + +#endif /* APR_POOL_DEBUG */ diff --git a/misc/beos/Makefile.in b/misc/beos/Makefile.in deleted file mode 100644 index 6ba04bef4d8..00000000000 --- a/misc/beos/Makefile.in +++ /dev/null @@ -1,62 +0,0 @@ -#CFLAGS=$(OPTIM) $(CFLAGS1) $(EXTRA_CFLAGS) -#LIBS=$(EXTRA_LIBS) $(LIBS1) -#INCLUDES=$(INCLUDES1) $(INCLUDES0) $(EXTRA_INCLUDES) -#LDFLAGS=$(LDFLAGS1) $(EXTRA_LDFLAGS) - -CC=@CC@ -RANLIB=@RANLIB@ -CFLAGS=@CFLAGS@ @OPTIM@ -LIBS=@LIBS@ -LDFLAGS=@LDFLAGS@ $(LIBS) -INCDIR=../../include -INCDIR1=../../file_io/unix -I../../locks/beos -I../../threadproc/beos - -INCLUDES=-I$(INCDIR) -I$(INCDIR1) -I. - -LIB=libmisc.a - -OBJS=misc_common.o - -.c.o: - $(CC) $(CFLAGS) -c $(INCLUDES) $< - -all: $(LIB) - -clean: - $(RM) -f *.o *.a *.so - -distclean: clean - -$(RM) -f Makefile - -$(OBJS): Makefile - -$(LIB): $(OBJS) - $(RM) -f $@ - $(AR) cr $@ $(OBJS) - $(RANLIB) $@ - -# -# We really don't expect end users to use this rule. It works only with -# gcc, and rebuilds Makefile.tmpl. You have to re-run Configure after -# using it. -# -depend: - cp Makefile.in Makefile.in.bak \ - && sed -ne '1,/^# DO NOT REMOVE/p' Makefile.in > Makefile.new \ - && gcc -MM $(INCLUDES) $(CFLAGS) *.c >> Makefile.new \ - && sed -e '1,$$s: $(INCDIR)/: $$(INCDIR)/:g' \ - -e '1,$$s: $(OSDIR)/: $$(OSDIR)/:g' Makefile.new \ - > Makefile.in \ - && rm Makefile.new - -# DO NOT REMOVE -getopt.o: getopt.c misc.h ../../include/apr_private.h \ - ../../include/apr_general.h ../../include/apr.h \ - ../../include/apr_errno.h ../../include/apr_pools.h \ - ../../include/apr_lib.h ../../include/apr_file_io.h \ - ../../include/apr_getopt.h -start.o: start.c misc.h ../../include/apr_private.h \ - ../../include/apr_general.h ../../include/apr.h \ - ../../include/apr_errno.h ../../include/apr_pools.h \ - ../../include/apr_lib.h ../../include/apr_file_io.h \ - ../../include/apr_getopt.h diff --git a/misc/beos/misc.h b/misc/beos/misc.h deleted file mode 100644 index 7c99c206a83..00000000000 --- a/misc/beos/misc.h +++ /dev/null @@ -1,97 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#ifndef MISC_H -#define MISC_H - -#include "apr_private.h" -#include "apr_general.h" -#include "apr_pools.h" -#include "apr_getopt.h" -#ifdef HAVE_STDLIB_H -#include <stdlib.h> -#endif -#ifdef HAVE_STDIO_H -#include <stdio.h> -#endif -#ifdef HAVE_STRING_H -#include <string.h> -#endif -#ifdef HAVE_SIGNAL_H -#include <signal.h> -#endif - -#include <kernel/OS.h> - -typedef struct datastruct { - void *data; - char *key; - struct datastruct *next; - struct datastruct *prev; -} datastruct; - -struct ap_other_child_rec_t { - struct ap_other_child_rec_t *next; - thread_id pid; /* this is actually a thread_id, but in order to - restrict the amount of code duplication we'll use - pid so that the Unix code won't have too many #ifdef's - */ - void (*maintenance) (int, void *); - void *data; - int write_fd; -}; - - -#endif /* ! MISC_H */ - diff --git a/misc/beos/misc_common.c b/misc/beos/misc_common.c deleted file mode 100644 index 86a11c4cfc2..00000000000 --- a/misc/beos/misc_common.c +++ /dev/null @@ -1,64 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -/* BeOS uses identical code so let's not have 2 copies... */ - -#include "../unix/start.c" - -#include "../unix/getopt.c" - -#include "../unix/otherchild.c" - -#include "../unix/canonerr.c" -#include "../unix/errorcodes.c" diff --git a/misc/beos/otherchild.c b/misc/beos/otherchild.c deleted file mode 100644 index 1239eedbc69..00000000000 --- a/misc/beos/otherchild.c +++ /dev/null @@ -1,180 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#include "misc.h" -#include "../../threadproc/beos/threadproc.h" - -static ap_other_child_rec_t *other_children = NULL; - -API_EXPORT(void) ap_register_other_child(ap_proc_t *pid, - void (*maintenance) (int reason, void *), - void *data, int write_fd, ap_pool_t *p) -{ - ap_other_child_rec_t *ocr; - - ocr = ap_palloc(p, sizeof(*ocr)); - ocr->tid = pid->tid; - ocr->maintenance = maintenance; - ocr->data = data; - ocr->write_fd = write_fd; - ocr->next = other_children; - other_children = ocr; -} - -API_EXPORT(void) ap_unregister_other_child(void *data) -{ - ap_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); - *pocr = nocr; - /* XXX: um, well we've just wasted some space in pconf ? */ - return; - } - } -} - -/* test to ensure that the write_fds are all still writable, otherwise - * invoke the maintenance functions as appropriate */ -static void probe_writable_fds(void) -{ - fd_set writable_fds; - int fd_max; - ap_other_child_rec_t *ocr, *nocr; - struct timeval tv; - int rc; - - if (other_children == NULL) - return; - - fd_max = 0; - FD_ZERO(&writable_fds); - do { - for (ocr = other_children; ocr; ocr = ocr->next) { - if (ocr->write_fd == -1) - continue; - FD_SET(ocr->write_fd, &writable_fds); - if (ocr->write_fd > fd_max) { - fd_max = ocr->write_fd; - } - } - if (fd_max == 0) - return; - - tv.tv_sec = 0; - tv.tv_usec = 0; - rc = select(fd_max + 1, NULL, &writable_fds, NULL, &tv); - } while (rc == -1 && errno == EINTR); - - if (rc == -1) { - /* XXX: uhh this could be really bad, we could have a bad file - * descriptor due to a bug in one of the maintenance routines */ - return; - } - if (rc == 0) - return; - - for (ocr = other_children; ocr; ocr = nocr) { - nocr = ocr->next; - if (ocr->write_fd == -1) - continue; - if (FD_ISSET(ocr->write_fd, &writable_fds)) - continue; - (*ocr->maintenance) (APR_OC_REASON_UNWRITABLE, ocr->data); - } -} - -API_EXPORT(ap_status_t) reap_other_child(ap_proc_t *pid) -{ - ap_other_child_rec_t *ocr, *nocr; - - for (ocr = other_children; ocr; ocr = nocr) { - nocr = ocr->next; - if (ocr->tid != pid->tid) - continue; - ocr->tid = -1; - (*ocr->maintenance) (APR_OC_REASON_DEATH, ocr->data); - return 0; - } - return APR_CHILD_NOTDONE; -} - -API_EXPORT(void) check_other_child(void) -{ - ap_other_child_rec_t *ocr, *nocr; - pid_t waitret; - - for (ocr = other_children; ocr; ocr = nocr) { - nocr = ocr->next; - if (ocr->tid == -1) - continue; - - waitret = waitpid(ocr->tid, NULL, WNOHANG); - if (waitret == ocr->tid) { - ocr->tid = -1; - (*ocr->maintenance) (APR_OC_REASON_DEATH, ocr->data); - } - else if (waitret == 0) { - (*ocr->maintenance) (APR_OC_REASON_RESTART, ocr->data); - } - else if (waitret == -1) { - /* uh what the heck? they didn't call unregister? */ - ocr->tid = -1; - (*ocr->maintenance) (APR_OC_REASON_LOST, ocr->data); - } - } -} - diff --git a/misc/beos/start.c b/misc/beos/start.c deleted file mode 100644 index f46f1bfe53b..00000000000 --- a/misc/beos/start.c +++ /dev/null @@ -1,153 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#include "misc.h" - -ap_status_t ap_create_pool(ap_pool_t **newcont, ap_pool_t *cont) -{ - ap_pool_t *new; - ap_pool_t *pool; - - if (cont) { - pool = ap_make_sub_pool(cont->pool, cont->apr_abort); - } - else { - pool = ap_make_sub_pool(NULL, NULL); - } - - if (pool == NULL) { - return APR_ENOPOOL; - } - - new = (ap_pool_t *)ap_palloc(cont, sizeof(ap_pool_t)); - - new->pool = pool; - new->prog_data = NULL; - - *newcont = new; - return APR_SUCCESS; -} - -ap_status_t ap_destroy_context(ap_pool_t *cont) -{ - ap_destroy_pool(cont); - return APR_SUCCESS; -} - -ap_status_t ap_set_userdata(void *data, char *key, - ap_status_t (*cleanup) (void *), - ap_pool_t *cont) -{ - datastruct *dptr = NULL, *dptr2 = NULL; - if (cont) { - dptr = cont->prog_data; - while (dptr) { - if (!strcmp(dptr->key, key)) - break; - dptr2 = dptr; - dptr = dptr->next; - } - if (dptr == NULL) { - dptr = ap_palloc(cont, sizeof(datastruct)); - dptr->next = dptr->prev = NULL; - dptr->key = ap_pstrdup(cont, key); - if (dptr2) { - dptr2->next = dptr; - dptr->prev = dptr2; - } - else { - cont->prog_data = dptr; - } - } - dptr->data = data; - ap_register_cleanup(cont, dptr->data, cleanup, cleanup); - return APR_SUCCESS; - } - return APR_ENOPOOL; -} - -ap_status_t ap_get_userdata(void **data, char *key, ap_pool_t *cont) -{ - datastruct *dptr = NULL; - if (cont) { - dptr = cont->prog_data; - while (dptr) { - if (!strcmp(dptr->key, key)) { - break; - } - dptr = dptr->next; - } - if (dptr) { - (*data) = dptr->data; - } - else { - (*data) = NULL; - } - return APR_SUCCESS; - } - return APR_ENOPOOL; -} - -ap_status_t ap_initialize(void) -{ - ap_status_t status; - status = ap_init_alloc(); - return status; -} - -void ap_terminate(void) -{ - ap_term_alloc(); -} - diff --git a/misc/netware/apr.xdc b/misc/netware/apr.xdc new file mode 100644 index 00000000000..12a7f6ba2df Binary files /dev/null and b/misc/netware/apr.xdc differ diff --git a/misc/netware/charset.c b/misc/netware/charset.c new file mode 100644 index 00000000000..b79add10b55 --- /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 00000000000..9f9db5c9c76 --- /dev/null +++ b/misc/netware/libprews.c @@ -0,0 +1,187 @@ +/* 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 __MWERKS__ +#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) +#endif +#ifdef USE_WINSOCK + WSADATA wsaData; +#endif + apr_status_t status; + + NX_LOCK_INFO_ALLOC(liblock, "Per-Application Data Lock", 0); + + 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 00000000000..a2baae7ecd3 --- /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 00000000000..e044a102283 --- /dev/null +++ b/misc/netware/start.c @@ -0,0 +1,199 @@ +/* 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" + +#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); + + 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/os2/.cvsignore b/misc/os2/.cvsignore deleted file mode 100644 index f3c7a7c5da6..00000000000 --- a/misc/os2/.cvsignore +++ /dev/null @@ -1 +0,0 @@ -Makefile diff --git a/misc/os2/misc.h b/misc/os2/misc.h deleted file mode 100644 index f6b0e4833f4..00000000000 --- a/misc/os2/misc.h +++ /dev/null @@ -1,55 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#include "../unix/misc.h" diff --git a/misc/unix/.cvsignore b/misc/unix/.cvsignore deleted file mode 100644 index f3c7a7c5da6..00000000000 --- a/misc/unix/.cvsignore +++ /dev/null @@ -1 +0,0 @@ -Makefile diff --git a/misc/unix/Makefile.in b/misc/unix/Makefile.in deleted file mode 100644 index 23c3d6c96eb..00000000000 --- a/misc/unix/Makefile.in +++ /dev/null @@ -1,91 +0,0 @@ -#CFLAGS=$(OPTIM) $(CFLAGS1) $(EXTRA_CFLAGS) -#LIBS=$(EXTRA_LIBS) $(LIBS1) -#INCLUDES=$(INCLUDES1) $(INCLUDES0) $(EXTRA_INCLUDES) -#LDFLAGS=$(LDFLAGS1) $(EXTRA_LDFLAGS) - -RM=@RM@ -CC=@CC@ -RANLIB=@RANLIB@ -CFLAGS=@CFLAGS@ @OPTIM@ -LIBS=@LIBS@ -LDFLAGS=@LDFLAGS@ $(LIBS) -INCDIR1=../../include -INCDIR2=../../file_io/@OSDIR@ -INCDIR3=../../locks/@OSDIR@ -INCDIR4=../../threadproc/@OSDIR@ -INCLUDES=-I$(INCDIR1) -I$(INCDIR2) -I$(INCDIR3) -I$(INCDIR4) -I. - -#LIB=libmisc.a - -OBJS=start.o getopt.o otherchild.o errorcodes.o rand.o canonerr.o - -.c.o: - $(CC) $(CFLAGS) -c $(INCLUDES) $< - -all: $(OBJS) - -clean: - $(RM) -f *.o *.a *.so - -distclean: clean - -$(RM) -f Makefile - -$(OBJS): Makefile - -#$(LIB): $(OBJS) -# $(RM) -f $@ -# $(AR) cr $@ $(OBJS) -# $(RANLIB) $@ - -# -# We really don't expect end users to use this rule. It works only with -# gcc, and rebuilds Makefile.tmpl. You have to re-run Configure after -# using it. -# -depend: - cp Makefile.in Makefile.in.bak \ - && sed -ne '1,/^# DO NOT REMOVE/p' Makefile.in > Makefile.new \ - && gcc -MM $(INCLUDES) $(CFLAGS) *.c >> Makefile.new \ - && sed -e '1,$$s: $(INCDIR)/: $$(INCDIR)/:g' \ - -e '1,$$s: $(OSDIR)/: $$(OSDIR)/:g' Makefile.new \ - > Makefile.in \ - && rm Makefile.new - -# DO NOT REMOVE -canonerr.o: canonerr.c misc.h ../../include/apr.h \ - ../../include/apr_private.h ../../include/apr_general.h \ - ../../include/apr_errno.h ../../include/apr_pools.h \ - ../../include/apr_lib.h ../../include/apr_file_io.h \ - ../../include/apr_time.h ../../include/apr_thread_proc.h \ - ../../include/apr_getopt.h -errorcodes.o: errorcodes.c misc.h ../../include/apr.h \ - ../../include/apr_private.h ../../include/apr_general.h \ - ../../include/apr_errno.h ../../include/apr_pools.h \ - ../../include/apr_lib.h ../../include/apr_file_io.h \ - ../../include/apr_time.h ../../include/apr_thread_proc.h \ - ../../include/apr_getopt.h -getopt.o: getopt.c misc.h ../../include/apr.h \ - ../../include/apr_private.h ../../include/apr_general.h \ - ../../include/apr_errno.h ../../include/apr_pools.h \ - ../../include/apr_lib.h ../../include/apr_file_io.h \ - ../../include/apr_time.h ../../include/apr_thread_proc.h \ - ../../include/apr_getopt.h -otherchild.o: otherchild.c misc.h ../../include/apr.h \ - ../../include/apr_private.h ../../include/apr_general.h \ - ../../include/apr_errno.h ../../include/apr_pools.h \ - ../../include/apr_lib.h ../../include/apr_file_io.h \ - ../../include/apr_time.h ../../include/apr_thread_proc.h \ - ../../include/apr_getopt.h ../../threadproc/unix/threadproc.h \ - ../../file_io/unix/fileio.h -rand.o: rand.c misc.h ../../include/apr.h ../../include/apr_private.h \ - ../../include/apr_general.h ../../include/apr_errno.h \ - ../../include/apr_pools.h ../../include/apr_lib.h \ - ../../include/apr_file_io.h ../../include/apr_time.h \ - ../../include/apr_thread_proc.h ../../include/apr_getopt.h -start.o: start.c misc.h ../../include/apr.h \ - ../../include/apr_private.h ../../include/apr_general.h \ - ../../include/apr_errno.h ../../include/apr_pools.h \ - ../../include/apr_lib.h ../../include/apr_file_io.h \ - ../../include/apr_time.h ../../include/apr_thread_proc.h \ - ../../include/apr_getopt.h ../../locks/unix/locks.h \ - ../../include/apr_lock.h diff --git a/misc/unix/canonerr.c b/misc/unix/canonerr.c deleted file mode 100644 index 6fee3e34deb..00000000000 --- a/misc/unix/canonerr.c +++ /dev/null @@ -1,69 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#include "misc.h" - -#ifndef OS2 - -int ap_canonical_error(ap_status_t errcode) -{ -#if defined(EAGAIN) && defined(EWOULDBLOCK) && (EAGAIN != EWOULDBLOCK) - if (errcode == EWOULDBLOCK) { - errcode = EAGAIN; - } -#endif - return errcode; -} - -#endif diff --git a/misc/unix/charset.c b/misc/unix/charset.c new file mode 100644 index 00000000000..a16310cd0c9 --- /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 00000000000..b41f8f17b52 --- /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 index 7d1e4cd4469..4f9b1d92474 100644 --- a/misc/unix/errorcodes.c +++ b/misc/unix/errorcodes.c @@ -1,81 +1,50 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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 "misc.h" +#include "apr_arch_misc.h" +#include "apr_strings.h" +#include "apr_lib.h" +#include "apr_dso.h" + +#include "apu_errno.h" + +#if APR_HAVE_NETDB_H +#include <netdb.h> +#endif +#ifdef HAVE_DLFCN_H +#include <dlfcn.h> +#endif /* - * stuffbuffer - Stuff contents of string 's' into buffer 'buf' - * w/o overflowing 'buf' then NULL terminate. + * 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, ap_size_t bufsize, const char *s) +static char *stuffbuffer(char *buf, apr_size_t bufsize, const char *s) { - ap_size_t len = strlen(s); - if (len > bufsize) - len = bufsize; - memcpy(buf, s, len); - if (len) - buf[len-1] = '\0'; + apr_cpystrn(buf,s,bufsize); return buf; } -static char *apr_error_string(ap_status_t statcode) +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_ENOFILE: - return "No file was provided and one was required."; case APR_EBADDATE: return "An invalid date has been provided"; case APR_EINVALSOCK: @@ -99,7 +68,19 @@ static char *apr_error_string(ap_status_t statcode) case APR_ENOSHMAVAIL: return "No shared memory is currently available"; case APR_EDSOOPEN: - return "Could not open the dso."; +#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 " @@ -118,6 +99,8 @@ static char *apr_error_string(ap_status_t statcode) 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: @@ -140,6 +123,33 @@ static char *apr_error_string(ap_status_t statcode) 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)"; + +/* APR Util error codes */ + case APR_ECRYPT: + return "Internal error in the crypto subsystem (specific information not available)"; + case APR_ENOENGINE: + return "No engine found for crypto subsystem"; + case APR_EINITENGINE: + return "Failed to init engine for crypto subsystem"; + default: return "Error string not specified yet"; } @@ -147,11 +157,11 @@ static char *apr_error_string(ap_status_t statcode) #ifdef OS2 -#define INCL_DOS -#include <os2.h> #include <ctype.h> -static char *apr_os_strerror(char* buf, ap_size_t bufsize, int err) +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]; @@ -161,7 +171,7 @@ static char *apr_os_strerror(char* buf, ap_size_t bufsize, int err) if (err >= 10000 && err < 12000) { /* socket error codes */ return stuffbuffer(buf, bufsize, - strerror(ap_canonical_error(err+APR_OS_START_SYSERR))); + strerror(apr_canonical_error(err+APR_OS_START_SYSERR))); } else if (DosGetMessage(NULL, 0, message, HUGE_STRING_LEN, err, "OSO001.MSG", &len) == 0) { @@ -170,13 +180,13 @@ static char *apr_os_strerror(char* buf, ap_size_t bufsize, int err) pos = result; if (len >= sizeof(result)) - len = sizeof(result-1); + len = sizeof(result) - 1; for (c=0; c<len; c++) { /* skip multiple whitespace */ - while (ap_isspace(message[c]) && ap_isspace(message[c+1])) + while (apr_isspace(message[c]) && apr_isspace(message[c+1])) c++; - *(pos++) = ap_isspace(message[c]) ? ' ' : message[c]; + *(pos++) = apr_isspace(message[c]) ? ' ' : message[c]; } *pos = 0; @@ -190,26 +200,255 @@ static char *apr_os_strerror(char* buf, ap_size_t bufsize, int err) */ 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 publically (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 -static char *apr_os_strerror(char* buf, ap_size_t bufsize, int err) +/* 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) { - return stuffbuffer(buf, bufsize,strerror(err)); +#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 -char *ap_strerror(ap_status_t statcode, char *buf, ap_size_t bufsize) +APR_DECLARE(char *) apr_strerror(apr_status_t statcode, char *buf, + apr_size_t bufsize) { if (statcode < APR_OS_START_ERROR) { - return stuffbuffer(buf, bufsize, strerror(statcode)); + return native_strerror(statcode, buf, bufsize); } - else if (statcode < APR_OS_START_USEERR) { + 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); + return apr_os_strerror(buf, bufsize, statcode - APR_OS_START_SYSERR); } } diff --git a/misc/unix/getopt.c b/misc/unix/getopt.c index 940e5b61217..24be3c82f89 100644 --- a/misc/unix/getopt.c +++ b/misc/unix/getopt.c @@ -31,94 +31,279 @@ * SUCH DAMAGE. */ -#include "misc.h" - -int ap_opterr = 1, /* if error message should be printed */ - ap_optind = 1, /* index into parent argv vector */ - ap_optopt, /* character checked for validity */ - ap_optreset; /* reset getopt */ -char *ap_optarg = ""; /* argument associated with option */ +#include "apr_arch_misc.h" +#include "apr_strings.h" +#include "apr_lib.h" #define EMSG "" -ap_status_t ap_getopt(ap_int32_t nargc, char *const *nargv, const char *ostr, ap_int32_t *rv, ap_pool_t *cont) +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) { - char *p; - static char *place = EMSG; /* option letter processing */ - char *oli; /* option letter list index */ - - if (ap_optreset || !*place) { /* update scanning pointer */ - ap_optreset = 0; - if (ap_optind >= nargc || *(place = nargv[ap_optind]) != '-') { - place = EMSG; - *rv = ap_optopt; + 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 (place[1] && *++place == '-') { /* found "--" */ - ++ap_optind; - place = EMSG; - *rv = ap_optopt; + if (os->place[1] && *++os->place == '-') { /* found "--" */ + ++os->ind; + os->place = EMSG; + *optch = os->opt; return (APR_EOF); } } /* option letter okay? */ - if ((ap_optopt = (int) *place++) == (int) ':' || - !(oli = strchr(ostr, ap_optopt))) { + 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 (ap_optopt == (int) '-') - { - *rv = ap_optopt; + if (os->opt == (int) '-') { + *optch = os->opt; return (APR_EOF); } - if (!*place) - ++ap_optind; - if (ap_opterr && *ostr != ':') { - if (!(p = strrchr(*nargv, '/'))) - p = *nargv; - else - ++p; - (void) fprintf(stderr, - "%s: illegal option -- %c\n", p, ap_optopt); + 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); } - *rv = ap_optopt; - return APR_BADCH; + *optch = os->opt; + return (APR_BADCH); } if (*++oli != ':') { /* don't need argument */ - ap_optarg = NULL; - if (!*place) - ++ap_optind; + *optarg = NULL; + if (!*os->place) + ++os->ind; } else { /* need an argument */ - if (*place) /* no white space */ - ap_optarg = place; - else if (nargc <= ++ap_optind) { /* no arg */ - place = EMSG; - if (*ostr == ':') - { - *rv = ap_optopt; + 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 (ap_opterr) { - if (!(p = strrchr(*nargv, '/'))) - p = *nargv; - else - ++p; - (void) fprintf(stderr, - "%s: option requires an argument -- %c\n", - p, ap_optopt); + if (os->errfn) { + (os->errfn)(os->errarg, + "%s: option requires an argument -- %c\n", + apr_filepath_name_get(*os->argv), os->opt); } - *rv = ap_optopt; + *optch = os->opt; return (APR_BADCH); } else /* white space */ - ap_optarg = nargv[ap_optind]; - place = EMSG; - ++ap_optind; + *optarg = os->argv[os->ind]; + os->place = EMSG; + ++os->ind; } - *rv = ap_optopt; + *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/misc.h b/misc/unix/misc.h deleted file mode 100644 index bb754bbf62e..00000000000 --- a/misc/unix/misc.h +++ /dev/null @@ -1,98 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#ifndef MISC_H -#define MISC_H - -#include "apr.h" -#include "apr_private.h" -#include "apr_general.h" -#include "apr_pools.h" -#include "apr_getopt.h" -#include "apr_thread_proc.h" -#include "apr_errno.h" -#ifdef HAVE_STDLIB_H -#include <stdlib.h> -#endif -#ifdef HAVE_STDIO_H -#include <stdio.h> -#endif -#ifdef HAVE_STRING_H -#include <string.h> -#endif -#ifdef HAVE_SIGNAL_H -#include <signal.h> -#endif -#ifdef HAVE_PTHREAD_H -#include <pthread.h> -#endif - -typedef struct datastruct { - void *data; - char *key; - struct datastruct *next; - struct datastruct *prev; -} datastruct; - -struct ap_other_child_rec_t { - struct ap_other_child_rec_t *next; - int pid; - void (*maintenance) (int, void *, int); - void *data; - int write_fd; -}; - - -#endif /* ! MISC_H */ - diff --git a/misc/unix/otherchild.c b/misc/unix/otherchild.c index dd2368685ad..a2fef19acad 100644 --- a/misc/unix/otherchild.c +++ b/misc/unix/otherchild.c @@ -1,89 +1,44 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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 "misc.h" -#include "threadproc.h" +#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 -#ifdef HAVE_SYS_WAIT_H +#if APR_HAVE_SYS_WAIT_H #include <sys/wait.h> #endif +#ifdef BEOS +#include <sys/socket.h> /* for fd_set definition! */ +#endif -static ap_other_child_rec_t *other_children = NULL; - -API_EXPORT(void) ap_register_other_child(ap_proc_t *pid, - void (*maintenance) (int reason, void *, int status), - void *data, int write_fd, ap_pool_t *p) -{ - ap_other_child_rec_t *ocr; - - ocr = ap_palloc(p, sizeof(*ocr)); - ocr->pid = pid->pid; - ocr->maintenance = maintenance; - ocr->data = data; - ocr->write_fd = write_fd; - ocr->next = other_children; - other_children = ocr; -} +static apr_other_child_rec_t *other_children = NULL; -API_EXPORT(void) ap_unregister_other_child(void *data) +static apr_status_t other_child_cleanup(void *data) { - ap_other_child_rec_t **pocr, *nocr; + apr_other_child_rec_t **pocr, *nocr; for (pocr = &other_children; *pocr; pocr = &(*pocr)->next) { if ((*pocr)->data == data) { @@ -91,100 +46,190 @@ API_EXPORT(void) ap_unregister_other_child(void *data) (*(*pocr)->maintenance) (APR_OC_REASON_UNREGISTER, (*pocr)->data, -1); *pocr = nocr; /* XXX: um, well we've just wasted some space in pconf ? */ - return; + return APR_SUCCESS; } } + return APR_SUCCESS; } -/* test to ensure that the write_fds are all still writable, otherwise - * invoke the maintenance functions as appropriate */ -static void probe_writable_fds(void) +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) { - fd_set writable_fds; - int fd_max; - ap_other_child_rec_t *ocr, *nocr; - struct timeval tv; - int rc; + apr_other_child_rec_t *ocr; - if (other_children == NULL) - return; + ocr = apr_palloc(p, sizeof(*ocr)); + ocr->p = p; + ocr->proc = proc; + ocr->maintenance = maintenance; + ocr->data = data; + 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; - fd_max = 0; - FD_ZERO(&writable_fds); - do { - for (ocr = other_children; ocr; ocr = ocr->next) { - if (ocr->write_fd == -1) - continue; - FD_SET(ocr->write_fd, &writable_fds); - if (ocr->write_fd > fd_max) { - fd_max = ocr->write_fd; - } + cur = other_children; + while (cur) { + if (cur->data == data) { + break; } - if (fd_max == 0) - return; + cur = cur->next; + } - tv.tv_sec = 0; - tv.tv_usec = 0; - rc = select(fd_max + 1, NULL, &writable_fds, NULL, &tv); - } while (rc == -1 && errno == EINTR); + /* segfault if this function called with invalid parm */ + apr_pool_cleanup_kill(cur->p, cur->data, other_child_cleanup); + other_child_cleanup(data); +} - if (rc == -1) { - /* XXX: uhh this could be really bad, we could have a bad file - * descriptor due to a bug in one of the maintenance routines */ - return; - } - if (rc == 0) - return; +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->write_fd == -1) + if (ocr->proc->pid != proc->pid) continue; - if (FD_ISSET(ocr->write_fd, &writable_fds)) - continue; - (*ocr->maintenance) (APR_OC_REASON_UNWRITABLE, ocr->data, -1); + + ocr->proc = NULL; + (*ocr->maintenance) (reason, ocr->data, status); + return APR_SUCCESS; } + return APR_EPROC_UNKNOWN; } -API_EXPORT(ap_status_t) ap_reap_other_child(ap_proc_t *pid, int status) +APR_DECLARE(void) apr_proc_other_child_refresh(apr_other_child_rec_t *ocr, + int reason) { - ap_other_child_rec_t *ocr, *nocr; + /* Todo: + * Implement code to detect if pipes are still alive. + */ +#ifdef WIN32 + DWORD status; - for (ocr = other_children; ocr; ocr = nocr) { - nocr = ocr->next; - if (ocr->pid != pid->pid) - continue; + if (ocr->proc == NULL) + return; - ocr->pid = -1; + 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); - return 0; } - return APR_CHILD_NOTDONE; -} -API_EXPORT(void) ap_check_other_child(void) -{ - ap_other_child_rec_t *ocr, *nocr; +#elif defined(OS2) + int rc; + int status; + RESULTCODES proc_rc; + PID ended_pid; + + if (ocr->proc == NULL) { + return; + } + + rc = DosWaitChild(DCWA_PROCESS, DCWW_NOWAIT, &proc_rc, &ended_pid, ocr->proc->pid); + + switch (rc) { + case 0: + ocr->proc = NULL; + status = (proc_rc.codeResult << 8) | proc_rc.codeTerminate; + (*ocr->maintenance) (APR_OC_REASON_DEATH, ocr->data, status); + break; + + case ERROR_CHILD_NOT_COMPLETE: + (*ocr->maintenance) (reason, ocr->data, -1); + break; + + default: + ocr->proc = NULL; + (*ocr->maintenance) (APR_OC_REASON_LOST, ocr->data, -1); + break; + } +#else /* ndef Win32 */ pid_t waitret; int status; - for (ocr = other_children; ocr; ocr = nocr) { - nocr = ocr->next; - if (ocr->pid == -1) - continue; + if (ocr->proc == NULL) + return; - waitret = waitpid(ocr->pid, &status, WNOHANG); - if (waitret == ocr->pid) { - ocr->pid = -1; - (*ocr->maintenance) (APR_OC_REASON_DEATH, ocr->data, status); - } - else if (waitret == 0) { - (*ocr->maintenance) (APR_OC_REASON_RESTART, ocr->data, -1); - } - else if (waitret == -1) { - /* uh what the heck? they didn't call unregister? */ - ocr->pid = -1; - (*ocr->maintenance) (APR_OC_REASON_LOST, ocr->data, -1); - } + 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 index aebd1d2f261..5e235990196 100644 --- a/misc/unix/rand.c +++ b/misc/unix/rand.c @@ -1,87 +1,277 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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 "misc.h" -#include <sys/types.h> +#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> -#ifdef HAVE_UNISTD_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 APR_HAS_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 */ + +#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 */ -#define XSTR(x) #x -#define STR(x) XSTR(x) +#if APR_HAS_RANDOM -ap_status_t ap_generate_random_bytes(unsigned char * buf, int length) +APR_DECLARE(apr_status_t) apr_generate_random_bytes(unsigned char *buf, + apr_size_t length) { -#ifdef DEV_RANDOM +#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); + } - int rnd; - size_t got, tot; + if (length > 0) { + /* We must have iterated through the list of sockets, + * and no go. Return the errno. + */ + return bad_errno; + } - if ((rnd = open(STR(DEV_RANDOM), O_RDONLY)) == -1) - return errno; +#elif defined(USE_GETRANDOM) - for (tot=0; tot<length; tot += got) - if ((got = read(rnd, buf+tot, length-tot)) < 0) - return errno; + do { + int rc; - close(rnd); + rc = getrandom(buf, length, GRND_NONBLOCK); + if (rc == -1) { + if (errno == EINTR) { + continue; + } + return errno; + } -#else /* use truerand */ + buf += rc; + length -= rc; + } while (length > 0); + +#elif 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; @@ -92,6 +282,10 @@ ap_status_t ap_generate_random_bytes(unsigned char * buf, int length) 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; @@ -99,4 +293,9 @@ ap_status_t ap_generate_random_bytes(unsigned char * buf, int length) #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 00000000000..4020e31fea2 --- /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 index fad86b50757..8dcc1d9897e 100644 --- a/misc/unix/start.c +++ b/misc/unix/start.c @@ -1,165 +1,89 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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 "misc.h" -#include "locks.h" - -ap_status_t ap_create_pool(ap_pool_t **newcont, ap_pool_t *cont) -{ - ap_pool_t *new; +#include "apr.h" +#include "apr_general.h" +#include "apr_pools.h" +#include "apr_signal.h" +#include "apr_atomic.h" - if (cont) { - new = ap_make_sub_pool(cont, cont->apr_abort); - } - else { - new = ap_make_sub_pool(NULL, NULL); - } - - if (new == NULL) { - return APR_ENOPOOL; - } +#include "apr_arch_proc_mutex.h" /* for apr_proc_mutex_unix_setup_lock() */ +#include "apr_arch_internal_time.h" - new->prog_data = NULL; - new->apr_abort = NULL; - - *newcont = new; - return APR_SUCCESS; -} -ap_status_t ap_destroy_context(ap_pool_t *cont) +APR_DECLARE(apr_status_t) apr_app_initialize(int *argc, + const char * const * *argv, + const char * const * *env) { - ap_destroy_pool(cont); - return APR_SUCCESS; + /* 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(); } -ap_status_t ap_set_userdata(void *data, char *key, - ap_status_t (*cleanup) (void *), - ap_pool_t *cont) -{ - datastruct *dptr = NULL, *dptr2 = NULL; - if (cont) { - dptr = cont->prog_data; - while (dptr) { - if (!strcmp(dptr->key, key)) - break; - dptr2 = dptr; - dptr = dptr->next; - } - if (dptr == NULL) { - dptr = ap_palloc(cont, sizeof(datastruct)); - dptr->next = dptr->prev = NULL; - dptr->key = ap_pstrdup(cont, key); - if (dptr2) { - dptr2->next = dptr; - dptr->prev = dptr2; - } - else { - cont->prog_data = dptr; - } - } - dptr->data = data; - ap_register_cleanup(cont, dptr->data, cleanup, cleanup); - return APR_SUCCESS; - } - return APR_ENOPOOL; -} +static int initialized = 0; -ap_status_t ap_get_userdata(void **data, char *key, ap_pool_t *cont) +APR_DECLARE(apr_status_t) apr_initialize(void) { - datastruct *dptr = NULL; - if (cont) { - dptr = cont->prog_data; - while (dptr) { - if (!strcmp(dptr->key, key)) { - break; - } - dptr = dptr->next; - } - if (dptr) { - (*data) = dptr->data; - } - else { - (*data) = NULL; - } + apr_pool_t *pool; + apr_status_t status; + + if (initialized++) { return APR_SUCCESS; } - return APR_ENOPOOL; -} -ap_status_t ap_initialize(void) -{ - ap_status_t status; #if !defined(BEOS) && !defined(OS2) - ap_unix_setup_lock(); + apr_proc_mutex_unix_setup_lock(); + apr_unix_setup_time(); #endif - status = ap_init_alloc(); - return status; + + 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 as well. + * 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; } -void ap_terminate(void) +APR_DECLARE_NONSTD(void) apr_terminate(void) { - ap_term_alloc(); + initialized--; + if (initialized) { + return; + } + apr_pool_terminate(); + } -ap_status_t ap_set_abort(int (*apr_abort)(int retcode), ap_pool_t *cont) +APR_DECLARE(void) apr_terminate2(void) { - if (cont == NULL) { - return APR_ENOPOOL; - } - else { - cont->apr_abort = apr_abort; - return APR_SUCCESS; - } + apr_terminate(); } - diff --git a/misc/unix/version.c b/misc/unix/version.c new file mode 100644 index 00000000000..2f111bf9dc0 --- /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 00000000000..4e08e33d756 --- /dev/null +++ b/misc/win32/apr_app.c @@ -0,0 +1,80 @@ +/* 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 dupenv; + + (void)apr_wastrtoastr(&argv, wargv, argc); + + dupenv = apr_wastrtoastr(&env, wenv, -1); + + _environ = apr_malloc_dbg((dupenv + 1) * sizeof (char *), + __FILE__, __LINE__ ); + memcpy(_environ, env, (dupenv + 1) * sizeof (char *)); + + /* 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) { + wenv = _wenviron; + _wenviron = NULL; + free((wchar_t **)wenv); + } + + apr_app_init_complete = 1; + + return main(argc, argv, env); +} diff --git a/misc/win32/aprlib.c b/misc/win32/aprlib.c deleted file mode 100644 index b54667430e0..00000000000 --- a/misc/win32/aprlib.c +++ /dev/null @@ -1,7 +0,0 @@ -/* - * Placeholder to force aprlib.dll creation with no LNK4001 error - * - * However, this isn't a bad place to store dynamic-only functions - * that determine which version of apr the application has loaded. - * These functions are of (less?) importance to static-bound apps. - */ diff --git a/misc/win32/canonerr.c b/misc/win32/canonerr.c deleted file mode 100644 index aff1e0fc438..00000000000 --- a/misc/win32/canonerr.c +++ /dev/null @@ -1,71 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#include "misc.h" - -/* - * Map Windows system errors to APR specific error codes. - * This routine should only be called when it is necessary to - * selectively react to errors returned by APR functions. - * - * hack alert: - * Certain Windows APR routines already canonicalize their - * return codes in most (and maybe all) cases that are - * interesting to Apache. For now, canonicalization - * on Windows is a no-op. - */ -int ap_canonical_error(ap_status_t code) -{ - return code; -} diff --git a/misc/win32/charset.c b/misc/win32/charset.c new file mode 100644 index 00000000000..41135b25d90 --- /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 00000000000..644f59b8801 --- /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/errorcodes.c b/misc/win32/errorcodes.c deleted file mode 100644 index bd725273f8c..00000000000 --- a/misc/win32/errorcodes.c +++ /dev/null @@ -1,196 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#include "apr_lib.h" -#include "misc.h" - -/* Todo: Merge this code with the code in the misc/unix directory. - * Most of it is common - */ - -/* - * stuffbuffer - Stuff contents of string 's' into buffer 'buf' - * w/o overflowing 'buf' then NULL terminate. - */ -static char *stuffbuffer(char *buf, ap_size_t bufsize, const char *s) -{ - ap_size_t len = strlen(s); - if (len > bufsize) - len = bufsize; - memcpy(buf, s, len); - if (len) - buf[len-1] = '\0'; - return buf; -} - -static char *apr_error_string(ap_status_t statcode) -{ - switch (statcode) { - case APR_ENOPOOL: - return "A new pool could not be created."; - case APR_ENOFILE: - return "No file was provided and one was required."; - 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: - return "Could not open the dso."; - 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_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"; - default: - return "Error string not specified yet"; - } -} - -static char *apr_os_strerror(char *buf, ap_size_t bufsize, ap_status_t errcode) -{ - DWORD len; - DWORD i; - - buf = ""; - - len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, - NULL, - errcode, - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */ - (LPTSTR) buf, - bufsize, - NULL); - - /* 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] = ' '; - } - return buf; -} - -char *ap_strerror(ap_status_t statcode, char* buf, ap_size_t bufsize) -{ - if (statcode < APR_OS_START_ERROR) { - return apr_os_strerror(buf, bufsize, statcode); - } - else if (statcode < APR_OS_START_USEERR) { - return stuffbuffer(buf, bufsize, apr_error_string(statcode)); - } - else if (statcode < APR_OS_START_SYSERR) { - return stuffbuffer(buf, bufsize, "APR does not understand this error code"); - } - else { - return apr_os_strerror(buf, bufsize, statcode - APR_OS_START_SYSERR); - } -} diff --git a/misc/win32/getopt.c b/misc/win32/getopt.c deleted file mode 100644 index bae5406a0f2..00000000000 --- a/misc/win32/getopt.c +++ /dev/null @@ -1,123 +0,0 @@ -/* - * 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 <stdio.h> -#include <stdlib.h> -#include <string.h> -#include "misc.h" - -int ap_opterr = 1, /* if error message should be printed */ - ap_optind = 1, /* index into parent argv vector */ - ap_optopt, /* character checked for validity */ - ap_optreset; /* reset getopt */ -char *ap_optarg = ""; /* argument associated with option */ - -#define EMSG "" - -ap_status_t ap_getopt(ap_int32_t nargc, char *const *nargv, const char *ostr, ap_int32_t *rv, ap_pool_t *cont) -{ - char *p; - static char *place = EMSG; /* option letter processing */ - char *oli; /* option letter list index */ - - if (ap_optreset || !*place) { /* update scanning pointer */ - ap_optreset = 0; - if (ap_optind >= nargc || *(place = nargv[ap_optind]) != '-') { - place = EMSG; - *rv = ap_optopt; - return (APR_EOF); - } - if (place[1] && *++place == '-') { /* found "--" */ - ++ap_optind; - place = EMSG; - *rv = ap_optopt; - return (APR_EOF); - } - } /* option letter okay? */ - if ((ap_optopt = (int) *place++) == (int) ':' || - !(oli = strchr(ostr, ap_optopt))) { - /* - * if the user didn't specify '-' as an option, - * assume it means -1. - */ - if (ap_optopt == (int) '-') - *rv = ap_optopt; - return (APR_EOF); - if (!*place) - ++ap_optind; - if (ap_opterr && *ostr != ':') { - if (!(p = strrchr(*nargv, '/'))) - p = *nargv; - else - ++p; - (void) fprintf(stderr, - "%s: illegal option -- %c\n", p, ap_optopt); - } - *rv = ap_optopt; - return APR_BADCH; - } - if (*++oli != ':') { /* don't need argument */ - ap_optarg = NULL; - if (!*place) - ++ap_optind; - } - else { /* need an argument */ - if (*place) /* no white space */ - ap_optarg = place; - else if (nargc <= ++ap_optind) { /* no arg */ - place = EMSG; - if (*ostr == ':') - *rv = ap_optopt; - return (APR_BADARG); - if (ap_opterr) { - if (!(p = strrchr(*nargv, '/'))) - p = *nargv; - else - ++p; - (void) fprintf(stderr, - "%s: option requires an argument -- %c\n", - p, ap_optopt); - } - *rv = ap_optopt; - return (APR_BADCH); - } - else /* white space */ - ap_optarg = nargv[ap_optind]; - place = EMSG; - ++ap_optind; - } - *rv = ap_optopt; - return APR_SUCCESS; -} - - diff --git a/misc/win32/internal.c b/misc/win32/internal.c new file mode 100644 index 00000000000..03362cf5982 --- /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/libapr.c b/misc/win32/libapr.c deleted file mode 100644 index b54667430e0..00000000000 --- a/misc/win32/libapr.c +++ /dev/null @@ -1,7 +0,0 @@ -/* - * Placeholder to force aprlib.dll creation with no LNK4001 error - * - * However, this isn't a bad place to store dynamic-only functions - * that determine which version of apr the application has loaded. - * These functions are of (less?) importance to static-bound apps. - */ diff --git a/misc/win32/misc.c b/misc/win32/misc.c new file mode 100644 index 00000000000..337739ca128 --- /dev/null +++ b/misc/win32/misc.c @@ -0,0 +1,241 @@ +/* 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) + { + static OSVERSIONINFO oslev; + oslev.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx(&oslev); + + if (oslev.dwPlatformId == VER_PLATFORM_WIN32_NT) + { + static unsigned int servpack = 0; + TCHAR *pservpack; + if ((pservpack = oslev.szCSDVersion)) { + while (*pservpack && !apr_isdigit(*pservpack)) { + pservpack++; + } + if (*pservpack) +#ifdef _UNICODE + servpack = _wtoi(pservpack); +#else + servpack = atoi(pservpack); +#endif + } + + 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) + apr_os_level = APR_WIN_7; + else + apr_os_level = APR_WIN_8; + } + else { + apr_os_level = APR_WIN_XP; + } + } +#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" }; +static HMODULE lateDllHandle[DLL_defined] = { + 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/misc.h b/misc/win32/misc.h deleted file mode 100644 index a1acdbccb44..00000000000 --- a/misc/win32/misc.h +++ /dev/null @@ -1,139 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#ifndef MISC_H -#define MISC_H - -#include "apr_general.h" -#include "apr_file_io.h" -#include "apr_errno.h" -#include "apr_getopt.h" - -typedef struct datastruct { - void *data; - char *key; - struct datastruct *next; - struct datastruct *prev; -} datastruct; - -#define WSAHighByte 2 -#define WSALowByte 0 -/* Platform specific designation of run time os version. - * Gaps allow for specific service pack levels that - * export new kernel or winsock functions or behavior. - */ -typedef enum { - APR_WIN_95 = 0, - APR_WIN_98 = 4, - APR_WIN_NT = 8, - APR_WIN_NT_4 = 12, - APR_WIN_NT_4_SP2 = 14, - APR_WIN_NT_4_SP3 = 15, - APR_WIN_NT_4_SP4 = 16, - APR_WIN_NT_4_SP6 = 18, - APR_WIN_2000 = 24 -} ap_oslevel_e; - - -typedef enum { - DLL_WINBASEAPI = 0, // kernel32 From WinBase.h - DLL_WINADVAPI = 1, // advapi32 From WinBase.h - DLL_WINSOCKAPI = 2, // mswsock From WinSock.h - DLL_WINSOCK2API = 3, // ws2_32 From WinSock2.h - DLL_defined = 4 // must define as last idx_ + 1 -} ap_dlltoken_e; - -FARPROC LoadLateDllFunc(ap_dlltoken_e fnLib, char *fnName, int ordinal); - -/* The LateFunctionName call WILL fault if the function cannot be loaded */ - -#define DECLARE_LATE_DLL_FUNC(lib, rettype, calltype, fn, ord, args, names) \ - typedef rettype (calltype *fpt##fn) args; \ - static fpt##fn pfn##fn = NULL; \ - __inline rettype Late##fn args \ - { if (!pfn##fn) \ - pfn##fn = (fpt##fn) LoadLateDllFunc(lib, #fn, ord); \ - return (*(pfn##fn)) names; }; \ - -/* Provide late bound declarations of every API function missing from - * one or more supported releases of the Win32 API - * - * lib is the enumerated token from ap_dlltoken_e, and must correspond - * to the string table entry in start.c used by the LoadLateDllFunc(). - * Token names (attempt to) follow Windows.h declarations prefixed by DLL_ - * in order to facilitate comparison. Use the exact declaration syntax - * and names from Windows.h to prevent ambigutity and bugs. - * - * rettype and calltype follow the original declaration in Windows.h - * fn is the true function name - beware Ansi/Unicode #defined macros - * ord is the ordinal within the library, use 0 if it varies between versions - * args is the parameter list following the original declaration, in parens - * names is the parameter list sans data types, enclosed in parens - * - * #undef/re#define the Ansi/Unicode generic name to abate confusion - * In the case of non-text functions, simply #define the original name - */ - -DECLARE_LATE_DLL_FUNC(DLL_WINBASEAPI, BOOL, WINAPI, GetFileAttributesExA, 0, ( - IN LPCSTR lpFileName, - IN GET_FILEEX_INFO_LEVELS fInfoLevelId, - OUT LPVOID lpFileInformation), - (lpFileName, fInfoLevelId, lpFileInformation)); -#undef GetFileAttributesEx -#define GetFileAttributesEx LateGetFileAttributesExA - -ap_status_t ap_get_oslevel(struct ap_pool_t *, ap_oslevel_e *); - -#endif /* ! MISC_H */ - diff --git a/misc/win32/names.c b/misc/win32/names.c deleted file mode 100644 index d831842c929..00000000000 --- a/misc/win32/names.c +++ /dev/null @@ -1,316 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#include "apr_private.h" -#include "apr_file_io.h" -#include "apr_general.h" -#include "apr_lib.h" -#include <errno.h> -#include <string.h> -#include <sys/stat.h> - -/* Returns TRUE if the input string is a string - * of one or more '.' characters. - */ -static BOOL OnlyDots(char *pString) -{ - char *c; - - if (*pString == '\0') - return FALSE; - - for (c = pString;*c;c++) - if (*c != '.') - return FALSE; - - return TRUE; -} - -/* Accepts as input a pathname, and tries to match it to an - * existing path and return the pathname in the case that - * is present on the existing path. This routine also - * converts alias names to long names. - */ -API_EXPORT(char *) ap_os_systemcase_filename(ap_pool_t *pCont, - const char *szFile) -{ - char buf[HUGE_STRING_LEN]; - char *pInputName; - char *p, *q; - BOOL bDone = FALSE; - BOOL bFileExists = TRUE; - HANDLE hFind; - WIN32_FIND_DATA wfd; - - if (!szFile || strlen(szFile) == 0 || strlen(szFile) >= sizeof(buf)) - return ap_pstrdup(pCont, ""); - - buf[0] = '\0'; - pInputName = ap_pstrdup(pCont, szFile); - - /* First convert all slashes to \ so Win32 calls work OK */ - for (p = pInputName; *p; p++) { - if (*p == '/') - *p = '\\'; - } - - p = pInputName; - /* If there is drive information, copy it over. */ - if (pInputName[1] == ':') { - buf[0] = tolower(*p++); - buf[1] = *p++; - buf[2] = '\0'; - - /* If all we have is a drive letter, then we are done */ - if (strlen(pInputName) == 2) - bDone = TRUE; - } - - q = p; - if (*p == '\\') { - p++; - if (*p == '\\') /* Possible UNC name */ - { - p++; - /* Get past the machine name. FindFirstFile */ - /* will not find a machine name only */ - p = strchr(p, '\\'); - if (p) - { - p++; - /* Get past the share name. FindFirstFile */ - /* will not find a \\machine\share name only */ - p = strchr(p, '\\'); - if (p) { - strncat(buf,q,p-q); - q = p; - p++; - } - } - - if (!p) - p = q; - } - } - - p = strchr(p, '\\'); - - while (!bDone) { - if (p) - *p = '\0'; - - if (strchr(q, '*') || strchr(q, '?')) - bFileExists = FALSE; - - /* If the path exists so far, call FindFirstFile - * again. However, if this portion of the path contains - * only '.' charaters, skip the call to FindFirstFile - * since it will convert '.' and '..' to actual names. - * Note: in the call to OnlyDots, we may have to skip - * a leading slash. - */ - if (bFileExists && !OnlyDots((*q == '.' ? q : q+1))) { - hFind = FindFirstFile(pInputName, &wfd); - - if (hFind == INVALID_HANDLE_VALUE) { - bFileExists = FALSE; - } - else { - FindClose(hFind); - - if (*q == '\\') - strcat(buf,"\\"); - strcat(buf, wfd.cFileName); - } - } - - if (!bFileExists || OnlyDots((*q == '.' ? q : q+1))) { - strcat(buf, q); - } - - if (p) { - q = p; - *p++ = '\\'; - p = strchr(p, '\\'); - } - else { - bDone = TRUE; - } - } - - /* First convert all slashes to / so server code handles it ok */ - for (p = buf; *p; p++) { - if (*p == '\\') - *p = '/'; - } - - return ap_pstrdup(pCont, buf); -} - -/* Perform canonicalization with the exception that the - * input case is preserved. - */ -char * canonical_filename(ap_pool_t *pCont, const char *szFile) -{ - char *pNewStr; - char *s; - char *p; - char *q; - - if (szFile == NULL || strlen(szFile) == 0) - return ap_pstrdup(pCont, ""); - - pNewStr = ap_pstrdup(pCont, szFile); - - /* Change all '\' characters to '/' characters. - * While doing this, remove any trailing '.'. - * Also, blow away any directories with 3 or - * more '.' - */ - for (p = pNewStr,s = pNewStr; *s; s++,p++) { - if (*s == '\\' || *s == '/') { - - q = p; - while (p > pNewStr && *(p-1) == '.') - p--; - - if (p == pNewStr && q-p <= 2 && *p == '.') - p = q; - else if (p > pNewStr && p < q && *(p-1) == '/') { - if (q-p > 2) - p--; - else - p = q; - } - - *p = '/'; - } - else { - *p = *s; - } - } - *p = '\0'; - - /* Blow away any final trailing '.' since on Win32 - * foo.bat == foo.bat. == foo.bat... etc. - * Also blow away any trailing spaces since - * "filename" == "filename " - */ - q = p; - while (p > pNewStr && (*(p-1) == '.' || *(p-1) == ' ')) - p--; - if ((p > pNewStr) || - (p == pNewStr && q-p > 2)) - *p = '\0'; - - - /* One more security issue to deal with. Win32 allows - * you to create long filenames. However, alias filenames - * are always created so that the filename will - * conform to 8.3 rules. According to the Microsoft - * Developer's network CD (1/98) - * "Automatically generated aliases are composed of the - * first six characters of the filename plus ~n - * (where n is a number) and the first three characters - * after the last period." - * Here, we attempt to detect and decode these names. - */ - p = strchr(pNewStr, '~'); - if (p != NULL) { - char *pConvertedName, *pQstr, *pPstr; - char buf[HUGE_STRING_LEN]; - /* We potentially have a short name. Call - * ap_os_systemcase_filename to examine the filesystem - * and possibly extract the long name. - */ - pConvertedName = ap_os_systemcase_filename(pCont, pNewStr); - - /* Since we want to preserve the incoming case as much - * as we can, compare for differences in the string and - * only substitute in the path names that changed. - */ - if (stricmp(pNewStr, pConvertedName)) { - buf[0] = '\0'; - - q = pQstr = pConvertedName; - p = pPstr = pNewStr; - do { - q = strchr(q,'/'); - p = strchr(p,'/'); - - if (p != NULL) { - *q = '\0'; - *p = '\0'; - } - - if (stricmp(pQstr, pPstr)) - strcat(buf, pQstr); /* Converted name */ - else - strcat(buf, pPstr); /* Original name */ - - - if (p != NULL) { - pQstr = q; - pPstr = p; - *q++ = '/'; - *p++ = '/'; - } - - } while (p != NULL); - - pNewStr = ap_pstrdup(pCont, buf); - } - } - return pNewStr; -} diff --git a/misc/win32/rand.c b/misc/win32/rand.c index 1f6770e6275..cb5a6537fb7 100644 --- a/misc/win32/rand.c +++ b/misc/win32/rand.c @@ -1,78 +1,69 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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 <wincrypt.h> +#include "apr_portable.h" +#include "apr_arch_misc.h" + -ap_status_t ap_generate_random_bytes(unsigned char * buf, int length) +APR_DECLARE(apr_status_t) apr_generate_random_bytes(unsigned char * buf, + apr_size_t length) { HCRYPTPROV hProv; + apr_status_t res = APR_SUCCESS; - if (!CryptAcquireContext(&hProv,NULL,NULL,PROV_RSA_FULL,0)) { - /* ap_log_error(APLOG_MARK, APLOG_CRIT, 0, s, - "Digest: Error acquiring context. Errno = %d", - GetLastError()); - exit(EXIT_FAILURE);*/ - return 1; + /* 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(); } - if (!CryptGenRandom(hProv,length,buf)) { - /* ap_log_error(APLOG_MARK, APLOG_CRIT, 0, s, - "Digest: Error generating secret. Errno = %d", - GetLastError()); - exit(EXIT_FAILURE);*/ - return 1; + 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 index 95fa14d960e..eb77d4a4ddd 100644 --- a/misc/win32/start.c +++ b/misc/win32/start.c @@ -1,258 +1,206 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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 "misc.h" #include "apr_general.h" -#include "apr_errno.h" #include "apr_pools.h" -#include "apr_lib.h" -#include <string.h> -#include <process.h> -#include <stdlib.h> +#include "apr_signal.h" +#include "shellapi.h" -ap_status_t clean_cont(void *data) -{ - return APR_SUCCESS; -} - +#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" -ap_status_t ap_create_pool(ap_pool_t **newcont, ap_pool_t *cont) -{ - ap_pool_t *new; +/* This symbol is _private_, although it must be exported. + */ +int APR_DECLARE_DATA apr_app_init_complete = 0; - if (cont) { - new = ap_make_sub_pool(cont, cont->apr_abort); - } - else { - new = ap_make_sub_pool(NULL, NULL); +#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, int args) +{ + 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; + + if (args < 0) { + for (args = 1, wch = arrsz; wch[0] || wch[1]; ++wch) + if (!*wch) + ++args; } - - if (new == NULL) { - return APR_ENOPOOL; + 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; } - - new->prog_data = NULL; - new->apr_abort = NULL; - *newcont = new; - return APR_SUCCESS; -} + *env = NULL; + free(strs); -ap_status_t ap_destroy_context(ap_pool_t *cont) -{ - ap_destroy_pool(cont); - return APR_SUCCESS; + return args; } +#endif -ap_status_t ap_get_oslevel(ap_pool_t *cont, ap_oslevel_e *level) +/* 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) { - static OSVERSIONINFO oslev; - static unsigned int servpack = 0; - static BOOL first = TRUE; - char *pservpack; - - if (first) { - first = FALSE; - oslev.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); - GetVersionEx(&oslev); - if (oslev.dwPlatformId == VER_PLATFORM_WIN32_NT) { - for (pservpack = oslev.szCSDVersion; - *pservpack && !isdigit(*pservpack); pservpack++) - ; - if (*pservpack) - servpack = atoi(pservpack); - } - } - if (oslev.dwPlatformId == VER_PLATFORM_WIN32_NT) { - if (oslev.dwMajorVersion == 5) { - (*level) = APR_WIN_2000; - } - else if (oslev.dwMajorVersion == 4) { - if (servpack >= 6) { - (*level) = APR_WIN_NT_4_SP6; - } - else if (servpack >= 4) { - (*level) = APR_WIN_NT_4_SP4; - } - else if (servpack >= 3) { - (*level) = APR_WIN_NT_4_SP3; - } - else if (servpack >= 2) { - (*level) = APR_WIN_NT_4_SP2; - } - else { - (*level) = APR_WIN_NT_4; - } - } - else { - (*level) = APR_WIN_NT; - } - return APR_SUCCESS; - } - else if (oslev.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) { - if (oslev.dwMinorVersion == 0) { - (*level) = APR_WIN_95; - return APR_SUCCESS; - } - else if (oslev.dwMinorVersion > 0) { - (*level) = APR_WIN_98; - return APR_SUCCESS; - } + apr_status_t rv = apr_initialize(); + + if (rv != APR_SUCCESS) { + return rv; } - return APR_EEXIST; -} -ap_status_t ap_set_userdata(void *data, char *key, - ap_status_t (*cleanup) (void *), - ap_pool_t *cont) -{ - datastruct *dptr = NULL, *dptr2 = NULL; - if (cont) { - dptr = cont->prog_data; - while (dptr) { - if (!strcmp(dptr->key, key)) - break; - dptr2 = dptr; - dptr = dptr->next; - } - if (dptr == NULL) { - dptr = ap_palloc(cont, sizeof(datastruct)); - dptr->next = dptr->prev = NULL; - dptr->key = ap_pstrdup(cont, key); - if (dptr2) { - dptr2->next = dptr; - dptr->prev = dptr2; - } - else { - cont->prog_data = dptr; - } +#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; } - dptr->data = data; - ap_register_cleanup(cont, dptr->data, cleanup, cleanup); - return APR_SUCCESS; - } - return APR_ENOPOOL; -} -ap_status_t ap_get_userdata(void **data, char *key, ap_pool_t *cont) -{ - datastruct *dptr = NULL; - if (cont) { - dptr = cont->prog_data; - while (dptr) { - if (!strcmp(dptr->key, key)) { - break; + apr_app_init_complete = 1; + + sysstr = GetCommandLineW(); + if (sysstr) { + wstrs = CommandLineToArgvW(sysstr, &wstrc); + if (wstrs) { + *argc = apr_wastrtoastr(argv, wstrs, wstrc); + GlobalFree(wstrs); } - dptr = dptr->next; } - if (dptr) { - (*data) = dptr->data; + + sysstr = GetEnvironmentStringsW(); + dupenv = warrsztoastr(&_environ, sysstr, -1); + + if (env) { + *env = apr_malloc_dbg((dupenv + 1) * sizeof (char *), + __FILE__, __LINE__ ); + memcpy((void*)*env, _environ, (dupenv + 1) * sizeof (char *)); } else { - (*data) = NULL; } - return APR_SUCCESS; - } - return APR_ENOPOOL; -} -/* 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" }; -static HMODULE lateDllHandle[DLL_defined] = { - NULL, NULL, NULL, NULL }; + 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); + } -FARPROC LoadLateDllFunc(ap_dlltoken_e fnLib, char* fnName, int ordinal) -{ - if (!lateDllHandle[fnLib]) { - lateDllHandle[fnLib] = LoadLibrary(lateDllName[fnLib]); - if (!lateDllHandle[fnLib]) - return NULL; } - if (ordinal) - return GetProcAddress(lateDllHandle[fnLib], (char *) ordinal); - else - return GetProcAddress(lateDllHandle[fnLib], fnName); +#endif + return rv; } -/* This puts one thread in a Listen for signals mode */ -ap_status_t ap_initialize(void) +static int initialized = 0; + +/* Provide to win32/thread.c */ +extern DWORD tls_apr_thread; + +APR_DECLARE(apr_status_t) apr_initialize(void) { - ap_status_t status; + apr_pool_t *pool; + apr_status_t status; int iVersionRequested; WSADATA wsaData; int err; -#if 0 - unsigned tid; + apr_oslevel_e osver; + + if (initialized++) { + return APR_SUCCESS; + } - if (_beginthreadex(NULL, 0, SignalHandling, NULL, 0, &tid) == 0) { + /* Initialize apr_os_level global */ + if (apr_get_oslevel(&osver) != APR_SUCCESS) { return APR_EEXIST; } - while (thread_ready() != 1) { - sleep(1); + tls_apr_thread = TlsAlloc(); + if ((status = apr_pool_initialize()) != APR_SUCCESS) + return status; + + if (apr_pool_create(&pool, NULL) != APR_SUCCESS) { + return APR_ENOPOOL; } -#endif + + apr_pool_tag(pool, "apr_initialize"); iVersionRequested = MAKEWORD(WSAHighByte, WSALowByte); err = WSAStartup((WORD) iVersionRequested, &wsaData); if (err) { - return APR_EEXIST; + return err; } if (LOBYTE(wsaData.wVersion) != WSAHighByte || HIBYTE(wsaData.wVersion) != WSALowByte) { @@ -260,12 +208,27 @@ ap_status_t ap_initialize(void) return APR_EEXIST; } - status = ap_init_alloc(); - return status; + apr_signal_init(pool); + + apr_threadproc_init(pool); + + return APR_SUCCESS; } -void ap_terminate(void) +APR_DECLARE_NONSTD(void) apr_terminate(void) { + initialized--; + if (initialized) { + return; + } + apr_pool_terminate(); + WSACleanup(); - ap_term_alloc(); + + 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 00000000000..280f4064720 --- /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; +} diff --git a/mmap/beos/Makefile.in b/mmap/beos/Makefile.in deleted file mode 100644 index eac4bf5dd97..00000000000 --- a/mmap/beos/Makefile.in +++ /dev/null @@ -1,64 +0,0 @@ -#CFLAGS=$(OPTIM) $(CFLAGS1) $(EXTRA_CFLAGS) -#LIBS=$(EXTRA_LIBS) $(LIBS1) -#INCLUDES=$(INCLUDES1) $(INCLUDES0) $(EXTRA_INCLUDES) -#LDFLAGS=$(LDFLAGS1) $(EXTRA_LDFLAGS) - -RM=@RM@ -CC=@CC@ -RANLIB=@RANLIB@ -CFLAGS=@CFLAGS@ @OPTIM@ -LIBS=@LIBS@ -LDFLAGS=@LDFLAGS@ $(LIBS) -INCDIR=../../include -I../../file_io/unix -INCLUDES=-I$(INCDIR) -I. - -LIB=libmmap.a - -OBJS=mmap.o mmap_common.o - -.c.o: - $(CC) $(CFLAGS) -c $(INCLUDES) $< - -all: $(LIB) - -clean: - $(RM) -f *.o *.a *.so - -distclean: clean - -$(RM) -f Makefile - -$(OBJS): Makefile - -$(LIB): $(OBJS) - $(RM) -f $@ - $(AR) cr $@ $(OBJS) - $(RANLIB) $@ - -# -# We really don't expect end users to use this rule. It works only with -# gcc, and rebuilds Makefile.tmpl. You have to re-run Configure after -# using it. -# -depend: - cp Makefile.in Makefile.in.bak \ - && sed -ne '1,/^# DO NOT REMOVE/p' Makefile.in > Makefile.new \ - && gcc -MM $(INCLUDES) $(CFLAGS) *.c >> Makefile.new \ - && sed -e '1,$$s: $(INCDIR)/: $$(INCDIR)/:g' \ - -e '1,$$s: $(OSDIR)/: $$(OSDIR)/:g' Makefile.new \ - > Makefile.in \ - && rm Makefile.new - -# DO NOT REMOVE -mmap.o: mmap.c mmap_h.h ../../include/apr_general.h \ - ../../include/apr.h ../../include/apr_errno.h \ - ../../include/apr_mmap.h ../../include/apr_network_io.h \ - ../../include/apr_file_io.h ../../include/apr_portable.h \ - ../../include/apr_thread_proc.h ../../include/apr_lock.h \ - ../../include/apr_time.h ../../include/apr_lib.h \ - ../../file_io/unix/fileio.h ../../include/apr_private.h -mmap_common.o: mmap_common.c ../unix/common.c ../unix/../beos/mmap_h.h \ - ../../include/apr_general.h ../../include/apr.h \ - ../../include/apr_errno.h ../../include/apr_mmap.h \ - ../../include/apr_network_io.h ../../include/apr_file_io.h \ - ../../include/apr_portable.h ../../include/apr_thread_proc.h \ - ../../include/apr_lock.h ../../include/apr_time.h diff --git a/mmap/beos/mmap.c b/mmap/beos/mmap.c deleted file mode 100644 index f7d97c4579b..00000000000 --- a/mmap/beos/mmap.c +++ /dev/null @@ -1,122 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#include "mmap_h.h" - -static ap_status_t mmap_cleanup(void *themmap) -{ - ap_mmap_t *mm = themmap; - int rv; - rv = delete_area(mm->area); - - if (rv == 0) { - mm->mm = 0; - mm->area = -1; - return APR_SUCCESS; - } - else - return errno; -} - -ap_status_t ap_mmap_create(ap_mmap_t **new, ap_file_t *file, ap_off_t offset, ap_size_t size, - ap_pool_t *cont) -{ - void *mm; - area_id aid = -1; - char *areaname = "apr_mmap\0"; - uint32 pages = 0; - - if (file == NULL || file->buffered || file->filedes == -1) - return APR_EBADF; - (*new) = (ap_mmap_t *)ap_palloc(cont, sizeof(ap_mmap_t)); - - pages = ((size -1) / B_PAGE_SIZE) + 1; - - ap_seek(file, APR_SET, &offset); - - aid = create_area(areaname, &mm , B_ANY_ADDRESS, pages * B_PAGE_SIZE, - B_FULL_LOCK, B_READ_AREA|B_WRITE_AREA); - - if (aid < B_NO_ERROR) { - /* we failed to get an mmap'd file... */ - return APR_ENOMEM; - } - - if (aid >= B_NO_ERROR) - read(file->filedes, mm, size); - - (*new)->mm = mm; - (*new)->size = size; - (*new)->area = aid; - (*new)->cntxt = cont; - - /* register the cleanup... */ - ap_register_cleanup((*new)->cntxt, (void*)(*new), mmap_cleanup, - ap_null_cleanup); - - return APR_SUCCESS; -} - -ap_status_t ap_mmap_delete(ap_mmap_t *mmap) -{ - ap_status_t rv; - if (mmap->area == -1) - return APR_ENOENT; - - if ((rv = mmap_cleanup(mmap)) == APR_SUCCESS) { - ap_kill_cleanup(mmap->cntxt, mmap, mmap_cleanup); - return APR_SUCCESS; - } - return rv; -} diff --git a/mmap/beos/mmap_common.c b/mmap/beos/mmap_common.c deleted file mode 100644 index 7742d0f9a77..00000000000 --- a/mmap/beos/mmap_common.c +++ /dev/null @@ -1,2 +0,0 @@ -#include "../unix/common.c" - diff --git a/mmap/beos/mmap_h.h b/mmap/beos/mmap_h.h deleted file mode 100644 index 89895377122..00000000000 --- a/mmap/beos/mmap_h.h +++ /dev/null @@ -1,79 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#ifndef MMAP_H_H -#define MMAP_H_H - -#include "apr_general.h" -#include "apr_mmap.h" -#include "apr_errno.h" -#include "apr_general.h" -#include "apr_portable.h" -#include "apr_lib.h" -#include "fileio.h" -#include <sys/stat.h> -#include <kernel/OS.h> -#include <errno.h> -#include <string.h> -#include <stdio.h> - -struct ap_mmap_t { - ap_pool_t *cntxt; - area_id area; - void *mm; - size_t size; -}; - -#endif /* ! FILE_IO_H */ - diff --git a/mmap/unix/.cvsignore b/mmap/unix/.cvsignore deleted file mode 100644 index f3c7a7c5da6..00000000000 --- a/mmap/unix/.cvsignore +++ /dev/null @@ -1 +0,0 @@ -Makefile diff --git a/mmap/unix/Makefile.in b/mmap/unix/Makefile.in deleted file mode 100644 index e24de80e4d5..00000000000 --- a/mmap/unix/Makefile.in +++ /dev/null @@ -1,66 +0,0 @@ -#CFLAGS=$(OPTIM) $(CFLAGS1) $(EXTRA_CFLAGS) -#LIBS=$(EXTRA_LIBS) $(LIBS1) -#INCLUDES=$(INCLUDES1) $(INCLUDES0) $(EXTRA_INCLUDES) -#LDFLAGS=$(LDFLAGS1) $(EXTRA_LDFLAGS) - -RM=@RM@ -CC=@CC@ -RANLIB=@RANLIB@ -CFLAGS=@CFLAGS@ @OPTIM@ -LIBS=@LIBS@ -LDFLAGS=@LDFLAGS@ $(LIBS) -INCDIR=../../include -INCDIR1=../../file_io/@OSDIR@ -INCLUDES=-I$(INCDIR) -I$(INCDIR1) -I. - -LIB=libmmap.a - -OBJS=mmap.o common.o - -.c.o: - $(CC) $(CFLAGS) -c $(INCLUDES) $< - -all: $(OBJS) - -clean: - $(RM) -f *.o *.a *.so - -distclean: clean - -$(RM) -f Makefile - -$(OBJS): Makefile - -#$(LIB): $(OBJS) -# $(RM) -f $@ -# $(AR) cr $@ $(OBJS) -# $(RANLIB) $@ - -# -# We really don't expect end users to use this rule. It works only with -# gcc, and rebuilds Makefile.tmpl. You have to re-run Configure after -# using it. -# -depend: - cp Makefile.in Makefile.in.bak \ - && sed -ne '1,/^# DO NOT REMOVE/p' Makefile.in > Makefile.new \ - && gcc -MM $(INCLUDES) $(CFLAGS) *.c >> Makefile.new \ - && sed -e '1,$$s: $(INCDIR)/: $$(INCDIR)/:g' \ - -e '1,$$s: $(OSDIR)/: $$(OSDIR)/:g' Makefile.new \ - > Makefile.in \ - && rm Makefile.new - -# DO NOT REMOVE -common.o: common.c mmap_h.h ../../include/apr_private.h \ - ../../include/apr_general.h ../../include/apr.h \ - ../../include/apr_errno.h ../../include/apr_mmap.h \ - ../../include/apr_network_io.h ../../include/apr_file_io.h \ - ../../include/apr_time.h ../../include/apr_portable.h \ - ../../include/apr_thread_proc.h ../../include/apr_lock.h \ - ../../file_io/unix/fileio.h ../../include/apr_lib.h -mmap.o: mmap.c mmap_h.h ../../include/apr_private.h \ - ../../include/apr_general.h ../../include/apr.h \ - ../../include/apr_errno.h ../../include/apr_mmap.h \ - ../../include/apr_network_io.h ../../include/apr_file_io.h \ - ../../include/apr_time.h ../../include/apr_portable.h \ - ../../include/apr_thread_proc.h ../../include/apr_lock.h \ - ../../file_io/unix/fileio.h ../../include/apr_lib.h diff --git a/mmap/unix/common.c b/mmap/unix/common.c index 34eb8fe929f..1172f3c89b9 100644 --- a/mmap/unix/common.c +++ b/mmap/unix/common.c @@ -1,55 +1,17 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. +/* 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. */ /* common .c @@ -61,17 +23,17 @@ * */ -#ifdef BEOS -#include "../beos/mmap_h.h" -#else -#include "mmap_h.h" -#endif +#include "apr.h" +#include "apr_private.h" +#include "apr_mmap.h" +#include "apr_errno.h" -#if HAVE_MMAP +#if APR_HAS_MMAP || defined(BEOS) -ap_status_t ap_mmap_offset(void **addr, ap_mmap_t *mmap, ap_off_t offset) -{ - if (offset < 0 || offset > mmap->size) +APR_DECLARE(apr_status_t) apr_mmap_offset(void **addr, apr_mmap_t *mmap, + apr_off_t offset) +{ + if (offset < 0 || (apr_size_t)offset > mmap->size) return APR_EINVAL; (*addr) = (char *) mmap->mm + offset; diff --git a/mmap/unix/mmap.c b/mmap/unix/mmap.c index 5e5b571f7d1..67195709674 100644 --- a/mmap/unix/mmap.c +++ b/mmap/unix/mmap.c @@ -1,120 +1,172 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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_general.h" +#include "apr_strings.h" +#include "apr_mmap.h" +#include "apr_errno.h" +#include "apr_arch_file_io.h" +#include "apr_portable.h" + +/* System headers required for the mmap library */ #ifdef BEOS -#include "../beos/mmap_h.h" -#else -#include "mmap_h.h" +#include <kernel/OS.h> +#endif +#if APR_HAVE_STRING_H +#include <string.h> +#endif +#if APR_HAVE_STDIO_H +#include <stdio.h> +#endif +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif +#ifdef HAVE_SYS_MMAN_H +#include <sys/mman.h> #endif -#include "apr_portable.h" - -#if HAVE_MMAP +#if APR_HAS_MMAP || defined(BEOS) -static ap_status_t mmap_cleanup(void *themmap) +static apr_status_t mmap_cleanup(void *themmap) { - ap_mmap_t *mm = themmap; - int rv; + apr_mmap_t *mm = themmap; + apr_mmap_t *next = APR_RING_NEXT(mm,link); + int rv = 0; + + /* we no longer refer to the mmaped region */ + APR_RING_REMOVE(mm,link); + APR_RING_NEXT(mm,link) = NULL; + APR_RING_PREV(mm,link) = NULL; + + if (next != mm) { + /* more references exist, so we're done */ + return APR_SUCCESS; + } + +#ifdef BEOS + rv = delete_area(mm->area); +#else rv = munmap(mm->mm, mm->size); +#endif + mm->mm = (void *)-1; if (rv == 0) { - mm->mm = (caddr_t)-1; return APR_SUCCESS; } - else - return errno; + return errno; } -ap_status_t ap_mmap_create(ap_mmap_t **new, ap_file_t *file, ap_off_t offset, - ap_size_t size, ap_pool_t *cont) +APR_DECLARE(apr_status_t) apr_mmap_create(apr_mmap_t **new, + apr_file_t *file, apr_off_t offset, + apr_size_t size, apr_int32_t flag, + apr_pool_t *cont) { - caddr_t mm; - - if (file == NULL || file->filedes == -1) + void *mm; +#ifdef BEOS + area_id aid = -1; + uint32 pages = 0; +#else + apr_int32_t native_flags = 0; +#endif + +#if APR_HAS_LARGE_FILES && defined(HAVE_MMAP64) +#define mmap mmap64 +#elif APR_HAS_LARGE_FILES && SIZEOF_OFF_T == 4 + /* LFS but no mmap64: check for overflow */ + if ((apr_int64_t)offset + size > INT_MAX) + return APR_EINVAL; +#endif + + if (size == 0) + return APR_EINVAL; + + if (file == NULL || file->filedes == -1 || file->buffered) return APR_EBADF; + (*new) = (apr_mmap_t *)apr_pcalloc(cont, sizeof(apr_mmap_t)); + +#ifdef BEOS + /* XXX: mmap shouldn't really change the seek offset */ + apr_file_seek(file, APR_SET, &offset); - (*new) = (ap_mmap_t *)ap_palloc(cont, sizeof(ap_mmap_t)); + /* There seems to be some strange interactions that mean our area must + * be set as READ & WRITE or writev will fail! Go figure... + * So we ignore the value in flags and always ask for both READ and WRITE + */ + pages = (size + B_PAGE_SIZE -1) / B_PAGE_SIZE; + aid = create_area("apr_mmap", &mm , B_ANY_ADDRESS, pages * B_PAGE_SIZE, + B_NO_LOCK, B_WRITE_AREA|B_READ_AREA); + + if (aid < B_NO_ERROR) { + /* we failed to get an area we can use... */ + *new = NULL; + return APR_ENOMEM; + } + + if (aid >= B_NO_ERROR) + read(file->filedes, mm, size); - ap_seek(file, APR_SET, &offset); - mm = mmap(NULL, size, PROT_READ, MAP_SHARED, file->filedes ,0); + (*new)->area = aid; +#else - if (mm == (caddr_t)-1) { + if (flag & APR_MMAP_WRITE) { + native_flags |= PROT_WRITE; + } + if (flag & APR_MMAP_READ) { + native_flags |= PROT_READ; + } + + mm = mmap(NULL, size, native_flags, MAP_SHARED, file->filedes, offset); + + if (mm == (void *)-1) { /* we failed to get an mmap'd file... */ - return APR_ENOMEM; + *new = NULL; + return errno; } +#endif + (*new)->mm = mm; (*new)->size = size; (*new)->cntxt = cont; + APR_RING_ELEM_INIT(*new, link); /* register the cleanup... */ - ap_register_cleanup((*new)->cntxt, (void*)(*new), mmap_cleanup, - ap_null_cleanup); + apr_pool_cleanup_register((*new)->cntxt, (void*)(*new), mmap_cleanup, + apr_pool_cleanup_null); return APR_SUCCESS; } -ap_status_t ap_mmap_delete(ap_mmap_t *mmap) +APR_DECLARE(apr_status_t) apr_mmap_dup(apr_mmap_t **new_mmap, + apr_mmap_t *old_mmap, + apr_pool_t *p) { - ap_status_t rv; + *new_mmap = (apr_mmap_t *)apr_pmemdup(p, old_mmap, sizeof(apr_mmap_t)); + (*new_mmap)->cntxt = p; - if (mmap->mm == (caddr_t) -1) - return APR_ENOENT; - - if ((rv = mmap_cleanup(mmap)) == APR_SUCCESS) { - ap_kill_cleanup(mmap->cntxt, mmap, mmap_cleanup); - return APR_SUCCESS; - } - return rv; + APR_RING_INSERT_AFTER(old_mmap, *new_mmap, link); + + apr_pool_cleanup_register(p, *new_mmap, mmap_cleanup, + apr_pool_cleanup_null); + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_mmap_delete(apr_mmap_t *mm) +{ + return apr_pool_cleanup_run(mm->cntxt, mm, mmap_cleanup); } #endif diff --git a/mmap/unix/mmap_h.h b/mmap/unix/mmap_h.h deleted file mode 100644 index fbb42b63d6f..00000000000 --- a/mmap/unix/mmap_h.h +++ /dev/null @@ -1,94 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#ifndef MMAP_H_H -#define MMAP_H_H - -#include "apr_private.h" -#include "apr_general.h" -#include "apr_mmap.h" -#include "apr_errno.h" -#include "fileio.h" -#ifdef BEOS -#include "../beos/mmap_h.h" -#else -#include "mmap_h.h" -#endif - -/* System headers required for the mmap library */ -#ifdef BEOS -#include <kernel/OS.h> -#endif -#if HAVE_STRING_H -#include <string.h> -#endif -#if HAVE_STDIO_H -#include <stdio.h> -#endif -#if HAVE_SYS_STAT_H -#include <sys/stat.h> -#endif -#if HAVE_SYS_MMAN_H -#include <sys/mman.h> -#endif -/* End System Headers */ - -struct ap_mmap_t { - ap_pool_t *cntxt; - void *mm; - size_t size; -}; - -#endif /* ! MMAP_H_H */ - diff --git a/mmap/win32/mmap.c b/mmap/win32/mmap.c new file mode 100644 index 00000000000..8fbb2f25bb0 --- /dev/null +++ b/mmap/win32/mmap.c @@ -0,0 +1,173 @@ +/* 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_general.h" +#include "apr_mmap.h" +#include "apr_errno.h" +#include "apr_arch_file_io.h" +#include "apr_portable.h" +#include "apr_strings.h" + +#if APR_HAS_MMAP + +static apr_status_t mmap_cleanup(void *themmap) +{ + apr_mmap_t *mm = themmap; + apr_mmap_t *next = APR_RING_NEXT(mm,link); + + /* we no longer refer to the mmaped region */ + APR_RING_REMOVE(mm,link); + APR_RING_NEXT(mm,link) = NULL; + APR_RING_PREV(mm,link) = NULL; + + if (next != mm) { + /* more references exist, so we're done */ + return APR_SUCCESS; + } + + if (mm->mv) { + if (!UnmapViewOfFile(mm->mv)) + { + apr_status_t rv = apr_get_os_error(); + CloseHandle(mm->mhandle); + mm->mv = NULL; + mm->mhandle = NULL; + return rv; + } + mm->mv = NULL; + } + if (mm->mhandle) + { + if (!CloseHandle(mm->mhandle)) + { + apr_status_t rv = apr_get_os_error(); + CloseHandle(mm->mhandle); + mm->mhandle = NULL; + return rv; + } + mm->mhandle = NULL; + } + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_mmap_create(apr_mmap_t **new, apr_file_t *file, + apr_off_t offset, apr_size_t size, + apr_int32_t flag, apr_pool_t *cont) +{ + static DWORD memblock = 0; + DWORD fmaccess = 0; + DWORD mvaccess = 0; + DWORD offlo; + DWORD offhi; + + if (size == 0) + return APR_EINVAL; + + if (flag & APR_MMAP_WRITE) + fmaccess |= PAGE_READWRITE; + else if (flag & APR_MMAP_READ) + fmaccess |= PAGE_READONLY; + + if (flag & APR_MMAP_READ) + mvaccess |= FILE_MAP_READ; + if (flag & APR_MMAP_WRITE) + mvaccess |= FILE_MAP_WRITE; + + if (!file || !file->filehand || file->filehand == INVALID_HANDLE_VALUE + || file->buffered) + return APR_EBADF; + + if (!memblock) + { + SYSTEM_INFO si; + GetSystemInfo(&si); + memblock = si.dwAllocationGranularity; + } + + *new = apr_pcalloc(cont, sizeof(apr_mmap_t)); + (*new)->pstart = (offset / memblock) * memblock; + (*new)->poffset = offset - (*new)->pstart; + (*new)->psize = (apr_size_t)((*new)->poffset) + size; + /* The size of the CreateFileMapping object is the current size + * of the size of the mmap object (e.g. file size), not the size + * of the mapped region! + */ + +#if APR_HAS_UNICODE_FS + IF_WIN_OS_IS_UNICODE + { + (*new)->mhandle = CreateFileMappingW(file->filehand, NULL, fmaccess, + 0, 0, NULL); + } +#endif +#if APR_HAS_ANSI_FS + ELSE_WIN_OS_IS_ANSI + { + (*new)->mhandle = CreateFileMappingA(file->filehand, NULL, fmaccess, + 0, 0, NULL); + } +#endif + if (!(*new)->mhandle || (*new)->mhandle == INVALID_HANDLE_VALUE) + { + *new = NULL; + return apr_get_os_error(); + } + + offlo = (DWORD)(*new)->pstart; + offhi = (DWORD)((*new)->pstart >> 32); + (*new)->mv = MapViewOfFile((*new)->mhandle, mvaccess, offhi, + offlo, (*new)->psize); + if (!(*new)->mv) + { + apr_status_t rv = apr_get_os_error(); + CloseHandle((*new)->mhandle); + *new = NULL; + return rv; + } + + (*new)->mm = (char*)((*new)->mv) + (*new)->poffset; + (*new)->size = size; + (*new)->cntxt = cont; + APR_RING_ELEM_INIT(*new, link); + + /* register the cleanup... */ + apr_pool_cleanup_register((*new)->cntxt, (void*)(*new), mmap_cleanup, + apr_pool_cleanup_null); + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_mmap_dup(apr_mmap_t **new_mmap, + apr_mmap_t *old_mmap, + apr_pool_t *p) +{ + *new_mmap = (apr_mmap_t *)apr_pmemdup(p, old_mmap, sizeof(apr_mmap_t)); + (*new_mmap)->cntxt = p; + + APR_RING_INSERT_AFTER(old_mmap, *new_mmap, link); + + apr_pool_cleanup_register(p, *new_mmap, mmap_cleanup, + apr_pool_cleanup_null); + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_mmap_delete(apr_mmap_t *mm) +{ + return apr_pool_cleanup_run(mm->cntxt, mm, mmap_cleanup); +} + +#endif diff --git a/network_io/beos/Makefile.in b/network_io/beos/Makefile.in deleted file mode 100644 index a8b094ef698..00000000000 --- a/network_io/beos/Makefile.in +++ /dev/null @@ -1,97 +0,0 @@ -#CFLAGS=$(OPTIM) $(CFLAGS1) $(EXTRA_CFLAGS) -#LIBS=$(EXTRA_LIBS) $(LIBS1) -#INCLUDES=$(INCLUDES1) $(INCLUDES0) $(EXTRA_INCLUDES) -#LDFLAGS=$(LDFLAGS1) $(EXTRA_LDFLAGS) - -CC=@CC@ -RANLIB=@RANLIB@ -CFLAGS=@CFLAGS@ @OPTIM@ -LIBS=@LIBS@ -LDFLAGS=@LDFLAGS@ $(LIBS) -INCDIR=../../include -I../../file_io/unix -INCLUDES=-I$(INCDIR) -I. - -LIB=libnetwork.a - -OBJS=poll.o \ - sendrecv.o \ - sockets.o \ - sockopt.o \ - inet_aton.o \ - sockaddr.o - -.c.o: - $(CC) $(CFLAGS) -c $(INCLUDES) $< - -all: $(LIB) - -clean: - $(RM) -f *.o *.a *.so - -distclean: clean - -$(RM) -f Makefile - -$(OBJS): Makefile - -$(LIB): $(OBJS) - $(RM) -f $@ - $(AR) cr $@ $(OBJS) - $(RANLIB) $@ - -# -# We really don't expect end users to use this rule. It works only with -# gcc, and rebuilds Makefile.tmpl. You have to re-run Configure after -# using it. -# -depend: - cp Makefile.in Makefile.in.bak \ - && sed -ne '1,/^# DO NOT REMOVE/p' Makefile.in > Makefile.new \ - && gcc -MM $(INCLUDES) $(CFLAGS) *.c >> Makefile.new \ - && sed -e '1,$$s: $(INCDIR)/: $$(INCDIR)/:g' \ - -e '1,$$s: $(OSDIR)/: $$(OSDIR)/:g' Makefile.new \ - > Makefile.in \ - && rm Makefile.new - -# DO NOT REMOVE -inet_aton.o: inet_aton.c networkio.h ../../include/apr_network_io.h \ - ../../include/apr_general.h ../../include/apr.h \ - ../../include/apr_errno.h ../../include/apr_file_io.h \ - ../../include/apr_time.h ../../include/apr_portable.h \ - ../../include/apr_thread_proc.h ../../include/apr_lock.h \ - ../../include/apr_lib.h ../../file_io/unix/fileio.h \ - ../../include/apr_private.h -poll.o: poll.c networkio.h ../../include/apr_network_io.h \ - ../../include/apr_general.h ../../include/apr.h \ - ../../include/apr_errno.h ../../include/apr_file_io.h \ - ../../include/apr_time.h ../../include/apr_portable.h \ - ../../include/apr_thread_proc.h ../../include/apr_lock.h \ - ../../include/apr_lib.h ../../file_io/unix/fileio.h \ - ../../include/apr_private.h -sendrecv.o: sendrecv.c networkio.h ../../include/apr_network_io.h \ - ../../include/apr_general.h ../../include/apr.h \ - ../../include/apr_errno.h ../../include/apr_file_io.h \ - ../../include/apr_time.h ../../include/apr_portable.h \ - ../../include/apr_thread_proc.h ../../include/apr_lock.h \ - ../../include/apr_lib.h ../../file_io/unix/fileio.h \ - ../../include/apr_private.h -sockaddr.o: sockaddr.c networkio.h ../../include/apr_network_io.h \ - ../../include/apr_general.h ../../include/apr.h \ - ../../include/apr_errno.h ../../include/apr_file_io.h \ - ../../include/apr_time.h ../../include/apr_portable.h \ - ../../include/apr_thread_proc.h ../../include/apr_lock.h \ - ../../include/apr_lib.h ../../file_io/unix/fileio.h \ - ../../include/apr_private.h -sockets.o: sockets.c networkio.h ../../include/apr_network_io.h \ - ../../include/apr_general.h ../../include/apr.h \ - ../../include/apr_errno.h ../../include/apr_file_io.h \ - ../../include/apr_time.h ../../include/apr_portable.h \ - ../../include/apr_thread_proc.h ../../include/apr_lock.h \ - ../../include/apr_lib.h ../../file_io/unix/fileio.h \ - ../../include/apr_private.h -sockopt.o: sockopt.c networkio.h ../../include/apr_network_io.h \ - ../../include/apr_general.h ../../include/apr.h \ - ../../include/apr_errno.h ../../include/apr_file_io.h \ - ../../include/apr_time.h ../../include/apr_portable.h \ - ../../include/apr_thread_proc.h ../../include/apr_lock.h \ - ../../include/apr_lib.h ../../file_io/unix/fileio.h \ - ../../include/apr_private.h diff --git a/network_io/beos/inet_aton.c b/network_io/beos/inet_aton.c deleted file mode 100644 index 732019c1177..00000000000 --- a/network_io/beos/inet_aton.c +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Copyright (c) 1983, 1990, 1993 - * 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. - */ - -/* - * Portions Copyright (c) 1993 by Digital Equipment Corporation. - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies, and that - * the name of Digital Equipment Corporation not be used in advertising or - * publicity pertaining to distribution of the document or software without - * specific, written prior permission. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL - * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT - * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL - * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR - * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS - * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS - * SOFTWARE. - */ - -/* - * Portions Copyright (c) 1996-1999 by Internet Software Consortium. - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS - * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE - * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL - * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR - * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS - * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS - * SOFTWARE. - */ - -#include "networkio.h" - -/* BeOS doesn't yet have it's own inet_aton and Bind won't be ported - * until R5, so this is from a Bind 8 distribution. It's currently untested. - */ - -int inet_aton(const char *cp, struct in_addr *addr) { - u_long val; - int base, n; - char c; - short parts[4]; - short *pp = parts; - int digit; - - c = *cp; - for (;;) { - /* - * Collect number up to ``.''. - * Values are specified as for C: - * 0x=hex, 0=octal, isdigit=decimal. - */ - if (!isdigit(c)) - return (0); - val = 0; base = 10; digit = 0; - if (c == '0') { - c = *++cp; - if (c == 'x' || c == 'X') - base = 16, c = *++cp; - else { - base = 8; - digit = 1 ; - } - } - for (;;) { - if (isascii(c) && isdigit(c)) { - if (base == 8 && (c == '8' || c == '9')) - return (0); - val = (val * base) + (c - '0'); - c = *++cp; - digit = 1; - } else if (base == 16 && isascii(c) && isxdigit(c)) { - val = (val << 4) | - (c + 10 - (islower(c) ? 'a' : 'A')); - c = *++cp; - digit = 1; - } else - break; - } - if (c == '.') { - /* - * Internet format: - * a.b.c.d - * a.b.c (with c treated as 16 bits) - * a.b (with b treated as 24 bits) - */ - if (pp >= parts + 3 || val > 0xff) - return (0); - *pp++ = val; - c = *++cp; - } else - break; - } - /* - * Check for trailing characters. - */ - if (c != '\0' && (!isascii(c) || !isspace(c))) - return (0); - /* - * Did we get a valid digit? - */ - if (!digit) - return (0); - /* - * Concoct the address according to - * the number of parts specified. - */ - n = pp - parts + 1; - switch (n) { - case 1: /* a -- 32 bits */ - break; - - case 2: /* a.b -- 8.24 bits */ - if (val > 0xffffff) - return (0); - val |= parts[0] << 24; - break; - - case 3: /* a.b.c -- 8.8.16 bits */ - if (val > 0xffff) - return (0); - val |= (parts[0] << 24) | (parts[1] << 16); - break; - - case 4: /* a.b.c.d -- 8.8.8.8 bits */ - if (val > 0xff) - return (0); - val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8); - break; - } - if (addr != NULL) - addr->s_addr = htonl(val); - return (1); -} diff --git a/network_io/beos/networkio.h b/network_io/beos/networkio.h deleted file mode 100644 index 3966acf433b..00000000000 --- a/network_io/beos/networkio.h +++ /dev/null @@ -1,112 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#ifndef NETWORK_IO_H -#define NETWORK_IO_H - -#include <socket.h> -#include <netdb.h> -#include <errno.h> -#include <string.h> -#include <stdlib.h> -#include <sys/time.h> -#include "apr_network_io.h" -#include "apr_general.h" -#include "apr_portable.h" -#include "apr_lib.h" -#include "fileio.h" -#include "apr_errno.h" - -/* The definition of isascii was missed from the PowerPC ctype.h - * - * It will be included in the next release, but until then... */ -#if __POWERPC__ -#define isascii(c) (((c) & ~0x7f)==0) -#endif - -#include "apr_general.h" -#include <ByteOrder.h> /* for the ntohs definition */ - -#define POLLIN 1 -#define POLLPRI 2 -#define POLLOUT 4 -#define POLLERR 8 -#define POLLHUP 16 -#define POLLNVAL 32 - -struct ap_socket_t { - ap_pool_t *cntxt; - int socketdes; - struct sockaddr_in *local_addr; - struct sockaddr_in *remote_addr; - int addr_len; - ap_interval_time_t timeout; - int connected; -}; - -struct ap_pollfd_t { - ap_pool_t *cntxt; - struct ap_socket_t *sock; - fd_set *read; - fd_set *write; - fd_set *except; - int highsock; -}; - -ap_int16_t get_event(ap_int16_t); - -int inet_aton(const char *cp, struct in_addr *addr); - -#endif /* ! NETWORK_IO_H */ - diff --git a/network_io/beos/poll.c b/network_io/beos/poll.c deleted file mode 100644 index 82e011ceac8..00000000000 --- a/network_io/beos/poll.c +++ /dev/null @@ -1,218 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#include "networkio.h" - -/* BeOS R4 doesn't have a poll function, but R5 will have */ -/* so for the time being we try our best with an implementaion that */ -/* uses select. However, select on beos isn't that hot either, so */ -/* until R5 we have to live with a less than perfect implementation */ - -/* Apparently those sneaky people at Be included support for write in */ -/* select for R4.5 of BeOS. So here we use code that uses the write */ -/* bits. */ - -ap_status_t ap_setup_poll(ap_pollfd_t **new, ap_int32_t num, ap_pool_t *cont) -{ - (*new) = (ap_pollfd_t *)ap_palloc(cont, sizeof(ap_pollfd_t) * num); - if ((*new) == NULL) { - return APR_ENOMEM; - } - (*new)->cntxt = cont; - (*new)->read = (fd_set *)ap_palloc(cont, sizeof(fd_set)); - (*new)->write = (fd_set *)ap_palloc(cont, sizeof(fd_set)); - (*new)->except = (fd_set *)ap_palloc(cont, sizeof(fd_set)); - FD_ZERO((*new)->read); - FD_ZERO((*new)->write); - FD_ZERO((*new)->except); - (*new)->highsock = -1; - return APR_SUCCESS; -} - -ap_status_t ap_add_poll_socket(ap_pollfd_t *aprset, - ap_socket_t *sock, ap_int16_t event) -{ - if (event & APR_POLLIN) { - FD_SET(sock->socketdes, aprset->read); - } - if (event & APR_POLLPRI) { - FD_SET(sock->socketdes, aprset->read); - } - if (event & APR_POLLOUT) { - FD_SET(sock->socketdes, aprset->write); - } - if (sock->socketdes > aprset->highsock) { - aprset->highsock = sock->socketdes; - } - return APR_SUCCESS; -} - -ap_status_t ap_poll(ap_pollfd_t *aprset, ap_int32_t *nsds, - ap_interval_time_t timeout) -{ - int rv; - struct timeval tv, *tvptr; - - if (timeout < 0) { - tvptr = NULL; - } - else { - tv.tv_sec = timeout / AP_USEC_PER_SEC; - tv.tv_usec = timeout % AP_USEC_PER_SEC; - tvptr = &tv; - } - - rv = select(aprset->highsock + 1, aprset->read, aprset->write, - NULL, tvptr); - - (*nsds) = rv; - if ((*nsds) == 0) { - return APR_TIMEUP; - } - if ((*nsds) < 0) { - return APR_EEXIST; - } - return APR_SUCCESS; -} - -ap_status_t ap_get_revents(ap_int16_t *event, ap_socket_t *sock, ap_pollfd_t *aprset) -{ - ap_int16_t revents = 0; - char data[256]; - int dummy = 256; - - if (FD_ISSET(sock->socketdes, aprset->read)) { - revents |= APR_POLLIN; - if (recv(sock->socketdes, &data, 0, 0) == -1) { - switch (errno) { - case ECONNRESET: - case ECONNABORTED: - case ESHUTDOWN: - case ENETRESET: { - revents ^= APR_POLLIN; - revents |= APR_POLLHUP; - break; - } - case ENOTSOCK: { - revents ^= APR_POLLIN; - revents |= APR_POLLNVAL; - } - default: { - revents ^= APR_POLLIN; - revents |= APR_POLLERR; - } - } - } - } - if (FD_ISSET(sock->socketdes, aprset->write)) { - revents |= APR_POLLOUT; - } - - /* Still no support for execpt bits in BeOS R4.5 so for the time being */ - /* we can't check this. Hopefully the error checking above will allow */ - /* sufficient errors to be recognised to cover this. */ - - /*if (FD_ISSET(sock->socketdes, aprset->except)) { - revents |= APR_POLLPRI; - }*/ - - (*event) = revents; - return APR_SUCCESS; -} - -ap_status_t ap_remove_poll_socket(ap_pollfd_t *aprset, ap_socket_t *sock) -{ - FD_CLR(sock->socketdes, aprset->read); - FD_CLR(sock->socketdes, aprset->read); - FD_CLR(sock->socketdes, aprset->write); - return APR_SUCCESS; -} - -ap_status_t ap_clear_poll_sockets(ap_pollfd_t *aprset, ap_int16_t event) -{ - if (event & APR_POLLIN) { - FD_ZERO(aprset->read); - } - if (event & APR_POLLPRI) { - FD_ZERO(aprset->read); - } - if (event & APR_POLLOUT) { - FD_ZERO(aprset->write); - } - aprset->highsock = 0; - return APR_SUCCESS; -} - -ap_status_t ap_get_polldata(ap_pollfd_t *pollfd, char *key, void *data) -{ - if (pollfd != NULL) { - return ap_get_userdata(data, key, pollfd->cntxt); - } - else { - data = NULL; - return APR_ENOFILE; - } -} - -ap_status_t ap_set_polldata(ap_pollfd_t *pollfd, void *data, char *key, - ap_status_t (*cleanup) (void *)) -{ - if (pollfd != NULL) { - return ap_set_userdata(data, key, cleanup, pollfd->cntxt); - } - else { - data = NULL; - return APR_ENOFILE; - } -} diff --git a/network_io/beos/sendrecv.c b/network_io/beos/sendrecv.c index 2cccb0b9b7e..201abf89c89 100644 --- a/network_io/beos/sendrecv.c +++ b/network_io/beos/sendrecv.c @@ -1,60 +1,27 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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 "networkio.h" +#include "apr_private.h" +#if BEOS_BONE /* BONE uses the unix code - woohoo */ +#include "../unix/sendrecv.c" +#else +#include "apr_arch_networkio.h" +#include "apr_time.h" -static ap_status_t wait_for_io_or_timeout(ap_socket_t *sock, int for_read) +static apr_status_t wait_for_io_or_timeout(apr_socket_t *sock, int for_read) { struct timeval tv, *tvptr; fd_set fdset; @@ -67,8 +34,8 @@ static ap_status_t wait_for_io_or_timeout(ap_socket_t *sock, int for_read) tvptr = NULL; } else { - tv.tv_sec = sock->timeout / AP_USEC_PER_SEC; - tv.tv_usec = sock->timeout % AP_USEC_PER_SEC; + tv.tv_sec = sock->timeout / APR_USEC_PER_SEC; + tv.tv_usec = sock->timeout % APR_USEC_PER_SEC; tvptr = &tv; } srv = select(sock->socketdes + 1, @@ -88,59 +55,162 @@ static ap_status_t wait_for_io_or_timeout(ap_socket_t *sock, int for_read) return APR_SUCCESS; } -ap_status_t ap_send(ap_socket_t *sock, const char *buf, ap_ssize_t *len) +#define SEND_WAIT APR_USEC_PER_SEC / 10 + +APR_DECLARE(apr_status_t) apr_socket_send(apr_socket_t *sock, const char *buf, + apr_size_t *len) { - ssize_t rv; + apr_ssize_t rv; do { rv = send(sock->socketdes, buf, (*len), 0); } while (rv == -1 && errno == EINTR); if (rv == -1 && errno == EWOULDBLOCK && sock->timeout > 0) { - ap_status_t arv = wait_for_io_or_timeout(sock, 0); + apr_int32_t snooze_val = SEND_WAIT; + apr_int32_t zzz = 0; + + do { + rv = send(sock->socketdes, buf, (*len), 0); + if (rv == -1 && errno == EWOULDBLOCK){ + apr_sleep (snooze_val); + zzz += snooze_val; + snooze_val += SEND_WAIT; + /* have we passed our timeout value */ + if (zzz > (sock->timeout * APR_USEC_PER_SEC)) + break; + } + } while (rv == -1 && (errno == EINTR || errno == EWOULDBLOCK)); + } + if (rv == -1) { + *len = 0; + return errno; + } + (*len) = rv; + + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_socket_recv(apr_socket_t *sock, char *buf, + apr_size_t *len) +{ + apr_ssize_t rv; + + do { + rv = recv(sock->socketdes, buf, (*len), 0); + } while (rv == -1 && errno == EINTR); + + if (rv == -1 && errno == EWOULDBLOCK && sock->timeout > 0) { + apr_status_t arv = wait_for_io_or_timeout(sock, 1); if (arv != APR_SUCCESS) { *len = 0; return arv; } else { do { - rv = send(sock->socketdes, buf, (*len), 0); + rv = recv(sock->socketdes, buf, (*len), 0); } while (rv == -1 && errno == EINTR); } } if (rv == -1) { - *len = 0; + (*len) = 0; return errno; } (*len) = rv; + if (rv == 0) + return APR_EOF; return APR_SUCCESS; } -ap_status_t ap_recv(ap_socket_t *sock, char *buf, ap_ssize_t *len) +/* BeOS doesn't have writev for sockets so we use the following instead... + */ +APR_DECLARE(apr_status_t) apr_socket_sendv(apr_socket_t * sock, + const struct iovec *vec, + apr_int32_t nvec, apr_size_t *len) { - ap_ssize_t rv; - + *len = vec[0].iov_len; + return apr_socket_send(sock, vec[0].iov_base, len); +} + +APR_DECLARE(apr_status_t) apr_socket_sendto(apr_socket_t *sock, + apr_sockaddr_t *where, + apr_int32_t flags, const char *buf, + apr_size_t *len) +{ + apr_ssize_t rv; + do { - rv = recv(sock->socketdes, buf, (*len), 0); + rv = sendto(sock->socketdes, buf, (*len), flags, + (const struct sockaddr*)&where->sa, + where->salen); } while (rv == -1 && errno == EINTR); - if (rv == -1 && errno == EWOULDBLOCK && sock->timeout > 0) { - ap_status_t arv = wait_for_io_or_timeout(sock, 1); + if (rv == -1 && (errno == EAGAIN || errno == EWOULDBLOCK) + && sock->timeout != 0) { + apr_status_t arv = wait_for_io_or_timeout(sock, 0); if (arv != APR_SUCCESS) { *len = 0; return arv; - } - else { + } else { do { - rv = recv(sock->socketdes, buf, (*len), 0); + rv = sendto(sock->socketdes, buf, (*len), flags, + (const struct sockaddr*)&where->sa, + where->salen); } while (rv == -1 && errno == EINTR); } } + if (rv == -1) { + *len = 0; + return errno; + } + *len = rv; + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_socket_recvfrom(apr_sockaddr_t *from, + apr_socket_t *sock, + apr_int32_t flags, char *buf, + apr_size_t *len) +{ + apr_ssize_t rv; + + if (from == NULL){ + return APR_ENOMEM; + /* Not sure if this is correct. Maybe we should just allocate + the memory?? + */ + } + + do { + rv = recvfrom(sock->socketdes, buf, (*len), flags, + (struct sockaddr*)&from->sa, &from->salen); + } while (rv == -1 && errno == EINTR); + + if (rv == -1 && (errno == EAGAIN || errno == EWOULDBLOCK) && + sock->timeout != 0) { + apr_status_t arv = wait_for_io_or_timeout(sock, 1); + if (arv != APR_SUCCESS) { + *len = 0; + return arv; + } else { + do { + rv = recvfrom(sock->socketdes, buf, (*len), flags, + (struct sockaddr*)&from->sa, &from->salen); + } while (rv == -1 && errno == EINTR); + } + } if (rv == -1) { (*len) = 0; return errno; } + + from->port = ntohs(from->sa.sin.sin_port); + (*len) = rv; + if (rv == 0) + return APR_EOF; + return APR_SUCCESS; } +#endif /* ! BEOS_BONE */ diff --git a/network_io/beos/sockaddr.c b/network_io/beos/sockaddr.c deleted file mode 100644 index e880fc364e1..00000000000 --- a/network_io/beos/sockaddr.c +++ /dev/null @@ -1,178 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#include "networkio.h" - -ap_status_t ap_set_local_port(ap_socket_t *sock, ap_uint32_t port) -{ - if (!sock) { - return APR_EBADF; - } - sock->local_addr->sin_port = htons((short)port); - return APR_SUCCESS; -} - -ap_status_t ap_set_remote_port(ap_socket_t *sock, ap_uint32_t port) -{ - if (!sock) { - return APR_EBADF; - } - sock->remote_addr->sin_port = htons((short)port); - return APR_SUCCESS; -} - -ap_status_t ap_get_local_port(ap_uint32_t *port, ap_socket_t *sock) -{ - if (!sock) { - return APR_EBADF; - } - *port = ntohs(sock->local_addr->sin_port); - return APR_SUCCESS; -} - -ap_status_t ap_get_remote_port(ap_uint32_t *port, ap_socket_t *sock) -{ - if (!sock) { - return APR_EBADF; - } - *port = ntohs(sock->remote_addr->sin_port); - return APR_SUCCESS; -} - -ap_status_t ap_set_local_ipaddr(ap_socket_t *sock, const char *addr) -{ - u_long ipaddr; - - if (!sock) { - return APR_EBADF; - } - - if (!strcmp(addr, APR_ANYADDR)) { - sock->local_addr->sin_addr.s_addr = htonl(INADDR_ANY); - return APR_SUCCESS; - } - - ipaddr = inet_addr(addr); - - if (ipaddr == -1) { - return errno; - } - - sock->local_addr->sin_addr.s_addr = ipaddr; - return APR_SUCCESS; -} - -ap_status_t ap_set_remote_ipaddr(ap_socket_t *sock, const char *addr) -{ - u_long ipaddr; - - if (!sock) { - return APR_EBADF; - } - - if (!strcmp(addr, APR_ANYADDR)) { - sock->remote_addr->sin_addr.s_addr = htonl(INADDR_ANY); - return APR_SUCCESS; - } - - ipaddr = inet_addr(addr); - - if (ipaddr == (u_long)-1) { - return errno; - } - - sock->remote_addr->sin_addr.s_addr = ipaddr; - return APR_SUCCESS; -} - -ap_status_t ap_get_local_ipaddr(char **addr, const ap_socket_t *sock) -{ - if (!sock) { - return APR_EBADF; - } - - *addr = ap_pstrdup(sock->cntxt, inet_ntoa(sock->local_addr->sin_addr)); - return APR_SUCCESS; -} - -ap_status_t ap_get_remote_ipaddr(char **addr, const ap_socket_t *sock) -{ - if (!sock) { - return APR_EBADF; - } - - *addr = ap_pstrdup(sock->cntxt, inet_ntoa(sock->remote_addr->sin_addr)); - return APR_SUCCESS; -} - - -ap_status_t ap_get_local_name(struct sockaddr_in **name, const ap_socket_t *sock) -{ - if (!sock) { - return APR_EBADF; - } - - *name = sock->local_addr; - return APR_SUCCESS; -} - -ap_status_t ap_get_remote_name(struct sockaddr_in **name, const ap_socket_t *sock) -{ - if (!sock) { - return APR_EBADF; - } - - *name = sock->remote_addr; - return APR_SUCCESS; -} diff --git a/network_io/beos/socketcommon.c b/network_io/beos/socketcommon.c new file mode 100644 index 00000000000..b9f594bbe0d --- /dev/null +++ b/network_io/beos/socketcommon.c @@ -0,0 +1,6 @@ +#include "../unix/inet_ntop.c" +#include "../unix/inet_pton.c" +#include "../unix/sockets.c" +#include "../unix/sockaddr.c" +#include "../unix/sockopt.c" +#include "../unix/socket_util.c" diff --git a/network_io/beos/sockets.c b/network_io/beos/sockets.c deleted file mode 100644 index 5a8afa6257e..00000000000 --- a/network_io/beos/sockets.c +++ /dev/null @@ -1,233 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#include "networkio.h" - -ap_status_t socket_cleanup(void *sock) -{ - ap_socket_t *thesocket = sock; - if (closesocket(thesocket->socketdes) == 0) { - thesocket->socketdes = -1; - return APR_SUCCESS; - } - else { - return errno; - } -} - -ap_status_t ap_create_tcp_socket(ap_socket_t **new, ap_pool_t *cont) -{ - (*new) = (ap_socket_t *)ap_palloc(cont,sizeof(ap_socket_t)); - - if ((*new) == NULL){ - return APR_ENOMEM; - } - - (*new)->cntxt = cont; - (*new)->local_addr = (struct sockaddr_in *) ap_palloc((*new)->cntxt, - sizeof (struct sockaddr_in)); - (*new)->remote_addr = (struct sockaddr_in *) ap_palloc((*new)->cntxt, - sizeof (struct sockaddr_in)); - if ((*new)->local_addr == NULL || (*new)->remote_addr==NULL){ - return APR_ENOMEM; - } - - (*new)->socketdes = socket(AF_INET ,SOCK_STREAM, 0); - (*new)->local_addr->sin_family = AF_INET; - (*new)->remote_addr->sin_family = AF_INET; - (*new)->addr_len = sizeof(*(*new)->local_addr); - memset(&(*new)->local_addr->sin_zero, 0, sizeof((*new)->local_addr->sin_zero)); - memset(&(*new)->remote_addr->sin_zero, 0, sizeof((*new)->remote_addr->sin_zero)); - - if ((*new)->socketdes < 0) { - return errno; - } - - (*new)->timeout = -1; - ap_register_cleanup((*new)->cntxt, (void *)(*new), - socket_cleanup, ap_null_cleanup); - return APR_SUCCESS; -} - -ap_status_t ap_shutdown(ap_socket_t *thesocket, ap_shutdown_how_e how) -{ - return shutdown(thesocket->socketdes, how); -} - -ap_status_t ap_close_socket(ap_socket_t *thesocket) -{ - ap_kill_cleanup(thesocket->cntxt,thesocket,socket_cleanup); - return socket_cleanup(thesocket); -} - -ap_status_t ap_bind(ap_socket_t *sock) -{ - if (bind(sock->socketdes, (struct sockaddr *)sock->local_addr, sock->addr_len) == -1) - return errno; - else - return APR_SUCCESS; -} - -ap_status_t ap_listen(ap_socket_t *sock, ap_int32_t backlog) -{ - if (listen(sock->socketdes, backlog) == -1) - return errno; - else - return APR_SUCCESS; -} - -ap_status_t ap_accept(ap_socket_t **new, const ap_socket_t *sock, ap_pool_t *connection_context) -{ - (*new) = (ap_socket_t *)ap_palloc(connection_context, - sizeof(ap_socket_t)); - - (*new)->cntxt = connection_context; - (*new)->local_addr = (struct sockaddr_in *)ap_palloc((*new)->cntxt, - sizeof(struct sockaddr_in)); - - (*new)->remote_addr = (struct sockaddr_in *)ap_palloc((*new)->cntxt, - sizeof(struct sockaddr_in)); - (*new)->addr_len = sizeof(struct sockaddr_in); - (*new)->connected = 1; - - (*new)->socketdes = accept(sock->socketdes, (struct sockaddr *)(*new)->remote_addr, - &(*new)->addr_len); - - if (getsockname((*new)->socketdes, (struct sockaddr *)(*new)->local_addr, - &((*new)->addr_len)) < 0) { - return errno; - } - if ((*new)->socketdes <0){ - return errno; - } - - ap_register_cleanup((*new)->cntxt, (void *)new, - socket_cleanup, ap_null_cleanup); - return APR_SUCCESS; -} - -ap_status_t ap_connect(ap_socket_t *sock, char *hostname) -{ - struct hostent *hp; - - hp = gethostbyname(hostname); - if ((sock->socketdes < 0) || (!sock->remote_addr)) { - return APR_ENOTSOCK; - } - - memcpy((char *)&sock->remote_addr->sin_addr, hp->h_addr , hp->h_length); - - sock->remote_addr->sin_family = AF_INET; - - memset(sock->remote_addr->sin_zero, 0, sizeof(sock->remote_addr->sin_zero)); - - sock->addr_len = sizeof(sock->remote_addr); - - if ((connect(sock->socketdes, (const struct sockaddr *)sock->remote_addr, sock->addr_len) < 0) - && (errno != EINPROGRESS)) { - return errno; - } else { - int namelen = sizeof(*sock->local_addr); - getsockname(sock->socketdes, (struct sockaddr *)sock->local_addr, &namelen); - sock->connected = 1; - } - - return APR_SUCCESS; -} - -ap_status_t ap_get_socketdata(void **data, char *key, ap_socket_t *sock) -{ - if (socket != NULL) { - return ap_get_userdata(data, key, sock->cntxt); - } - else { - data = NULL; - return APR_ENOSOCKET; - } -} - -ap_status_t ap_set_socketdata(ap_socket_t *sock, void *data, char *key, - ap_status_t (*cleanup) (void *)) -{ - if (sock != NULL) { - return ap_set_userdata(data, key, cleanup, sock->cntxt); - } - else { - data = NULL; - return APR_ENOSOCKET; - } -} - -ap_status_t ap_get_os_sock(ap_os_sock_t *thesock, ap_socket_t *sock) -{ - if (sock == NULL) { - return APR_ENOSOCKET; - } - *thesock = sock->socketdes; - return APR_SUCCESS; -} - -ap_status_t ap_put_os_sock(ap_socket_t **sock, ap_os_sock_t *thesock, - ap_pool_t *cont) -{ - if (cont == NULL) { - return APR_ENOPOOL; - } - if ((*sock) == NULL) { - (*sock) = (ap_socket_t *)ap_palloc(cont, sizeof(ap_socket_t)); - (*sock)->cntxt = cont; - } - (*sock)->socketdes = *thesock; - return APR_SUCCESS; -} diff --git a/network_io/beos/sockopt.c b/network_io/beos/sockopt.c deleted file mode 100644 index 6472fe4eed7..00000000000 --- a/network_io/beos/sockopt.c +++ /dev/null @@ -1,112 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#include "networkio.h" - -ap_status_t ap_setsocketopt(ap_socket_t *sock, ap_int32_t opt, ap_int32_t on) -{ - int one; - if (on){ - one = 1; - }else { - one = 0; - } - if (opt & APR_SO_SNDBUF) - return APR_ENOTIMPL; - - if (opt & APR_SO_DEBUG) { - if (setsockopt(sock->socketdes, SOL_SOCKET, SO_DEBUG, &one, sizeof(one)) == -1) { - return errno; - } - } - if (opt & APR_SO_REUSEADDR) { - if (setsockopt(sock->socketdes, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) == -1) { - return errno; - } - } - if (opt & APR_SO_NONBLOCK) { - if (setsockopt(sock->socketdes, SOL_SOCKET, SO_NONBLOCK, &one, sizeof(one)) == -1){ - return errno; - } - } - return APR_SUCCESS; -} - -ap_status_t ap_gethostname(char * buf, int len, ap_pool_t *cont) -{ - if (gethostname(buf, len) == -1){ - return errno; - } else { - return APR_SUCCESS; - } -} - -ap_status_t ap_get_remote_hostname(char **name, ap_socket_t *sock) -{ - struct hostent *hptr; - - hptr = gethostbyaddr((char *)&(sock->remote_addr->sin_addr), - sizeof(struct in_addr), AF_INET); - if (hptr != NULL) { - *name = ap_pstrdup(sock->cntxt, hptr->h_name); - if (*name) { - return APR_SUCCESS; - } - return APR_ENOMEM; - } - - /* XXX - Is this threadsafe? - manoj */ - /* on BeOS h_errno is a global... */ - return h_errno; -} diff --git a/network_io/os2/.cvsignore b/network_io/os2/.cvsignore deleted file mode 100644 index f3c7a7c5da6..00000000000 --- a/network_io/os2/.cvsignore +++ /dev/null @@ -1 +0,0 @@ -Makefile diff --git a/network_io/os2/Makefile.in b/network_io/os2/Makefile.in deleted file mode 100644 index 54dfb7d331a..00000000000 --- a/network_io/os2/Makefile.in +++ /dev/null @@ -1,91 +0,0 @@ -#CFLAGS=$(OPTIM) $(CFLAGS1) $(EXTRA_CFLAGS) -#LIBS=$(EXTRA_LIBS) $(LIBS1) -#INCLUDES=$(INCLUDES1) $(INCLUDES0) $(EXTRA_INCLUDES) -#LDFLAGS=$(LDFLAGS1) $(EXTRA_LDFLAGS) - -CC=@CC@ -RANLIB=@RANLIB@ -CFLAGS=@CFLAGS@ @OPTIM@ -LIBS=@LIBS@ -LDFLAGS=@LDFLAGS@ $(LIBS) -INCDIR=../../inc -INCDIR1=../../include -INCLUDES=-I$(INCDIR) -I$(INCDIR1) -I. - -LIB=network.a - -OBJS=poll.o \ - sendrecv.o \ - sockets.o \ - sockopt.o \ - sockaddr.o \ - os2calls.o - -.c.o: - $(CC) $(CFLAGS) -c $(INCLUDES) $< - -all: $(LIB) - -clean: - $(RM) -f *.o *.a *.so - -distclean: clean - -$(RM) -f Makefile - -$(OBJS): Makefile - -$(LIB): $(OBJS) - $(RM) -f $@ - $(AR) cr $@ $(OBJS) - $(RANLIB) $@ - -# -# We really don't expect end users to use this rule. It works only with -# gcc, and rebuilds Makefile.tmpl. You have to re-run Configure after -# using it. -# -depend: - cp Makefile.in Makefile.in.bak \ - && sed -ne '1,/^# DO NOT REMOVE/p' Makefile.in > Makefile.new \ - && gcc -MM $(INCLUDES) $(CFLAGS) *.c | sed -e "s%\\\\\(.\)%/\\1%g" >> Makefile.new \ - && sed -e '1,$$s: $(INCDIR)/: $$(INCDIR)/:g' \ - -e '1,$$s: $(INCDIR1)/: $$(INCDIR1)/:g' \ - -e '1,$$s: $(OSDIR)/: $$(OSDIR)/:g' Makefile.new \ - > Makefile.in \ - && rm Makefile.new - -# DO NOT REMOVE -os2calls.o: os2calls.c networkio.h $(INCDIR1)/apr_network_io.h \ - $(INCDIR1)/apr_general.h $(INCDIR1)/apr.h \ - $(INCDIR1)/apr_errno.h $(INCDIR1)/apr_file_io.h \ - $(INCDIR1)/apr_time.h os2calls.h $(INCDIR1)/apr_portable.h \ - $(INCDIR1)/apr_thread_proc.h $(INCDIR1)/apr_lock.h \ - $(INCDIR1)/apr_lib.h -poll.o: poll.c networkio.h $(INCDIR1)/apr_network_io.h \ - $(INCDIR1)/apr_general.h $(INCDIR1)/apr.h \ - $(INCDIR1)/apr_errno.h $(INCDIR1)/apr_file_io.h \ - $(INCDIR1)/apr_time.h os2calls.h $(INCDIR1)/apr_portable.h \ - $(INCDIR1)/apr_thread_proc.h $(INCDIR1)/apr_lock.h \ - $(INCDIR1)/apr_lib.h -sendrecv.o: sendrecv.c networkio.h $(INCDIR1)/apr_network_io.h \ - $(INCDIR1)/apr_general.h $(INCDIR1)/apr.h \ - $(INCDIR1)/apr_errno.h $(INCDIR1)/apr_file_io.h \ - $(INCDIR1)/apr_time.h os2calls.h $(INCDIR1)/apr_lib.h \ - $(INCDIR1)/apr_thread_proc.h -sockaddr.o: sockaddr.c ../unix/sockaddr.c ../unix/networkio.h \ - $(INCDIR1)/apr_private.h $(INCDIR1)/apr_network_io.h \ - $(INCDIR1)/apr_general.h $(INCDIR1)/apr.h \ - $(INCDIR1)/apr_errno.h $(INCDIR1)/apr_file_io.h \ - $(INCDIR1)/apr_time.h $(INCDIR1)/apr_lib.h \ - $(INCDIR1)/apr_thread_proc.h -sockets.o: sockets.c networkio.h $(INCDIR1)/apr_network_io.h \ - $(INCDIR1)/apr_general.h $(INCDIR1)/apr.h \ - $(INCDIR1)/apr_errno.h $(INCDIR1)/apr_file_io.h \ - $(INCDIR1)/apr_time.h os2calls.h $(INCDIR1)/apr_portable.h \ - $(INCDIR1)/apr_thread_proc.h $(INCDIR1)/apr_lock.h \ - $(INCDIR1)/apr_lib.h -sockopt.o: sockopt.c networkio.h $(INCDIR1)/apr_network_io.h \ - $(INCDIR1)/apr_general.h $(INCDIR1)/apr.h \ - $(INCDIR1)/apr_errno.h $(INCDIR1)/apr_file_io.h \ - $(INCDIR1)/apr_time.h os2calls.h $(INCDIR1)/apr_lib.h \ - $(INCDIR1)/apr_thread_proc.h diff --git a/network_io/os2/inet_ntop.c b/network_io/os2/inet_ntop.c new file mode 100644 index 00000000000..f1f79d49489 --- /dev/null +++ b/network_io/os2/inet_ntop.c @@ -0,0 +1 @@ +#include "../unix/inet_ntop.c" diff --git a/network_io/os2/inet_pton.c b/network_io/os2/inet_pton.c new file mode 100644 index 00000000000..dbd3ac454b0 --- /dev/null +++ b/network_io/os2/inet_pton.c @@ -0,0 +1 @@ +#include "../unix/inet_pton.c" diff --git a/network_io/os2/multicast.c b/network_io/os2/multicast.c new file mode 100644 index 00000000000..f1ab4990e22 --- /dev/null +++ b/network_io/os2/multicast.c @@ -0,0 +1 @@ +#include "../unix/multicast.c" diff --git a/network_io/os2/networkio.h b/network_io/os2/networkio.h deleted file mode 100644 index 63424de6a74..00000000000 --- a/network_io/os2/networkio.h +++ /dev/null @@ -1,97 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#ifndef NETWORK_IO_H -#define NETWORK_IO_H - -#include "apr_network_io.h" -#include "apr_general.h" -#include "os2calls.h" - -struct ap_socket_t { - ap_pool_t *cntxt; - int socketdes; - struct sockaddr_in *local_addr; - struct sockaddr_in *remote_addr; - int addr_len; - ap_interval_time_t timeout; - int nonblock; -}; - -struct ap_pollfd_t { - ap_pool_t *cntxt; - int *socket_list; - int *r_socket_list; - int num_read; - int num_write; - int num_except; - int num_total; -}; - -/* Error codes returned from sock_errno() */ -#define SOCBASEERR 10000 -#define SOCEPERM (SOCBASEERR+1) /* Not owner */ -#define SOCESRCH (SOCBASEERR+3) /* No such process */ -#define SOCEINTR (SOCBASEERR+4) /* Interrupted system call */ -#define SOCENXIO (SOCBASEERR+6) /* No such device or address */ -#define SOCEBADF (SOCBASEERR+9) /* Bad file number */ -#define SOCEACCES (SOCBASEERR+13) /* Permission denied */ -#define SOCEFAULT (SOCBASEERR+14) /* Bad address */ -#define SOCEINVAL (SOCBASEERR+22) /* Invalid argument */ -#define SOCEMFILE (SOCBASEERR+24) /* Too many open files */ -#define SOCEPIPE (SOCBASEERR+32) /* Broken pipe */ -#define SOCEOS2ERR (SOCBASEERR+100) /* OS/2 Error */ - -#endif /* ! NETWORK_IO_H */ - diff --git a/network_io/os2/os2calls.c b/network_io/os2/os2calls.c index 586ab0a8eaa..c0aec855afe 100644 --- a/network_io/os2/os2calls.c +++ b/network_io/os2/os2calls.c @@ -1,64 +1,24 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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 "networkio.h" +#include "apr_arch_networkio.h" #include "apr_network_io.h" #include "apr_portable.h" #include "apr_general.h" #include "apr_lib.h" -#define INCL_DOS -#include <os2.h> static int os2_socket_init(int, int ,int); @@ -79,6 +39,8 @@ int (*apr_os2_setsockopt)(int, int, int, char *, int) = NULL; int (*apr_os2_shutdown)(int, int) = NULL; int (*apr_os2_soclose)(int) = NULL; int (*apr_os2_writev)(int, struct iovec *, int) = NULL; +int (*apr_os2_sendto)(int, const char *, int, int, const struct sockaddr *, int); +int (*apr_os2_recvfrom)(int, char *, int, int, struct sockaddr *, int *); static HMODULE hSO32DLL; @@ -93,7 +55,7 @@ static int os2_fn_link() rc = DosLoadModule(errorstr, sizeof(errorstr), "SO32DLL", &hSO32DLL); if (rc) - return APR_OS2_STATUS(rc); + return APR_FROM_OS_ERROR(rc); rc = DosQueryProcAddr(hSO32DLL, 0, "SOCKET", &apr_os2_socket); @@ -145,8 +107,14 @@ static int os2_fn_link() if (!rc) rc = DosQueryProcAddr(hSO32DLL, 0, "WRITEV", &apr_os2_writev); + if (!rc) + rc = DosQueryProcAddr(hSO32DLL, 0, "SENDTO", &apr_os2_sendto); + + if (!rc) + rc = DosQueryProcAddr(hSO32DLL, 0, "RECVFROM", &apr_os2_recvfrom); + if (rc) - return APR_OS2_STATUS(rc); + return APR_FROM_OS_ERROR(rc); } DosExitCritSec(); diff --git a/network_io/os2/os2calls.h b/network_io/os2/os2calls.h deleted file mode 100644 index 40d54ee6e68..00000000000 --- a/network_io/os2/os2calls.h +++ /dev/null @@ -1,140 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#include <sys/types.h> -#include <sys/socket.h> - -extern int (*apr_os2_socket)(int, int, int); -extern int (*apr_os2_select)(int *, int, int, int, long); -extern int (*apr_os2_sock_errno)(); -extern int (*apr_os2_accept)(int, struct sockaddr *, int *); -extern int (*apr_os2_bind)(int, struct sockaddr *, int); -extern int (*apr_os2_connect)(int, struct sockaddr *, int); -extern int (*apr_os2_getpeername)(int, struct sockaddr *, int *); -extern int (*apr_os2_getsockname)(int, struct sockaddr *, int *); -extern int (*apr_os2_getsockopt)(int, int, int, char *, int *); -extern int (*apr_os2_ioctl)(int, int, caddr_t, int); -extern int (*apr_os2_listen)(int, int); -extern int (*apr_os2_recv)(int, char *, int, int); -extern int (*apr_os2_send)(int, const char *, int, int); -extern int (*apr_os2_setsockopt)(int, int, int, char *, int); -extern int (*apr_os2_shutdown)(int, int); -extern int (*apr_os2_soclose)(int); -extern int (*apr_os2_writev)(int, struct iovec *, int); - -#define socket apr_os2_socket -#define select apr_os2_select -#define sock_errno apr_os2_sock_errno -#define accept apr_os2_accept -#define bind apr_os2_bind -#define connect apr_os2_connect -#define getpeername apr_os2_getpeername -#define getsockname apr_os2_getsockname -#define getsockopt apr_os2_getsockopt -#define ioctl apr_os2_ioctl -#define listen apr_os2_listen -#define recv apr_os2_recv -#define send apr_os2_send -#define setsockopt apr_os2_setsockopt -#define shutdown apr_os2_shutdown -#define soclose apr_os2_soclose -#define writev apr_os2_writev - - -/* Error codes returned by above calls */ -#define SOCBASEERR 10000 - -#define SOCEPERM (SOCBASEERR+1) /* Not owner */ -#define SOCESRCH (SOCBASEERR+3) /* No such process */ -#define SOCEINTR (SOCBASEERR+4) /* Interrupted system call */ -#define SOCENXIO (SOCBASEERR+6) /* No such device or address */ -#define SOCEBADF (SOCBASEERR+9) /* Bad file number */ -#define SOCEACCES (SOCBASEERR+13) /* Permission denied */ -#define SOCEFAULT (SOCBASEERR+14) /* Bad address */ -#define SOCEINVAL (SOCBASEERR+22) /* Invalid argument */ -#define SOCEMFILE (SOCBASEERR+24) /* Too many open files */ -#define SOCEPIPE (SOCBASEERR+32) /* Broken pipe */ -#define SOCEOS2ERR (SOCBASEERR+100) /* OS/2 Error */ -#define SOCEWOULDBLOCK (SOCBASEERR+35) /* Operation would block */ -#define SOCEINPROGRESS (SOCBASEERR+36) /* Operation now in progress */ -#define SOCEALREADY (SOCBASEERR+37) /* Operation already in progress */ -#define SOCENOTSOCK (SOCBASEERR+38) /* Socket operation on non-socket */ -#define SOCEDESTADDRREQ (SOCBASEERR+39) /* Destination address required */ -#define SOCEMSGSIZE (SOCBASEERR+40) /* Message too long */ -#define SOCEPROTOTYPE (SOCBASEERR+41) /* Protocol wrong type for socket */ -#define SOCENOPROTOOPT (SOCBASEERR+42) /* Protocol not available */ -#define SOCEPROTONOSUPPORT (SOCBASEERR+43) /* Protocol not supported */ -#define SOCESOCKTNOSUPPORT (SOCBASEERR+44) /* Socket type not supported */ -#define SOCEOPNOTSUPP (SOCBASEERR+45) /* Operation not supported on socket */ -#define SOCEPFNOSUPPORT (SOCBASEERR+46) /* Protocol family not supported */ -#define SOCEAFNOSUPPORT (SOCBASEERR+47) /* Address family not supported by protocol family */ -#define SOCEADDRINUSE (SOCBASEERR+48) /* Address already in use */ -#define SOCEADDRNOTAVAIL (SOCBASEERR+49) /* Can't assign requested address */ -#define SOCENETDOWN (SOCBASEERR+50) /* Network is down */ -#define SOCENETUNREACH (SOCBASEERR+51) /* Network is unreachable */ -#define SOCENETRESET (SOCBASEERR+52) /* Network dropped connection on reset */ -#define SOCECONNABORTED (SOCBASEERR+53) /* Software caused connection abort */ -#define SOCECONNRESET (SOCBASEERR+54) /* Connection reset by peer */ -#define SOCENOBUFS (SOCBASEERR+55) /* No buffer space available */ -#define SOCEISCONN (SOCBASEERR+56) /* Socket is already connected */ -#define SOCENOTCONN (SOCBASEERR+57) /* Socket is not connected */ -#define SOCESHUTDOWN (SOCBASEERR+58) /* Can't send after socket shutdown */ -#define SOCETOOMANYREFS (SOCBASEERR+59) /* Too many references: can't splice */ -#define SOCETIMEDOUT (SOCBASEERR+60) /* Connection timed out */ -#define SOCECONNREFUSED (SOCBASEERR+61) /* Connection refused */ -#define SOCELOOP (SOCBASEERR+62) /* Too many levels of symbolic links */ -#define SOCENAMETOOLONG (SOCBASEERR+63) /* File name too long */ -#define SOCEHOSTDOWN (SOCBASEERR+64) /* Host is down */ -#define SOCEHOSTUNREACH (SOCBASEERR+65) /* No route to host */ -#define SOCENOTEMPTY (SOCBASEERR+66) /* Directory not empty */ diff --git a/network_io/os2/poll.c b/network_io/os2/poll.c deleted file mode 100644 index a36854ff018..00000000000 --- a/network_io/os2/poll.c +++ /dev/null @@ -1,233 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#include "networkio.h" -#include "apr_network_io.h" -#include "apr_general.h" -#include "apr_portable.h" -#include "apr_lib.h" -#include <sys/time.h> -#include <stdlib.h> -#define INCL_DOS -#include <os2.h> - -/* OS/2 doesn't have a poll function, implement using OS/2 style select */ - -ap_status_t ap_setup_poll(ap_pollfd_t **new, ap_int32_t num, ap_pool_t *cont) -{ - *new = (ap_pollfd_t *)ap_palloc(cont, sizeof(ap_pollfd_t)); - - if (*new == NULL) { - return APR_ENOMEM; - } - - (*new)->socket_list = ap_palloc(cont, sizeof(int) * num); - - if ((*new)->socket_list == NULL) { - return APR_ENOMEM; - } - - (*new)->r_socket_list = ap_palloc(cont, sizeof(int) * num); - - if ((*new)->r_socket_list == NULL) { - return APR_ENOMEM; - } - - (*new)->cntxt = cont; - (*new)->num_total = 0; - (*new)->num_read = 0; - (*new)->num_write = 0; - (*new)->num_except = 0; - - return APR_SUCCESS; -} - - - -ap_status_t ap_add_poll_socket(ap_pollfd_t *aprset, - ap_socket_t *sock, ap_int16_t events) -{ - int i; - - if (events & APR_POLLIN) { - for (i=aprset->num_total; i>aprset->num_read; i--) - aprset->socket_list[i] = aprset->socket_list[i-1]; - aprset->socket_list[i] = sock->socketdes; - aprset->num_read++; - aprset->num_total++; - } - - if (events & APR_POLLOUT) { - for (i=aprset->num_total; i>aprset->num_read + aprset->num_write; i--) - aprset->socket_list[i] = aprset->socket_list[i-1]; - aprset->socket_list[i] = sock->socketdes; - aprset->num_write++; - aprset->num_total++; - } - - if (events &APR_POLLPRI) { - aprset->socket_list[aprset->num_total] = sock->socketdes; - aprset->num_except++; - aprset->num_total++; - } - return APR_SUCCESS; -} - - - -ap_status_t ap_poll(ap_pollfd_t *pollfdset, ap_int32_t *nsds, - ap_interval_time_t timeout) -{ - int i; - int rv = 0; - time_t starttime; - struct timeval tv; - - timeout /= AP_USEC_PER_SEC; /* TODO: rework for microseconds and axe this */ - - tv.tv_sec = timeout; - tv.tv_usec = 0; - time(&starttime); - - do { - for (i=0; i<pollfdset->num_total; i++) { - pollfdset->r_socket_list[i] = pollfdset->socket_list[i]; - } - - rv = select(pollfdset->r_socket_list, - pollfdset->num_read, - pollfdset->num_write, - pollfdset->num_except, - timeout >= 0 ? timeout * 1000 : -1); - - if (rv < 0 && sock_errno() == SOCEINTR && timeout >= 0 ) { - time_t elapsed = time(NULL) - starttime; - - if (timeout <= elapsed) - break; - - timeout -= elapsed; - } - } while ( rv < 0 && sock_errno() == SOCEINTR ); - - (*nsds) = rv; - return rv < 0 ? APR_OS2_STATUS(sock_errno()) : APR_SUCCESS; -} - - - -ap_status_t ap_get_revents(ap_int16_t *event, ap_socket_t *sock, ap_pollfd_t *aprset) -{ - int i; - - *event = 0; - - for (i=0; i < aprset->num_total; i++) { - if (aprset->socket_list[i] == sock->socketdes && aprset->r_socket_list[i] > 0) { - if (i < aprset->num_read) - *event |= APR_POLLIN; - else if (i < aprset->num_read + aprset->num_write) - *event |= APR_POLLOUT; - else - *event |= APR_POLLPRI; - } - } - - return APR_SUCCESS; -} - - - -ap_status_t ap_mask_poll_socket(ap_pollfd_t *aprset, - ap_socket_t *sock, ap_int16_t events) -{ - int start, *count, pos; - - while (events) { - if (events & APR_POLLIN) { - start = 0; - count = &aprset->num_read; - events -= APR_POLLIN; - } else if (events & APR_POLLOUT) { - start = aprset->num_read; - count = &aprset->num_write; - events -= APR_POLLOUT; - } else if (events & APR_POLLPRI) { - start = aprset->num_read + aprset->num_write; - count = &aprset->num_except; - events -= APR_POLLPRI; - } else - break; - - for (pos=start; pos < start+(*count) && aprset->socket_list[pos] != sock->socketdes; pos++); - - if (pos < start+(*count)) { - aprset->num_total--; - (*count)--; - - for (;pos<aprset->num_total; pos++) { - aprset->socket_list[pos] = aprset->socket_list[pos+1]; - } - } - } - - return APR_SUCCESS; -} - - - -ap_status_t ap_remove_poll_socket(ap_pollfd_t *aprset, ap_socket_t *sock) -{ - return ap_mask_poll_socket(aprset, sock, APR_POLLIN|APR_POLLOUT|APR_POLLPRI); -} diff --git a/network_io/os2/sendrecv.c b/network_io/os2/sendrecv.c index a2bf144295e..4f67b3b312d 100644 --- a/network_io/os2/sendrecv.c +++ b/network_io/os2/sendrecv.c @@ -1,69 +1,36 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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 "networkio.h" +#include "apr_arch_networkio.h" #include "apr_errno.h" #include "apr_general.h" #include "apr_network_io.h" #include "apr_lib.h" #include <sys/time.h> -ap_status_t ap_send(ap_socket_t *sock, const char *buf, ap_ssize_t *len) +APR_DECLARE(apr_status_t) apr_socket_send(apr_socket_t *sock, const char *buf, + apr_size_t *len) { - ssize_t rv; + apr_ssize_t rv; int fds, err = 0; + if (*len > 65536) { + *len = 65536; + } + do { if (!sock->nonblock || err == SOCEWOULDBLOCK) { fds = sock->socketdes; @@ -79,7 +46,7 @@ ap_status_t ap_send(ap_socket_t *sock, const char *buf, ap_ssize_t *len) if (err == SOCEINTR) continue; - return APR_OS2_STATUS(err); + return APR_FROM_OS_ERROR(err); } } @@ -89,7 +56,7 @@ ap_status_t ap_send(ap_socket_t *sock, const char *buf, ap_ssize_t *len) if (err) { *len = 0; - return APR_OS2_STATUS(err); + return APR_FROM_OS_ERROR(err); } (*len) = rv; @@ -98,13 +65,14 @@ ap_status_t ap_send(ap_socket_t *sock, const char *buf, ap_ssize_t *len) -ap_status_t ap_recv(ap_socket_t *sock, char *buf, ap_ssize_t *len) +APR_DECLARE(apr_status_t) apr_socket_recv(apr_socket_t *sock, char *buf, + apr_size_t *len) { - ssize_t rv; + apr_ssize_t rv; int fds, err = 0; do { - if (!sock->nonblock || err == SOCEWOULDBLOCK) { + if (!sock->nonblock || (err == SOCEWOULDBLOCK && sock->timeout != 0)) { fds = sock->socketdes; rv = select(&fds, 1, 0, 0, sock->timeout >= 0 ? sock->timeout/1000 : -1); @@ -118,33 +86,41 @@ ap_status_t ap_recv(ap_socket_t *sock, char *buf, ap_ssize_t *len) if (err == SOCEINTR) continue; - return APR_OS2_STATUS(err); + return APR_FROM_OS_ERROR(err); } } rv = recv(sock->socketdes, buf, (*len), 0); err = rv < 0 ? sock_errno() : 0; - } while (err == SOCEINTR || err == SOCEWOULDBLOCK); + } while (err == SOCEINTR || (err == SOCEWOULDBLOCK && sock->timeout != 0)); if (err) { *len = 0; - return APR_OS2_STATUS(err); + return APR_FROM_OS_ERROR(err); } (*len) = rv; - return APR_SUCCESS; + return rv == 0 ? APR_EOF : APR_SUCCESS; } -ap_status_t ap_sendv(ap_socket_t *sock, const struct iovec *vec, ap_int32_t nvec, ap_int32_t *len) +APR_DECLARE(apr_status_t) apr_socket_sendv(apr_socket_t *sock, + const struct iovec *vec, + apr_int32_t nvec, apr_size_t *len) { - ap_status_t rv; + apr_status_t rv; struct iovec *tmpvec; int fds, err = 0; + int nv_tosend, total = 0; - tmpvec = alloca(sizeof(struct iovec) * nvec); - memcpy(tmpvec, vec, sizeof(struct iovec) * nvec); + /* Make sure writev() only gets fed 64k at a time */ + for ( nv_tosend = 0; nv_tosend < nvec && total + vec[nv_tosend].iov_len < 65536; nv_tosend++ ) { + total += vec[nv_tosend].iov_len; + } + + tmpvec = alloca(sizeof(struct iovec) * nv_tosend); + memcpy(tmpvec, vec, sizeof(struct iovec) * nv_tosend); do { if (!sock->nonblock || err == SOCEWOULDBLOCK) { @@ -161,19 +137,37 @@ ap_status_t ap_sendv(ap_socket_t *sock, const struct iovec *vec, ap_int32_t nvec if (err == SOCEINTR) continue; - return APR_OS2_STATUS(err); + return APR_FROM_OS_ERROR(err); } } - rv = writev(sock->socketdes, tmpvec, nvec); + rv = writev(sock->socketdes, tmpvec, nv_tosend); err = rv < 0 ? sock_errno() : 0; } while (err == SOCEINTR || err == SOCEWOULDBLOCK); if (err) { *len = 0; - return APR_OS2_STATUS(err); + return APR_FROM_OS_ERROR(err); } *len = rv; return APR_SUCCESS; } + + + +APR_DECLARE(apr_status_t) apr_socket_wait(apr_socket_t *sock, apr_wait_type_t direction) +{ + int pollsocket = sock->socketdes; + int wait_rc = select(&pollsocket, direction == APR_WAIT_READ, + direction == APR_WAIT_WRITE, 0, sock->timeout / 1000); + + if (wait_rc == 0) { + return APR_TIMEUP; + } + else if (wait_rc < 0) { + return APR_FROM_OS_ERROR(sock_errno()); + } + + return APR_SUCCESS; +} diff --git a/network_io/os2/sendrecv_udp.c b/network_io/os2/sendrecv_udp.c new file mode 100644 index 00000000000..1aea02c2591 --- /dev/null +++ b/network_io/os2/sendrecv_udp.c @@ -0,0 +1,116 @@ +/* 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_networkio.h" +#include "apr_errno.h" +#include "apr_general.h" +#include "apr_network_io.h" +#include "apr_support.h" +#include "apr_lib.h" +#include <sys/time.h> + +static apr_status_t wait_socket_ready(apr_socket_t *sock, int readwrite) +{ + int pollsocket = sock->socketdes; + int wait_rc = select(&pollsocket, readwrite == 0, readwrite == 1, 0, sock->timeout / 1000); + + if (wait_rc == 0) { + return APR_TIMEUP; + } + else if (wait_rc < 0) { + return APR_FROM_OS_ERROR(sock_errno()); + } + + return APR_SUCCESS; +} + + + +APR_DECLARE(apr_status_t) apr_socket_sendto(apr_socket_t *sock, + apr_sockaddr_t *where, + apr_int32_t flags, const char *buf, + apr_size_t *len) +{ + apr_ssize_t rv; + int serrno; + + do { + rv = sendto(sock->socketdes, buf, (*len), flags, + (struct sockaddr*)&where->sa, + where->salen); + + if (rv == -1) { + serrno = sock_errno(); + + if (serrno == SOCEWOULDBLOCK && sock->timeout != 0) { + apr_status_t wait_status = wait_socket_ready(sock, 1); + + if (wait_status != APR_SUCCESS) { + *len = 0; + return wait_status; + } + } + else if (serrno != SOCEINTR) { + *len = 0; + return APR_FROM_OS_ERROR(serrno); + } + } + else { + *len = rv; + return APR_SUCCESS; + } + } while (1); +} + + + +APR_DECLARE(apr_status_t) apr_socket_recvfrom(apr_sockaddr_t *from, + apr_socket_t *sock, + apr_int32_t flags, char *buf, + apr_size_t *len) +{ + apr_ssize_t rv; + int serrno; + + do { + from->salen = sizeof(from->sa); + rv = recvfrom(sock->socketdes, buf, (*len), flags, + (struct sockaddr*)&from->sa, + &from->salen); + + if (rv == -1) { + serrno = sock_errno(); + + if (serrno == SOCEWOULDBLOCK && sock->timeout != 0) { + apr_status_t wait_status = wait_socket_ready(sock, 0); + + if (wait_status != APR_SUCCESS) { + *len = 0; + return wait_status; + } + } + else if (serrno != SOCEINTR) { + *len = 0; + return APR_FROM_OS_ERROR(serrno); + } + } + else { + *len = rv; + apr_sockaddr_vars_set(from, from->sa.sin.sin_family, ntohs(from->sa.sin.sin_port)); + return (rv == 0 && sock->type == SOCK_STREAM) ? APR_EOF : APR_SUCCESS; + } + } while (1); +} diff --git a/network_io/os2/socket_util.c b/network_io/os2/socket_util.c new file mode 100644 index 00000000000..cdc1cea8940 --- /dev/null +++ b/network_io/os2/socket_util.c @@ -0,0 +1 @@ +#include "../unix/socket_util.c" diff --git a/network_io/os2/sockets.c b/network_io/os2/sockets.c index 737af928b10..89d987603bb 100644 --- a/network_io/os2/sockets.c +++ b/network_io/os2/sockets.c @@ -1,62 +1,26 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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 "networkio.h" +#include "apr_arch_networkio.h" +#include "apr_arch_inherit.h" #include "apr_network_io.h" #include "apr_general.h" #include "apr_portable.h" #include "apr_lib.h" +#include "apr_strings.h" #include <errno.h> #include <string.h> #include <sys/socket.h> @@ -64,194 +28,295 @@ #include <netinet/in.h> #include <arpa/inet.h> #include <netdb.h> -#include "os2calls.h" +#include "apr_arch_os2calls.h" -static ap_status_t socket_cleanup(void *sock) +static apr_status_t socket_cleanup(void *sock) { - ap_socket_t *thesocket = sock; + apr_socket_t *thesocket = sock; + + if (thesocket->socketdes < 0) { + return APR_EINVALSOCK; + } + if (soclose(thesocket->socketdes) == 0) { thesocket->socketdes = -1; return APR_SUCCESS; } else { - return APR_OS2_STATUS(sock_errno()); + return APR_FROM_OS_ERROR(sock_errno()); } } -ap_status_t ap_create_tcp_socket(ap_socket_t **new, ap_pool_t *cont) +static void set_socket_vars(apr_socket_t *sock, int family, int type, int protocol) { - (*new) = (ap_socket_t *)ap_palloc(cont, sizeof(ap_socket_t)); + sock->type = type; + sock->protocol = protocol; + apr_sockaddr_vars_set(sock->local_addr, family, 0); + apr_sockaddr_vars_set(sock->remote_addr, family, 0); +} + +static void alloc_socket(apr_socket_t **new, apr_pool_t *p) +{ + *new = (apr_socket_t *)apr_pcalloc(p, sizeof(apr_socket_t)); + (*new)->pool = p; + (*new)->local_addr = (apr_sockaddr_t *)apr_pcalloc((*new)->pool, + sizeof(apr_sockaddr_t)); + (*new)->local_addr->pool = p; + + (*new)->remote_addr = (apr_sockaddr_t *)apr_pcalloc((*new)->pool, + sizeof(apr_sockaddr_t)); + (*new)->remote_addr->pool = p; + (*new)->remote_addr_unknown = 1; + + /* Create a pollset with room for one descriptor. */ + /* ### check return codes */ + (void) apr_pollset_create(&(*new)->pollset, 1, p, 0); +} + +APR_DECLARE(apr_status_t) apr_socket_protocol_get(apr_socket_t *sock, int *protocol) +{ + *protocol = sock->protocol; + return APR_SUCCESS; +} - if ((*new) == NULL) { - return APR_ENOMEM; +APR_DECLARE(apr_status_t) apr_socket_create(apr_socket_t **new, int family, int type, + int protocol, apr_pool_t *cont) +{ + int downgrade = (family == AF_UNSPEC); + apr_pollfd_t pfd; + int oprotocol = protocol; + + if (family == AF_UNSPEC) { +#if APR_HAVE_IPV6 + family = AF_INET6; +#else + family = AF_INET; +#endif } - (*new)->cntxt = cont; - (*new)->local_addr = (struct sockaddr_in *)ap_palloc((*new)->cntxt, - sizeof(struct sockaddr_in)); - (*new)->remote_addr = (struct sockaddr_in *)ap_palloc((*new)->cntxt, - sizeof(struct sockaddr_in)); - - if ((*new)->local_addr == NULL || (*new)->remote_addr == NULL) { - return APR_ENOMEM; + + if (family == APR_UNIX) { + protocol = 0; } - - (*new)->socketdes = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - (*new)->local_addr->sin_family = AF_INET; - (*new)->remote_addr->sin_family = AF_INET; + alloc_socket(new, cont); + + (*new)->socketdes = socket(family, type, protocol); +#if APR_HAVE_IPV6 + if ((*new)->socketdes < 0 && downgrade) { + family = AF_INET; + (*new)->socketdes = socket(family, type, protocol); + } +#endif - (*new)->addr_len = sizeof(*(*new)->local_addr); - if ((*new)->socketdes < 0) { - return APR_OS2_STATUS(sock_errno()); + return APR_FROM_OS_ERROR(sock_errno()); } + set_socket_vars(*new, family, type, oprotocol); + (*new)->timeout = -1; (*new)->nonblock = FALSE; - ap_register_cleanup((*new)->cntxt, (void *)(*new), - socket_cleanup, ap_null_cleanup); + apr_pool_cleanup_register((*new)->pool, (void *)(*new), + socket_cleanup, apr_pool_cleanup_null); + return APR_SUCCESS; } -ap_status_t ap_shutdown(ap_socket_t *thesocket, ap_shutdown_how_e how) +APR_DECLARE(apr_status_t) apr_socket_shutdown(apr_socket_t *thesocket, + apr_shutdown_how_e how) { if (shutdown(thesocket->socketdes, how) == 0) { return APR_SUCCESS; } else { - return APR_OS2_STATUS(sock_errno()); + return APR_FROM_OS_ERROR(sock_errno()); } } -ap_status_t ap_close_socket(ap_socket_t *thesocket) +APR_DECLARE(apr_status_t) apr_socket_close(apr_socket_t *thesocket) { - ap_kill_cleanup(thesocket->cntxt, thesocket, socket_cleanup); + apr_pool_cleanup_kill(thesocket->pool, thesocket, socket_cleanup); return socket_cleanup(thesocket); } - - - -ap_status_t ap_bind(ap_socket_t *sock) +APR_DECLARE(apr_status_t) apr_socket_bind(apr_socket_t *sock, + apr_sockaddr_t *sa) { - if (bind(sock->socketdes, (struct sockaddr *)sock->local_addr, sock->addr_len) == -1) - return APR_OS2_STATUS(sock_errno()); - else + if (bind(sock->socketdes, + (struct sockaddr *)&sa->sa, + sa->salen) == -1) + return APR_FROM_OS_ERROR(sock_errno()); + else { + sock->local_addr = sa; + /* XXX IPv6 - this assumes sin_port and sin6_port at same offset */ + if (sock->local_addr->sa.sin.sin_port == 0) { /* no need for ntohs() when comparing w/ 0 */ + sock->local_port_unknown = 1; /* kernel got us an ephemeral port */ + } return APR_SUCCESS; + } } -ap_status_t ap_listen(ap_socket_t *sock, ap_int32_t backlog) +APR_DECLARE(apr_status_t) apr_socket_listen(apr_socket_t *sock, + apr_int32_t backlog) { if (listen(sock->socketdes, backlog) == -1) - return APR_OS2_STATUS(sock_errno()); + return APR_FROM_OS_ERROR(sock_errno()); else return APR_SUCCESS; } -ap_status_t ap_accept(ap_socket_t **new, const ap_socket_t *sock, ap_pool_t *connection_context) +APR_DECLARE(apr_status_t) apr_socket_accept(apr_socket_t **new, + apr_socket_t *sock, + apr_pool_t *connection_context) { - (*new) = (ap_socket_t *)ap_palloc(connection_context, - sizeof(ap_socket_t)); - - (*new)->cntxt = connection_context; - (*new)->remote_addr = (struct sockaddr_in *)ap_palloc((*new)->cntxt, - sizeof(struct sockaddr_in)); - (*new)->local_addr = sock->local_addr; - (*new)->addr_len = sizeof(struct sockaddr_in); + alloc_socket(new, connection_context); + set_socket_vars(*new, sock->local_addr->sa.sin.sin_family, SOCK_STREAM, sock->protocol); + (*new)->timeout = -1; (*new)->nonblock = FALSE; - (*new)->socketdes = accept(sock->socketdes, (struct sockaddr *)(*new)->remote_addr, - &(*new)->addr_len); + (*new)->socketdes = accept(sock->socketdes, + (struct sockaddr *)&(*new)->remote_addr->sa, + &(*new)->remote_addr->salen); if ((*new)->socketdes < 0) { - return APR_OS2_STATUS(sock_errno()); + return APR_FROM_OS_ERROR(sock_errno()); } - ap_register_cleanup((*new)->cntxt, (void *)(*new), - socket_cleanup, ap_null_cleanup); + *(*new)->local_addr = *sock->local_addr; + (*new)->local_addr->pool = connection_context; + (*new)->remote_addr->port = ntohs((*new)->remote_addr->sa.sin.sin_port); + + /* fix up any pointers which are no longer valid */ + if (sock->local_addr->sa.sin.sin_family == AF_INET) { + (*new)->local_addr->ipaddr_ptr = &(*new)->local_addr->sa.sin.sin_addr; + } + + apr_pool_cleanup_register((*new)->pool, (void *)(*new), + socket_cleanup, apr_pool_cleanup_null); return APR_SUCCESS; } -ap_status_t ap_connect(ap_socket_t *sock, char *hostname) +APR_DECLARE(apr_status_t) apr_socket_connect(apr_socket_t *sock, + apr_sockaddr_t *sa) { - struct hostent *hp; - - if (hostname != NULL) { - hp = gethostbyname(hostname); - - if ((sock->socketdes < 0) || (!sock->remote_addr)) { - return APR_ENOTSOCK; - } - if (!hp) { - if (h_errno == TRY_AGAIN) { - return EAGAIN; - } - return h_errno; - } - - memcpy((char *)&sock->remote_addr->sin_addr, hp->h_addr_list[0], hp->h_length); - sock->addr_len = sizeof(*sock->remote_addr); - } - - if ((connect(sock->socketdes, (struct sockaddr *)sock->remote_addr, sock->addr_len) < 0) && + if ((connect(sock->socketdes, (struct sockaddr *)&sa->sa.sin, + sa->salen) < 0) && (sock_errno() != SOCEINPROGRESS)) { - return APR_OS2_STATUS(sock_errno()); + return APR_FROM_OS_ERROR(sock_errno()); } else { - int namelen = sizeof(*sock->local_addr); - getsockname(sock->socketdes, (struct sockaddr *)sock->local_addr, &namelen); + int namelen = sizeof(sock->local_addr->sa.sin); + getsockname(sock->socketdes, (struct sockaddr *)&sock->local_addr->sa.sin, + &namelen); + sock->remote_addr = sa; return APR_SUCCESS; } } +APR_DECLARE(apr_status_t) apr_socket_type_get(apr_socket_t *sock, int *type) +{ + *type = sock->type; + return APR_SUCCESS; +} - -ap_status_t ap_get_socketdata(void **data, char *key, ap_socket_t *socket) +APR_DECLARE(apr_status_t) apr_socket_data_get(void **data, const char *key, + apr_socket_t *sock) { - if (socket != NULL) { - return ap_get_userdata(data, key, socket->cntxt); - } - else { - data = NULL; - return APR_ENOSOCKET; + sock_userdata_t *cur = sock->userdata; + + *data = NULL; + + while (cur) { + if (!strcmp(cur->key, key)) { + *data = cur->data; + break; + } + cur = cur->next; } + + return APR_SUCCESS; } -ap_status_t ap_set_socketdata(ap_socket_t *socket, void *data, char *key, - ap_status_t (*cleanup) (void *)) +APR_DECLARE(apr_status_t) apr_socket_data_set(apr_socket_t *sock, void *data, const char *key, + apr_status_t (*cleanup) (void *)) { - if (socket != NULL) { - return ap_set_userdata(data, key, cleanup, socket->cntxt); - } - else { - data = NULL; - return APR_ENOSOCKET; + sock_userdata_t *new = apr_palloc(sock->pool, sizeof(sock_userdata_t)); + + new->key = apr_pstrdup(sock->pool, key); + new->data = data; + new->next = sock->userdata; + sock->userdata = new; + + if (cleanup) { + apr_pool_cleanup_register(sock->pool, data, cleanup, cleanup); } + + return APR_SUCCESS; } -ap_status_t ap_get_os_sock(ap_os_sock_t *thesock, ap_socket_t *sock) +APR_DECLARE(apr_status_t) apr_os_sock_get(apr_os_sock_t *thesock, apr_socket_t *sock) { - if (sock == NULL) { - return APR_ENOSOCKET; - } *thesock = sock->socketdes; return APR_SUCCESS; } +APR_DECLARE(apr_status_t) apr_os_sock_make(apr_socket_t **apr_sock, + apr_os_sock_info_t *os_sock_info, + apr_pool_t *cont) +{ + alloc_socket(apr_sock, cont); + set_socket_vars(*apr_sock, os_sock_info->family, os_sock_info->type, os_sock_info->protocol); + (*apr_sock)->timeout = -1; + (*apr_sock)->socketdes = *os_sock_info->os_sock; + if (os_sock_info->local) { + memcpy(&(*apr_sock)->local_addr->sa.sin, + os_sock_info->local, + (*apr_sock)->local_addr->salen); + /* XXX IPv6 - this assumes sin_port and sin6_port at same offset */ + (*apr_sock)->local_addr->port = ntohs((*apr_sock)->local_addr->sa.sin.sin_port); + } + else { + (*apr_sock)->local_port_unknown = (*apr_sock)->local_interface_unknown = 1; + } + if (os_sock_info->remote) { + memcpy(&(*apr_sock)->remote_addr->sa.sin, + os_sock_info->remote, + (*apr_sock)->remote_addr->salen); + /* XXX IPv6 - this assumes sin_port and sin6_port at same offset */ + (*apr_sock)->remote_addr->port = ntohs((*apr_sock)->remote_addr->sa.sin.sin_port); + } + else { + (*apr_sock)->remote_addr_unknown = 1; + } + + apr_pool_cleanup_register((*apr_sock)->pool, (void *)(*apr_sock), + socket_cleanup, apr_pool_cleanup_null); + return APR_SUCCESS; +} -ap_status_t ap_put_os_sock(ap_socket_t **sock, ap_os_sock_t *thesock, ap_pool_t *cont) +APR_DECLARE(apr_status_t) apr_os_sock_put(apr_socket_t **sock, apr_os_sock_t *thesock, apr_pool_t *cont) { if (cont == NULL) { return APR_ENOPOOL; } if ((*sock) == NULL) { - (*sock) = (ap_socket_t *)ap_palloc(cont, sizeof(ap_socket_t)); - (*sock)->cntxt = cont; + alloc_socket(sock, cont); + set_socket_vars(*sock, AF_INET, SOCK_STREAM, 0); + (*sock)->timeout = -1; } + + (*sock)->local_port_unknown = (*sock)->local_interface_unknown = 1; + (*sock)->remote_addr_unknown = 1; (*sock)->socketdes = *thesock; return APR_SUCCESS; } +APR_POOL_IMPLEMENT_ACCESSOR(socket); + +APR_IMPLEMENT_INHERIT_SET(socket, inherit, pool, socket_cleanup) + +APR_IMPLEMENT_INHERIT_UNSET(socket, inherit, pool, socket_cleanup) + diff --git a/network_io/os2/sockopt.c b/network_io/os2/sockopt.c index 1da0c6bf6df..2ada4fc4760 100644 --- a/network_io/os2/sockopt.c +++ b/network_io/os2/sockopt.c @@ -1,61 +1,24 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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 "networkio.h" +#include "apr_arch_networkio.h" #include "apr_network_io.h" #include "apr_general.h" #include "apr_lib.h" +#include "apr_strings.h" #include <errno.h> #include <string.h> #include <sys/socket.h> @@ -66,7 +29,16 @@ #include <sys/so_ioctl.h> -ap_status_t ap_setsocketopt(ap_socket_t *sock, ap_int32_t opt, ap_int32_t on) +APR_DECLARE(apr_status_t) apr_socket_timeout_set(apr_socket_t *sock, + apr_interval_time_t t) +{ + sock->timeout = t; + return APR_SUCCESS; +} + + +APR_DECLARE(apr_status_t) apr_socket_opt_set(apr_socket_t *sock, + apr_int32_t opt, apr_int32_t on) { int one; struct linger li; @@ -78,72 +50,95 @@ ap_status_t ap_setsocketopt(ap_socket_t *sock, ap_int32_t opt, ap_int32_t on) if (opt & APR_SO_KEEPALIVE) { if (setsockopt(sock->socketdes, SOL_SOCKET, SO_KEEPALIVE, (void *)&one, sizeof(int)) == -1) { - return APR_OS2_STATUS(sock_errno()); + return APR_FROM_OS_ERROR(sock_errno()); } } if (opt & APR_SO_DEBUG) { if (setsockopt(sock->socketdes, SOL_SOCKET, SO_DEBUG, (void *)&one, sizeof(int)) == -1) { - return APR_OS2_STATUS(sock_errno()); + return APR_FROM_OS_ERROR(sock_errno()); + } + } + if (opt & APR_SO_BROADCAST) { + if (setsockopt(sock->socketdes, SOL_SOCKET, SO_BROADCAST, (void *)&one, sizeof(int)) == -1) { + return APR_FROM_OS_ERROR(sock_errno()); } } if (opt & APR_SO_REUSEADDR) { if (setsockopt(sock->socketdes, SOL_SOCKET, SO_REUSEADDR, (void *)&one, sizeof(int)) == -1) { - return APR_OS2_STATUS(sock_errno()); + return APR_FROM_OS_ERROR(sock_errno()); } } if (opt & APR_SO_SNDBUF) { if (setsockopt(sock->socketdes, SOL_SOCKET, SO_SNDBUF, (void *)&on, sizeof(int)) == -1) { - return APR_OS2_STATUS(sock_errno()); + return APR_FROM_OS_ERROR(sock_errno()); } } if (opt & APR_SO_NONBLOCK) { if (ioctl(sock->socketdes, FIONBIO, (caddr_t)&one, sizeof(one)) == -1) { - return APR_OS2_STATUS(sock_errno()); + return APR_FROM_OS_ERROR(sock_errno()); } else { sock->nonblock = one; } } if (opt & APR_SO_LINGER) { li.l_onoff = on; - li.l_linger = MAX_SECS_TO_LINGER; + li.l_linger = APR_MAX_SECS_TO_LINGER; if (setsockopt(sock->socketdes, SOL_SOCKET, SO_LINGER, (char *) &li, sizeof(struct linger)) == -1) { - return APR_OS2_STATUS(sock_errno()); + return APR_FROM_OS_ERROR(sock_errno()); } } - if (opt & APR_SO_TIMEOUT) { - sock->timeout = on; + if (opt & APR_TCP_NODELAY) { + if (setsockopt(sock->socketdes, IPPROTO_TCP, TCP_NODELAY, (void *)&on, sizeof(int)) == -1) { + return APR_FROM_OS_ERROR(sock_errno()); + } } return APR_SUCCESS; } - -ap_status_t ap_gethostname(char *buf, ap_int32_t len, ap_pool_t *cont) +APR_DECLARE(apr_status_t) apr_socket_timeout_get(apr_socket_t *sock, + apr_interval_time_t *t) { - if (gethostname(buf, len) == -1) - return APR_OS2_STATUS(sock_errno()); - else - return APR_SUCCESS; + *t = sock->timeout; + return APR_SUCCESS; } +APR_DECLARE(apr_status_t) apr_socket_opt_get(apr_socket_t *sock, + apr_int32_t opt, apr_int32_t *on) +{ + switch(opt) { + default: + return APR_EINVAL; + } + return APR_SUCCESS; +} + -ap_status_t ap_get_remote_hostname(char **name, ap_socket_t *sock) +APR_DECLARE(apr_status_t) apr_socket_atmark(apr_socket_t *sock, int *atmark) { - struct hostent *hptr; - - hptr = gethostbyaddr((char *)&(sock->remote_addr->sin_addr), - sizeof(struct in_addr), AF_INET); - if (hptr != NULL) { - *name = ap_pstrdup(sock->cntxt, hptr->h_name); - if (*name) { - return APR_SUCCESS; - } - return APR_ENOMEM; + int oobmark; + + if (ioctl(sock->socketdes, SIOCATMARK, (void*)&oobmark, sizeof(oobmark)) < 0) { + return APR_FROM_OS_ERROR(sock_errno()); } - /* XXX - Is this threadsafe? */ - return h_errno; + *atmark = (oobmark != 0); + + return APR_SUCCESS; } +APR_DECLARE(apr_status_t) apr_gethostname(char *buf, apr_int32_t len, + apr_pool_t *cont) +{ + if (gethostname(buf, len) == -1) { + buf[0] = '\0'; + return APR_FROM_OS_ERROR(sock_errno()); + } + else if (!memchr(buf, '\0', len)) { /* buffer too small */ + buf[0] = '\0'; + return APR_ENAMETOOLONG; + } + return APR_SUCCESS; +} diff --git a/network_io/unix/.cvsignore b/network_io/unix/.cvsignore deleted file mode 100644 index f3c7a7c5da6..00000000000 --- a/network_io/unix/.cvsignore +++ /dev/null @@ -1 +0,0 @@ -Makefile diff --git a/network_io/unix/Makefile.in b/network_io/unix/Makefile.in deleted file mode 100644 index ee0bc8bf6f4..00000000000 --- a/network_io/unix/Makefile.in +++ /dev/null @@ -1,82 +0,0 @@ -#CFLAGS=$(OPTIM) $(CFLAGS1) $(EXTRA_CFLAGS) -#LIBS=$(EXTRA_LIBS) $(LIBS1) -#INCLUDES=$(INCLUDES1) $(INCLUDES0) $(EXTRA_INCLUDES) -#LDFLAGS=$(LDFLAGS1) $(EXTRA_LDFLAGS) - -RM=@RM@ -CC=@CC@ -RANLIB=@RANLIB@ -CFLAGS=@CFLAGS@ @OPTIM@ -LIBS=@LIBS@ -LDFLAGS=@LDFLAGS@ $(LIBS) -INCDIR=../../include -INCLUDES=-I$(INCDIR) -I. - -LIB=libnetwork.a - -OBJS=poll.o \ - sendrecv.o \ - sockets.o \ - sockopt.o \ - sockaddr.o - -.c.o: - $(CC) $(CFLAGS) -c $(INCLUDES) $< - -all: $(OBJS) - -clean: - $(RM) -f *.o *.a *.so - -distclean: clean - -$(RM) -f Makefile - -$(OBJS): Makefile - -#$(LIB): $(OBJS) -# $(RM) -f $@ -# $(AR) cr $@ $(OBJS) -# $(RANLIB) $@ - -# -# We really don't expect end users to use this rule. It works only with -# gcc, and rebuilds Makefile.tmpl. You have to re-run Configure after -# using it. -# -depend: - cp Makefile.in Makefile.in.bak \ - && sed -ne '1,/^# DO NOT REMOVE/p' Makefile.in > Makefile.new \ - && gcc -MM $(INCLUDES) $(CFLAGS) *.c >> Makefile.new \ - && sed -e '1,$$s: $(INCDIR)/: $$(INCDIR)/:g' \ - -e '1,$$s: $(OSDIR)/: $$(OSDIR)/:g' Makefile.new \ - > Makefile.in \ - && rm Makefile.new - -# DO NOT REMOVE -poll.o: poll.c networkio.h $(INCDIR)/apr_private.h \ - $(INCDIR)/apr_network_io.h $(INCDIR)/apr_general.h \ - $(INCDIR)/apr.h $(INCDIR)/apr_errno.h \ - $(INCDIR)/apr_file_io.h $(INCDIR)/apr_time.h \ - $(INCDIR)/apr_lib.h $(INCDIR)/apr_thread_proc.h -sendrecv.o: sendrecv.c networkio.h $(INCDIR)/apr_private.h \ - $(INCDIR)/apr_network_io.h $(INCDIR)/apr_general.h \ - $(INCDIR)/apr.h $(INCDIR)/apr_errno.h \ - $(INCDIR)/apr_file_io.h $(INCDIR)/apr_time.h \ - $(INCDIR)/apr_lib.h $(INCDIR)/apr_thread_proc.h \ - ../../file_io/unix/fileio.h -sockaddr.o: sockaddr.c networkio.h $(INCDIR)/apr_private.h \ - $(INCDIR)/apr_network_io.h $(INCDIR)/apr_general.h \ - $(INCDIR)/apr.h $(INCDIR)/apr_errno.h \ - $(INCDIR)/apr_file_io.h $(INCDIR)/apr_time.h \ - $(INCDIR)/apr_lib.h $(INCDIR)/apr_thread_proc.h -sockets.o: sockets.c networkio.h $(INCDIR)/apr_private.h \ - $(INCDIR)/apr_network_io.h $(INCDIR)/apr_general.h \ - $(INCDIR)/apr.h $(INCDIR)/apr_errno.h \ - $(INCDIR)/apr_file_io.h $(INCDIR)/apr_time.h \ - $(INCDIR)/apr_lib.h $(INCDIR)/apr_thread_proc.h \ - $(INCDIR)/apr_portable.h $(INCDIR)/apr_lock.h -sockopt.o: sockopt.c networkio.h $(INCDIR)/apr_private.h \ - $(INCDIR)/apr_network_io.h $(INCDIR)/apr_general.h \ - $(INCDIR)/apr.h $(INCDIR)/apr_errno.h \ - $(INCDIR)/apr_file_io.h $(INCDIR)/apr_time.h \ - $(INCDIR)/apr_lib.h $(INCDIR)/apr_thread_proc.h diff --git a/network_io/unix/inet_ntop.c b/network_io/unix/inet_ntop.c new file mode 100644 index 00000000000..78dd3baae53 --- /dev/null +++ b/network_io/unix/inet_ntop.c @@ -0,0 +1,243 @@ +/* Copyright (c) 1996 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +#include "apr_private.h" +#include "apr_arch_networkio.h" +#include "apr_strings.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_NETINET_IN_H +#include <netinet/in.h> +#endif +#if APR_HAVE_ARPA_INET_H +#include <arpa/inet.h> +#endif +#include <string.h> +#if APR_HAVE_ERRNO_H +#include <errno.h> +#endif +#include <stdio.h> + +#ifndef IN6ADDRSZ +#define IN6ADDRSZ 16 +#endif + +#ifndef INT16SZ +#define INT16SZ sizeof(apr_int16_t) +#endif + +#ifndef __P +#define __P(x) x +#endif + +#if !defined(EAFNOSUPPORT) && defined(WSAEAFNOSUPPORT) +#define EAFNOSUPPORT WSAEAFNOSUPPORT +#endif + +/* + * WARNING: Don't even consider trying to compile this on a system where + * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX. + */ + +static const char *inet_ntop4 __P((const unsigned char *src, char *dst, apr_size_t size)); +#if APR_HAVE_IPV6 +static const char *inet_ntop6 __P((const unsigned char *src, char *dst, apr_size_t size)); +#endif + +/* char * + * inet_ntop(af, src, dst, size) + * convert a network format address to presentation format. + * return: + * pointer to presentation format address (`dst'), or NULL (see errno). + * author: + * Paul Vixie, 1996. + */ +const char * +apr_inet_ntop(int af, const void *src, char *dst, apr_size_t size) +{ + switch (af) { + case AF_INET: + return (inet_ntop4(src, dst, size)); +#if APR_HAVE_IPV6 + case AF_INET6: + return (inet_ntop6(src, dst, size)); +#endif + default: + errno = EAFNOSUPPORT; + return (NULL); + } + /* NOTREACHED */ +} + +/* const char * + * inet_ntop4(src, dst, size) + * format an IPv4 address, more or less like inet_ntoa() + * return: + * `dst' (as a const) + * notes: + * (1) uses no statics + * (2) takes a u_char* not an in_addr as input + * author: + * Paul Vixie, 1996. + */ +static const char * +inet_ntop4(const unsigned char *src, char *dst, apr_size_t size) +{ + const apr_size_t MIN_SIZE = 16; /* space for 255.255.255.255\0 */ + int n = 0; + char *next = dst; + + if (size < MIN_SIZE) { + errno = ENOSPC; + return NULL; + } + do { + unsigned char u = *src++; + if (u > 99) { + *next++ = '0' + u/100; + u %= 100; + *next++ = '0' + u/10; + u %= 10; + } + else if (u > 9) { + *next++ = '0' + u/10; + u %= 10; + } + *next++ = '0' + u; + *next++ = '.'; + n++; + } while (n < 4); + *--next = 0; + return dst; +} + +#if APR_HAVE_IPV6 +/* const char * + * inet_ntop6(src, dst, size) + * convert IPv6 binary address into presentation (printable) format + * author: + * Paul Vixie, 1996. + */ +static const char * +inet_ntop6(const unsigned char *src, char *dst, apr_size_t size) +{ + /* + * Note that int32_t and int16_t need only be "at least" large enough + * to contain a value of the specified size. On some systems, like + * Crays, there is no such thing as an integer variable with 16 bits. + * Keep this in mind if you think this function should have been coded + * to use pointer overlays. All the world's not a VAX. + */ + char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp; + struct { int base, len; } best = {-1, 0}, cur = {-1, 0}; + unsigned int words[IN6ADDRSZ / INT16SZ]; + int i; + const unsigned char *next_src, *src_end; + unsigned int *next_dest; + + /* + * Preprocess: + * Copy the input (bytewise) array into a wordwise array. + * Find the longest run of 0x00's in src[] for :: shorthanding. + */ + next_src = src; + src_end = src + IN6ADDRSZ; + next_dest = words; + i = 0; + do { + unsigned int next_word = (unsigned int)*next_src++; + next_word <<= 8; + next_word |= (unsigned int)*next_src++; + *next_dest++ = next_word; + + if (next_word == 0) { + if (cur.base == -1) { + cur.base = i; + cur.len = 1; + } + else { + cur.len++; + } + } else { + if (cur.base != -1) { + if (best.base == -1 || cur.len > best.len) { + best = cur; + } + cur.base = -1; + } + } + + i++; + } while (next_src < src_end); + + if (cur.base != -1) { + if (best.base == -1 || cur.len > best.len) { + best = cur; + } + } + if (best.base != -1 && best.len < 2) { + best.base = -1; + } + + /* + * Format the result. + */ + tp = tmp; + for (i = 0; i < (IN6ADDRSZ / INT16SZ);) { + /* Are we inside the best run of 0x00's? */ + if (i == best.base) { + *tp++ = ':'; + i += best.len; + continue; + } + /* Are we following an initial run of 0x00s or any real hex? */ + if (i != 0) { + *tp++ = ':'; + } + /* Is this address an encapsulated IPv4? */ + if (i == 6 && best.base == 0 && + (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) { + if (!inet_ntop4(src+12, tp, sizeof tmp - (tp - tmp))) { + return (NULL); + } + tp += strlen(tp); + break; + } + tp += apr_snprintf(tp, sizeof tmp - (tp - tmp), "%x", words[i]); + i++; + } + /* Was it a trailing run of 0x00's? */ + if (best.base != -1 && (best.base + best.len) == (IN6ADDRSZ / INT16SZ)) { + *tp++ = ':'; + } + *tp++ = '\0'; + + /* + * Check for overflow, copy, and we're done. + */ + if ((apr_size_t)(tp - tmp) > size) { + errno = ENOSPC; + return (NULL); + } + strcpy(dst, tmp); + return (dst); +} +#endif diff --git a/network_io/unix/inet_pton.c b/network_io/unix/inet_pton.c new file mode 100644 index 00000000000..d41f74965ab --- /dev/null +++ b/network_io/unix/inet_pton.c @@ -0,0 +1,240 @@ +/* Copyright (c) 1996 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +#include "apr_private.h" +#include "apr_arch_networkio.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_NETINET_IN_H +#include <netinet/in.h> +#endif +#if APR_HAVE_ARPA_INET_H +#include <arpa/inet.h> +#endif +#include <string.h> +#if APR_HAVE_ERRNO_H +#include <errno.h> +#endif + +#ifndef IN6ADDRSZ +#define IN6ADDRSZ 16 +#endif + +#ifndef INT16SZ +#define INT16SZ sizeof(apr_int16_t) +#endif + +#ifndef INADDRSZ +#define INADDRSZ 4 +#endif + +#ifndef __P +#define __P(x) x +#endif + +#if !defined(EAFNOSUPPORT) && defined(WSAEAFNOSUPPORT) +#define EAFNOSUPPORT WSAEAFNOSUPPORT +#endif + +/* + * WARNING: Don't even consider trying to compile this on a system where + * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX. + */ + +static int inet_pton4 __P((const char *src, unsigned char *dst)); +#if APR_HAVE_IPV6 +static int inet_pton6 __P((const char *src, unsigned char *dst)); +#endif + +/* int + * inet_pton(af, src, dst) + * convert from presentation format (which usually means ASCII printable) + * to network format (which is usually some kind of binary format). + * return: + * 1 if the address was valid for the specified address family + * 0 if the address wasn't valid (`dst' is untouched in this case) + * -1 if some other error occurred (`dst' is untouched in this case, too) + * author: + * Paul Vixie, 1996. + */ +int +apr_inet_pton(int af, const char *src, void *dst) +{ + switch (af) { + case AF_INET: + return (inet_pton4(src, dst)); +#if APR_HAVE_IPV6 + case AF_INET6: + return (inet_pton6(src, dst)); +#endif + default: + errno = EAFNOSUPPORT; + return (-1); + } + /* NOTREACHED */ +} + +/* int + * inet_pton4(src, dst) + * like inet_aton() but without all the hexadecimal and shorthand. + * return: + * 1 if `src' is a valid dotted quad, else 0. + * notice: + * does not touch `dst' unless it's returning 1. + * author: + * Paul Vixie, 1996. + */ +static int +inet_pton4(const char *src, unsigned char *dst) +{ + static const char digits[] = "0123456789"; + int saw_digit, octets, ch; + unsigned char tmp[INADDRSZ], *tp; + + saw_digit = 0; + octets = 0; + *(tp = tmp) = 0; + while ((ch = *src++) != '\0') { + const char *pch; + + if ((pch = strchr(digits, ch)) != NULL) { + unsigned int new = *tp * 10 + (unsigned int)(pch - digits); + + if (new > 255) + return (0); + *tp = new; + if (! saw_digit) { + if (++octets > 4) + return (0); + saw_digit = 1; + } + } else if (ch == '.' && saw_digit) { + if (octets == 4) + return (0); + *++tp = 0; + saw_digit = 0; + } else + return (0); + } + if (octets < 4) + return (0); + + memcpy(dst, tmp, INADDRSZ); + return (1); +} + +#if APR_HAVE_IPV6 +/* int + * inet_pton6(src, dst) + * convert presentation level address to network order binary form. + * return: + * 1 if `src' is a valid [RFC1884 2.2] address, else 0. + * notice: + * (1) does not touch `dst' unless it's returning 1. + * (2) :: in a full address is silently ignored. + * credit: + * inspired by Mark Andrews. + * author: + * Paul Vixie, 1996. + */ +static int +inet_pton6(const char *src, unsigned char *dst) +{ + static const char xdigits_l[] = "0123456789abcdef", + xdigits_u[] = "0123456789ABCDEF"; + unsigned char tmp[IN6ADDRSZ], *tp, *endp, *colonp; + const char *xdigits, *curtok; + int ch, saw_xdigit; + unsigned int val; + + memset((tp = tmp), '\0', IN6ADDRSZ); + endp = tp + IN6ADDRSZ; + colonp = NULL; + /* Leading :: requires some special handling. */ + if (*src == ':') + if (*++src != ':') + return (0); + curtok = src; + saw_xdigit = 0; + val = 0; + while ((ch = *src++) != '\0') { + const char *pch; + + if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL) + pch = strchr((xdigits = xdigits_u), ch); + if (pch != NULL) { + val <<= 4; + val |= (pch - xdigits); + if (val > 0xffff) + return (0); + saw_xdigit = 1; + continue; + } + if (ch == ':') { + curtok = src; + if (!saw_xdigit) { + if (colonp) + return (0); + colonp = tp; + continue; + } + if (tp + INT16SZ > endp) + return (0); + *tp++ = (unsigned char) (val >> 8) & 0xff; + *tp++ = (unsigned char) val & 0xff; + saw_xdigit = 0; + val = 0; + continue; + } + if (ch == '.' && ((tp + INADDRSZ) <= endp) && + inet_pton4(curtok, tp) > 0) { + tp += INADDRSZ; + saw_xdigit = 0; + break; /* '\0' was seen by inet_pton4(). */ + } + return (0); + } + if (saw_xdigit) { + if (tp + INT16SZ > endp) + return (0); + *tp++ = (unsigned char) (val >> 8) & 0xff; + *tp++ = (unsigned char) val & 0xff; + } + if (colonp != NULL) { + /* + * Since some memmove()'s erroneously fail to handle + * overlapping regions, we'll do the shift by hand. + */ + const apr_ssize_t n = tp - colonp; + apr_ssize_t i; + + for (i = 1; i <= n; i++) { + endp[- i] = colonp[n - i]; + colonp[n - i] = 0; + } + tp = endp; + } + if (tp != endp) + return (0); + memcpy(dst, tmp, IN6ADDRSZ); + return (1); +} +#endif diff --git a/network_io/unix/multicast.c b/network_io/unix/multicast.c new file mode 100644 index 00000000000..a8c85ce69ec --- /dev/null +++ b/network_io/unix/multicast.c @@ -0,0 +1,316 @@ +/* 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_networkio.h" +#include "apr_network_io.h" +#include "apr_support.h" +#include "apr_portable.h" +#include "apr_arch_inherit.h" + +#ifdef HAVE_GETIFADDRS +#include <net/if.h> +#if APR_HAVE_IFADDRS_H +#include <ifaddrs.h> +#endif +#endif + +#ifdef HAVE_STRUCT_IPMREQ +static void fill_mip_v4(struct ip_mreq *mip, apr_sockaddr_t *mcast, + apr_sockaddr_t *iface) +{ + mip->imr_multiaddr = mcast->sa.sin.sin_addr; + if (iface == NULL) { + mip->imr_interface.s_addr = INADDR_ANY; + } + else { + mip->imr_interface = iface->sa.sin.sin_addr; + } +} + +/* This function is only interested in AF_INET6 sockets, so a noop + * "return 0" implementation for the !APR_HAVE_IPV6 build is + * sufficient. */ +static unsigned int find_if_index(const apr_sockaddr_t *iface) +{ + unsigned int index = 0; +#if defined(HAVE_GETIFADDRS) && APR_HAVE_IFADDRS_H && APR_HAVE_IPV6 + struct ifaddrs *ifp, *ifs; + + /** + * TODO: getifaddrs is only portable to *BSD and OS X. Using ioctl + * and SIOCGIFCONF is needed for Linux/Solaris support. + * + * There is a wrapper that takes the messy ioctl interface into + * getifaddrs. The license is acceptable, but, It is a fairly large + * chunk of code. + */ + if (getifaddrs(&ifs) != 0) { + return 0; + } + + for (ifp = ifs; ifp; ifp = ifp->ifa_next) { + if (ifp->ifa_addr != NULL && ifp->ifa_addr->sa_family == AF_INET6) { + if (memcmp(&iface->sa.sin6.sin6_addr, + &((struct sockaddr_in6*)ifp->ifa_addr)->sin6_addr, + sizeof(iface->sa.sin6.sin6_addr)) == 0) { + index = if_nametoindex(ifp->ifa_name); + break; + } + } + } + + freeifaddrs(ifs); +#endif + return index; +} + +#if APR_HAVE_IPV6 +static void fill_mip_v6(struct ipv6_mreq *mip, const apr_sockaddr_t *mcast, + const apr_sockaddr_t *iface) +{ + memcpy(&mip->ipv6mr_multiaddr, mcast->ipaddr_ptr, + sizeof(mip->ipv6mr_multiaddr)); + + if (iface == NULL) { + mip->ipv6mr_interface = 0; + } + else { + mip->ipv6mr_interface = find_if_index(iface); + } +} + +#endif + +static int sock_is_ipv4(apr_socket_t *sock) +{ + if (sock->local_addr->family == APR_INET) + return 1; + return 0; +} + +#if APR_HAVE_IPV6 +static int sock_is_ipv6(apr_socket_t *sock) +{ + if (sock->local_addr->family == APR_INET6) + return 1; + return 0; +} +#endif + +static apr_status_t do_mcast(int type, apr_socket_t *sock, + apr_sockaddr_t *mcast, apr_sockaddr_t *iface, + apr_sockaddr_t *source) +{ + struct ip_mreq mip4; + apr_status_t rv = APR_SUCCESS; +#if APR_HAVE_IPV6 + struct ipv6_mreq mip6; +#endif +#ifdef GROUP_FILTER_SIZE + struct group_source_req mip; + int ip_proto; +#endif + + if (source != NULL) { +#ifdef GROUP_FILTER_SIZE + if (sock_is_ipv4(sock)) { + ip_proto = IPPROTO_IP; + } +#if APR_HAVE_IPV6 + else if (sock_is_ipv6(sock)) { + ip_proto = IPPROTO_IPV6; + } +#endif + else { + return APR_ENOTIMPL; + } + + if (type == IP_ADD_MEMBERSHIP) + type = MCAST_JOIN_SOURCE_GROUP; + else if (type == IP_DROP_MEMBERSHIP) + type = MCAST_LEAVE_SOURCE_GROUP; + else + return APR_ENOTIMPL; + + mip.gsr_interface = find_if_index(iface); + memcpy(&mip.gsr_group, mcast->ipaddr_ptr, sizeof(mip.gsr_group)); + memcpy(&mip.gsr_source, source->ipaddr_ptr, sizeof(mip.gsr_source)); + + if (setsockopt(sock->socketdes, ip_proto, type, (const void *) &mip, + sizeof(mip)) == -1) { + rv = errno; + } +#else + /* We do not support Source-Specific Multicast. */ + return APR_ENOTIMPL; +#endif + } + else { + if (sock_is_ipv4(sock)) { + + fill_mip_v4(&mip4, mcast, iface); + + if (setsockopt(sock->socketdes, IPPROTO_IP, type, + (const void *) &mip4, sizeof(mip4)) == -1) { + rv = errno; + } + } +#if APR_HAVE_IPV6 && defined(IPV6_JOIN_GROUP) && defined(IPV6_LEAVE_GROUP) + else if (sock_is_ipv6(sock)) { + if (type == IP_ADD_MEMBERSHIP) { + type = IPV6_JOIN_GROUP; + } + else if (type == IP_DROP_MEMBERSHIP) { + type = IPV6_LEAVE_GROUP; + } + else { + return APR_ENOTIMPL; + } + + fill_mip_v6(&mip6, mcast, iface); + + if (setsockopt(sock->socketdes, IPPROTO_IPV6, type, + (const void *) &mip6, sizeof(mip6)) == -1) { + rv = errno; + } + } +#endif + else { + rv = APR_ENOTIMPL; + } + } + return rv; +} + +/* Set the IP_MULTICAST_TTL or IP_MULTICAST_LOOP option, or IPv6 + * equivalents, for the socket, to the given value. Note that this + * function *only works* for those particular option types. */ +static apr_status_t do_mcast_opt(int type, apr_socket_t *sock, + apr_byte_t value) +{ + apr_status_t rv = APR_SUCCESS; + + if (sock_is_ipv4(sock)) { + /* For the IP_MULTICAST_* options, this must be a (char *) + * pointer. */ + if (setsockopt(sock->socketdes, IPPROTO_IP, type, + (const void *) &value, sizeof(value)) == -1) { + rv = errno; + } + } +#if APR_HAVE_IPV6 + else if (sock_is_ipv6(sock)) { + /* For the IPV6_* options, an (int *) pointer must be used. */ + int ivalue = value; + + if (type == IP_MULTICAST_TTL) { + type = IPV6_MULTICAST_HOPS; + } + else if (type == IP_MULTICAST_LOOP) { + type = IPV6_MULTICAST_LOOP; + } + else { + return APR_ENOTIMPL; + } + + if (setsockopt(sock->socketdes, IPPROTO_IPV6, type, + (const void *) &ivalue, sizeof(ivalue)) == -1) { + rv = errno; + } + } +#endif + else { + rv = APR_ENOTIMPL; + } + + return rv; +} +#endif + +APR_DECLARE(apr_status_t) apr_mcast_join(apr_socket_t *sock, + apr_sockaddr_t *join, + apr_sockaddr_t *iface, + apr_sockaddr_t *source) +{ +#if defined(IP_ADD_MEMBERSHIP) && defined(HAVE_STRUCT_IPMREQ) + return do_mcast(IP_ADD_MEMBERSHIP, sock, join, iface, source); +#else + return APR_ENOTIMPL; +#endif +} + +APR_DECLARE(apr_status_t) apr_mcast_leave(apr_socket_t *sock, + apr_sockaddr_t *addr, + apr_sockaddr_t *iface, + apr_sockaddr_t *source) +{ +#if defined(IP_DROP_MEMBERSHIP) && defined(HAVE_STRUCT_IPMREQ) + return do_mcast(IP_DROP_MEMBERSHIP, sock, addr, iface, source); +#else + return APR_ENOTIMPL; +#endif +} + +APR_DECLARE(apr_status_t) apr_mcast_hops(apr_socket_t *sock, apr_byte_t ttl) +{ +#if defined(IP_MULTICAST_TTL) && defined(HAVE_STRUCT_IPMREQ) + return do_mcast_opt(IP_MULTICAST_TTL, sock, ttl); +#else + return APR_ENOTIMPL; +#endif +} + +APR_DECLARE(apr_status_t) apr_mcast_loopback(apr_socket_t *sock, + apr_byte_t opt) +{ +#if defined(IP_MULTICAST_LOOP) && defined(HAVE_STRUCT_IPMREQ) + return do_mcast_opt(IP_MULTICAST_LOOP, sock, opt); +#else + return APR_ENOTIMPL; +#endif +} + +APR_DECLARE(apr_status_t) apr_mcast_interface(apr_socket_t *sock, + apr_sockaddr_t *iface) +{ +#if defined(IP_MULTICAST_IF) && defined(HAVE_STRUCT_IPMREQ) + apr_status_t rv = APR_SUCCESS; + + if (sock_is_ipv4(sock)) { + if (setsockopt(sock->socketdes, IPPROTO_IP, IP_MULTICAST_IF, + (const void *) &iface->sa.sin.sin_addr, + sizeof(iface->sa.sin.sin_addr)) == -1) { + rv = errno; + } + } +#if APR_HAVE_IPV6 + else if (sock_is_ipv6(sock)) { + unsigned int idx = find_if_index(iface); + if (setsockopt(sock->socketdes, IPPROTO_IPV6, IPV6_MULTICAST_IF, + (const void *) &idx, sizeof(idx)) == -1) { + rv = errno; + } + } +#endif + else { + rv = APR_ENOTIMPL; + } + return rv; +#else + return APR_ENOTIMPL; +#endif +} diff --git a/network_io/unix/networkio.h b/network_io/unix/networkio.h deleted file mode 100644 index 9880b04318d..00000000000 --- a/network_io/unix/networkio.h +++ /dev/null @@ -1,139 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#ifndef NETWORK_IO_H -#define NETWORK_IO_H - -#include "apr_private.h" -#include "apr_network_io.h" -#include "apr_errno.h" -#include "apr_general.h" -#include "apr_lib.h" - -/* System headers the network I/O library needs */ -#if HAVE_SYS_TYPES_H -#include <sys/types.h> -#endif -#if HAVE_SYS_UIO_H -#include <sys/uio.h> -#endif -#if HAVE_POLL_H -#include <poll.h> -#endif -#if HAVE_ERRNO_H -#include <errno.h> -#endif -#if HAVE_SYS_TIME_H -#include <sys/time.h> -#endif -#if HAVE_UNISTD_H -#include <unistd.h> -#endif -#if HAVE_STRING_H -#include <string.h> -#endif -#if HAVE_NETINET_TCP_H -#include <netinet/tcp.h> -#endif -#if HAVE_NETINET_IN_H -#include <netinet/in.h> -#endif -#if HAVE_ARPA_INET_H -#include <arpa/inet.h> -#endif -#if HAVE_SYS_SOCKET_H -#include <sys/socket.h> -#endif -#if HAVE_NETDB_H -#include <netdb.h> -#endif -#if HAVE_FCNTL_H -#include <fcntl.h> -#endif -#if HAVE_SYS_SENDFILE_H -#include <sys/sendfile.h> -#endif -/* End System Headers */ - -struct ap_socket_t { - ap_pool_t *cntxt; - int socketdes; - struct sockaddr_in *local_addr; - struct sockaddr_in *remote_addr; - socklen_t addr_len; - ap_interval_time_t timeout; -#ifndef HAVE_POLL - int connected; -#endif -}; - -struct ap_pollfd_t { - ap_pool_t *cntxt; -#ifdef HAVE_POLL - struct pollfd *pollset; - int num; - int curpos; -#else - fd_set *read; - fd_set *write; - fd_set *except; - int highsock; -#endif - ap_int16_t *events; - ap_int16_t *revents; - -}; - -#endif /* ! NETWORK_IO_H */ - diff --git a/network_io/unix/poll.c b/network_io/unix/poll.c deleted file mode 100644 index df1cfba97ce..00000000000 --- a/network_io/unix/poll.c +++ /dev/null @@ -1,381 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#include "networkio.h" - -#ifdef HAVE_POLL /* We can just use poll to do our socket polling. */ - -ap_status_t ap_setup_poll(ap_pollfd_t **new, ap_int32_t num, ap_pool_t *cont) -{ - (*new) = (ap_pollfd_t *)ap_palloc(cont, sizeof(ap_pollfd_t)); - if ((*new) == NULL) { - return APR_ENOMEM; - } - (*new)->pollset = (struct pollfd *)ap_palloc(cont, - sizeof(struct pollfd) * num); - - if ((*new)->pollset == NULL) { - return APR_ENOMEM; - } - (*new)->num = num; - (*new)->cntxt = cont; - (*new)->curpos = 0; - return APR_SUCCESS; -} - -static ap_int16_t get_event(ap_int16_t event) -{ - ap_int16_t rv = 0; - - if (event & APR_POLLIN) - rv |= POLLIN; - if (event & APR_POLLPRI) - rv |= POLLPRI; - if (event & APR_POLLOUT) - rv |= POLLOUT; - if (event & APR_POLLERR) - rv |= POLLERR; - if (event & APR_POLLHUP) - rv |= POLLHUP; - if (event & APR_POLLNVAL) - rv |= POLLNVAL; - - return rv; -} - -static ap_int16_t get_revent(ap_int16_t event) -{ - ap_int16_t rv = 0; - - if (event & POLLIN) - rv |= APR_POLLIN; - if (event & POLLPRI) - rv |= APR_POLLPRI; - if (event & POLLOUT) - rv |= APR_POLLOUT; - if (event & POLLERR) - rv |= APR_POLLERR; - if (event & POLLHUP) - rv |= APR_POLLHUP; - if (event & POLLNVAL) - rv |= APR_POLLNVAL; - - return rv; -} - -ap_status_t ap_add_poll_socket(ap_pollfd_t *aprset, - ap_socket_t *sock, ap_int16_t event) -{ - int i = 0; - - while (i < aprset->curpos && aprset->pollset[i].fd != sock->socketdes) { - i++; - } - if (i >= aprset->curpos) { - if(aprset->curpos == aprset->num) { - return APR_ENOMEM; - } - aprset->curpos++; - } - aprset->pollset[i].fd = sock->socketdes; - aprset->pollset[i].events = get_event(event); - - return APR_SUCCESS; -} - -ap_status_t ap_poll(ap_pollfd_t *aprset, ap_int32_t *nsds, - ap_interval_time_t timeout) -{ - int rv; - - if (timeout > 0) { - timeout /= 1000; /* convert microseconds to milliseconds */ - } - - rv = poll(aprset->pollset, aprset->curpos, timeout); - (*nsds) = rv; - - if ((*nsds) < 0) { - return errno; - } - return APR_SUCCESS; -} - -ap_status_t ap_get_revents(ap_int16_t *event, ap_socket_t *sock, ap_pollfd_t *aprset) -{ - int i = 0; - - while (i < aprset->curpos && aprset->pollset[i].fd != sock->socketdes) { - i++; - } - if (i >= aprset->curpos) { - return APR_EINVALSOCK; - } - (*event) = get_revent(aprset->pollset[i].revents); - return APR_SUCCESS; -} - -ap_status_t ap_mask_poll_socket(ap_pollfd_t *aprset, - ap_socket_t *sock, ap_int16_t events) -{ - ap_int16_t newevents; - int i = 0; - - while (i < aprset->curpos && aprset->pollset[i].fd != sock->socketdes) { - i++; - } - if (i >= aprset->curpos) { - return APR_NOTFOUND; - } - newevents = get_event(events); - if (aprset->events[i] & newevents) { - aprset->events[i] ^= newevents; - } - - return APR_SUCCESS; -} - -ap_status_t ap_remove_poll_socket(ap_pollfd_t *aprset, ap_socket_t *sock) -{ - int i = 0; - while(i < aprset->curpos && aprset->pollset[i].fd != sock->socketdes) { - i++; - } - if(i >= aprset->curpos) { - return APR_NOTFOUND; - } - while(++i < aprset->curpos) { - aprset->pollset[i-1].fd = aprset->pollset[i].fd; - aprset->pollset[i-1].events = aprset->pollset[i].events; - } - --aprset->curpos; - return APR_SUCCESS; -} - -ap_status_t ap_clear_poll_sockets(ap_pollfd_t *aprset, ap_int16_t events) -{ - int i = 0; - ap_int16_t newevents; - - newevents = get_event(events); - - while (i < aprset->curpos) { - if (aprset->events[i] & newevents) { - aprset->events[i] ^= newevents; - } - i++; - } - return APR_SUCCESS; -} - -#else /* Use select to mimic poll */ - -ap_status_t ap_setup_poll(ap_pollfd_t **new, ap_int32_t num, ap_pool_t *cont) -{ - (*new) = (ap_pollfd_t *)ap_palloc(cont, sizeof(ap_pollfd_t) * num); - if ((*new) == NULL) { - return APR_ENOMEM; - } - (*new)->cntxt = cont; - (*new)->read = (fd_set *)ap_palloc(cont, sizeof(fd_set)); - (*new)->write = (fd_set *)ap_palloc(cont, sizeof(fd_set)); - (*new)->except = (fd_set *)ap_palloc(cont, sizeof(fd_set)); - FD_ZERO((*new)->read); - FD_ZERO((*new)->write); - FD_ZERO((*new)->except); - (*new)->highsock = -1; - return APR_SUCCESS; -} - -ap_status_t ap_add_poll_socket(ap_pollfd_t *aprset, - ap_socket_t *sock, ap_int16_t event) -{ - if (event & APR_POLLIN) { - FD_SET(sock->socketdes, aprset->read); - } - if (event & APR_POLLPRI) { - FD_SET(sock->socketdes, aprset->read); - } - if (event & APR_POLLOUT) { - FD_SET(sock->socketdes, aprset->write); - } - if (sock->socketdes > aprset->highsock) { - aprset->highsock = sock->socketdes; - } - return APR_SUCCESS; -} - -ap_status_t ap_poll(ap_pollfd_t *aprset, ap_int32_t *nsds, - ap_interval_time_t timeout) -{ - int rv; - struct timeval tv, *tvptr; - - if (timeout < 0) { - tvptr = NULL; - } - else { - tv.tv_sec = timeout / AP_USEC_PER_SEC; - tv.tv_usec = timeout % AP_USEC_PER_SEC; - tvptr = &tv; - } - - rv = select(aprset->highsock + 1, aprset->read, aprset->write, - aprset->except, tvptr); - - (*nsds) = rv; - if ((*nsds) == 0) { - return APR_TIMEUP; - } - if ((*nsds) < 0) { - return APR_EEXIST; - } - return APR_SUCCESS; -} - -ap_status_t ap_get_revents(ap_int16_t *event, ap_socket_t *sock, ap_pollfd_t *aprset) -{ - ap_int16_t revents = 0; - char data[1]; - int flags = MSG_PEEK; - - /* We just want to PEEK at the data, so I am setting up a dummy WSABUF - * variable here. - */ - if (FD_ISSET(sock->socketdes, aprset->read)) { - revents |= APR_POLLIN; - if (sock->connected - && recv(sock->socketdes, data, sizeof data, flags) == -1) { - switch (errno) { - case ECONNRESET: - case ECONNABORTED: - case ESHUTDOWN: - case ENETRESET: - revents ^= APR_POLLIN; - revents |= APR_POLLHUP; - break; - case ENOTSOCK: - revents ^= APR_POLLIN; - revents |= APR_POLLNVAL; - break; - default: - revents ^= APR_POLLIN; - revents |= APR_POLLERR; - break; - } - } - } - if (FD_ISSET(sock->socketdes, aprset->write)) { - revents |= APR_POLLOUT; - } - /* I am assuming that the except is for out of band data, not a failed - * connection on a non-blocking socket. Might be a bad assumption, but - * it works for now. rbb. - */ - if (FD_ISSET(sock->socketdes, aprset->except)) { - revents |= APR_POLLPRI; - } - - (*event) = revents; - return APR_SUCCESS; -} - -ap_status_t ap_remove_poll_socket(ap_pollfd_t *aprset, ap_socket_t *sock) -{ - FD_CLR(sock->socketdes, aprset->read); - FD_CLR(sock->socketdes, aprset->read); - FD_CLR(sock->socketdes, aprset->write); - return APR_SUCCESS; -} - -ap_status_t ap_clear_poll_sockets(ap_pollfd_t *aprset, ap_int16_t event) -{ - if (event & APR_POLLIN) { - FD_ZERO(aprset->read); - } - if (event & APR_POLLPRI) { - FD_ZERO(aprset->read); - } - if (event & APR_POLLOUT) { - FD_ZERO(aprset->write); - } - aprset->highsock = 0; - return APR_SUCCESS; -} - -#endif - -ap_status_t ap_get_polldata(ap_pollfd_t *pollfd, char *key, void *data) -{ - if (pollfd != NULL) { - return ap_get_userdata(data, key, pollfd->cntxt); - } - else { - data = NULL; - return APR_ENOFILE; - } -} - -ap_status_t ap_set_polldata(ap_pollfd_t *pollfd, void *data, char *key, - ap_status_t (*cleanup) (void *)) -{ - if (pollfd != NULL) { - return ap_set_userdata(data, key, cleanup, pollfd->cntxt); - } - else { - data = NULL; - return APR_ENOFILE; - } -} - diff --git a/network_io/unix/sendrecv.c b/network_io/unix/sendrecv.c index be163461a57..b9e580b1b01 100644 --- a/network_io/unix/sendrecv.c +++ b/network_io/unix/sendrecv.c @@ -1,155 +1,171 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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 "networkio.h" +#include "apr_arch_networkio.h" +#include "apr_support.h" -#ifdef HAVE_SENDFILE -/* This file is needed to allow us access to the ap_file_t internals. */ -#include "../../file_io/unix/fileio.h" +#if APR_HAS_SENDFILE +/* This file is needed to allow us access to the apr_file_t internals. */ +#include "apr_arch_file_io.h" +#endif /* APR_HAS_SENDFILE */ -/* Glibc2.1.1 fails to define TCP_CORK. This is a bug that will be - *fixed in the next release. It should be 3 - */ -#if !defined(TCP_CORK) && defined(__linux__) -#define TCP_CORK 3 +/* osreldate.h is only needed on FreeBSD for sendfile detection */ +#if defined(__FreeBSD__) +#include <osreldate.h> #endif -#endif /* HAVE_SENDFILE */ - -static ap_status_t wait_for_io_or_timeout(ap_socket_t *sock, int for_read) +apr_status_t apr_socket_send(apr_socket_t *sock, const char *buf, + apr_size_t *len) { - struct timeval tv, *tvptr; - fd_set fdset; - int srv; + apr_ssize_t rv; + + if (sock->options & APR_INCOMPLETE_WRITE) { + sock->options &= ~APR_INCOMPLETE_WRITE; + goto do_select; + } do { - FD_ZERO(&fdset); - FD_SET(sock->socketdes, &fdset); - if (sock->timeout < 0) { - tvptr = NULL; + rv = write(sock->socketdes, buf, (*len)); + } while (rv == -1 && errno == EINTR); + + while (rv == -1 && (errno == EAGAIN || errno == EWOULDBLOCK) + && (sock->timeout > 0)) { + apr_status_t arv; +do_select: + arv = apr_wait_for_io_or_timeout(NULL, sock, 0); + if (arv != APR_SUCCESS) { + *len = 0; + return arv; } else { - tv.tv_sec = sock->timeout / AP_USEC_PER_SEC; - tv.tv_usec = sock->timeout % AP_USEC_PER_SEC; - tvptr = &tv; + do { + rv = write(sock->socketdes, buf, (*len)); + } while (rv == -1 && errno == EINTR); } - srv = select(sock->socketdes + 1, - for_read ? &fdset : NULL, - for_read ? NULL : &fdset, - NULL, - tvptr); - /* TODO - timeout should be smaller on repeats of this loop */ - } while (srv == -1 && errno == EINTR); - - if (srv == 0) { - return APR_TIMEUP; } - else if (srv < 0) { - return errno; + if (rv == -1) { + *len = 0; + return errno; } + if ((sock->timeout > 0) && (rv < *len)) { + sock->options |= APR_INCOMPLETE_WRITE; + } + (*len) = rv; return APR_SUCCESS; } -ap_status_t ap_send(ap_socket_t *sock, const char *buf, ap_ssize_t *len) +apr_status_t apr_socket_recv(apr_socket_t *sock, char *buf, apr_size_t *len) { - ssize_t rv; - + apr_ssize_t rv; + apr_status_t arv; + + if (sock->options & APR_INCOMPLETE_READ) { + sock->options &= ~APR_INCOMPLETE_READ; + goto do_select; + } + do { - rv = write(sock->socketdes, buf, (*len)); + rv = read(sock->socketdes, buf, (*len)); } while (rv == -1 && errno == EINTR); - if (rv == -1 && - (errno == EAGAIN || errno == EWOULDBLOCK) && - sock->timeout != 0) { - ap_status_t arv = wait_for_io_or_timeout(sock, 0); - if (arv != APR_SUCCESS) { - *len = 0; - return arv; - } + while ((rv == -1) && (errno == EAGAIN || errno == EWOULDBLOCK) + && (sock->timeout > 0)) { +do_select: + arv = apr_wait_for_io_or_timeout(NULL, sock, 1); + if (arv != APR_SUCCESS) { + *len = 0; + return arv; + } else { do { - rv = write(sock->socketdes, buf, (*len)); + rv = read(sock->socketdes, buf, (*len)); } while (rv == -1 && errno == EINTR); } } if (rv == -1) { - *len = 0; - return errno; + (*len) = 0; + return errno; + } + if ((sock->timeout > 0) && (rv < *len)) { + sock->options |= APR_INCOMPLETE_READ; } (*len) = rv; + if (rv == 0) { + return APR_EOF; + } + return APR_SUCCESS; +} + +apr_status_t apr_socket_sendto(apr_socket_t *sock, apr_sockaddr_t *where, + apr_int32_t flags, const char *buf, + apr_size_t *len) +{ + apr_ssize_t rv; + + do { + rv = sendto(sock->socketdes, buf, (*len), flags, + (const struct sockaddr*)&where->sa, + where->salen); + } while (rv == -1 && errno == EINTR); + + while ((rv == -1) && (errno == EAGAIN || errno == EWOULDBLOCK) + && (sock->timeout > 0)) { + apr_status_t arv = apr_wait_for_io_or_timeout(NULL, sock, 0); + if (arv != APR_SUCCESS) { + *len = 0; + return arv; + } else { + do { + rv = sendto(sock->socketdes, buf, (*len), flags, + (const struct sockaddr*)&where->sa, + where->salen); + } while (rv == -1 && errno == EINTR); + } + } + if (rv == -1) { + *len = 0; + return errno; + } + *len = rv; return APR_SUCCESS; } -ap_status_t ap_recv(ap_socket_t *sock, char *buf, ap_ssize_t *len) +apr_status_t apr_socket_recvfrom(apr_sockaddr_t *from, apr_socket_t *sock, + apr_int32_t flags, char *buf, + apr_size_t *len) { - ssize_t rv; + apr_ssize_t rv; + from->salen = sizeof(from->sa); + do { - rv = read(sock->socketdes, buf, (*len)); + rv = recvfrom(sock->socketdes, buf, (*len), flags, + (struct sockaddr*)&from->sa, &from->salen); } while (rv == -1 && errno == EINTR); - if (rv == -1 && - (errno == EAGAIN || errno == EWOULDBLOCK) && - sock->timeout != 0) { - ap_status_t arv = wait_for_io_or_timeout(sock, 1); - if (arv != APR_SUCCESS) { - *len = 0; - return arv; - } - else { + while ((rv == -1) && (errno == EAGAIN || errno == EWOULDBLOCK) + && (sock->timeout > 0)) { + apr_status_t arv = apr_wait_for_io_or_timeout(NULL, sock, 1); + if (arv != APR_SUCCESS) { + *len = 0; + return arv; + } else { do { - rv = read(sock->socketdes, buf, (*len)); + rv = recvfrom(sock->socketdes, buf, (*len), flags, + (struct sockaddr*)&from->sa, &from->salen); } while (rv == -1 && errno == EINTR); } } @@ -157,290 +173,949 @@ ap_status_t ap_recv(ap_socket_t *sock, char *buf, ap_ssize_t *len) (*len) = 0; return errno; } + + /* + * Check if we have a valid address. recvfrom() with MSG_PEEK may return + * success without filling in the address. + */ + if (from->salen > APR_OFFSETOF(struct sockaddr_in, sin_port)) { + apr_sockaddr_vars_set(from, from->sa.sin.sin_family, + ntohs(from->sa.sin.sin_port)); + } + (*len) = rv; + if (rv == 0 && sock->type == SOCK_STREAM) { + return APR_EOF; + } + return APR_SUCCESS; } -ap_status_t ap_sendv(ap_socket_t * sock, const struct iovec *vec, - ap_int32_t nvec, ap_int32_t *len) +apr_status_t apr_socket_sendv(apr_socket_t * sock, const struct iovec *vec, + apr_int32_t nvec, apr_size_t *len) { - ssize_t rv; +#ifdef HAVE_WRITEV + apr_ssize_t rv; + apr_size_t requested_len = 0; + apr_int32_t i; + + for (i = 0; i < nvec; i++) { + requested_len += vec[i].iov_len; + } + + if (sock->options & APR_INCOMPLETE_WRITE) { + sock->options &= ~APR_INCOMPLETE_WRITE; + goto do_select; + } do { rv = writev(sock->socketdes, vec, nvec); } while (rv == -1 && errno == EINTR); - if (rv == -1 && - (errno == EAGAIN || errno == EWOULDBLOCK) && - sock->timeout != 0) { - ap_status_t arv = wait_for_io_or_timeout(sock, 0); - if (arv != APR_SUCCESS) { - *len = 0; - return arv; - } + while ((rv == -1) && (errno == EAGAIN || errno == EWOULDBLOCK) + && (sock->timeout > 0)) { + apr_status_t arv; +do_select: + arv = apr_wait_for_io_or_timeout(NULL, sock, 0); + if (arv != APR_SUCCESS) { + *len = 0; + return arv; + } else { do { - rv = writev(sock->socketdes, vec, nvec); + rv = writev(sock->socketdes, vec, nvec); } while (rv == -1 && errno == EINTR); } } if (rv == -1) { - *len = 0; - return errno; + *len = 0; + return errno; + } + if ((sock->timeout > 0) && (rv < requested_len)) { + sock->options |= APR_INCOMPLETE_WRITE; } (*len) = rv; return APR_SUCCESS; +#else + *len = vec[0].iov_len; + return apr_socket_send(sock, vec[0].iov_base, len); +#endif } -#if defined(HAVE_SENDFILE) +apr_status_t apr_socket_wait(apr_socket_t *sock, apr_wait_type_t direction) +{ + return apr_wait_for_io_or_timeout(NULL, sock, direction == APR_WAIT_READ); +} + +#if APR_HAS_SENDFILE + +/* TODO: Verify that all platforms handle the fd the same way, + * i.e. that they don't move the file pointer. + */ +/* TODO: what should flags be? int_32? */ + +/* Define a structure to pass in when we have a NULL header value */ +static apr_hdtr_t no_hdtr; - /* TODO: Verify that all platforms handle the fd the same way - * (i.e. not moving current file pointer) - * - Should flags be an int_32 or what? - */ +#if (defined(__linux__) || defined(__GNU__)) && defined(HAVE_WRITEV) -#if defined(__linux__) && defined(HAVE_WRITEV) -ap_status_t ap_sendfile(ap_socket_t *sock, ap_file_t *file, - ap_hdtr_t *hdtr, ap_off_t *offset, ap_size_t *len, - ap_int32_t flags) +apr_status_t apr_socket_sendfile(apr_socket_t *sock, apr_file_t *file, + apr_hdtr_t *hdtr, apr_off_t *offset, + apr_size_t *len, apr_int32_t flags) { + int nopush_set = 0, rv, i; + apr_size_t bytes_to_send = *len; + apr_status_t arv; + apr_size_t n; + +#if APR_HAS_LARGE_FILES && defined(HAVE_SENDFILE64) + apr_off_t off = *offset; +#define sendfile sendfile64 + +#elif APR_HAS_LARGE_FILES && SIZEOF_OFF_T == 4 + /* 64-bit apr_off_t but no sendfile64(): fail if trying to send + * past the 2Gb limit. */ + off_t off; + + if ((apr_int64_t)*offset + bytes_to_send > INT_MAX) { + *len = 0; + return EINVAL; + } + + off = *offset; + +#else off_t off = *offset; - int corkflag = 1; - int rv, nbytes = 0; - ap_status_t arv; - /* TCP_CORK keeps us from sending partial frames when we shouldn't */ - rv = setsockopt(sock->socketdes, SOL_TCP, TCP_CORK, - (const void *) &corkflag, sizeof(corkflag)); - if (rv == -1) { - *len = 0; - return errno; + /* Multiple reports have shown sendfile failing with EINVAL if + * passed a >=2Gb count value on some 64-bit kernels. It won't + * noticably hurt performance to limit each call to <2Gb at a + * time, so avoid that issue here: */ + if (sizeof(off_t) == 8 && bytes_to_send > INT_MAX) { + bytes_to_send = INT_MAX; + } +#endif + + /* Until further notice. */ + *len = 0; + + if (!hdtr) { + hdtr = &no_hdtr; + } + else if ((hdtr->numheaders > 0 || hdtr->numtrailers > 0) + && !apr_is_option_set(sock, APR_TCP_NOPUSH)) { + /* cork before writing headers */ + rv = apr_socket_opt_set(sock, APR_TCP_NOPUSH, 1); + if (rv != APR_SUCCESS) { + return rv; + } + nopush_set = 1; } - /* Now write the headers */ if (hdtr->numheaders > 0) { - ap_int32_t hdrbytes; - arv = ap_sendv(sock, hdtr->headers, hdtr->numheaders, &hdrbytes); + apr_size_t total_hdrbytes; + + /* Now write the headers */ + arv = apr_socket_sendv(sock, hdtr->headers, hdtr->numheaders, &n); + *len += n; if (arv != APR_SUCCESS) { - *len = 0; - return errno; + return arv; + } + + /* If this was a partial write and we aren't doing timeouts, + * return now with the partial byte count; this is a non-blocking + * socket. + */ + total_hdrbytes = 0; + for (i = 0; i < hdtr->numheaders; i++) { + total_hdrbytes += hdtr->headers[i].iov_len; + } + if (n < total_hdrbytes) { + if (nopush_set) { + return apr_socket_opt_set(sock, APR_TCP_NOPUSH, 0); + } + return APR_SUCCESS; } - nbytes += hdrbytes; + } + + if (sock->options & APR_INCOMPLETE_WRITE) { + sock->options &= ~APR_INCOMPLETE_WRITE; + goto do_select; } do { - rv = sendfile(sock->socketdes, /* socket */ - file->filedes, /* open file descriptor of the file to be sent */ - &off, /* where in the file to start */ - *len /* number of bytes to send */ - ); + rv = sendfile(sock->socketdes, /* socket */ + file->filedes, /* open file descriptor of the file to be sent */ + &off, /* where in the file to start */ + bytes_to_send); /* number of bytes to send */ } while (rv == -1 && errno == EINTR); - if (rv == -1 && - (errno == EAGAIN || errno == EWOULDBLOCK) && - sock->timeout != 0) { - arv = wait_for_io_or_timeout(sock, 0); - if (arv != APR_SUCCESS) { - *len = 0; - return arv; - } + while ((rv == -1) && (errno == EAGAIN || errno == EWOULDBLOCK) + && (sock->timeout > 0)) { +do_select: + arv = apr_wait_for_io_or_timeout(NULL, sock, 0); + if (arv != APR_SUCCESS) { + return arv; + } else { do { - rv = sendfile(sock->socketdes, /* socket */ - file->filedes, /* open file descriptor of the file to be sent */ - &off, /* where in the file to start */ - *len); /* number of bytes to send */ + rv = sendfile(sock->socketdes, /* socket */ + file->filedes, /* open file descriptor of the file to be sent */ + &off, /* where in the file to start */ + bytes_to_send); /* number of bytes to send */ } while (rv == -1 && errno == EINTR); } } if (rv == -1) { - *len = nbytes; - return errno; + arv = errno; + if (nopush_set) { + apr_socket_opt_set(sock, APR_TCP_NOPUSH, 0); + } + return arv; } - nbytes += rv; + *len += rv; + + if ((apr_size_t)rv < bytes_to_send) { + if (nopush_set) { + arv = apr_socket_opt_set(sock, APR_TCP_NOPUSH, 0); + } + else { + arv = APR_SUCCESS; + } + if (rv > 0) { + + /* If this was a partial write, return now with the + * partial byte count; this is a non-blocking socket. + */ + + if (sock->timeout > 0) { + sock->options |= APR_INCOMPLETE_WRITE; + } + return arv; + } + else { + /* If the file got smaller mid-request, eventually the offset + * becomes equal to the new file size and the kernel returns 0. + * Make this an error so the caller knows to log something and + * exit. + */ + return APR_EOF; + } + } /* Now write the footers */ if (hdtr->numtrailers > 0) { - ap_int32_t trbytes; - arv = ap_sendv(sock, hdtr->trailers, hdtr->numtrailers, &trbytes); - nbytes += trbytes; + arv = apr_socket_sendv(sock, hdtr->trailers, hdtr->numtrailers, &n); + *len += n; + if (nopush_set) { + apr_socket_opt_set(sock, APR_TCP_NOPUSH, 0); + } if (arv != APR_SUCCESS) { - *len = nbytes; - return errno; + return arv; } } - /* Uncork to send queued frames */ - corkflag = 0; - rv = setsockopt(sock->socketdes, SOL_TCP, TCP_CORK, - (const void *) &corkflag, sizeof(corkflag)); - - (*len) = nbytes; - return rv < 0 ? errno : APR_SUCCESS; + return APR_SUCCESS; } -/* These are just demos of how the code for the other OSes. - * I haven't tested these, but they're right in terms of interface. - * I just wanted to see what types of vars would be required from other OSes. - */ +#elif defined(DARWIN) + +/* OS/X Release 10.5 or greater */ +apr_status_t apr_socket_sendfile(apr_socket_t *sock, apr_file_t *file, + apr_hdtr_t *hdtr, apr_off_t *offset, + apr_size_t *len, apr_int32_t flags) +{ + apr_off_t nbytes = 0; + apr_size_t bytes_to_send = *len; + apr_status_t arv; + apr_size_t n; + int rv = 0; + + /* Until further notice. */ + *len = 0; + + /* Ignore flags for now. */ + flags = 0; + + if (!hdtr) { + hdtr = &no_hdtr; + } + + /* OS X can send the headers/footers as part of the system call, + * but how it counts bytes isn't documented properly. We use + * apr_socket_sendv() instead. + */ + if (hdtr->numheaders > 0) { + apr_size_t total_hdrbytes; + int i; + + /* Now write the headers */ + arv = apr_socket_sendv(sock, hdtr->headers, hdtr->numheaders, &n); + *len += n; + if (arv != APR_SUCCESS) { + return arv; + } + + total_hdrbytes = 0; + for (i = 0; i < hdtr->numheaders; i++) { + total_hdrbytes += hdtr->headers[i].iov_len; + } + if (n < total_hdrbytes) { + return APR_SUCCESS; + } + } + + do { + if (!bytes_to_send) { + break; + } + if (sock->options & APR_INCOMPLETE_WRITE) { + apr_status_t arv; + sock->options &= ~APR_INCOMPLETE_WRITE; + arv = apr_wait_for_io_or_timeout(NULL, sock, 0); + if (arv != APR_SUCCESS) { + return arv; + } + } -#elif defined(__FreeBSD__) + nbytes = bytes_to_send; + rv = sendfile(file->filedes, /* file to be sent */ + sock->socketdes, /* socket */ + *offset, /* where in the file to start */ + &nbytes, /* number of bytes to write/written */ + NULL, /* Headers/footers */ + flags); /* undefined, set to 0 */ + + if (rv == -1) { + if (errno == EAGAIN) { + if (sock->timeout > 0) { + sock->options |= APR_INCOMPLETE_WRITE; + } + /* BSD's sendfile can return -1/EAGAIN even if it + * sent bytes. Sanitize the result so we get normal EAGAIN + * semantics w.r.t. bytes sent. + */ + if (nbytes) { + *len += nbytes; + /* normal exit for a big file & non-blocking io */ + return APR_SUCCESS; + } + if (sock->timeout <= 0) { + /* normal exit for a non-blocking io which would block */ + break; + } + } + } + else { /* rv == 0 (or the kernel is broken) */ + if (nbytes == 0) { + /* Most likely the file got smaller after the stat. + * Return an error so the caller can do the Right Thing. + */ + return APR_EOF; + } + *len += nbytes; + } + } while (rv == -1 && (errno == EINTR || errno == EAGAIN)); + + if (rv == -1) { + return errno; + } + + /* Now write the footers */ + if (hdtr->numtrailers > 0) { + arv = apr_socket_sendv(sock, hdtr->trailers, hdtr->numtrailers, &n); + *len += n; + if (arv != APR_SUCCESS) { + return arv; + } + } + + return APR_SUCCESS; +} + +#elif defined(__FreeBSD__) || defined(__DragonFly__) /* Release 3.1 or greater */ -ap_status_t ap_sendfile(ap_socket_t * sock, ap_file_t * file, - ap_hdtr_t * hdtr, ap_off_t * offset, ap_size_t * len, - ap_int32_t flags) +apr_status_t apr_socket_sendfile(apr_socket_t * sock, apr_file_t * file, + apr_hdtr_t * hdtr, apr_off_t * offset, + apr_size_t * len, apr_int32_t flags) { - off_t nbytes; + off_t nbytes = 0; int rv; +#if defined(__FreeBSD_version) && __FreeBSD_version < 460001 + int i; +#endif struct sf_hdtr headerstruct; + apr_size_t bytes_to_send = *len; + apr_status_t arv; + + /* Until further notice. */ + *len = 0; + + /* Ignore flags for now. */ + flags = 0; + + if (!hdtr) { + hdtr = &no_hdtr; + } + +#if defined(__FreeBSD_version) && __FreeBSD_version < 460001 + else if (hdtr->numheaders) { + + /* On early versions of FreeBSD sendfile, the number of bytes to send + * must include the length of the headers. Don't look at the man page + * for this :( Instead, look at the logic in + * src/sys/kern/uipc_syscalls::sendfile(). + * + * This was fixed in the middle of 4.6-STABLE + */ + for (i = 0; i < hdtr->numheaders; i++) { + bytes_to_send += hdtr->headers[i].iov_len; + } + } +#endif headerstruct.headers = hdtr->headers; headerstruct.hdr_cnt = hdtr->numheaders; headerstruct.trailers = hdtr->trailers; headerstruct.trl_cnt = hdtr->numtrailers; - /* FreeBSD can send the headers/footers as part of the system call */ do { - rv = sendfile(file->filedes, /* open file descriptor of the file to be sent */ - sock->socketdes, /* socket */ - *offset, /* where in the file to start */ - (size_t) * len, /* number of bytes to send */ - &headerstruct, /* Headers/footers */ - &nbytes, /* number of bytes written */ - flags /* undefined, set to 0 */ - ); - } while (rv == -1 && errno == EINTR); + if (sock->options & APR_INCOMPLETE_WRITE) { + sock->options &= ~APR_INCOMPLETE_WRITE; + arv = apr_wait_for_io_or_timeout(NULL, sock, 0); + if (arv != APR_SUCCESS) { + return arv; + } + } + if (bytes_to_send) { + /* We won't dare call sendfile() if we don't have + * header or file bytes to send because bytes_to_send == 0 + * means send the whole file. + */ + rv = sendfile(file->filedes, /* file to be sent */ + sock->socketdes, /* socket */ + *offset, /* where in the file to start */ + bytes_to_send, /* number of bytes to send */ + &headerstruct, /* Headers/footers */ + &nbytes, /* number of bytes written */ + flags); /* undefined, set to 0 */ - if (rv == -1 && - (errno == EAGAIN || errno == EWOULDBLOCK) && - sock->timeout != 0) { - ap_status_t arv = wait_for_io_or_timeout(sock, 0); - if (arv != APR_SUCCESS) { - *len = 0; - return arv; - } + if (rv == -1) { + if (errno == EAGAIN) { + if (sock->timeout > 0) { + sock->options |= APR_INCOMPLETE_WRITE; + } + /* FreeBSD's sendfile can return -1/EAGAIN even if it + * sent bytes. Sanitize the result so we get normal EAGAIN + * semantics w.r.t. bytes sent. + */ + if (nbytes) { + *len += nbytes; + /* normal exit for a big file & non-blocking io */ + return APR_SUCCESS; + } + if (sock->timeout <= 0) { + /* normal exit for a non-blocking io which would block */ + break; + } + } + } + else { /* rv == 0 (or the kernel is broken) */ + if (nbytes == 0) { + /* Most likely the file got smaller after the stat. + * Return an error so the caller can do the Right Thing. + */ + return APR_EOF; + } + *len += nbytes; + } + } else { - do { - rv = sendfile(file->filedes, /* open file descriptor of the file to be sent */ - sock->socketdes, /* socket */ - *offset, /* where in the file to start */ - (size_t) * len, /* number of bytes to send */ - &headerstruct, /* Headers/footers */ - &nbytes, /* number of bytes written */ - flags /* undefined, set to 0 */ - ); - } while (rv == -1 && errno == EINTR); + /* just trailer bytes... use writev() + */ + rv = writev(sock->socketdes, + hdtr->trailers, + hdtr->numtrailers); + if (rv > 0) { + *len += rv; + } + else if (rv == -1 && errno == EAGAIN) { + if (sock->timeout > 0) { + sock->options |= APR_INCOMPLETE_WRITE; + } + else { + break; + } + } } - } + } while (rv == -1 && (errno == EINTR || errno == EAGAIN)); - (*len) = nbytes; if (rv == -1) { return errno; } return APR_SUCCESS; } -#elif defined(__HPUX__) +#elif defined(__hpux) || defined(__hpux__) + +/* HP cc in ANSI mode defines __hpux; gcc defines __hpux__ */ -#error "there's no way this ap_sendfile implementation works -djg" +/* HP-UX Version 10.30 or greater + * (no worries, because we only get here if autoconfiguration found sendfile) + */ -/* HP-UX Version 10.30 or greater */ -ap_status_t ap_sendfile(ap_socket_t * sock, ap_file_t * file, - ap_hdtr_t * hdtr, ap_off_t * offset, ap_size_t * len, - ap_int32_t flags) +/* ssize_t sendfile(int s, int fd, off_t offset, size_t nbytes, + * const struct iovec *hdtrl, int flags); + * + * nbytes is the number of bytes to send just from the file; as with FreeBSD, + * if nbytes == 0, the rest of the file (from offset) is sent + */ + +apr_status_t apr_socket_sendfile(apr_socket_t *sock, apr_file_t *file, + apr_hdtr_t *hdtr, apr_off_t *offset, + apr_size_t *len, apr_int32_t flags) { - int i, ptr = 0; - size_t nbytes = 0, headerlen = 0, trailerlen = 0; - struct sf_hdtr headerstruct; + int i; + apr_ssize_t rc; + apr_size_t nbytes = *len, headerlen, trailerlen; struct iovec hdtrarray[2]; - void *headerbuf, *trailerbuf; + char *headerbuf, *trailerbuf; +#if APR_HAS_LARGE_FILES && defined(HAVE_SENDFILE64) + /* later HP-UXes have a sendfile64() */ +#define sendfile sendfile64 + apr_off_t off = *offset; - /* HP-UX can only send one header iovec and one footer iovec */ +#elif APR_HAS_LARGE_FILES && SIZEOF_OFF_T == 4 + /* HP-UX 11.00 doesn't have a sendfile64(): fail if trying to send + * past the 2Gb limit */ + off_t off; - for (i = 0; i < hdtr->numheaders; i++) { - headerlen += hdtr->headers[i].iov_len; + if ((apr_int64_t)*offset + *len > INT_MAX) { + return EINVAL; } + off = *offset; +#else + apr_off_t off = *offset; +#endif + + if (!hdtr) { + hdtr = &no_hdtr; + } + + /* Ignore flags for now. */ + flags = 0; + + /* HP-UX can only send one header iovec and one footer iovec; try to + * only allocate storage to combine input iovecs when we really have to + */ - /* XXX: BUHHH? wow, what a memory leak! */ - headerbuf = ap_palloc(sock->cntxt, headerlen); + switch(hdtr->numheaders) { + case 0: + hdtrarray[0].iov_base = NULL; + hdtrarray[0].iov_len = 0; + break; + case 1: + hdtrarray[0] = hdtr->headers[0]; + break; + default: + headerlen = 0; + for (i = 0; i < hdtr->numheaders; i++) { + headerlen += hdtr->headers[i].iov_len; + } - for (i = 0; i < hdtr->numheaders; i++) { - memcpy(headerbuf + ptr, hdtr->headers[i].iov_base, - hdtr->headers[i].iov_len); - ptr += hdtr->headers[i].iov_len; + /* XXX: BUHHH? wow, what a memory leak! */ + headerbuf = hdtrarray[0].iov_base = apr_palloc(sock->pool, headerlen); + hdtrarray[0].iov_len = headerlen; + + for (i = 0; i < hdtr->numheaders; i++) { + memcpy(headerbuf, hdtr->headers[i].iov_base, + hdtr->headers[i].iov_len); + headerbuf += hdtr->headers[i].iov_len; + } } - for (i = 0; i < hdtr->numtrailers; i++) { - trailerlen += hdtr->headers[i].iov_len; + switch(hdtr->numtrailers) { + case 0: + hdtrarray[1].iov_base = NULL; + hdtrarray[1].iov_len = 0; + break; + case 1: + hdtrarray[1] = hdtr->trailers[0]; + break; + default: + trailerlen = 0; + for (i = 0; i < hdtr->numtrailers; i++) { + trailerlen += hdtr->trailers[i].iov_len; + } + + /* XXX: BUHHH? wow, what a memory leak! */ + trailerbuf = hdtrarray[1].iov_base = apr_palloc(sock->pool, trailerlen); + hdtrarray[1].iov_len = trailerlen; + + for (i = 0; i < hdtr->numtrailers; i++) { + memcpy(trailerbuf, hdtr->trailers[i].iov_base, + hdtr->trailers[i].iov_len); + trailerbuf += hdtr->trailers[i].iov_len; + } } - /* XXX: BUHHH? wow, what a memory leak! */ - trailerbuf = ap_palloc(sock->cntxt, trailerlen); + do { + if (nbytes) { /* any bytes to send from the file? */ + rc = sendfile(sock->socketdes, /* socket */ + file->filedes, /* file descriptor to send */ + off, /* where in the file to start */ + nbytes, /* number of bytes to send from file */ + hdtrarray, /* Headers/footers */ + flags); /* undefined, set to 0 */ + } + else { /* we can't call sendfile() with no bytes to send from the file */ + rc = writev(sock->socketdes, hdtrarray, 2); + } + } while (rc == -1 && errno == EINTR); + + while ((rc == -1) && (errno == EAGAIN || errno == EWOULDBLOCK) + && (sock->timeout > 0)) { + apr_status_t arv = apr_wait_for_io_or_timeout(NULL, sock, 0); + + if (arv != APR_SUCCESS) { + *len = 0; + return arv; + } + else { + do { + if (nbytes) { + rc = sendfile(sock->socketdes, /* socket */ + file->filedes, /* file descriptor to send */ + off, /* where in the file to start */ + nbytes, /* number of bytes to send from file */ + hdtrarray, /* Headers/footers */ + flags); /* undefined, set to 0 */ + } + else { /* we can't call sendfile() with no bytes to send from the file */ + rc = writev(sock->socketdes, hdtrarray, 2); + } + } while (rc == -1 && errno == EINTR); + } + } - for (i = 0; i < hdtr->numtrailers; i++) { - memcpy(trailerbuf + ptr, hdtr->trailers[i].iov_base, - hdtr->trailers[i].iov_len); - ptr += hdtr->trailers[i].iov_len; + if (rc == -1) { + *len = 0; + return errno; } - hdtrarray[0].iov_base = headerbuf; - hdtrarray[0].iov_len = headerlen; - hdtrarray[1].iov_base = trailerbuf; - hdtrarray[1].iov_len = trailerlen; + /* Set len to the number of bytes written */ + *len = rc; + return APR_SUCCESS; +} +#elif defined(_AIX) || defined(__MVS__) +/* AIX and OS/390 have the same send_file() interface. + * + * subtle differences: + * AIX doesn't update the file ptr but OS/390 does + * + * availability (correctly determined by autoconf): + * + * AIX - version 4.3.2 with APAR IX85388, or version 4.3.3 and above + * OS/390 - V2R7 and above + */ +apr_status_t apr_socket_sendfile(apr_socket_t * sock, apr_file_t * file, + apr_hdtr_t * hdtr, apr_off_t * offset, + apr_size_t * len, apr_int32_t flags) +{ + int i, ptr, rv = 0; + void * hbuf=NULL, * tbuf=NULL; + apr_status_t arv; + struct sf_parms parms; + + if (!hdtr) { + hdtr = &no_hdtr; + } + + /* Ignore flags for now. */ + flags = 0; + + /* word to the wise: by default, AIX stores files sent by send_file() + * in the network buffer cache... there are supposedly scenarios + * where the most recent copy of the file won't be sent, but I can't + * recreate the potential problem, perhaps because of the way we + * use send_file()... if you suspect such a problem, try turning + * on the SF_SYNC_CACHE flag + */ + + /* AIX can also send the headers/footers as part of the system call */ + parms.header_length = 0; + if (hdtr && hdtr->numheaders) { + if (hdtr->numheaders == 1) { + parms.header_data = hdtr->headers[0].iov_base; + parms.header_length = hdtr->headers[0].iov_len; + } + else { + for (i = 0; i < hdtr->numheaders; i++) { + parms.header_length += hdtr->headers[i].iov_len; + } +#if 0 + /* Keepalives make apr_palloc a bad idea */ + hbuf = malloc(parms.header_length); +#else + /* but headers are small, so maybe we can hold on to the + * memory for the life of the socket... + */ + hbuf = apr_palloc(sock->pool, parms.header_length); +#endif + ptr = 0; + for (i = 0; i < hdtr->numheaders; i++) { + memcpy((char *)hbuf + ptr, hdtr->headers[i].iov_base, + hdtr->headers[i].iov_len); + ptr += hdtr->headers[i].iov_len; + } + parms.header_data = hbuf; + } + } + else parms.header_data = NULL; + parms.trailer_length = 0; + if (hdtr && hdtr->numtrailers) { + if (hdtr->numtrailers == 1) { + parms.trailer_data = hdtr->trailers[0].iov_base; + parms.trailer_length = hdtr->trailers[0].iov_len; + } + else { + for (i = 0; i < hdtr->numtrailers; i++) { + parms.trailer_length += hdtr->trailers[i].iov_len; + } +#if 0 + /* Keepalives make apr_palloc a bad idea */ + tbuf = malloc(parms.trailer_length); +#else + tbuf = apr_palloc(sock->pool, parms.trailer_length); +#endif + ptr = 0; + for (i = 0; i < hdtr->numtrailers; i++) { + memcpy((char *)tbuf + ptr, hdtr->trailers[i].iov_base, + hdtr->trailers[i].iov_len); + ptr += hdtr->trailers[i].iov_len; + } + parms.trailer_data = tbuf; + } + } + else { + parms.trailer_data = NULL; + } + + /* Whew! Headers and trailers set up. Now for the file data */ + + parms.file_descriptor = file->filedes; + parms.file_offset = *offset; + parms.file_bytes = *len; + + /* O.K. All set up now. Let's go to town */ + + if (sock->options & APR_INCOMPLETE_WRITE) { + sock->options &= ~APR_INCOMPLETE_WRITE; + goto do_select; + } do { - rv = sendfile(sock->socketdes, /* socket */ - file->filedes, /* file descriptor to send */ - *offset, /* where in the file to start */ - /* XXX: as far as i can see, nbytes == 0 always here -djg */ - nbytes, /* number of bytes to send */ - hdtrarray, /* Headers/footers */ - flags /* undefined, set to 0 */ - ); + rv = send_file(&(sock->socketdes), /* socket */ + &(parms), /* all data */ + flags); /* flags */ } while (rv == -1 && errno == EINTR); - if (rv == -1 && - (errno == EAGAIN || errno == EWOULDBLOCK) && - sock->timeout != 0) { - ap_status_t arv = wait_for_io_or_timeout(sock, 0); - + while ((rv == -1) && (errno == EAGAIN || errno == EWOULDBLOCK) + && (sock->timeout > 0)) { +do_select: + arv = apr_wait_for_io_or_timeout(NULL, sock, 0); if (arv != APR_SUCCESS) { - /* jlt: not tested, but this matches other sendfile logic */ - (*len) = 0; + *len = 0; return arv; } else { do { - rv = sendfile(sock->socketdes, /* socket */ - file->filedes, /* file descriptor to send */ - *offset, /* where in the file to start */ - /* XXX: as far as i can see, nbytes == 0 always here -djg */ - nbytes, /* number of bytes to send */ - hdtrarray, /* Headers/footers */ - flags /* undefined, set to 0 */ - ); + rv = send_file(&(sock->socketdes), /* socket */ + &(parms), /* all data */ + flags); /* flags */ } while (rv == -1 && errno == EINTR); } } + (*len) = parms.bytes_sent; + +#if 0 + /* Clean up after ourselves */ + if(hbuf) free(hbuf); + if(tbuf) free(tbuf); +#endif if (rv == -1) { - *len = 0; return errno; } + if ((sock->timeout > 0) + && (parms.bytes_sent + < (parms.file_bytes + parms.header_length + parms.trailer_length))) { + sock->options |= APR_INCOMPLETE_WRITE; + } + + return APR_SUCCESS; +} +#elif defined(__osf__) && defined (__alpha) +/* Tru64's sendfile implementation doesn't work, and we need to make sure that + * we don't use it until it is fixed. If it is used as it is now, it will + * hang the machine and the only way to fix it is a reboot. + */ +#elif defined(HAVE_SENDFILEV) +/* Solaris 8's sendfilev() interface + * + * SFV_FD_SELF refers to our memory space. + * + * Required Sparc patches (or newer): + * 111297-01, 108528-09, 109472-06, 109234-03, 108995-02, 111295-01, 109025-03, + * 108991-13 + * Required x86 patches (or newer): + * 111298-01, 108529-09, 109473-06, 109235-04, 108996-02, 111296-01, 109026-04, + * 108992-13 + */ - /* Set len to the number of bytes written */ - (*len) = rv; +#if APR_HAS_LARGE_FILES && defined(HAVE_SENDFILEV64) +#define sendfilevec_t sendfilevec64_t +#define sendfilev sendfilev64 +#endif + +apr_status_t apr_socket_sendfile(apr_socket_t *sock, apr_file_t *file, + apr_hdtr_t *hdtr, apr_off_t *offset, + apr_size_t *len, apr_int32_t flags) +{ + apr_status_t rv, arv; + apr_size_t nbytes; + sendfilevec_t *sfv; + int vecs, curvec, i, repeat; + apr_size_t requested_len = 0; + + if (!hdtr) { + hdtr = &no_hdtr; + } + + /* Ignore flags for now. */ + flags = 0; + + /* Calculate how much space we need. */ + vecs = hdtr->numheaders + hdtr->numtrailers + 1; + sfv = apr_palloc(sock->pool, sizeof(sendfilevec_t) * vecs); + + curvec = 0; + + /* Add the headers */ + for (i = 0; i < hdtr->numheaders; i++, curvec++) { + sfv[curvec].sfv_fd = SFV_FD_SELF; + sfv[curvec].sfv_flag = 0; + /* Cast to unsigned long to prevent sign extension of the + * pointer value for the LFS case; see PR 39463. */ + sfv[curvec].sfv_off = (unsigned long)hdtr->headers[i].iov_base; + sfv[curvec].sfv_len = hdtr->headers[i].iov_len; + requested_len += sfv[curvec].sfv_len; + } + + /* If the len is 0, we skip the file. */ + if (*len) + { + sfv[curvec].sfv_fd = file->filedes; + sfv[curvec].sfv_flag = 0; + sfv[curvec].sfv_off = *offset; + sfv[curvec].sfv_len = *len; + requested_len += sfv[curvec].sfv_len; + + curvec++; + } + else { + vecs--; + } + + /* Add the footers */ + for (i = 0; i < hdtr->numtrailers; i++, curvec++) { + sfv[curvec].sfv_fd = SFV_FD_SELF; + sfv[curvec].sfv_flag = 0; + sfv[curvec].sfv_off = (unsigned long)hdtr->trailers[i].iov_base; + sfv[curvec].sfv_len = hdtr->trailers[i].iov_len; + requested_len += sfv[curvec].sfv_len; + } + + /* If the last write couldn't send all the requested data, + * wait for the socket to become writable before proceeding + */ + if (sock->options & APR_INCOMPLETE_WRITE) { + sock->options &= ~APR_INCOMPLETE_WRITE; + arv = apr_wait_for_io_or_timeout(NULL, sock, 0); + if (arv != APR_SUCCESS) { + *len = 0; + return arv; + } + } + + /* Actually do the sendfilev + * + * Solaris may return -1/EAGAIN even if it sent bytes on a non-block sock. + * + * If no bytes were originally sent (nbytes == 0) and we are on a TIMEOUT + * socket (which as far as the OS is concerned is a non-blocking socket), + * we want to retry after waiting for the other side to read the data (as + * determined by poll). Once it is clear to send, we want to retry + * sending the sendfilevec_t once more. + */ + arv = 0; + do { + /* Clear out the repeat */ + repeat = 0; + + /* socket, vecs, number of vecs, bytes written */ + rv = sendfilev(sock->socketdes, sfv, vecs, &nbytes); + + if (rv == -1 && errno == EAGAIN) { + if (nbytes) { + rv = 0; + } + else if (!arv && (sock->timeout > 0)) { + apr_status_t t = apr_wait_for_io_or_timeout(NULL, sock, 0); + + if (t != APR_SUCCESS) { + *len = 0; + return t; + } + + arv = 1; + repeat = 1; + } + } + } while ((rv == -1 && errno == EINTR) || repeat); + + if (rv == -1) { + *len = 0; + return errno; + } + + /* Update how much we sent */ + *len = nbytes; + + if (nbytes == 0) { + /* Most likely the file got smaller after the stat. + * Return an error so the caller can do the Right Thing. + */ + return APR_EOF; + } + + if ((sock->timeout > 0) && (*len < requested_len)) { + sock->options |= APR_INCOMPLETE_WRITE; + } return APR_SUCCESS; } #else -/* TODO: Add AIX support */ -#endif /* __linux__, __FreeBSD__, __HPUX__ */ -#endif /* HAVE_SENDFILE */ +#error APR has detected sendfile on your system, but nobody has written a +#error version of it for APR yet. To get past this, either write +#error apr_socket_sendfile or change APR_HAS_SENDFILE in apr.h to 0. +#endif /* __linux__, __FreeBSD__, __DragonFly__, __HPUX__, _AIX, __MVS__, + Tru64/OSF1 */ +#endif /* APR_HAS_SENDFILE */ diff --git a/network_io/unix/sockaddr.c b/network_io/unix/sockaddr.c index a95fa8f0333..8e4bde3e3b4 100644 --- a/network_io/unix/sockaddr.c +++ b/network_io/unix/sockaddr.c @@ -1,161 +1,1279 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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 "networkio.h" +#include "apr_arch_networkio.h" +#include "apr_strings.h" +#include "apr.h" +#include "apr_lib.h" +#include "apr_strings.h" +#include "apr_private.h" + +#if APR_HAVE_STDLIB_H +#include <stdlib.h> +#endif + +#ifdef HAVE_NET_IF_H +#include <net/if.h> +#endif + +#define APR_WANT_STRFUNC +#include "apr_want.h" + +struct apr_ipsubnet_t { + int family; +#if APR_HAVE_IPV6 + apr_uint32_t sub[4]; /* big enough for IPv4 and IPv6 addresses */ + apr_uint32_t mask[4]; +#else + apr_uint32_t sub[1]; + apr_uint32_t mask[1]; +#endif +}; -ap_status_t ap_set_local_port(ap_socket_t *sock, ap_uint32_t port) +#if !defined(NETWARE) && !defined(WIN32) +#ifdef HAVE_SET_H_ERRNO +#define SET_H_ERRNO(newval) set_h_errno(newval) +#else +#define SET_H_ERRNO(newval) h_errno = (newval) +#endif +#else +#define SET_H_ERRNO(newval) +#endif + +#if APR_HAS_THREADS && !defined(GETHOSTBYNAME_IS_THREAD_SAFE) && \ + defined(HAVE_GETHOSTBYNAME_R) +/* This is the maximum size that may be returned from the reentrant + * gethostbyname_r function. If the system tries to use more, it + * should return ERANGE. + */ +#define GETHOSTBYNAME_BUFLEN 512 +#endif + +#ifdef _AIX +/* Some levels of AIX getaddrinfo() don't like servname = "0", so + * set servname to "1" when port is 0 and fix it up later. + */ +#define AIX_SERVNAME_HACK 1 +#else +#define AIX_SERVNAME_HACK 0 +#endif + +#ifdef _WIN32_WCE +/* XXX: BS solution. Need an HAVE_GETSERVBYNAME and actually + * do something here, to provide the obvious proto mappings. + */ +static void *getservbyname(const char *name, const char *proto) { - sock->local_addr->sin_port = htons((short)port); - return APR_SUCCESS; + return NULL; } +#endif +static apr_status_t get_local_addr(apr_socket_t *sock) +{ + sock->local_addr->salen = sizeof(sock->local_addr->sa); + if (getsockname(sock->socketdes, (struct sockaddr *)&sock->local_addr->sa, + &sock->local_addr->salen) < 0) { + return apr_get_netos_error(); + } + else { + sock->local_port_unknown = sock->local_interface_unknown = 0; + /* XXX assumes sin_port and sin6_port at same offset */ + sock->local_addr->port = ntohs(sock->local_addr->sa.sin.sin_port); + return APR_SUCCESS; + } +} +static apr_status_t get_remote_addr(apr_socket_t *sock) +{ + sock->remote_addr->salen = sizeof(sock->remote_addr->sa); + if (getpeername(sock->socketdes, (struct sockaddr *)&sock->remote_addr->sa, + &sock->remote_addr->salen) < 0) { + return apr_get_netos_error(); + } + else { + sock->remote_addr_unknown = 0; + /* XXX assumes sin_port and sin6_port at same offset */ + sock->remote_addr->port = ntohs(sock->remote_addr->sa.sin.sin_port); + return APR_SUCCESS; + } +} -ap_status_t ap_set_remote_port(ap_socket_t *sock, ap_uint32_t port) +APR_DECLARE(apr_status_t) apr_sockaddr_ip_getbuf(char *buf, apr_size_t buflen, + apr_sockaddr_t *sockaddr) { - sock->remote_addr->sin_port = htons((short)port); + if (!apr_inet_ntop(sockaddr->family, sockaddr->ipaddr_ptr, buf, buflen)) { + return APR_ENOSPC; + } + +#if APR_HAVE_IPV6 + if (sockaddr->family == AF_INET6 + && IN6_IS_ADDR_V4MAPPED((struct in6_addr *)sockaddr->ipaddr_ptr) + && buflen > strlen("::ffff:")) { + /* This is an IPv4-mapped IPv6 address; drop the leading + * part of the address string so we're left with the familiar + * IPv4 format. + */ + memmove(buf, buf + strlen("::ffff:"), + strlen(buf + strlen("::ffff:"))+1); + } + + /* ensure NUL termination if the buffer is too short */ + buf[buflen-1] = '\0'; + +#ifdef HAVE_IF_INDEXTONAME + /* Append scope name for link-local addresses. */ + if (sockaddr->family == AF_INET6 + && IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)sockaddr->ipaddr_ptr)) { + char scbuf[IF_NAMESIZE], *p = buf + strlen(buf); + + if (if_indextoname(sockaddr->sa.sin6.sin6_scope_id, scbuf) == scbuf) { + /* Space check, need room for buf + '%' + scope + '\0'. + * Assert: buflen >= strlen(buf) + strlen(scbuf) + 2 + * Equiv: buflen >= (p-buf) + strlen(buf) + 2 + * Thus, fail in inverse condition: */ + if (buflen < strlen(scbuf) + (p - buf) + 2) { + return APR_ENOSPC; + } + *p++ = '%'; + memcpy(p, scbuf, strlen(scbuf) + 1); + } + } +#endif /* HAVE_IF_INDEXTONAME */ +#endif /* APR_HAVE_IPV6 */ + return APR_SUCCESS; } +APR_DECLARE(apr_status_t) apr_sockaddr_ip_get(char **addr, + apr_sockaddr_t *sockaddr) +{ + *addr = apr_palloc(sockaddr->pool, sockaddr->addr_str_len); + return apr_sockaddr_ip_getbuf(*addr, sockaddr->addr_str_len, sockaddr); +} +void apr_sockaddr_vars_set(apr_sockaddr_t *addr, int family, apr_port_t port) +{ + addr->family = family; + addr->sa.sin.sin_family = family; + if (port) { + /* XXX IPv6: assumes sin_port and sin6_port at same offset */ + addr->sa.sin.sin_port = htons(port); + addr->port = port; + } +#if AIX_SERVNAME_HACK + else { + addr->sa.sin.sin_port = htons(port); + } +#endif -ap_status_t ap_get_local_port(ap_uint32_t *port, ap_socket_t *sock) + if (family == APR_INET) { + addr->salen = sizeof(struct sockaddr_in); + addr->addr_str_len = 16; + addr->ipaddr_ptr = &(addr->sa.sin.sin_addr); + addr->ipaddr_len = sizeof(struct in_addr); + } +#if APR_HAVE_IPV6 + else if (family == APR_INET6) { + addr->salen = sizeof(struct sockaddr_in6); + addr->addr_str_len = 46; + addr->ipaddr_ptr = &(addr->sa.sin6.sin6_addr); + addr->ipaddr_len = sizeof(struct in6_addr); + } +#endif +#if APR_HAVE_SOCKADDR_UN + else if (family == APR_UNIX) { + addr->salen = sizeof(struct sockaddr_un); + addr->addr_str_len = sizeof(addr->sa.unx.sun_path);; + addr->ipaddr_ptr = &(addr->sa.unx.sun_path); + addr->ipaddr_len = addr->addr_str_len; + } +#endif +} + +APR_DECLARE(apr_status_t) apr_socket_addr_get(apr_sockaddr_t **sa, + apr_interface_e which, + apr_socket_t *sock) { - *port = ntohs(sock->local_addr->sin_port); + if (which == APR_LOCAL) { + if (sock->local_interface_unknown || sock->local_port_unknown) { + apr_status_t rv = get_local_addr(sock); + + if (rv != APR_SUCCESS) { + return rv; + } + } + *sa = sock->local_addr; + } + else if (which == APR_REMOTE) { + if (sock->remote_addr_unknown) { + apr_status_t rv = get_remote_addr(sock); + + if (rv != APR_SUCCESS) { + return rv; + } + } + *sa = sock->remote_addr; + } + else { + *sa = NULL; + return APR_EINVAL; + } return APR_SUCCESS; } +APR_DECLARE(apr_status_t) apr_parse_addr_port(char **addr, + char **scope_id, + apr_port_t *port, + const char *str, + apr_pool_t *p) +{ + const char *ch, *lastchar; + int big_port; + apr_size_t addrlen; + + *addr = NULL; /* assume not specified */ + *scope_id = NULL; /* assume not specified */ + *port = 0; /* assume not specified */ + + /* First handle the optional port number. That may be all that + * is specified in the string. + */ + ch = lastchar = str + strlen(str) - 1; + while (ch >= str && apr_isdigit(*ch)) { + --ch; + } + + if (ch < str) { /* Entire string is the port. */ + big_port = atoi(str); + if (big_port < 1 || big_port > 65535) { + return APR_EINVAL; + } + *port = big_port; + return APR_SUCCESS; + } + + if (*ch == ':' && ch < lastchar) { /* host and port number specified */ + if (ch == str) { /* string starts with ':' -- bad */ + return APR_EINVAL; + } + big_port = atoi(ch + 1); + if (big_port < 1 || big_port > 65535) { + return APR_EINVAL; + } + *port = big_port; + lastchar = ch - 1; + } + + /* now handle the hostname */ + addrlen = lastchar - str + 1; + +/* XXX we don't really have to require APR_HAVE_IPV6 for this; + * just pass char[] for ipaddr (so we don't depend on struct in6_addr) + * and always define APR_INET6 + */ +#if APR_HAVE_IPV6 + if (*str == '[') { + const char *end_bracket = memchr(str, ']', addrlen); + struct in6_addr ipaddr; + const char *scope_delim; + + if (!end_bracket || end_bracket != lastchar) { + *port = 0; + return APR_EINVAL; + } + + /* handle scope id; this is the only context where it is allowed */ + scope_delim = memchr(str, '%', addrlen); + if (scope_delim) { + if (scope_delim == end_bracket - 1) { /* '%' without scope id */ + *port = 0; + return APR_EINVAL; + } + addrlen = scope_delim - str - 1; + *scope_id = apr_pstrmemdup(p, scope_delim + 1, end_bracket - scope_delim - 1); + } + else { + addrlen = addrlen - 2; /* minus 2 for '[' and ']' */ + } + + *addr = apr_pstrmemdup(p, str + 1, addrlen); + if (apr_inet_pton(AF_INET6, *addr, &ipaddr) != 1) { + *addr = NULL; + *scope_id = NULL; + *port = 0; + return APR_EINVAL; + } + } + else +#endif + { + /* XXX If '%' is not a valid char in a DNS name, we *could* check + * for bogus scope ids first. + */ + *addr = apr_pstrmemdup(p, str, addrlen); + } + return APR_SUCCESS; +} +#if defined(HAVE_GETADDRINFO) -ap_status_t ap_get_remote_port(ap_uint32_t *port, ap_socket_t *sock) +static apr_status_t call_resolver(apr_sockaddr_t **sa, + const char *hostname, apr_int32_t family, + apr_port_t port, apr_int32_t flags, + apr_pool_t *p) { - *port = ntohs(sock->remote_addr->sin_port); + struct addrinfo hints, *ai, *ai_list; + apr_sockaddr_t *prev_sa; + int error; + char *servname = NULL; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = family; + hints.ai_socktype = SOCK_STREAM; +#ifdef HAVE_GAI_ADDRCONFIG + if (family == APR_UNSPEC) { + /* By default, only look up addresses using address types for + * which a local interface is configured, i.e. no IPv6 if no + * IPv6 interfaces configured. */ + hints.ai_flags = AI_ADDRCONFIG; + } +#endif + +#ifdef __MVS__ + /* z/OS will not return IPv4 address under AF_UNSPEC if any IPv6 results + * are returned, w/o AI_ALL. + */ + if (family == APR_UNSPEC) { + hints.ai_flags |= AI_ALL; + } +#endif + + if(hostname == NULL) { +#ifdef AI_PASSIVE + /* If hostname is NULL, assume we are trying to bind to all + * interfaces. */ + hints.ai_flags |= AI_PASSIVE; +#endif + /* getaddrinfo according to RFC 2553 must have either hostname + * or servname non-NULL. + */ +#ifdef OSF1 + /* The Tru64 5.0 getaddrinfo() can only resolve services given + * by the name listed in /etc/services; a numeric or unknown + * servname gets an EAI_SERVICE error. So just resolve the + * appropriate anyaddr and fill in the port later. */ + hostname = family == AF_INET6 ? "::" : "0.0.0.0"; + servname = NULL; +#ifdef AI_NUMERICHOST + hints.ai_flags |= AI_NUMERICHOST; +#endif +#else +#if AIX_SERVNAME_HACK + if (!port) { + servname = "1"; + } + else +#endif /* AIX_SERVNAME_HACK */ + servname = apr_itoa(p, port); +#endif /* OSF1 */ + } + error = getaddrinfo(hostname, servname, &hints, &ai_list); +#ifdef HAVE_GAI_ADDRCONFIG + /* + * Using AI_ADDRCONFIG involves some unfortunate guesswork because it + * does not consider loopback addresses when trying to determine if + * IPv4 or IPv6 is configured on a system (see RFC 3493). + * This is a problem if one actually wants to listen on or connect to + * the loopback address of a protocol family that is not otherwise + * configured on the system. See PR 52709. + * To work around some of the problems, retry without AI_ADDRCONFIG + * in case of EAI_ADDRFAMILY. + * XXX: apr_sockaddr_info_get() should really accept a flag to determine + * XXX: if AI_ADDRCONFIG's guesswork is wanted and if the address is + * XXX: to be used for listen() or connect(). + * + * In case of EAI_BADFLAGS, AI_ADDRCONFIG is not supported. + */ + if ((family == APR_UNSPEC) && (error == EAI_BADFLAGS +#ifdef EAI_ADDRFAMILY + || error == EAI_ADDRFAMILY +#endif + )) { + hints.ai_flags &= ~AI_ADDRCONFIG; + error = getaddrinfo(hostname, servname, &hints, &ai_list); + } +#endif + if (error) { +#if defined(WIN32) + return apr_get_netos_error(); +#else + if (error == EAI_SYSTEM) { + return errno ? errno : APR_EGENERAL; + } + else + { + /* issues with representing this with APR's error scheme: + * glibc uses negative values for these numbers, perhaps so + * they don't conflict with h_errno values... Tru64 uses + * positive values which conflict with h_errno values + */ +#if defined(NEGATIVE_EAI) + error = -error; +#endif + return error + APR_OS_START_EAIERR; + } +#endif /* WIN32 */ + } + + prev_sa = NULL; + ai = ai_list; + while (ai) { /* while more addresses to report */ + apr_sockaddr_t *new_sa; + + /* Ignore anything bogus: getaddrinfo in some old versions of + * glibc will return AF_UNIX entries for APR_UNSPEC+AI_PASSIVE + * lookups. */ +#if APR_HAVE_IPV6 + if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) { +#else + if (ai->ai_family != AF_INET) { +#endif + ai = ai->ai_next; + continue; + } + + new_sa = apr_pcalloc(p, sizeof(apr_sockaddr_t)); + + new_sa->pool = p; + memcpy(&new_sa->sa, ai->ai_addr, ai->ai_addrlen); + apr_sockaddr_vars_set(new_sa, ai->ai_family, port); + + if (!prev_sa) { /* first element in new list */ + if (hostname) { + new_sa->hostname = apr_pstrdup(p, hostname); + } + *sa = new_sa; + } + else { + new_sa->hostname = prev_sa->hostname; + prev_sa->next = new_sa; + } + + prev_sa = new_sa; + ai = ai->ai_next; + } + freeaddrinfo(ai_list); + + if (prev_sa == NULL) { + /* + * getaddrinfo returned only useless entries and *sa is still empty. + * This should be treated as an error. + */ + return APR_EGENERAL; + } + return APR_SUCCESS; } +static apr_status_t find_addresses(apr_sockaddr_t **sa, + const char *hostname, apr_int32_t family, + apr_port_t port, apr_int32_t flags, + apr_pool_t *p) +{ + if (flags & APR_IPV4_ADDR_OK) { + apr_status_t error = call_resolver(sa, hostname, AF_INET, port, flags, p); + +#if APR_HAVE_IPV6 + if (error) { + family = AF_INET6; /* try again */ + } + else +#endif + return error; + } +#if APR_HAVE_IPV6 + else if (flags & APR_IPV6_ADDR_OK) { + apr_status_t error = call_resolver(sa, hostname, AF_INET6, port, flags, p); + + if (error) { + family = AF_INET; /* try again */ + } + else { + return APR_SUCCESS; + } + } +#endif + + return call_resolver(sa, hostname, family, port, flags, p); +} +#else /* end of HAVE_GETADDRINFO code */ -ap_status_t ap_set_local_ipaddr(ap_socket_t *sock, const char *addr) +static apr_status_t find_addresses(apr_sockaddr_t **sa, + const char *hostname, apr_int32_t family, + apr_port_t port, apr_int32_t flags, + apr_pool_t *p) { - u_long ipaddr; - - if (!strcmp(addr, APR_ANYADDR)) { - sock->local_addr->sin_addr.s_addr = htonl(INADDR_ANY); - return APR_SUCCESS; + struct hostent *hp; + apr_sockaddr_t *prev_sa; + int curaddr; +#if APR_HAS_THREADS && !defined(GETHOSTBYNAME_IS_THREAD_SAFE) && \ + defined(HAVE_GETHOSTBYNAME_R) && !defined(BEOS) +#ifdef GETHOSTBYNAME_R_HOSTENT_DATA + struct hostent_data hd; +#else + /* If you see ERANGE, that means GETHOSBYNAME_BUFLEN needs to be + * bumped. */ + char tmp[GETHOSTBYNAME_BUFLEN]; +#endif + int hosterror; +#endif + struct hostent hs; + struct in_addr ipaddr; + char *addr_list[2]; + const char *orig_hostname = hostname; + + if (hostname == NULL) { + /* if we are given a NULL hostname, assume '0.0.0.0' */ + hostname = "0.0.0.0"; } - - ipaddr = inet_addr(addr); - - if (ipaddr == -1) { - return errno; + + if (*hostname >= '0' && *hostname <= '9' && + strspn(hostname, "0123456789.") == strlen(hostname)) { + + ipaddr.s_addr = inet_addr(hostname); + addr_list[0] = (char *)&ipaddr; + addr_list[1] = NULL; /* just one IP in list */ + hs.h_addr_list = (char **)addr_list; + hp = &hs; } - - sock->local_addr->sin_addr.s_addr = ipaddr; + else { +#if APR_HAS_THREADS && !defined(GETHOSTBYNAME_IS_THREAD_SAFE) && \ + defined(HAVE_GETHOSTBYNAME_R) && !defined(BEOS) +#if defined(GETHOSTBYNAME_R_HOSTENT_DATA) + /* AIX, HP/UX, D/UX et alia */ + gethostbyname_r(hostname, &hs, &hd); + hp = &hs; +#else +#if defined(GETHOSTBYNAME_R_GLIBC2) + /* Linux glibc2+ */ + gethostbyname_r(hostname, &hs, tmp, GETHOSTBYNAME_BUFLEN - 1, + &hp, &hosterror); +#else + /* Solaris, Irix et alia */ + hp = gethostbyname_r(hostname, &hs, tmp, GETHOSTBYNAME_BUFLEN - 1, + &hosterror); +#endif /* !defined(GETHOSTBYNAME_R_GLIBC2) */ + if (!hp) { + return (hosterror + APR_OS_START_SYSERR); + } +#endif /* !defined(GETHOSTBYNAME_R_HOSTENT_DATA) */ +#else + hp = gethostbyname(hostname); +#endif + + if (!hp) { +#ifdef WIN32 + return apr_get_netos_error(); +#else + return (h_errno + APR_OS_START_SYSERR); +#endif + } + } + + prev_sa = NULL; + curaddr = 0; + while (hp->h_addr_list[curaddr]) { + apr_sockaddr_t *new_sa = apr_pcalloc(p, sizeof(apr_sockaddr_t)); + + new_sa->pool = p; + new_sa->sa.sin.sin_addr = *(struct in_addr *)hp->h_addr_list[curaddr]; + apr_sockaddr_vars_set(new_sa, AF_INET, port); + + if (!prev_sa) { /* first element in new list */ + if (orig_hostname) { + new_sa->hostname = apr_pstrdup(p, orig_hostname); + } + *sa = new_sa; + } + else { + new_sa->hostname = prev_sa->hostname; + prev_sa->next = new_sa; + } + + prev_sa = new_sa; + ++curaddr; + } + + if (prev_sa == NULL) { + /* this should not happen but no result should be treated as error */ + return APR_EGENERAL; + } + return APR_SUCCESS; } +#endif /* end of !HAVE_GETADDRINFO code */ +APR_DECLARE(apr_status_t) apr_sockaddr_info_get(apr_sockaddr_t **sa, + const char *hostname, + apr_int32_t family, apr_port_t port, + apr_int32_t flags, apr_pool_t *p) +{ + apr_int32_t masked; + *sa = NULL; -ap_status_t ap_set_remote_ipaddr(ap_socket_t *sock, const char *addr) + if ((masked = flags & (APR_IPV4_ADDR_OK | APR_IPV6_ADDR_OK))) { + if (!hostname || + family != APR_UNSPEC || + masked == (APR_IPV4_ADDR_OK | APR_IPV6_ADDR_OK)) { + return APR_EINVAL; + } +#if !APR_HAVE_IPV6 + if (flags & APR_IPV6_ADDR_OK) { + return APR_ENOTIMPL; + } +#endif + } + if (family == APR_UNSPEC && hostname && *hostname == '/') + family = APR_UNIX; + if (family == APR_UNIX) { +#if APR_HAVE_SOCKADDR_UN + if (hostname) { + *sa = apr_pcalloc(p, sizeof(apr_sockaddr_t)); + (*sa)->pool = p; + apr_cpystrn((*sa)->sa.unx.sun_path, hostname, + sizeof((*sa)->sa.unx.sun_path)); + (*sa)->hostname = apr_pstrdup(p, hostname); + (*sa)->family = APR_UNIX; + (*sa)->sa.unx.sun_family = APR_UNIX; + (*sa)->salen = sizeof(struct sockaddr_un); + (*sa)->addr_str_len = sizeof((*sa)->sa.unx.sun_path); + (*sa)->ipaddr_ptr = &((*sa)->sa.unx.sun_path); + (*sa)->ipaddr_len = (*sa)->addr_str_len; + + return APR_SUCCESS; + } + else +#endif + { + *sa = NULL; + return APR_ENOTIMPL; + } + } +#if !APR_HAVE_IPV6 + /* What may happen is that APR is not IPv6-enabled, but we're still + * going to call getaddrinfo(), so we have to tell the OS we only + * want IPv4 addresses back since we won't know what to do with + * IPv6 addresses. + */ + if (family == APR_UNSPEC) { + family = APR_INET; + } +#endif + + return find_addresses(sa, hostname, family, port, flags, p); +} + +APR_DECLARE(apr_status_t) apr_sockaddr_info_copy(apr_sockaddr_t **dst, + const apr_sockaddr_t *src, + apr_pool_t *p) { - u_long ipaddr; - - if (!strcmp(addr, APR_ANYADDR)) { - sock->remote_addr->sin_addr.s_addr = htonl(INADDR_ANY); + apr_sockaddr_t *d; + const apr_sockaddr_t *s; + + for (*dst = d = NULL, s = src; s; s = s->next) { + if (!d) { + *dst = d = apr_pmemdup(p, s, sizeof *s); + } + else { + d = d->next = apr_pmemdup(p, s, sizeof *s); + } + if (s->hostname) { + if (s == src || s->hostname != src->hostname) { + d->hostname = apr_pstrdup(p, s->hostname); + } + else { + d->hostname = (*dst)->hostname; + } + } + if (s->servname) { + if (s == src || s->servname != src->servname) { + d->servname = apr_pstrdup(p, s->servname); + } + else { + d->servname = (*dst)->servname; + } + } + d->pool = p; + apr_sockaddr_vars_set(d, s->family, s->port); + } + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_getnameinfo(char **hostname, + apr_sockaddr_t *sockaddr, + apr_int32_t flags) +{ +#if defined(HAVE_GETNAMEINFO) + int rc; +#if defined(NI_MAXHOST) + char tmphostname[NI_MAXHOST]; +#else + char tmphostname[256]; +#endif + + /* don't know if it is portable for getnameinfo() to set h_errno; + * clear it then see if it was set */ + SET_H_ERRNO(0); + + /* default flags are NI_NAMREQD; otherwise, getnameinfo() will return + * a numeric address string if it fails to resolve the host name; + * that is *not* what we want here + * + * For IPv4-mapped IPv6 addresses, drop down to IPv4 before calling + * getnameinfo() to avoid getnameinfo bugs (MacOS X, glibc). + */ +#if APR_HAVE_IPV6 + if (sockaddr->family == AF_INET6 && + IN6_IS_ADDR_V4MAPPED(&sockaddr->sa.sin6.sin6_addr)) { + struct sockaddr_in tmpsa; + tmpsa.sin_family = AF_INET; + tmpsa.sin_port = 0; + tmpsa.sin_addr.s_addr = ((apr_uint32_t *)sockaddr->ipaddr_ptr)[3]; +#ifdef SIN6_LEN + tmpsa.sin_len = sizeof(tmpsa); +#endif + + rc = getnameinfo((const struct sockaddr *)&tmpsa, sizeof(tmpsa), + tmphostname, sizeof(tmphostname), NULL, 0, + flags != 0 ? flags : NI_NAMEREQD); + } +#if APR_HAVE_SOCKADDR_UN + else if (sockaddr->family == APR_UNIX) { + *hostname = apr_pstrdup(sockaddr->pool, sockaddr->hostname); return APR_SUCCESS; } - - ipaddr = inet_addr(addr); - - if (ipaddr == (u_long)-1) { - return errno; +#endif + else +#endif + rc = getnameinfo((const struct sockaddr *)&sockaddr->sa, sockaddr->salen, + tmphostname, sizeof(tmphostname), NULL, 0, + flags != 0 ? flags : NI_NAMEREQD); + if (rc != 0) { + *hostname = NULL; + +#ifndef WIN32 + /* something went wrong. Look at the EAI_ error code */ + if (rc == EAI_SYSTEM) { + /* EAI_SYSTEM System error returned in errno. */ + /* IMHO, Implementations that set h_errno a simply broken. */ + if (h_errno) { /* for broken implementations which set h_errno */ + return h_errno + APR_OS_START_SYSERR; + } + else { /* "normal" case */ + return errno + APR_OS_START_SYSERR; + } + } + else +#endif + { +#if defined(NEGATIVE_EAI) + if (rc < 0) rc = -rc; +#endif + return rc + APR_OS_START_EAIERR; /* return the EAI_ error */ + } } - - sock->remote_addr->sin_addr.s_addr = ipaddr; + *hostname = sockaddr->hostname = apr_pstrdup(sockaddr->pool, + tmphostname); return APR_SUCCESS; +#else +#if APR_HAS_THREADS && !defined(GETHOSTBYADDR_IS_THREAD_SAFE) && \ + defined(HAVE_GETHOSTBYADDR_R) && !defined(BEOS) +#ifdef GETHOSTBYNAME_R_HOSTENT_DATA + struct hostent_data hd; +#else + char tmp[GETHOSTBYNAME_BUFLEN]; +#endif + int hosterror; + struct hostent hs, *hptr; + +#if defined(GETHOSTBYNAME_R_HOSTENT_DATA) + /* AIX, HP/UX, D/UX et alia */ + gethostbyaddr_r((char *)&sockaddr->sa.sin.sin_addr, + sizeof(struct in_addr), AF_INET, &hs, &hd); + hptr = &hs; +#else +#if defined(GETHOSTBYNAME_R_GLIBC2) + /* Linux glibc2+ */ + gethostbyaddr_r((char *)&sockaddr->sa.sin.sin_addr, + sizeof(struct in_addr), AF_INET, + &hs, tmp, GETHOSTBYNAME_BUFLEN - 1, &hptr, &hosterror); +#else + /* Solaris, Irix et alia */ + hptr = gethostbyaddr_r((char *)&sockaddr->sa.sin.sin_addr, + sizeof(struct in_addr), AF_INET, + &hs, tmp, GETHOSTBYNAME_BUFLEN, &hosterror); +#endif /* !defined(GETHOSTBYNAME_R_GLIBC2) */ + if (!hptr) { + *hostname = NULL; + return hosterror + APR_OS_START_SYSERR; + } +#endif /* !defined(GETHOSTBYNAME_R_HOSTENT_DATA) */ +#else + struct hostent *hptr; + hptr = gethostbyaddr((char *)&sockaddr->sa.sin.sin_addr, + sizeof(struct in_addr), AF_INET); +#endif + + if (hptr) { + *hostname = sockaddr->hostname = apr_pstrdup(sockaddr->pool, hptr->h_name); + return APR_SUCCESS; + } + *hostname = NULL; +#if defined(WIN32) + return apr_get_netos_error(); +#elif defined(OS2) + return h_errno; +#else + return h_errno + APR_OS_START_SYSERR; +#endif +#endif } +APR_DECLARE(apr_status_t) apr_getservbyname(apr_sockaddr_t *sockaddr, + const char *servname) +{ +#if APR_HAS_THREADS && !defined(GETSERVBYNAME_IS_THREAD_SAFE) && \ + defined(HAVE_GETSERVBYNAME_R) && \ + (defined(GETSERVBYNAME_R_GLIBC2) || defined(GETSERVBYNAME_R_SOLARIS) || \ + defined(GETSERVBYNAME_R_OSF1)) + struct servent se; +#if defined(GETSERVBYNAME_R_OSF1) + struct servent_data sed; + + memset(&sed, 0, sizeof(sed)); /* must zero fill before use */ +#else +#if defined(GETSERVBYNAME_R_GLIBC2) + struct servent *res; +#endif + char buf[1024]; +#endif +#else + struct servent *se; +#endif + if (servname == NULL) + return APR_EINVAL; -ap_status_t ap_get_local_ipaddr(char **addr, const ap_socket_t *sock) +#if APR_HAS_THREADS && !defined(GETSERVBYNAME_IS_THREAD_SAFE) && \ + defined(HAVE_GETSERVBYNAME_R) && \ + (defined(GETSERVBYNAME_R_GLIBC2) || defined(GETSERVBYNAME_R_SOLARIS) || \ + defined(GETSERVBYNAME_R_OSF1)) +#if defined(GETSERVBYNAME_R_GLIBC2) + if (getservbyname_r(servname, NULL, + &se, buf, sizeof(buf), &res) == 0 && res != NULL) { + sockaddr->port = ntohs(res->s_port); + sockaddr->servname = apr_pstrdup(sockaddr->pool, servname); + sockaddr->sa.sin.sin_port = res->s_port; + return APR_SUCCESS; + } +#elif defined(GETSERVBYNAME_R_SOLARIS) + if (getservbyname_r(servname, NULL, &se, buf, sizeof(buf)) != NULL) { + sockaddr->port = ntohs(se.s_port); + sockaddr->servname = apr_pstrdup(sockaddr->pool, servname); + sockaddr->sa.sin.sin_port = se.s_port; + return APR_SUCCESS; + } +#elif defined(GETSERVBYNAME_R_OSF1) + if (getservbyname_r(servname, NULL, &se, &sed) == 0) { + sockaddr->port = ntohs(se.s_port); + sockaddr->servname = apr_pstrdup(sockaddr->pool, servname); + sockaddr->sa.sin.sin_port = se.s_port; + return APR_SUCCESS; + } +#endif +#else + if ((se = getservbyname(servname, NULL)) != NULL){ + sockaddr->port = ntohs(se->s_port); + sockaddr->servname = apr_pstrdup(sockaddr->pool, servname); + sockaddr->sa.sin.sin_port = se->s_port; + return APR_SUCCESS; + } +#endif + return APR_ENOENT; +} + +#define V4MAPPED_EQUAL(a,b) \ +((a)->sa.sin.sin_family == AF_INET && \ + (b)->sa.sin.sin_family == AF_INET6 && \ + IN6_IS_ADDR_V4MAPPED((struct in6_addr *)(b)->ipaddr_ptr) && \ + !memcmp((a)->ipaddr_ptr, \ + &((struct in6_addr *)(b)->ipaddr_ptr)->s6_addr[12], \ + (a)->ipaddr_len)) + +#if APR_HAVE_IPV6 +#define SCOPE_OR_ZERO(sa_) ((sa_)->family != AF_INET6 ? 0 : \ + ((sa_)->sa.sin6.sin6_scope_id)) +#else +#define SCOPE_OR_ZERO(sa_) (0) +#endif + +APR_DECLARE(int) apr_sockaddr_equal(const apr_sockaddr_t *addr1, + const apr_sockaddr_t *addr2) { - *addr = ap_pstrdup(sock->cntxt, inet_ntoa(sock->local_addr->sin_addr)); - return APR_SUCCESS; + if (addr1->ipaddr_len == addr2->ipaddr_len + && !memcmp(addr1->ipaddr_ptr, addr2->ipaddr_ptr, addr1->ipaddr_len) + && SCOPE_OR_ZERO(addr1) == SCOPE_OR_ZERO(addr2)) { + return 1; + } +#if APR_HAVE_IPV6 + if (V4MAPPED_EQUAL(addr1, addr2)) { + return 1; + } + if (V4MAPPED_EQUAL(addr2, addr1)) { + return 1; + } +#endif + return 0; /* not equal */ } +APR_DECLARE(int) apr_sockaddr_is_wildcard(const apr_sockaddr_t *addr) +{ + static const char inaddr_any[ +#if APR_HAVE_IPV6 + sizeof(struct in6_addr) +#else + sizeof(struct in_addr) +#endif + ] = {0}; + if (addr->ipaddr_ptr /* IP address initialized */ + && addr->ipaddr_len <= sizeof inaddr_any) { /* else bug elsewhere? */ + if (!memcmp(inaddr_any, addr->ipaddr_ptr, addr->ipaddr_len)) { + return 1; + } +#if APR_HAVE_IPV6 + if (addr->family == AF_INET6 + && IN6_IS_ADDR_V4MAPPED((struct in6_addr *)addr->ipaddr_ptr)) { + struct in_addr *v4 = (struct in_addr *)&((apr_uint32_t *)addr->ipaddr_ptr)[3]; -ap_status_t ap_get_remote_ipaddr(char **addr, const ap_socket_t *sock) + if (!memcmp(inaddr_any, v4, sizeof *v4)) { + return 1; + } + } +#endif + } + return 0; +} + +static apr_status_t parse_network(apr_ipsubnet_t *ipsub, const char *network) { - *addr = ap_pstrdup(sock->cntxt, inet_ntoa(sock->remote_addr->sin_addr)); + /* legacy syntax for ip addrs: a.b.c. ==> a.b.c.0/24 for example */ + int shift; + char *s, *t; + int octet; + char buf[sizeof "255.255.255.255"]; + + if (strlen(network) < sizeof buf) { + strcpy(buf, network); + } + else { + return APR_EBADIP; + } + + /* parse components */ + s = buf; + ipsub->sub[0] = 0; + ipsub->mask[0] = 0; + shift = 24; + while (*s) { + t = s; + if (!apr_isdigit(*t)) { + return APR_EBADIP; + } + while (apr_isdigit(*t)) { + ++t; + } + if (*t == '.') { + *t++ = 0; + } + else if (*t) { + return APR_EBADIP; + } + if (shift < 0) { + return APR_EBADIP; + } + octet = atoi(s); + if (octet < 0 || octet > 255) { + return APR_EBADIP; + } + ipsub->sub[0] |= octet << shift; + ipsub->mask[0] |= 0xFFUL << shift; + s = t; + shift -= 8; + } + ipsub->sub[0] = ntohl(ipsub->sub[0]); + ipsub->mask[0] = ntohl(ipsub->mask[0]); + ipsub->family = AF_INET; return APR_SUCCESS; } +/* return values: + * APR_EINVAL not an IP address; caller should see if it is something else + * APR_BADIP IP address portion is is not valid + * APR_BADMASK mask portion is not valid + */ - -#if HAVE_NETINET_IN_H -ap_status_t ap_get_local_name(struct sockaddr_in **name, const ap_socket_t *sock) +static apr_status_t parse_ip(apr_ipsubnet_t *ipsub, const char *ipstr, int network_allowed) { - *name = sock->local_addr; + /* supported flavors of IP: + * + * . IPv6 numeric address string (e.g., "fe80::1") + * + * IMPORTANT: Don't store IPv4-mapped IPv6 address as an IPv6 address. + * + * . IPv4 numeric address string (e.g., "127.0.0.1") + * + * . IPv4 network string (e.g., "9.67") + * + * IMPORTANT: This network form is only allowed if network_allowed is on. + */ + int rc; + +#if APR_HAVE_IPV6 + rc = apr_inet_pton(AF_INET6, ipstr, ipsub->sub); + if (rc == 1) { + if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)ipsub->sub)) { + /* apr_ipsubnet_test() assumes that we don't create IPv4-mapped IPv6 + * addresses; this of course forces the user to specify IPv4 addresses + * in a.b.c.d style instead of ::ffff:a.b.c.d style. + */ + return APR_EBADIP; + } + ipsub->family = AF_INET6; + } + else +#endif + { + rc = apr_inet_pton(AF_INET, ipstr, ipsub->sub); + if (rc == 1) { + ipsub->family = AF_INET; + } + } + if (rc != 1) { + if (network_allowed) { + return parse_network(ipsub, ipstr); + } + else { + return APR_EBADIP; + } + } return APR_SUCCESS; } +static int looks_like_ip(const char *ipstr) +{ + if (strlen(ipstr) == 0) { + return 0; + } + + if (strchr(ipstr, ':')) { + /* definitely not a hostname; assume it is intended to be an IPv6 address */ + return 1; + } + /* simple IPv4 address string check */ + while ((*ipstr == '.') || apr_isdigit(*ipstr)) + ipstr++; + return (*ipstr == '\0'); +} -ap_status_t ap_get_remote_name(struct sockaddr_in **name, const ap_socket_t *sock) +static void fix_subnet(apr_ipsubnet_t *ipsub) { - *name = sock->remote_addr; + /* in case caller specified more bits in network address than are + * valid according to the mask, turn off the extra bits + */ + int i; + + for (i = 0; i < sizeof ipsub->mask / sizeof(apr_int32_t); i++) { + ipsub->sub[i] &= ipsub->mask[i]; + } +} + +/* be sure not to store any IPv4 address as a v4-mapped IPv6 address */ +APR_DECLARE(apr_status_t) apr_ipsubnet_create(apr_ipsubnet_t **ipsub, const char *ipstr, + const char *mask_or_numbits, apr_pool_t *p) +{ + apr_status_t rv; + char *endptr; + long bits, maxbits = 32; + + /* filter out stuff which doesn't look remotely like an IP address; this helps + * callers like mod_access which have a syntax allowing hostname or IP address; + * APR_EINVAL tells the caller that it was probably not intended to be an IP + * address + */ + if (!looks_like_ip(ipstr)) { + return APR_EINVAL; + } + + *ipsub = apr_pcalloc(p, sizeof(apr_ipsubnet_t)); + + /* assume ipstr is an individual IP address, not a subnet */ + memset((*ipsub)->mask, 0xFF, sizeof (*ipsub)->mask); + + rv = parse_ip(*ipsub, ipstr, mask_or_numbits == NULL); + if (rv != APR_SUCCESS) { + return rv; + } + + if (mask_or_numbits) { +#if APR_HAVE_IPV6 + if ((*ipsub)->family == AF_INET6) { + maxbits = 128; + } +#endif + bits = strtol(mask_or_numbits, &endptr, 10); + if (*endptr == '\0' && bits > 0 && bits <= maxbits) { + /* valid num-bits string; fill in mask appropriately */ + int cur_entry = 0; + apr_int32_t cur_bit_value; + + memset((*ipsub)->mask, 0, sizeof (*ipsub)->mask); + while (bits > 32) { + (*ipsub)->mask[cur_entry] = 0xFFFFFFFF; /* all 32 bits */ + bits -= 32; + ++cur_entry; + } + cur_bit_value = 0x80000000; + while (bits) { + (*ipsub)->mask[cur_entry] |= cur_bit_value; + --bits; + cur_bit_value /= 2; + } + (*ipsub)->mask[cur_entry] = htonl((*ipsub)->mask[cur_entry]); + } + else if (apr_inet_pton(AF_INET, mask_or_numbits, (*ipsub)->mask) == 1 && + (*ipsub)->family == AF_INET) { + /* valid IPv4 netmask */ + } + else { + return APR_EBADMASK; + } + } + + fix_subnet(*ipsub); + return APR_SUCCESS; } + +APR_DECLARE(int) apr_ipsubnet_test(apr_ipsubnet_t *ipsub, apr_sockaddr_t *sa) +{ +#if APR_HAVE_IPV6 + /* XXX This line will segv on Win32 build with APR_HAVE_IPV6, + * but without the IPV6 drivers installed. + */ + if (sa->family == AF_INET) { + if (ipsub->family == AF_INET && + ((sa->sa.sin.sin_addr.s_addr & ipsub->mask[0]) == ipsub->sub[0])) { + return 1; + } + } + else if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)sa->ipaddr_ptr)) { + if (ipsub->family == AF_INET && + (((apr_uint32_t *)sa->ipaddr_ptr)[3] & ipsub->mask[0]) == ipsub->sub[0]) { + return 1; + } + } + else if (sa->family == AF_INET6 && ipsub->family == AF_INET6) { + apr_uint32_t *addr = (apr_uint32_t *)sa->ipaddr_ptr; + + if ((addr[0] & ipsub->mask[0]) == ipsub->sub[0] && + (addr[1] & ipsub->mask[1]) == ipsub->sub[1] && + (addr[2] & ipsub->mask[2]) == ipsub->sub[2] && + (addr[3] & ipsub->mask[3]) == ipsub->sub[3]) { + return 1; + } + } +#else + if ((sa->sa.sin.sin_addr.s_addr & ipsub->mask[0]) == ipsub->sub[0]) { + return 1; + } +#endif /* APR_HAVE_IPV6 */ + return 0; /* no match */ +} + +APR_DECLARE(apr_status_t) apr_sockaddr_zone_set(apr_sockaddr_t *sa, + const char *zone_id) +{ +#if !APR_HAVE_IPV6 || !defined(HAVE_IF_NAMETOINDEX) + return APR_ENOTIMPL; +#else + unsigned int idx; + + if (sa->family != APR_INET6 + || !IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)sa->ipaddr_ptr)) { + return APR_EBADIP; + } + + idx = if_nametoindex(zone_id); + if (idx) { + sa->sa.sin6.sin6_scope_id = idx; + return APR_SUCCESS; + } + + if (errno != ENODEV) { + return errno; + } + else { + char *endptr; + apr_int64_t i = apr_strtoi64(zone_id, &endptr, 10); + + if (*endptr != '\0' || errno || i < 1 || i > APR_INT16_MAX) { + return APR_EGENERAL; + } + + sa->sa.sin6.sin6_scope_id = i; + return APR_SUCCESS; + } +#endif +} + +APR_DECLARE(apr_status_t) apr_sockaddr_zone_get(const apr_sockaddr_t *sa, + const char **name, + apr_uint32_t *id, + apr_pool_t *p) +{ +#if !APR_HAVE_IPV6 || !defined(HAVE_IF_INDEXTONAME) + return APR_ENOTIMPL; +#else + if (sa->family != APR_INET6 || !sa->sa.sin6.sin6_scope_id) { + return APR_EBADIP; + } + + if (name) { + char *buf = apr_palloc(p, IF_NAMESIZE); + if (if_indextoname(sa->sa.sin6.sin6_scope_id, buf) == NULL) + return errno; + *name = buf; + } + + if (id) *id = sa->sa.sin6.sin6_scope_id; + + return APR_SUCCESS; #endif +} diff --git a/network_io/unix/socket_util.c b/network_io/unix/socket_util.c new file mode 100644 index 00000000000..93fe25976ad --- /dev/null +++ b/network_io/unix/socket_util.c @@ -0,0 +1,75 @@ +/* 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_network_io.h" +#include "apr_poll.h" + +APR_DECLARE(apr_status_t) apr_socket_atreadeof(apr_socket_t *sock, int *atreadeof) +{ + apr_pollfd_t pfds[1]; + apr_status_t rv; + apr_int32_t nfds; + + /* The purpose here is to return APR_SUCCESS only in cases in + * which it can be unambiguously determined whether or not the + * socket will return EOF on next read. In case of an unexpected + * error, return that. */ + + pfds[0].reqevents = APR_POLLIN; + pfds[0].desc_type = APR_POLL_SOCKET; + pfds[0].desc.s = sock; + + do { + rv = apr_poll(&pfds[0], 1, &nfds, 0); + } while (APR_STATUS_IS_EINTR(rv)); + + if (APR_STATUS_IS_TIMEUP(rv)) { + /* Read buffer empty -> subsequent reads would block, so, + * definitely not at EOF. */ + *atreadeof = 0; + return APR_SUCCESS; + } + else if (rv) { + /* Some other error -> unexpected error. */ + return rv; + } + /* Many platforms return only APR_POLLIN; OS X returns APR_POLLHUP|APR_POLLIN */ + else if (nfds == 1 && (pfds[0].rtnevents & APR_POLLIN) == APR_POLLIN) { + apr_sockaddr_t unused; + apr_size_t len = 1; + char buf; + + /* The socket is readable - peek to see whether it returns EOF + * without consuming bytes from the socket buffer. */ + rv = apr_socket_recvfrom(&unused, sock, MSG_PEEK, &buf, &len); + if (rv == APR_EOF) { + *atreadeof = 1; + return APR_SUCCESS; + } + else if (rv) { + /* Read error -> unexpected error. */ + return rv; + } + else { + *atreadeof = 0; + return APR_SUCCESS; + } + } + + /* Should not fall through here. */ + return APR_EGENERAL; +} + diff --git a/network_io/unix/sockets.c b/network_io/unix/sockets.c index a583c2ef783..e95ce2c7dde 100644 --- a/network_io/unix/sockets.c +++ b/network_io/unix/sockets.c @@ -1,63 +1,70 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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 "networkio.h" +#include "apr_arch_networkio.h" +#include "apr_network_io.h" +#include "apr_strings.h" +#include "apr_support.h" #include "apr_portable.h" +#include "apr_arch_inherit.h" + +#ifdef BEOS_R5 +#undef close +#define close closesocket +#endif /* BEOS_R5 */ + +#if APR_HAVE_SOCKADDR_UN +#define GENERIC_INADDR_ANY_LEN sizeof(struct sockaddr_un) +#else +#define GENERIC_INADDR_ANY_LEN 16 +#endif + +/* big enough for IPv4, IPv6 and optionally sun_path */ +static char generic_inaddr_any[GENERIC_INADDR_ANY_LEN] = {0}; + +static apr_status_t socket_cleanup(void *sock) +{ + apr_socket_t *thesocket = sock; + int sd = thesocket->socketdes; + + /* Set socket descriptor to -1 before close(), so that there is no + * chance of returning an already closed FD from apr_os_sock_get(). + */ + thesocket->socketdes = -1; + +#if APR_HAVE_SOCKADDR_UN + if (thesocket->bound && thesocket->local_addr->family == APR_UNIX) { + /* XXX: Check for return values ? */ + unlink(thesocket->local_addr->hostname); + } +#endif + if (close(sd) == 0) { + return APR_SUCCESS; + } + else { + /* Restore, close() was not successful. */ + thesocket->socketdes = sd; + + return errno; + } +} -static ap_status_t socket_cleanup(void *sock) +static apr_status_t socket_child_cleanup(void *sock) { - ap_socket_t *thesocket = sock; + apr_socket_t *thesocket = sock; if (close(thesocket->socketdes) == 0) { thesocket->socketdes = -1; return APR_SUCCESS; @@ -67,64 +74,169 @@ static ap_status_t socket_cleanup(void *sock) } } -ap_status_t ap_create_tcp_socket(ap_socket_t **new, ap_pool_t *cont) +static void set_socket_vars(apr_socket_t *sock, int family, int type, int protocol) +{ + sock->type = type; + sock->protocol = protocol; + apr_sockaddr_vars_set(sock->local_addr, family, 0); + apr_sockaddr_vars_set(sock->remote_addr, family, 0); + sock->options = 0; +#if defined(BEOS) && !defined(BEOS_BONE) + /* BeOS pre-BONE has TCP_NODELAY on by default and it can't be + * switched off! + */ + sock->options |= APR_TCP_NODELAY; +#endif +} + +static void alloc_socket(apr_socket_t **new, apr_pool_t *p) { - (*new) = (ap_socket_t *)ap_palloc(cont, sizeof(ap_socket_t)); + *new = (apr_socket_t *)apr_pcalloc(p, sizeof(apr_socket_t)); + (*new)->pool = p; + (*new)->local_addr = (apr_sockaddr_t *)apr_pcalloc((*new)->pool, + sizeof(apr_sockaddr_t)); + (*new)->local_addr->pool = p; + (*new)->remote_addr = (apr_sockaddr_t *)apr_pcalloc((*new)->pool, + sizeof(apr_sockaddr_t)); + (*new)->remote_addr->pool = p; + (*new)->remote_addr_unknown = 1; +#ifndef WAITIO_USES_POLL + /* Create a pollset with room for one descriptor. */ + /* ### check return codes */ + (void) apr_pollset_create(&(*new)->pollset, 1, p, 0); +#endif +} + +apr_status_t apr_socket_protocol_get(apr_socket_t *sock, int *protocol) +{ + *protocol = sock->protocol; + return APR_SUCCESS; +} + +apr_status_t apr_socket_create(apr_socket_t **new, int ofamily, int type, + int protocol, apr_pool_t *cont) +{ + int family = ofamily, flags = 0; + int oprotocol = protocol; + +#ifdef HAVE_SOCK_CLOEXEC + flags |= SOCK_CLOEXEC; +#endif - if ((*new) == NULL) { - return APR_ENOMEM; + if (family == APR_UNSPEC) { +#if APR_HAVE_IPV6 + family = APR_INET6; +#else + family = APR_INET; +#endif + } +#if APR_HAVE_SOCKADDR_UN + if (family == APR_UNIX) { + protocol = 0; } - (*new)->cntxt = cont; - (*new)->local_addr = (struct sockaddr_in *)ap_palloc((*new)->cntxt, - sizeof(struct sockaddr_in)); - (*new)->remote_addr = (struct sockaddr_in *)ap_palloc((*new)->cntxt, - sizeof(struct sockaddr_in)); +#endif + alloc_socket(new, cont); - if ((*new)->local_addr == NULL || (*new)->remote_addr == NULL) { - return APR_ENOMEM; +#ifndef BEOS_R5 + (*new)->socketdes = socket(family, type|flags, protocol); +#else + /* For some reason BeOS R5 has an unconventional protocol numbering, + * so we need to translate here. */ + switch (protocol) { + case 0: + (*new)->socketdes = socket(family, type|flags, 0); + break; + case APR_PROTO_TCP: + (*new)->socketdes = socket(family, type|flags, IPPROTO_TCP); + break; + case APR_PROTO_UDP: + (*new)->socketdes = socket(family, type|flags, IPPROTO_UDP); + break; + case APR_PROTO_SCTP: + default: + errno = EPROTONOSUPPORT; + (*new)->socketdes = -1; + break; } - - (*new)->socketdes = socket(AF_INET ,SOCK_STREAM, IPPROTO_TCP); +#endif /* BEOS_R5 */ - (*new)->local_addr->sin_family = AF_INET; - (*new)->remote_addr->sin_family = AF_INET; +#if APR_HAVE_IPV6 + if ((*new)->socketdes < 0 && ofamily == APR_UNSPEC) { + family = APR_INET; + (*new)->socketdes = socket(family, type|flags, protocol); + } +#endif - (*new)->addr_len = sizeof(*(*new)->local_addr); - if ((*new)->socketdes < 0) { return errno; } + set_socket_vars(*new, family, type, oprotocol); + +#ifndef HAVE_SOCK_CLOEXEC + { + int flags; + apr_status_t rv; + + if ((flags = fcntl((*new)->socketdes, F_GETFD)) == -1) { + rv = errno; + close((*new)->socketdes); + (*new)->socketdes = -1; + return rv; + } + + flags |= FD_CLOEXEC; + if (fcntl((*new)->socketdes, F_SETFD, flags) == -1) { + rv = errno; + close((*new)->socketdes); + (*new)->socketdes = -1; + return rv; + } + } +#endif + (*new)->timeout = -1; - ap_register_cleanup((*new)->cntxt, (void *)(*new), - socket_cleanup, ap_null_cleanup); + (*new)->inherit = 0; + apr_pool_cleanup_register((*new)->pool, (void *)(*new), socket_cleanup, + socket_child_cleanup); + return APR_SUCCESS; } -ap_status_t ap_shutdown(ap_socket_t *thesocket, ap_shutdown_how_e how) +apr_status_t apr_socket_shutdown(apr_socket_t *thesocket, + apr_shutdown_how_e how) { - if (shutdown(thesocket->socketdes, how) == 0) { - return APR_SUCCESS; - } - else { - return errno; - } + return (shutdown(thesocket->socketdes, how) == -1) ? errno : APR_SUCCESS; } -ap_status_t ap_close_socket(ap_socket_t *thesocket) +apr_status_t apr_socket_close(apr_socket_t *thesocket) { - ap_kill_cleanup(thesocket->cntxt, thesocket, socket_cleanup); - return socket_cleanup(thesocket); + return apr_pool_cleanup_run(thesocket->pool, thesocket, socket_cleanup); } -ap_status_t ap_bind(ap_socket_t *sock) +apr_status_t apr_socket_bind(apr_socket_t *sock, apr_sockaddr_t *sa) { - if (bind(sock->socketdes, (struct sockaddr *)sock->local_addr, sock->addr_len) == -1) + if (bind(sock->socketdes, + (struct sockaddr *)&sa->sa, sa->salen) == -1) { return errno; - else + } + else { + sock->local_addr = sa; + /* XXX IPv6 - this assumes sin_port and sin6_port at same offset */ +#if APR_HAVE_SOCKADDR_UN + if (sock->local_addr->family == APR_UNIX) { + sock->bound = 1; + sock->local_port_unknown = 1; + } + else +#endif + if (sock->local_addr->sa.sin.sin_port == 0) { /* no need for ntohs() when comparing w/ 0 */ + sock->local_port_unknown = 1; /* kernel got us an ephemeral port */ + } return APR_SUCCESS; + } } -ap_status_t ap_listen(ap_socket_t *sock, ap_int32_t backlog) +apr_status_t apr_socket_listen(apr_socket_t *sock, apr_int32_t backlog) { if (listen(sock->socketdes, backlog) == -1) return errno; @@ -132,130 +244,329 @@ ap_status_t ap_listen(ap_socket_t *sock, ap_int32_t backlog) return APR_SUCCESS; } -ap_status_t ap_accept(ap_socket_t **new, const ap_socket_t *sock, ap_pool_t *connection_context) +apr_status_t apr_socket_accept(apr_socket_t **new, apr_socket_t *sock, + apr_pool_t *connection_context) { - (*new) = (ap_socket_t *)ap_palloc(connection_context, - sizeof(ap_socket_t)); + int s; + apr_sockaddr_t sa; + + sa.salen = sizeof(sa.sa); + +#ifdef HAVE_ACCEPT4 + { + int flags = SOCK_CLOEXEC; + +#if defined(SOCK_NONBLOCK) && APR_O_NONBLOCK_INHERITED + /* With FreeBSD accept4() (avail in 10+), O_NONBLOCK is not inherited + * (unlike Linux). Mimic the accept() behavior here in a way that + * may help other platforms. + */ + if (apr_is_option_set(sock, APR_SO_NONBLOCK) == 1) { + flags |= SOCK_NONBLOCK; + } +#endif + s = accept4(sock->socketdes, (struct sockaddr *)&sa.sa, &sa.salen, flags); + } +#else + s = accept(sock->socketdes, (struct sockaddr *)&sa.sa, &sa.salen); +#endif + + if (s < 0) { + return errno; + } +#ifdef TPF + if (s == 0) { + /* 0 is an invalid socket for TPF */ + return APR_EINTR; + } +#endif + alloc_socket(new, connection_context); - (*new)->cntxt = connection_context; - (*new)->local_addr = (struct sockaddr_in *)ap_palloc((*new)->cntxt, - sizeof(struct sockaddr_in)); + /* Set up socket variables -- note that it may be possible for + * *new to be an AF_INET socket when sock is AF_INET6 in some + * dual-stack configurations, so ensure that the remote_/local_addr + * structures are adjusted for the family of the accepted + * socket: */ + set_socket_vars(*new, sa.sa.sin.sin_family, SOCK_STREAM, sock->protocol); - (*new)->remote_addr = (struct sockaddr_in *)ap_palloc((*new)->cntxt, - sizeof(struct sockaddr_in)); - (*new)->addr_len = sizeof(struct sockaddr_in); #ifndef HAVE_POLL (*new)->connected = 1; #endif + (*new)->timeout = -1; - (*new)->socketdes = accept(sock->socketdes, (struct sockaddr *)(*new)->remote_addr, - &(*new)->addr_len); + (*new)->remote_addr_unknown = 0; - if ((*new)->socketdes < 0) { - return errno; + (*new)->socketdes = s; + + /* Copy in peer's address. */ + (*new)->remote_addr->sa = sa.sa; + (*new)->remote_addr->salen = sa.salen; + + *(*new)->local_addr = *sock->local_addr; + + /* The above assignment just overwrote the pool entry. Setting the local_addr + pool for the accepted socket back to what it should be. Otherwise all + allocations for this socket will come from a server pool that is not + freed until the process goes down.*/ + (*new)->local_addr->pool = connection_context; + + /* fix up any pointers which are no longer valid */ + if (sock->local_addr->sa.sin.sin_family == AF_INET) { + (*new)->local_addr->ipaddr_ptr = &(*new)->local_addr->sa.sin.sin_addr; + } +#if APR_HAVE_IPV6 + else if (sock->local_addr->sa.sin.sin_family == AF_INET6) { + (*new)->local_addr->ipaddr_ptr = &(*new)->local_addr->sa.sin6.sin6_addr; + } +#endif +#if APR_HAVE_SOCKADDR_UN + else if (sock->local_addr->sa.sin.sin_family == AF_UNIX) { + *(*new)->remote_addr = *sock->local_addr; + (*new)->local_addr->ipaddr_ptr = &((*new)->local_addr->sa.unx.sun_path); + (*new)->remote_addr->ipaddr_ptr = &((*new)->remote_addr->sa.unx.sun_path); + } + if (sock->local_addr->sa.sin.sin_family != AF_UNIX) +#endif + (*new)->remote_addr->port = ntohs((*new)->remote_addr->sa.sin.sin_port); + if (sock->local_port_unknown) { + /* not likely for a listening socket, but theoretically possible :) */ + (*new)->local_port_unknown = 1; + } + +#if APR_TCP_NODELAY_INHERITED + if (apr_is_option_set(sock, APR_TCP_NODELAY) == 1) { + apr_set_option(*new, APR_TCP_NODELAY, 1); + } +#endif /* TCP_NODELAY_INHERITED */ +#if APR_O_NONBLOCK_INHERITED + if (apr_is_option_set(sock, APR_SO_NONBLOCK) == 1) { + apr_set_option(*new, APR_SO_NONBLOCK, 1); } +#endif /* APR_O_NONBLOCK_INHERITED */ - if (getsockname((*new)->socketdes, (struct sockaddr *)(*new)->local_addr, - &((*new)->addr_len)) < 0) { - return errno; + if (sock->local_interface_unknown || + !memcmp(sock->local_addr->ipaddr_ptr, + generic_inaddr_any, + sock->local_addr->ipaddr_len)) { + /* If the interface address inside the listening socket's local_addr wasn't + * up-to-date, we don't know local interface of the connected socket either. + * + * If the listening socket was not bound to a specific interface, we + * don't know the local_addr of the connected socket. + */ + (*new)->local_interface_unknown = 1; } - ap_register_cleanup((*new)->cntxt, (void *)(*new), - socket_cleanup, ap_null_cleanup); +#ifndef HAVE_ACCEPT4 + { + int flags; + apr_status_t rv; + + if ((flags = fcntl((*new)->socketdes, F_GETFD)) == -1) { + rv = errno; + close((*new)->socketdes); + (*new)->socketdes = -1; + return rv; + } + + flags |= FD_CLOEXEC; + if (fcntl((*new)->socketdes, F_SETFD, flags) == -1) { + rv = errno; + close((*new)->socketdes); + (*new)->socketdes = -1; + return rv; + } + } +#endif + + (*new)->inherit = 0; + apr_pool_cleanup_register((*new)->pool, (void *)(*new), socket_cleanup, + socket_cleanup); return APR_SUCCESS; } -ap_status_t ap_connect(ap_socket_t *sock, char *hostname) +apr_status_t apr_socket_connect(apr_socket_t *sock, apr_sockaddr_t *sa) { - struct hostent *hp; + int rc; - if (hostname != NULL) { - hp = gethostbyname(hostname); + do { + rc = connect(sock->socketdes, + (const struct sockaddr *)&sa->sa.sin, + sa->salen); + } while (rc == -1 && errno == EINTR); - if ((sock->socketdes < 0) || (!sock->remote_addr)) { - return APR_ENOTSOCK; + /* we can see EINPROGRESS the first time connect is called on a non-blocking + * socket; if called again, we can see EALREADY + */ + if ((rc == -1) && (errno == EINPROGRESS || errno == EALREADY) + && (sock->timeout > 0)) { + rc = apr_wait_for_io_or_timeout(NULL, sock, 0); + if (rc != APR_SUCCESS) { + return rc; } - if (!hp) { - return (h_errno + APR_OS_START_SYSERR); + +#ifdef SO_ERROR + { + int error; + apr_socklen_t len = sizeof(error); + if ((rc = getsockopt(sock->socketdes, SOL_SOCKET, SO_ERROR, + (char *)&error, &len)) < 0) { + return errno; + } + if (error) { + return error; + } } - - memcpy((char *)&sock->remote_addr->sin_addr, hp->h_addr_list[0], hp->h_length); +#endif /* SO_ERROR */ + } - sock->addr_len = sizeof(*sock->remote_addr); + if (memcmp(sa->ipaddr_ptr, generic_inaddr_any, sa->ipaddr_len)) { + /* A real remote address was passed in. If the unspecified + * address was used, the actual remote addr will have to be + * determined using getpeername() if required. */ + sock->remote_addr_unknown = 0; + + /* Copy the address structure details in. */ + sock->remote_addr->sa = sa->sa; + sock->remote_addr->salen = sa->salen; + /* Adjust ipaddr_ptr et al. */ + apr_sockaddr_vars_set(sock->remote_addr, sa->family, sa->port); } - if ((connect(sock->socketdes, (const struct sockaddr *)sock->remote_addr, sock->addr_len) < 0) && - (errno != EINPROGRESS)) { + if (sock->local_addr->port == 0) { + /* connect() got us an ephemeral port */ + sock->local_port_unknown = 1; + } +#if APR_HAVE_SOCKADDR_UN + if (sock->local_addr->sa.sin.sin_family == AF_UNIX) { + /* Assign connect address as local. */ + sock->local_addr = sa; + } + else +#endif + if (!memcmp(sock->local_addr->ipaddr_ptr, + generic_inaddr_any, + sock->local_addr->ipaddr_len)) { + /* not bound to specific local interface; connect() had to assign + * one for the socket + */ + sock->local_interface_unknown = 1; + } + + if (rc == -1 && errno != EISCONN) { return errno; } - else { - socklen_t namelen = sizeof(*sock->local_addr); - getsockname(sock->socketdes, (struct sockaddr *)sock->local_addr, &namelen); + #ifndef HAVE_POLL - sock->connected=1; + sock->connected=1; #endif - return APR_SUCCESS; - } + return APR_SUCCESS; } -ap_status_t ap_get_socketdata(void **data, char *key, ap_socket_t *sock) +apr_status_t apr_socket_type_get(apr_socket_t *sock, int *type) { - if (sock != NULL) { - return ap_get_userdata(data, key, sock->cntxt); - } - else { - data = NULL; - return APR_ENOSOCKET; - } + *type = sock->type; + return APR_SUCCESS; } -ap_status_t ap_set_socketdata(ap_socket_t *sock, void *data, char *key, - ap_status_t (*cleanup) (void *)) +apr_status_t apr_socket_data_get(void **data, const char *key, apr_socket_t *sock) { - if (sock != NULL) { - return ap_set_userdata(data, key, cleanup, sock->cntxt); - } - else { - data = NULL; - return APR_ENOSOCKET; + sock_userdata_t *cur = sock->userdata; + + *data = NULL; + + while (cur) { + if (!strcmp(cur->key, key)) { + *data = cur->data; + break; + } + cur = cur->next; } + + return APR_SUCCESS; } -ap_status_t ap_get_os_sock(ap_os_sock_t *thesock, ap_socket_t *sock) +apr_status_t apr_socket_data_set(apr_socket_t *sock, void *data, const char *key, + apr_status_t (*cleanup) (void *)) { - if (sock == NULL) { - return APR_ENOSOCKET; + sock_userdata_t *new = apr_palloc(sock->pool, sizeof(sock_userdata_t)); + + new->key = apr_pstrdup(sock->pool, key); + new->data = data; + new->next = sock->userdata; + sock->userdata = new; + + if (cleanup) { + apr_pool_cleanup_register(sock->pool, data, cleanup, cleanup); } + + return APR_SUCCESS; +} + +apr_status_t apr_os_sock_get(apr_os_sock_t *thesock, apr_socket_t *sock) +{ *thesock = sock->socketdes; return APR_SUCCESS; } -ap_status_t ap_put_os_sock(ap_socket_t **sock, ap_os_sock_t *thesock, - ap_pool_t *cont) +apr_status_t apr_os_sock_make(apr_socket_t **apr_sock, + apr_os_sock_info_t *os_sock_info, + apr_pool_t *cont) { - if (cont == NULL) { - return APR_ENOPOOL; + alloc_socket(apr_sock, cont); + set_socket_vars(*apr_sock, os_sock_info->family, os_sock_info->type, os_sock_info->protocol); + (*apr_sock)->timeout = -1; + (*apr_sock)->socketdes = *os_sock_info->os_sock; + if (os_sock_info->local) { + memcpy(&(*apr_sock)->local_addr->sa.sin, + os_sock_info->local, + (*apr_sock)->local_addr->salen); + /* XXX IPv6 - this assumes sin_port and sin6_port at same offset */ + (*apr_sock)->local_addr->port = ntohs((*apr_sock)->local_addr->sa.sin.sin_port); + } + else { + (*apr_sock)->local_port_unknown = (*apr_sock)->local_interface_unknown = 1; + } + if (os_sock_info->remote) { +#ifndef HAVE_POLL + (*apr_sock)->connected = 1; +#endif + memcpy(&(*apr_sock)->remote_addr->sa.sin, + os_sock_info->remote, + (*apr_sock)->remote_addr->salen); + /* XXX IPv6 - this assumes sin_port and sin6_port at same offset */ + (*apr_sock)->remote_addr->port = ntohs((*apr_sock)->remote_addr->sa.sin.sin_port); + } + else { + (*apr_sock)->remote_addr_unknown = 1; } + + (*apr_sock)->inherit = 0; + apr_pool_cleanup_register((*apr_sock)->pool, (void *)(*apr_sock), + socket_cleanup, socket_cleanup); + return APR_SUCCESS; +} + +apr_status_t apr_os_sock_put(apr_socket_t **sock, apr_os_sock_t *thesock, + apr_pool_t *cont) +{ + /* XXX Bogus assumption that *sock points at anything legit */ if ((*sock) == NULL) { - (*sock) = (ap_socket_t *)ap_palloc(cont, sizeof(ap_socket_t)); - (*sock)->cntxt = cont; - (*sock)->local_addr = (struct sockaddr_in *)ap_palloc((*sock)->cntxt, - sizeof(struct sockaddr_in)); - (*sock)->remote_addr = (struct sockaddr_in *)ap_palloc((*sock)->cntxt, - sizeof(struct sockaddr_in)); - - if ((*sock)->local_addr == NULL || (*sock)->remote_addr == NULL) { - return APR_ENOMEM; - } - - (*sock)->addr_len = sizeof(*(*sock)->local_addr); + alloc_socket(sock, cont); + /* XXX IPv6 figure out the family here! */ + /* XXX figure out the actual socket type here */ + /* *or* just decide that apr_os_sock_put() has to be told the family and type */ + set_socket_vars(*sock, APR_INET, SOCK_STREAM, 0); (*sock)->timeout = -1; - if (getsockname(*thesock, (struct sockaddr *)(*sock)->local_addr, - &((*sock)->addr_len)) < 0) { - return errno; - } } + (*sock)->local_port_unknown = (*sock)->local_interface_unknown = 1; + (*sock)->remote_addr_unknown = 1; (*sock)->socketdes = *thesock; return APR_SUCCESS; } +APR_POOL_IMPLEMENT_ACCESSOR(socket) + +APR_IMPLEMENT_INHERIT_SET(socket, inherit, pool, socket_cleanup) + +APR_IMPLEMENT_INHERIT_UNSET(socket, inherit, pool, socket_cleanup) diff --git a/network_io/unix/sockopt.c b/network_io/unix/sockopt.c index 45f64a5f5ef..c48ab06a540 100644 --- a/network_io/unix/sockopt.c +++ b/network_io/unix/sockopt.c @@ -1,61 +1,27 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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 "networkio.h" +#include "apr_arch_networkio.h" +#include "apr_strings.h" -static ap_status_t soblock(int sd) + +static apr_status_t soblock(int sd) { +/* BeOS uses setsockopt at present for non blocking... */ +#ifndef BEOS int fd_flags; fd_flags = fcntl(sd, F_GETFL, 0); @@ -64,19 +30,24 @@ static ap_status_t soblock(int sd) #elif defined(O_NDELAY) fd_flags &= ~O_NDELAY; #elif defined(FNDELAY) - fd_flags &= ~O_FNDELAY; + fd_flags &= ~FNDELAY; #else - /* XXXX: this breaks things, but an alternative isn't obvious...*/ - return -1; +#error Please teach APR how to make sockets blocking on your platform. #endif if (fcntl(sd, F_SETFL, fd_flags) == -1) { return errno; } +#else + int on = 0; + if (setsockopt(sd, SOL_SOCKET, SO_NONBLOCK, &on, sizeof(int)) < 0) + return errno; +#endif /* BEOS */ return APR_SUCCESS; } -static ap_status_t sononblock(int sd) +static apr_status_t sononblock(int sd) { +#ifndef BEOS int fd_flags; fd_flags = fcntl(sd, F_GETFL, 0); @@ -85,97 +56,406 @@ static ap_status_t sononblock(int sd) #elif defined(O_NDELAY) fd_flags |= O_NDELAY; #elif defined(FNDELAY) - fd_flags |= O_FNDELAY; + fd_flags |= FNDELAY; #else - /* XXXX: this breaks things, but an alternative isn't obvious...*/ - return -1; +#error Please teach APR how to make sockets non-blocking on your platform. #endif if (fcntl(sd, F_SETFL, fd_flags) == -1) { return errno; } +#else + int on = 1; + if (setsockopt(sd, SOL_SOCKET, SO_NONBLOCK, &on, sizeof(int)) < 0) + return errno; +#endif /* BEOS */ + return APR_SUCCESS; +} + + +apr_status_t apr_socket_timeout_set(apr_socket_t *sock, apr_interval_time_t t) +{ + apr_status_t stat; + + /* If our new timeout is non-negative and our old timeout was + * negative, then we need to ensure that we are non-blocking. + * Conversely, if our new timeout is negative and we had + * non-negative timeout, we must make sure our socket is blocking. + * We want to avoid calling fcntl more than necessary on the + * socket. + */ + if (t >= 0 && sock->timeout < 0) { + if (apr_is_option_set(sock, APR_SO_NONBLOCK) != 1) { + if ((stat = sononblock(sock->socketdes)) != APR_SUCCESS) { + return stat; + } + apr_set_option(sock, APR_SO_NONBLOCK, 1); + } + } + else if (t < 0 && sock->timeout >= 0) { + if (apr_is_option_set(sock, APR_SO_NONBLOCK) != 0) { + if ((stat = soblock(sock->socketdes)) != APR_SUCCESS) { + return stat; + } + apr_set_option(sock, APR_SO_NONBLOCK, 0); + } + } + /* must disable the incomplete read support if we disable + * a timeout + */ + if (t <= 0) { + sock->options &= ~APR_INCOMPLETE_READ; + } + sock->timeout = t; return APR_SUCCESS; } -ap_status_t ap_setsocketopt(ap_socket_t *sock, ap_int32_t opt, ap_int32_t on) + +apr_status_t apr_socket_opt_set(apr_socket_t *sock, + apr_int32_t opt, apr_int32_t on) { int one; - struct linger li; - ap_status_t stat; + apr_status_t rv; if (on) one = 1; else one = 0; - - if (opt & APR_SO_KEEPALIVE) { - if (setsockopt(sock->socketdes, SOL_SOCKET, SO_KEEPALIVE, (void *)&one, sizeof(int)) == -1) { - return errno; + switch(opt) { + case APR_SO_KEEPALIVE: +#ifdef SO_KEEPALIVE + if (on != apr_is_option_set(sock, APR_SO_KEEPALIVE)) { + if (setsockopt(sock->socketdes, SOL_SOCKET, SO_KEEPALIVE, (void *)&one, sizeof(int)) == -1) { + return errno; + } + apr_set_option(sock, APR_SO_KEEPALIVE, on); } - } - if (opt & APR_SO_DEBUG) { - if (setsockopt(sock->socketdes, SOL_SOCKET, SO_DEBUG, (void *)&one, sizeof(int)) == -1) { - return errno; +#else + return APR_ENOTIMPL; +#endif + break; + case APR_SO_DEBUG: + if (on != apr_is_option_set(sock, APR_SO_DEBUG)) { + if (setsockopt(sock->socketdes, SOL_SOCKET, SO_DEBUG, (void *)&one, sizeof(int)) == -1) { + return errno; + } + apr_set_option(sock, APR_SO_DEBUG, on); } - } - if (opt & APR_SO_REUSEADDR) { - if (setsockopt(sock->socketdes, SOL_SOCKET, SO_REUSEADDR, (void *)&one, sizeof(int)) == -1) { - return errno; + break; + case APR_SO_BROADCAST: +#ifdef SO_BROADCAST + if (on != apr_is_option_set(sock, APR_SO_BROADCAST)) { + if (setsockopt(sock->socketdes, SOL_SOCKET, SO_BROADCAST, (void *)&one, sizeof(int)) == -1) { + return errno; + } + apr_set_option(sock, APR_SO_BROADCAST, on); } - } - if (opt & APR_SO_SNDBUF) { +#else + return APR_ENOTIMPL; +#endif + break; + case APR_SO_REUSEADDR: + if (on != apr_is_option_set(sock, APR_SO_REUSEADDR)) { + if (setsockopt(sock->socketdes, SOL_SOCKET, SO_REUSEADDR, (void *)&one, sizeof(int)) == -1) { + return errno; + } + apr_set_option(sock, APR_SO_REUSEADDR, on); + } + break; + case APR_SO_SNDBUF: +#ifdef SO_SNDBUF if (setsockopt(sock->socketdes, SOL_SOCKET, SO_SNDBUF, (void *)&on, sizeof(int)) == -1) { return errno; } - } - if (opt & APR_SO_NONBLOCK) { - if (on) { - if ((stat = soblock(sock->socketdes)) != APR_SUCCESS) - return stat; +#else + return APR_ENOTIMPL; +#endif + break; + case APR_SO_RCVBUF: +#ifdef SO_RCVBUF + if (setsockopt(sock->socketdes, SOL_SOCKET, SO_RCVBUF, (void *)&on, sizeof(int)) == -1) { + return errno; } - else { - if ((stat = sononblock(sock->socketdes)) != APR_SUCCESS) - return stat; +#else + return APR_ENOTIMPL; +#endif + break; + case APR_SO_NONBLOCK: + if (apr_is_option_set(sock, APR_SO_NONBLOCK) != on) { + if (on) { + if ((rv = sononblock(sock->socketdes)) != APR_SUCCESS) + return rv; + } + else { + if ((rv = soblock(sock->socketdes)) != APR_SUCCESS) + return rv; + } + apr_set_option(sock, APR_SO_NONBLOCK, on); } - } - if (opt & APR_SO_LINGER) { - li.l_onoff = on; - li.l_linger = MAX_SECS_TO_LINGER; - if (setsockopt(sock->socketdes, SOL_SOCKET, SO_LINGER, (char *) &li, sizeof(struct linger)) == -1) { + break; + case APR_SO_LINGER: +#ifdef SO_LINGER + if (apr_is_option_set(sock, APR_SO_LINGER) != on) { + struct linger li; + li.l_onoff = on; + li.l_linger = APR_MAX_SECS_TO_LINGER; + if (setsockopt(sock->socketdes, SOL_SOCKET, SO_LINGER, (char *) &li, sizeof(struct linger)) == -1) { + return errno; + } + apr_set_option(sock, APR_SO_LINGER, on); + } +#else + return APR_ENOTIMPL; +#endif + break; + case APR_TCP_DEFER_ACCEPT: +#if defined(TCP_DEFER_ACCEPT) + if (apr_is_option_set(sock, APR_TCP_DEFER_ACCEPT) != on) { + int optlevel = IPPROTO_TCP; + int optname = TCP_DEFER_ACCEPT; + + if (setsockopt(sock->socketdes, optlevel, optname, + (void *)&on, sizeof(int)) == -1) { + return errno; + } + apr_set_option(sock, APR_TCP_DEFER_ACCEPT, on); + } +#else + return APR_ENOTIMPL; +#endif + break; + case APR_TCP_NODELAY: +#if defined(TCP_NODELAY) + if (apr_is_option_set(sock, APR_TCP_NODELAY) != on) { + int optlevel = IPPROTO_TCP; + int optname = TCP_NODELAY; + +#if APR_HAVE_SCTP + if (sock->protocol == IPPROTO_SCTP) { + optlevel = IPPROTO_SCTP; + optname = SCTP_NODELAY; + } +#endif + if (setsockopt(sock->socketdes, optlevel, optname, (void *)&on, sizeof(int)) == -1) { + return errno; + } + apr_set_option(sock, APR_TCP_NODELAY, on); + } +#else + /* BeOS pre-BONE has TCP_NODELAY set by default. + * As it can't be turned off we might as well check if they're asking + * for it to be turned on! + */ +#ifdef BEOS + if (on == 1) + return APR_SUCCESS; + else +#endif + return APR_ENOTIMPL; +#endif + break; + case APR_TCP_NOPUSH: +#if APR_TCP_NOPUSH_FLAG + /* TCP_NODELAY and TCP_CORK are mutually exclusive on Linux + * kernels < 2.6; on newer kernels they can be used together + * and TCP_CORK takes preference, which is the desired + * behaviour. On older kernels, TCP_NODELAY must be toggled + * to "off" whilst TCP_CORK is in effect. */ + if (apr_is_option_set(sock, APR_TCP_NOPUSH) != on) { +#ifndef HAVE_TCP_NODELAY_WITH_CORK + int optlevel = IPPROTO_TCP; + int optname = TCP_NODELAY; + +#if APR_HAVE_SCTP + if (sock->protocol == IPPROTO_SCTP) { + optlevel = IPPROTO_SCTP; + optname = SCTP_NODELAY; + } +#endif + /* OK we're going to change some settings here... */ + if (apr_is_option_set(sock, APR_TCP_NODELAY) == 1 && on) { + /* Now toggle TCP_NODELAY to off, if TCP_CORK is being + * turned on: */ + int tmpflag = 0; + if (setsockopt(sock->socketdes, optlevel, optname, + (void*)&tmpflag, sizeof(int)) == -1) { + return errno; + } + apr_set_option(sock, APR_RESET_NODELAY, 1); + apr_set_option(sock, APR_TCP_NODELAY, 0); + } else if (on) { + apr_set_option(sock, APR_RESET_NODELAY, 0); + } +#endif /* HAVE_TCP_NODELAY_WITH_CORK */ + + /* OK, now we can just set the TCP_NOPUSH flag accordingly...*/ + if (setsockopt(sock->socketdes, IPPROTO_TCP, APR_TCP_NOPUSH_FLAG, + (void*)&on, sizeof(int)) == -1) { + return errno; + } + apr_set_option(sock, APR_TCP_NOPUSH, on); +#ifndef HAVE_TCP_NODELAY_WITH_CORK + if (!on && apr_is_option_set(sock, APR_RESET_NODELAY)) { + /* Now, if TCP_CORK was just turned off, turn + * TCP_NODELAY back on again if it was earlier toggled + * to off: */ + int tmpflag = 1; + if (setsockopt(sock->socketdes, optlevel, optname, + (void*)&tmpflag, sizeof(int)) == -1) { + return errno; + } + apr_set_option(sock, APR_RESET_NODELAY,0); + apr_set_option(sock, APR_TCP_NODELAY, 1); + } +#endif /* HAVE_TCP_NODELAY_WITH_CORK */ + } +#else + return APR_ENOTIMPL; +#endif + break; + case APR_INCOMPLETE_READ: + apr_set_option(sock, APR_INCOMPLETE_READ, on); + break; + case APR_IPV6_V6ONLY: +#if APR_HAVE_IPV6 && defined(IPV6_V6ONLY) + /* we don't know the initial setting of this option, + * so don't check sock->options since that optimization + * won't work + */ + if (setsockopt(sock->socketdes, IPPROTO_IPV6, IPV6_V6ONLY, + (void *)&on, sizeof(int)) == -1) { return errno; } - } - if (opt & APR_SO_TIMEOUT) { - sock->timeout = on; - if ((stat = sononblock(sock->socketdes)) != APR_SUCCESS) { - return stat; + apr_set_option(sock, APR_IPV6_V6ONLY, on); +#else + return APR_ENOTIMPL; +#endif + break; + case APR_SO_FREEBIND: +#if defined(IP_FREEBIND) + if (setsockopt(sock->socketdes, SOL_IP, IP_FREEBIND, + (void *)&one, sizeof(int)) == -1) { + return errno; } + apr_set_option(sock, APR_SO_FREEBIND, on); +#elif 0 /* defined(IP_BINDANY) ... */ + /* TODO: insert FreeBSD support here, note family specific + * options, IP_BINDANY vs IPV6_BINDANY */ +#else + return APR_ENOTIMPL; +#endif + break; + default: + return APR_EINVAL; } - return APR_SUCCESS; + + return APR_SUCCESS; } -ap_status_t ap_gethostname(char *buf, ap_int32_t len, ap_pool_t *cont) + +apr_status_t apr_socket_timeout_get(apr_socket_t *sock, apr_interval_time_t *t) +{ + *t = sock->timeout; + return APR_SUCCESS; +} + + +apr_status_t apr_socket_opt_get(apr_socket_t *sock, + apr_int32_t opt, apr_int32_t *on) +{ + switch(opt) { + default: + *on = apr_is_option_set(sock, opt); + } + return APR_SUCCESS; +} + + +apr_status_t apr_socket_atmark(apr_socket_t *sock, int *atmark) { - if (gethostname(buf, len) == -1) +#ifndef BEOS_R5 + int oobmark; + + if (ioctl(sock->socketdes, SIOCATMARK, (void*) &oobmark) < 0) + return apr_get_netos_error(); + + *atmark = (oobmark != 0); + + return APR_SUCCESS; +#else /* BEOS_R5 */ + return APR_ENOTIMPL; +#endif +} + +apr_status_t apr_gethostname(char *buf, apr_int32_t len, apr_pool_t *cont) +{ +#ifdef BEOS_R5 + if (gethostname(buf, len) == 0) { +#else + if (gethostname(buf, len) != 0) { +#endif + buf[0] = '\0'; return errno; - else - return APR_SUCCESS; + } + else if (!memchr(buf, '\0', len)) { /* buffer too small */ + /* note... most platforms just truncate in this condition + * linux+glibc return an error + */ + buf[0] = '\0'; + return APR_ENAMETOOLONG; + } + return APR_SUCCESS; } -ap_status_t ap_get_remote_hostname(char **name, ap_socket_t *sock) +#if APR_HAS_SO_ACCEPTFILTER +apr_status_t apr_socket_accept_filter(apr_socket_t *sock, const char *name, + const char *args) { - struct hostent *hptr; - - hptr = gethostbyaddr((char *)&(sock->remote_addr->sin_addr), - sizeof(struct in_addr), AF_INET); - if (hptr != NULL) { - *name = ap_pstrdup(sock->cntxt, hptr->h_name); - if (*name) { + struct accept_filter_arg af; + socklen_t optlen = sizeof(af); + + /* FreeBSD returns an error if the filter is already set; ignore + * this call if we previously set it to the same value. + */ + if ((getsockopt(sock->socketdes, SOL_SOCKET, SO_ACCEPTFILTER, + &af, &optlen)) == 0) { + if (!strcmp(name, af.af_name) && !strcmp(args, af.af_arg)) { return APR_SUCCESS; } - return APR_ENOMEM; } - /* XXX - Is referencing h_errno threadsafe? */ - return (h_errno + APR_OS_START_SYSERR); + /* Uhh, at least in FreeBSD 9 the fields are declared as arrays of + * these lengths; did sizeof not work in some ancient release? + * + * FreeBSD kernel sets the last byte to a '\0'. + */ + apr_cpystrn(af.af_name, name, 16); + apr_cpystrn(af.af_arg, args, 256 - 16); + + if ((setsockopt(sock->socketdes, SOL_SOCKET, SO_ACCEPTFILTER, + &af, sizeof(af))) < 0) { + return errno; + } + return APR_SUCCESS; } +#endif + +APR_PERMS_SET_IMPLEMENT(socket) +{ +#if APR_HAVE_SOCKADDR_UN + apr_status_t rv = APR_SUCCESS; + apr_socket_t *socket = (apr_socket_t *)thesocket; + if (socket->local_addr->family == APR_UNIX) { + if (!(perms & APR_FPROT_GSETID)) + gid = -1; + if (fchown(socket->socketdes, uid, gid) < 0) { + rv = errno; + } + } + else + rv = APR_EINVAL; + return rv; +#else + return APR_ENOTIMPL; +#endif +} diff --git a/network_io/win32/networkio.h b/network_io/win32/networkio.h deleted file mode 100644 index 58d82f8b126..00000000000 --- a/network_io/win32/networkio.h +++ /dev/null @@ -1,83 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#ifndef NETWORK_IO_H -#define NETWORK_IO_H - -#include "apr_network_io.h" -#include "apr_general.h" - -struct ap_socket_t { - ap_pool_t *cntxt; - SOCKET sock; - struct sockaddr_in *local_addr; - struct sockaddr_in *remote_addr; - size_t addr_len; - ap_interval_time_t timeout; -}; - -struct ap_pollfd_t { - ap_pool_t *cntxt; - fd_set *read; - int numread; - fd_set *write; - int numwrite; - fd_set *except; - int numexcept; -}; - -ap_status_t status_from_res_error(int); - -#endif /* ! NETWORK_IO_H */ - diff --git a/network_io/win32/poll.c b/network_io/win32/poll.c deleted file mode 100644 index b7eb0603629..00000000000 --- a/network_io/win32/poll.c +++ /dev/null @@ -1,259 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#include "networkio.h" -#include "apr_network_io.h" -#include "apr_general.h" -#include "apr_lib.h" -#include <errno.h> -#include <windows.h> -#include <time.h> - - -ap_status_t ap_setup_poll(ap_pollfd_t **new, ap_int32_t num, ap_pool_t *cont) -{ - (*new) = (ap_pollfd_t *)ap_palloc(cont, sizeof(ap_pollfd_t) * num); - if ((*new) == NULL) { - return APR_ENOMEM; - } - (*new)->cntxt = cont; - (*new)->read = (fd_set *)ap_palloc(cont, sizeof(fd_set)); - (*new)->write = (fd_set *)ap_palloc(cont, sizeof(fd_set)); - (*new)->except = (fd_set *)ap_palloc(cont, sizeof(fd_set)); - FD_ZERO((*new)->read); - (*new)->numread = 0; - FD_ZERO((*new)->write); - (*new)->numwrite = 0; - FD_ZERO((*new)->except); - (*new)->numexcept = 0; - return APR_SUCCESS; -} - -ap_status_t ap_add_poll_socket(ap_pollfd_t *aprset, - ap_socket_t *sock, ap_int16_t event) -{ - if (event & APR_POLLIN) { - FD_SET(sock->sock, aprset->read); - aprset->numread++; - } - if (event & APR_POLLPRI) { - FD_SET(sock->sock, aprset->read); - aprset->numexcept++; - } - if (event & APR_POLLOUT) { - FD_SET(sock->sock, aprset->write); - aprset->numwrite++; - } - return APR_SUCCESS; -} - -ap_status_t ap_poll(ap_pollfd_t *aprset, ap_int32_t *nsds, - ap_interval_time_t timeout) -{ - int rv; - struct timeval tv, *tvptr; - fd_set *newread = NULL; - fd_set *newwrite = NULL; - fd_set *newexcept = NULL; - - if (aprset->numread != 0) { - newread = aprset->read; - } - if (aprset->numwrite != 0) { - newwrite = aprset->write; - } - if (aprset->numexcept != 0) { - newexcept = aprset->except; - } - - if (newread == NULL && newwrite == NULL && newexcept == NULL) { - Sleep(timeout / 1000); /* convert microseconds into milliseconds */ - return APR_TIMEUP; /* TODO - get everybody in synch with Win32 ap_status_t */ - } - else { - if (timeout < 0) { - tvptr = NULL; - } - else { - tv.tv_sec = (long)(timeout / AP_USEC_PER_SEC); - tv.tv_usec = (long)(timeout % AP_USEC_PER_SEC); - tvptr = &tv; - } - rv = select(500, /* ignored on Windows */ - newread, newwrite, newexcept, tvptr); - } - - (*nsds) = rv; - if ((*nsds) < 0) { - rv = GetLastError(); - return APR_EEXIST; /* TODO - get everybody in synch with Win32 ap_status_t */ - } - return APR_SUCCESS; -} - -ap_status_t ap_get_revents(ap_int16_t *event, ap_socket_t *sock, ap_pollfd_t *aprset) -{ - ap_int16_t revents = 0; - WSABUF data; - int dummy; - int flags = MSG_PEEK; - - /* We just want to PEEK at the data, so I am setting up a dummy WSABUF - * variable here. - */ - data.len = 256; - data.buf = (char *)ap_palloc(aprset->cntxt, 256); - - if (FD_ISSET(sock->sock, aprset->read)) { - revents |= APR_POLLIN; - if (WSARecv(sock->sock, &data, 1, &dummy, &flags, NULL, - NULL) == SOCKET_ERROR) { - dummy = WSAGetLastError(); - switch (dummy) { - case WSAECONNRESET: - case WSAECONNABORTED: - case WSAESHUTDOWN: - case WSAENETRESET: { - revents ^= APR_POLLIN; - revents |= APR_POLLHUP; - break; - } - case WSAENOTSOCK: { - revents ^= APR_POLLIN; - revents |= APR_POLLNVAL; - } - default: { - revents ^= APR_POLLIN; - revents |= APR_POLLERR; - } - } - } - } - if (FD_ISSET(sock->sock, aprset->write)) { - revents |= APR_POLLOUT; - } - /* I am assuming that the except is for out of band data, not a failed - * connection on a non-blocking socket. Might be a bad assumption, but - * it works for now. rbb. - */ - if (FD_ISSET(sock->sock, aprset->except)) { - revents |= APR_POLLPRI; - } - - (*event) = revents; - return APR_SUCCESS; -} - -ap_status_t ap_get_polldata(ap_pollfd_t *pollfd, char *key, void *data) -{ - if (pollfd != NULL) { - return ap_get_userdata(data, key, pollfd->cntxt); - } - else { - data = NULL; - return APR_ENOFILE; - } -} - -ap_status_t ap_set_polldata(ap_pollfd_t *pollfd, void *data, char *key, - ap_status_t (*cleanup) (void *)) -{ - if (pollfd != NULL) { - return ap_set_userdata(data, key, cleanup, pollfd->cntxt); - } - else { - data = NULL; - return APR_ENOFILE; - } -} - -ap_status_t ap_mask_poll_socket(ap_pollfd_t *aprset, - ap_socket_t *sock, ap_int16_t events) -{ - if (events & APR_POLLIN) { - FD_CLR(sock->sock, aprset->read); - aprset->numread--; - } - if (events & APR_POLLPRI) { - FD_CLR(sock->sock, aprset->except); - aprset->numexcept--; - } - if (events & APR_POLLOUT) { - FD_CLR(sock->sock, aprset->write); - aprset->numwrite--; - } - return APR_SUCCESS; -} - -ap_status_t ap_remove_poll_socket(ap_pollfd_t *aprset, ap_socket_t *sock) -{ - return ap_mask_poll_socket(aprset, sock, ~0); -} - -ap_status_t ap_clear_poll_sockets(ap_pollfd_t *aprset, ap_int16_t events) -{ - if (events & APR_POLLIN) { - FD_ZERO(aprset->read); - aprset->numread = 0; - } - if (events & APR_POLLPRI) { - FD_ZERO(aprset->read); - aprset->numexcept = 0; - } - if (events & APR_POLLOUT) { - FD_ZERO(aprset->write); - aprset->numwrite = 0; - } - return APR_SUCCESS; -} diff --git a/network_io/win32/sendrecv.c b/network_io/win32/sendrecv.c index 33d39fb0713..61bc20746fe 100644 --- a/network_io/win32/sendrecv.c +++ b/network_io/win32/sendrecv.c @@ -1,78 +1,61 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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 "networkio.h" +#include "apr_arch_networkio.h" #include "apr_errno.h" #include "apr_general.h" #include "apr_network_io.h" #include "apr_lib.h" -#include "fileio.h" +#include "apr_arch_file_io.h" +#if APR_HAVE_TIME_H #include <time.h> +#endif -ap_status_t ap_send(ap_socket_t *sock, const char *buf, ap_ssize_t *len) +/* MAX_SEGMENT_SIZE is the maximum amount of data that will be sent to a client + * in one call of TransmitFile. This number must be small enough to give the + * slowest client time to receive the data before the socket timeout triggers. + * The same problem can exist with apr_socket_send(). In that case, we rely on + * the application to adjust socket timeouts and max send segment + * sizes appropriately. + * For example, Apache will in most cases call apr_socket_send() with less + * than 8193 bytes. + */ +#define MAX_SEGMENT_SIZE 65536 +#define WSABUF_ON_STACK 50 + +APR_DECLARE(apr_status_t) apr_socket_send(apr_socket_t *sock, const char *buf, + apr_size_t *len) { - ap_ssize_t rv; + apr_ssize_t rv; WSABUF wsaData; int lasterror; DWORD dwBytes = 0; - wsaData.len = *len; + wsaData.len = (u_long)*len; wsaData.buf = (char*) buf; - rv = WSASend(sock->sock, &wsaData, 1, &dwBytes, 0, NULL, NULL); +#ifndef _WIN32_WCE + rv = WSASend(sock->socketdes, &wsaData, 1, &dwBytes, 0, NULL, NULL); +#else + rv = send(sock->socketdes, wsaData.buf, wsaData.len, 0); + dwBytes = rv; +#endif if (rv == SOCKET_ERROR) { - lasterror = WSAGetLastError(); + lasterror = apr_get_netos_error(); + *len = 0; return lasterror; } @@ -81,183 +64,432 @@ ap_status_t ap_send(ap_socket_t *sock, const char *buf, ap_ssize_t *len) return APR_SUCCESS; } -ap_status_t ap_recv(ap_socket_t *sock, char *buf, ap_ssize_t *len) + +APR_DECLARE(apr_status_t) apr_socket_recv(apr_socket_t *sock, char *buf, + apr_size_t *len) { - ap_ssize_t rv; + apr_ssize_t rv; WSABUF wsaData; int lasterror; DWORD dwBytes = 0; DWORD flags = 0; - wsaData.len = *len; + wsaData.len = (u_long)*len; wsaData.buf = (char*) buf; - rv = WSARecv(sock->sock, &wsaData, 1, &dwBytes, &flags, NULL, NULL); +#ifndef _WIN32_WCE + rv = WSARecv(sock->socketdes, &wsaData, 1, &dwBytes, &flags, NULL, NULL); +#else + rv = recv(sock->socketdes, wsaData.buf, wsaData.len, 0); + dwBytes = rv; +#endif if (rv == SOCKET_ERROR) { - lasterror = WSAGetLastError(); + lasterror = apr_get_netos_error(); + *len = 0; return lasterror; } *len = dwBytes; - return APR_SUCCESS; + return dwBytes == 0 ? APR_EOF : APR_SUCCESS; } -ap_status_t ap_sendv(ap_socket_t *sock, const struct iovec *vec, - ap_int32_t nvec, ap_int32_t *nbytes) + +APR_DECLARE(apr_status_t) apr_socket_sendv(apr_socket_t *sock, + const struct iovec *vec, + apr_int32_t in_vec, apr_size_t *nbytes) { - ap_ssize_t rv; - int i; - int lasterror; + apr_status_t rc = APR_SUCCESS; + apr_ssize_t rv; + apr_size_t cur_len; + apr_int32_t nvec = 0; + int i, j = 0; DWORD dwBytes = 0; + WSABUF *pWsaBuf; - LPWSABUF pWsaData = (LPWSABUF) malloc(sizeof(WSABUF) * nvec); + for (i = 0; i < in_vec; i++) { + cur_len = vec[i].iov_len; + nvec++; + while (cur_len > APR_DWORD_MAX) { + nvec++; + cur_len -= APR_DWORD_MAX; + } + } - if (!pWsaData) + pWsaBuf = (nvec <= WSABUF_ON_STACK) ? _alloca(sizeof(WSABUF) * (nvec)) + : malloc(sizeof(WSABUF) * (nvec)); + if (!pWsaBuf) return APR_ENOMEM; + for (i = 0; i < in_vec; i++) { + char * base = vec[i].iov_base; + cur_len = vec[i].iov_len; + + do { + if (cur_len > APR_DWORD_MAX) { + pWsaBuf[j].buf = base; + pWsaBuf[j].len = APR_DWORD_MAX; + cur_len -= APR_DWORD_MAX; + base += APR_DWORD_MAX; + } + else { + pWsaBuf[j].buf = base; + pWsaBuf[j].len = (DWORD)cur_len; + cur_len = 0; + } + j++; + + } while (cur_len > 0); + } +#ifndef _WIN32_WCE + rv = WSASend(sock->socketdes, pWsaBuf, nvec, &dwBytes, 0, NULL, NULL); + if (rv == SOCKET_ERROR) { + rc = apr_get_netos_error(); + } +#else for (i = 0; i < nvec; i++) { - pWsaData[i].buf = vec[i].iov_base; - pWsaData[i].len = vec[i].iov_len; + rv = send(sock->socketdes, pWsaBuf[i].buf, pWsaBuf[i].len, 0); + if (rv == SOCKET_ERROR) { + rc = apr_get_netos_error(); + break; + } + dwBytes += rv; + } +#endif + if (nvec > WSABUF_ON_STACK) + free(pWsaBuf); + + *nbytes = dwBytes; + return rc; +} + + +APR_DECLARE(apr_status_t) apr_socket_sendto(apr_socket_t *sock, + apr_sockaddr_t *where, + apr_int32_t flags, const char *buf, + apr_size_t *len) +{ + apr_ssize_t rv; + + rv = sendto(sock->socketdes, buf, (int)*len, flags, + (const struct sockaddr*)&where->sa, + where->salen); + if (rv == SOCKET_ERROR) { + *len = 0; + return apr_get_netos_error(); } - rv = WSASend(sock->sock, pWsaData, nvec, &dwBytes, 0, NULL, NULL); + *len = rv; + return APR_SUCCESS; +} + + +APR_DECLARE(apr_status_t) apr_socket_recvfrom(apr_sockaddr_t *from, + apr_socket_t *sock, + apr_int32_t flags, + char *buf, apr_size_t *len) +{ + apr_ssize_t rv; + + from->salen = sizeof(from->sa); + + rv = recvfrom(sock->socketdes, buf, (int)*len, flags, + (struct sockaddr*)&from->sa, &from->salen); if (rv == SOCKET_ERROR) { - lasterror = WSAGetLastError(); - free(pWsaData); - return lasterror; + (*len) = 0; + return apr_get_netos_error(); } - free(pWsaData); + apr_sockaddr_vars_set(from, from->sa.sin.sin_family, + ntohs(from->sa.sin.sin_port)); - *nbytes = dwBytes; + (*len) = rv; + if (rv == 0 && sock->type == SOCK_STREAM) + return APR_EOF; + + return APR_SUCCESS; +} + + +#if APR_HAS_SENDFILE +static apr_status_t collapse_iovec(char **off, apr_size_t *len, + struct iovec *iovec, int numvec, + char *buf, apr_size_t buflen) +{ + if (numvec == 1) { + *off = iovec[0].iov_base; + *len = iovec[0].iov_len; + } + else { + int i; + for (i = 0; i < numvec; i++) { + *len += iovec[i].iov_len; + } + + if (*len > buflen) { + *len = 0; + return APR_INCOMPLETE; + } + + *off = buf; + + for (i = 0; i < numvec; i++) { + memcpy(buf, iovec[i].iov_base, iovec[i].iov_len); + buf += iovec[i].iov_len; + } + } return APR_SUCCESS; } -#if defined(HAVE_SENDFILE) + + /* - * ap_status_t ap_sendfile(ap_socket_t *, ap_file_t *, ap_hdtr_t *, - * ap_off_t *, ap_size_t *, ap_int32_t flags) + * apr_status_t apr_socket_sendfile(apr_socket_t *, apr_file_t *, apr_hdtr_t *, + * apr_off_t *, apr_size_t *, apr_int32_t flags) * Send a file from an open file descriptor to a socket, along with * optional headers and trailers * arg 1) The socket to which we're writing * arg 2) The open file from which to read * arg 3) A structure containing the headers and trailers to send * arg 4) Offset into the file where we should begin writing - * arg 5) Number of bytes to send - * arg 6) OS-specific flags to pass to sendfile() + * arg 5) Number of bytes to send out of the file + * arg 6) APR flags that are mapped to OS specific flags */ -ap_status_t ap_sendfile(ap_socket_t * sock, ap_file_t * file, - ap_hdtr_t * hdtr, ap_off_t * offset, ap_size_t * len, - ap_int32_t flags) +APR_DECLARE(apr_status_t) apr_socket_sendfile(apr_socket_t *sock, + apr_file_t *file, + apr_hdtr_t *hdtr, + apr_off_t *offset, + apr_size_t *len, + apr_int32_t flags) { -/* - *#define WAIT_FOR_EVENT - * Note: Waiting for the socket directly is much faster than creating a seperate - * wait event. There are a couple of dangerous aspects to waiting directly - * for the socket. First, we should not wait on the socket if concurrent threads - * can wait-on/signal the same socket. This shouldn't be happening with Apache since - * a socket is uniquely tied to a thread. This will change when we begin using - * async I/O with completion ports on the socket. Second, I am not sure how the - * socket timeout code will work. I am hoping the socket will be signaled if the - * setsockopt timeout expires. Need to verify this... - */ - ap_ssize_t rv; - OVERLAPPED overlapped; - TRANSMIT_FILE_BUFFERS tfb, *ptfb = NULL; - int i, ptr = 0; - int lasterror = APR_SUCCESS; + apr_status_t status = APR_SUCCESS; + apr_status_t rv; + apr_off_t curoff = *offset; DWORD dwFlags = 0; + apr_size_t nbytes; + TRANSMIT_FILE_BUFFERS tfb, *ptfb = NULL; + apr_size_t bytes_to_send; /* Bytes to send out of the file (not including headers) */ + int disconnected = 0; + int sendv_trailers = 0; + char hdtrbuf[4096]; -#if 0 - if (flags | APR_SENDFILE_KEEP_SOCKET) - dwFlags |= TF_REUSE_SOCKET; - if (flags | APR_SENDFILE_CLOSE_SOCKET) - dwFlags |= TF_DISCONNECT; -#else - dwFlags = 0; -#endif + if (apr_os_level < APR_WIN_NT) { + return APR_ENOTIMPL; + } + + /* Use len to keep track of number of total bytes sent (including headers) */ + bytes_to_send = *len; + *len = 0; + + /* Handle the goofy case of sending headers/trailers and a zero byte file */ + if (!bytes_to_send && hdtr) { + if (hdtr->numheaders) { + rv = apr_socket_sendv(sock, hdtr->headers, hdtr->numheaders, + &nbytes); + if (rv != APR_SUCCESS) + return rv; + *len += nbytes; + } + if (hdtr->numtrailers) { + rv = apr_socket_sendv(sock, hdtr->trailers, hdtr->numtrailers, + &nbytes); + if (rv != APR_SUCCESS) + return rv; + *len += nbytes; + } + return APR_SUCCESS; + } - /* TransmitFile can only send one header and one footer */ memset(&tfb, '\0', sizeof (tfb)); + + /* Collapse the headers into a single buffer */ if (hdtr && hdtr->numheaders) { + apr_size_t head_length = tfb.HeadLength; ptfb = &tfb; - if (hdtr->numheaders == 1) { - ptfb->Head = hdtr->headers[0].iov_base; - ptfb->HeadLength = hdtr->headers[0].iov_len; - } - else { - /* Need to collapse all the header fragments into one buffer */ - for (i = 0; i < hdtr->numheaders; i++) { - ptfb->HeadLength += hdtr->headers[i].iov_len; - } - ptfb->Head = ap_palloc(sock->cntxt, ptfb->HeadLength); /* Should this be a malloc? */ + nbytes = 0; + rv = collapse_iovec((char **)&ptfb->Head, &head_length, + hdtr->headers, hdtr->numheaders, + hdtrbuf, sizeof(hdtrbuf)); - for (i = 0; i < hdtr->numheaders; i++) { - memcpy((char*)ptfb->Head + ptr, hdtr->headers[i].iov_base, - hdtr->headers[i].iov_len); - ptr += hdtr->headers[i].iov_len; - } + tfb.HeadLength = (DWORD)head_length; + + /* If not enough buffer, punt to sendv */ + if (rv == APR_INCOMPLETE) { + rv = apr_socket_sendv(sock, hdtr->headers, hdtr->numheaders, &nbytes); + if (rv != APR_SUCCESS) + return rv; + *len += nbytes; + ptfb = NULL; } } - if (hdtr && hdtr->numtrailers) { - ptfb = &tfb; - if (hdtr->numtrailers == 1) { - ptfb->Tail = hdtr->trailers[0].iov_base; - ptfb->TailLength = hdtr->trailers[0].iov_len; + + /* Initialize the overlapped structure used on TransmitFile + */ + if (!sock->overlapped) { + sock->overlapped = apr_pcalloc(sock->pool, sizeof(OVERLAPPED)); + sock->overlapped->hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + } + while (bytes_to_send) { + DWORD xmitbytes; + + if (bytes_to_send > MAX_SEGMENT_SIZE) { + xmitbytes = MAX_SEGMENT_SIZE; } else { - /* Need to collapse all the trailer fragments into one buffer */ - for (i = 0; i < hdtr->numtrailers; i++) { - ptfb->TailLength += hdtr->headers[i].iov_len; - } + /* Last call to TransmitFile() */ + xmitbytes = (DWORD)bytes_to_send; + /* Collapse the trailers into a single buffer */ + if (hdtr && hdtr->numtrailers) { + apr_size_t tail_length = tfb.TailLength; + ptfb = &tfb; + rv = collapse_iovec((char**) &ptfb->Tail, &tail_length, + hdtr->trailers, hdtr->numtrailers, + hdtrbuf + ptfb->HeadLength, + sizeof(hdtrbuf) - ptfb->HeadLength); - ptfb->Tail = ap_palloc(sock->cntxt, ptfb->TailLength); /* Should this be a malloc? */ + tfb.TailLength = (DWORD)tail_length; - for (i = 0; i < hdtr->numtrailers; i++) { - memcpy((char*)ptfb->Tail + ptr, hdtr->trailers[i].iov_base, - hdtr->trailers[i].iov_len); - ptr += hdtr->trailers[i].iov_len; + if (rv == APR_INCOMPLETE) { + /* If not enough buffer, punt to sendv, later */ + sendv_trailers = 1; + } + } + /* Disconnect the socket after last send */ + if ((flags & APR_SENDFILE_DISCONNECT_SOCKET) + && !sendv_trailers) { + dwFlags |= TF_REUSE_SOCKET; + dwFlags |= TF_DISCONNECT; + disconnected = 1; } } + + sock->overlapped->Offset = (DWORD)(curoff); +#if APR_HAS_LARGE_FILES + sock->overlapped->OffsetHigh = (DWORD)(curoff >> 32); +#endif + /* XXX BoundsChecker claims dwFlags must not be zero. */ + rv = TransmitFile(sock->socketdes, /* socket */ + file->filehand, /* open file descriptor of the file to be sent */ + xmitbytes, /* number of bytes to send. 0=send all */ + 0, /* Number of bytes per send. 0=use default */ + sock->overlapped, /* OVERLAPPED structure */ + ptfb, /* header and trailer buffers */ + dwFlags); /* flags to control various aspects of TransmitFile */ + if (!rv) { + status = apr_get_netos_error(); + if ((status == APR_FROM_OS_ERROR(ERROR_IO_PENDING)) || + (status == APR_FROM_OS_ERROR(WSA_IO_PENDING))) + { + rv = WaitForSingleObject(sock->overlapped->hEvent, + (DWORD)(sock->timeout >= 0 + ? sock->timeout_ms : INFINITE)); + if (rv == WAIT_OBJECT_0) { + status = APR_SUCCESS; + if (!disconnected) { + if (!WSAGetOverlappedResult(sock->socketdes, + sock->overlapped, + &xmitbytes, + FALSE, + &dwFlags)) { + status = apr_get_netos_error(); + } + /* Ugly code alert: WSAGetOverlappedResult returns + * a count of all bytes sent. This loop only + * tracks bytes sent out of the file. + */ + else if (ptfb) { + xmitbytes -= (ptfb->HeadLength + ptfb->TailLength); + } + } + } + else if (rv == WAIT_TIMEOUT) { + status = APR_FROM_OS_ERROR(WAIT_TIMEOUT); + } + else if (rv == WAIT_ABANDONED) { + /* Hummm... WAIT_ABANDONDED is not an error code. It is + * a return specific to the Win32 WAIT functions that + * indicates that a thread exited while holding a + * mutex. Should consider triggering an assert + * to detect the condition... + */ + status = APR_FROM_OS_ERROR(WAIT_TIMEOUT); + } + else + status = apr_get_os_error(); + } + } + if (status != APR_SUCCESS) + break; + + bytes_to_send -= xmitbytes; + curoff += xmitbytes; + *len += xmitbytes; + /* Adjust len for any headers/trailers sent */ + if (ptfb) { + *len += (ptfb->HeadLength + ptfb->TailLength); + memset(&tfb, '\0', sizeof (tfb)); + ptfb = NULL; + } } - /* Initialize the overlapped structure */ - memset(&overlapped,'\0', sizeof(overlapped)); - if (offset && *offset) { - overlapped.Offset = *offset; - } -#ifdef WAIT_FOR_EVENT - overlapped.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); -#endif - - rv = TransmitFile(sock->sock, /* socket */ - file->filehand, /* open file descriptor of the file to be sent */ - *len, /* number of bytes to send. 0=send all */ - 0, /* Number of bytes per send. 0=use default */ - &overlapped, /* OVERLAPPED structure */ - ptfb, /* header and trailer buffers */ - dwFlags); /* flags to control various aspects of TransmitFile */ - if (!rv) { - lasterror = WSAGetLastError(); - if (lasterror == ERROR_IO_PENDING) { -#ifdef WAIT_FOR_EVENT - rv = WaitForSingleObject(overlapped.hEvent, - sock->timeout >= 0 ? sock->timeout / 1000 : INFINITE); -#else - rv = WaitForSingleObject((HANDLE) sock->sock, - sock->timeout >= 0 ? sock->timeout / 1000 : INFINITE); -#endif - if (rv == WAIT_OBJECT_0) - lasterror = APR_SUCCESS; - else if (rv == WAIT_TIMEOUT) - lasterror = WAIT_TIMEOUT; - else if (rv == WAIT_ABANDONED) - lasterror = WAIT_ABANDONED; - else - lasterror = GetLastError(); + + if (status == APR_SUCCESS) { + if (sendv_trailers) { + rv = apr_socket_sendv(sock, hdtr->trailers, hdtr->numtrailers, &nbytes); + if (rv != APR_SUCCESS) + return rv; + *len += nbytes; + } + + + /* Mark the socket as disconnected, but do not close it. + * Note: The application must have stored the socket prior to making + * the call to apr_socket_sendfile in order to either reuse it + * or close it. + */ + if (disconnected) { + sock->disconnected = 1; + sock->socketdes = INVALID_SOCKET; } } -#ifdef WAIT_FOR_EVENT - CloseHandle(overlapped.hEvent); -#endif - return lasterror; + + return status; } + #endif + +APR_DECLARE(apr_status_t) apr_socket_wait(apr_socket_t *sock, apr_wait_type_t direction) +{ + fd_set fdset, *rptr, *wptr; + int rc; + struct timeval tv, *tvptr; + + FD_ZERO(&fdset); + FD_SET(sock->socketdes, &fdset); + + if (direction == APR_WAIT_READ) { + rptr = &fdset; + wptr = NULL; + } + else { /* APR_WAIT_WRITE */ + rptr = NULL; + wptr = &fdset; + } + + if (sock->timeout < 0) { + tvptr = NULL; + } + else { + /* casts for winsock/timeval definition */ + tv.tv_sec = (long)apr_time_sec(sock->timeout); + tv.tv_usec = (int)apr_time_usec(sock->timeout); + tvptr = &tv; + } + rc = select(/* ignored */ FD_SETSIZE+1, rptr, wptr, NULL, tvptr); + if (rc == SOCKET_ERROR) { + return apr_get_netos_error(); + } + else if (!rc) { + return APR_FROM_OS_ERROR(WSAETIMEDOUT); + } + + return APR_SUCCESS; +} + diff --git a/network_io/win32/sockaddr.c b/network_io/win32/sockaddr.c deleted file mode 100644 index 7010539fb76..00000000000 --- a/network_io/win32/sockaddr.c +++ /dev/null @@ -1,159 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#include "networkio.h" -#include "apr_network_io.h" -#include "apr_general.h" -#include "apr_lib.h" -#include <string.h> - - -ap_status_t ap_set_local_port(ap_socket_t *sock, ap_uint32_t port) -{ - sock->local_addr->sin_port = htons((short)port); - return APR_SUCCESS; -} - - - -ap_status_t ap_set_remote_port(ap_socket_t *sock, ap_uint32_t port) -{ - sock->remote_addr->sin_port = htons((short)port); - return APR_SUCCESS; -} - - - -ap_status_t ap_get_local_port(ap_uint32_t *port, ap_socket_t *sock) -{ - *port = ntohs(sock->local_addr->sin_port); - return APR_SUCCESS; -} - - - -ap_status_t ap_get_remote_port(ap_uint32_t *port, ap_socket_t *sock) -{ - *port = ntohs(sock->remote_addr->sin_port); - return APR_SUCCESS; -} - - - -ap_status_t ap_set_local_ipaddr(ap_socket_t *sock, const char *addr) -{ - u_long ipaddr; - - if (!strcmp(addr, APR_ANYADDR)) { - sock->local_addr->sin_addr.s_addr = htonl(INADDR_ANY); - return APR_SUCCESS; - } - - ipaddr = inet_addr(addr); - - if (ipaddr == INADDR_NONE) { - return WSAEADDRNOTAVAIL; - } - - sock->local_addr->sin_addr.s_addr = ipaddr; - return APR_SUCCESS; -} - -ap_status_t ap_set_remote_ipaddr(ap_socket_t *sock, const char *addr) -{ - u_long ipaddr; - - if (!strcmp(addr, APR_ANYADDR)) { - sock->remote_addr->sin_addr.s_addr = htonl(INADDR_ANY); - return APR_SUCCESS; - } - - ipaddr = inet_addr(addr); - - if (ipaddr == INADDR_NONE) { - return WSAEADDRNOTAVAIL; - } - - sock->remote_addr->sin_addr.s_addr = ipaddr; - return APR_SUCCESS; -} - -ap_status_t ap_get_local_ipaddr(char **addr, const ap_socket_t *sock) -{ - *addr = ap_pstrdup(sock->cntxt, inet_ntoa(sock->local_addr->sin_addr)); - return APR_SUCCESS; -} - - - -ap_status_t ap_get_remote_ipaddr(char **addr, const ap_socket_t *sock) -{ - *addr = ap_pstrdup(sock->cntxt, inet_ntoa(sock->remote_addr->sin_addr)); - return APR_SUCCESS; -} - - -ap_status_t ap_get_local_name(struct sockaddr_in **name, const ap_socket_t *sock) -{ - *name = sock->local_addr; - return APR_SUCCESS; -} - - - -ap_status_t ap_get_remote_name(struct sockaddr_in **name, const ap_socket_t *sock) -{ - *name = sock->remote_addr; - return APR_SUCCESS; -} diff --git a/network_io/win32/sockets.c b/network_io/win32/sockets.c index 02f243bdc55..9c30f70eb4d 100644 --- a/network_io/win32/sockets.c +++ b/network_io/win32/sockets.c @@ -1,118 +1,184 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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 "networkio.h" +#include "apr_arch_networkio.h" #include "apr_network_io.h" #include "apr_general.h" #include "apr_lib.h" #include "apr_portable.h" +#include "apr_strings.h" #include <string.h> -#include <winsock2.h> -#include <windows.h> +#include "apr_arch_inherit.h" +#include "apr_arch_misc.h" +/* Borrow the definition of SOMAXCONN_HINT() from Windows SDK 8, + * in case the SDK we are building against doesn't have it. + */ +#ifndef SOMAXCONN_HINT +#define SOMAXCONN_HINT(b) (-(b)) +#endif -static ap_status_t socket_cleanup(void *sock) +static char generic_inaddr_any[16] = {0}; /* big enough for IPv4 or IPv6 */ + +static apr_status_t socket_cleanup(void *sock) { - ap_socket_t *thesocket = sock; - if (closesocket(thesocket->sock) != SOCKET_ERROR) { - thesocket->sock = INVALID_SOCKET; - return APR_SUCCESS; + apr_socket_t *thesocket = sock; + + if (thesocket->socketdes != INVALID_SOCKET) { + if (closesocket(thesocket->socketdes) == SOCKET_ERROR) { + return apr_get_netos_error(); + } + thesocket->socketdes = INVALID_SOCKET; } - else { - return APR_EEXIST; +#if APR_HAS_SENDFILE + if (thesocket->overlapped) { + CloseHandle(thesocket->overlapped->hEvent); + thesocket->overlapped = NULL; } +#endif + return APR_SUCCESS; } -ap_status_t ap_create_tcp_socket(ap_socket_t **new, ap_pool_t *cont) +static void set_socket_vars(apr_socket_t *sock, int family, int type, int protocol) { - (*new) = (ap_socket_t *)ap_palloc(cont, sizeof(ap_socket_t)); - - if ((*new) == NULL) { - return APR_ENOMEM; + sock->type = type; + sock->protocol = protocol; + apr_sockaddr_vars_set(sock->local_addr, family, 0); + apr_sockaddr_vars_set(sock->remote_addr, family, 0); +#if APR_HAVE_IPV6 + /* hard-coded behavior for older Windows IPv6 */ + if (apr_os_level < APR_WIN_VISTA && family == AF_INET6) { + apr_set_option(sock, APR_IPV6_V6ONLY, 1); } - (*new)->cntxt = cont; - (*new)->local_addr = (struct sockaddr_in *)ap_pcalloc((*new)->cntxt, - sizeof(struct sockaddr_in)); - (*new)->remote_addr = (struct sockaddr_in *)ap_palloc((*new)->cntxt, - sizeof(struct sockaddr_in)); +#endif +} +static void alloc_socket(apr_socket_t **new, apr_pool_t *p) +{ + *new = (apr_socket_t *)apr_pcalloc(p, sizeof(apr_socket_t)); + (*new)->pool = p; + (*new)->local_addr = (apr_sockaddr_t *)apr_pcalloc((*new)->pool, + sizeof(apr_sockaddr_t)); + (*new)->local_addr->pool = p; + + (*new)->remote_addr = (apr_sockaddr_t *)apr_pcalloc((*new)->pool, + sizeof(apr_sockaddr_t)); + (*new)->remote_addr->pool = p; + (*new)->remote_addr_unknown = 1; + + /* Create a pollset with room for one descriptor. */ + /* ### check return codes */ + (void) apr_pollset_create(&(*new)->pollset, 1, p, 0); +} + +APR_DECLARE(apr_status_t) apr_socket_protocol_get(apr_socket_t *sock, + int *protocol) +{ + *protocol = sock->protocol; + return APR_SUCCESS; +} - if (((*new)->local_addr == NULL) || ((*new)->remote_addr == NULL)) { - return APR_ENOMEM; +APR_DECLARE(apr_status_t) apr_socket_create(apr_socket_t **new, int family, + int type, int protocol, + apr_pool_t *cont) +{ +#if APR_HAVE_IPV6 + int downgrade = (family == AF_UNSPEC); +#endif + + if (family == AF_UNSPEC) { +#if APR_HAVE_IPV6 + family = AF_INET6; +#else + family = AF_INET; +#endif } + + alloc_socket(new, cont); + /* For right now, we are not using socket groups. We may later. * No flags to use when creating a socket, so use 0 for that parameter as well. */ - (*new)->sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - if ((*new)->sock == INVALID_SOCKET) { - return WSAGetLastError(); + (*new)->socketdes = socket(family, type, protocol); +#if APR_HAVE_IPV6 + if ((*new)->socketdes == INVALID_SOCKET && downgrade) { + family = AF_INET; + (*new)->socketdes = socket(family, type, protocol); } +#endif - (*new)->local_addr->sin_family = AF_INET; + if ((*new)->socketdes == INVALID_SOCKET) { + return apr_get_netos_error(); + } - (*new)->addr_len = sizeof(*(*new)->local_addr); +#ifdef WIN32 + /* Socket handles are never truly inheritable, there are too many + * bugs associated. WSADuplicateSocket will copy them, but for our + * purposes, always transform the socket() created as a non-inherited + * handle + */ +#if APR_HAS_UNICODE_FS && !defined(_WIN32_WCE) + IF_WIN_OS_IS_UNICODE { + /* A different approach. Many users report errors such as + * (32538)An operation was attempted on something that is not + * a socket. : Parent: WSADuplicateSocket failed... + * + * This appears that the duplicated handle is no longer recognized + * as a socket handle. SetHandleInformation should overcome that + * problem by not altering the handle identifier. But this won't + * work on 9x - it's unsupported. + */ + SetHandleInformation((HANDLE) (*new)->socketdes, + HANDLE_FLAG_INHERIT, 0); + } +#if APR_HAS_ANSI_FS + /* only if APR_HAS_ANSI_FS && APR_HAS_UNICODE_FS */ + ELSE_WIN_OS_IS_ANSI +#endif +#endif +#if APR_HAS_ANSI_FS || defined(_WIN32_WCE) + { + HANDLE hProcess = GetCurrentProcess(); + HANDLE dup; + if (DuplicateHandle(hProcess, (HANDLE) (*new)->socketdes, hProcess, + &dup, 0, FALSE, DUPLICATE_SAME_ACCESS)) { + closesocket((*new)->socketdes); + (*new)->socketdes = (SOCKET) dup; + } + } +#endif + +#endif /* def WIN32 */ + + set_socket_vars(*new, family, type, protocol); + + (*new)->timeout = -1; + (*new)->disconnected = 0; + + apr_pool_cleanup_register((*new)->pool, (void *)(*new), + socket_cleanup, apr_pool_cleanup_null); - (*new)->local_addr->sin_port = 0; - - ap_register_cleanup((*new)->cntxt, (void *)(*new), - socket_cleanup, ap_null_cleanup); return APR_SUCCESS; } -ap_status_t ap_shutdown(ap_socket_t *thesocket, ap_shutdown_how_e how) +APR_DECLARE(apr_status_t) apr_socket_shutdown(apr_socket_t *thesocket, + apr_shutdown_how_e how) { - int winhow; + int winhow = 0; +#ifdef SD_RECEIVE switch (how) { case APR_SHUTDOWN_READ: { winhow = SD_RECEIVE; @@ -126,144 +192,369 @@ ap_status_t ap_shutdown(ap_socket_t *thesocket, ap_shutdown_how_e how) winhow = SD_BOTH; break; } + default: + return APR_BADARG; } - if (shutdown(thesocket->sock, winhow) == 0) { +#endif + if (shutdown(thesocket->socketdes, winhow) == 0) { return APR_SUCCESS; } else { - return WSAGetLastError(); + return apr_get_netos_error(); } } -ap_status_t ap_close_socket(ap_socket_t *thesocket) +APR_DECLARE(apr_status_t) apr_socket_close(apr_socket_t *thesocket) { - ap_kill_cleanup(thesocket->cntxt, thesocket, socket_cleanup); + apr_pool_cleanup_kill(thesocket->pool, thesocket, socket_cleanup); return socket_cleanup(thesocket); } -ap_status_t ap_bind(ap_socket_t *sock) +APR_DECLARE(apr_status_t) apr_socket_bind(apr_socket_t *sock, + apr_sockaddr_t *sa) { - if (bind(sock->sock, (struct sockaddr *)sock->local_addr, sock->addr_len) == -1) { - return WSAGetLastError(); + if (bind(sock->socketdes, + (struct sockaddr *)&sa->sa, + sa->salen) == -1) { + return apr_get_netos_error(); } - else + else { + sock->local_addr = sa; + if (sock->local_addr->sa.sin.sin_port == 0) { + sock->local_port_unknown = 1; /* ephemeral port */ + } return APR_SUCCESS; + } } -ap_status_t ap_listen(ap_socket_t *sock, ap_int32_t backlog) +APR_DECLARE(apr_status_t) apr_socket_listen(apr_socket_t *sock, + apr_int32_t backlog) { - if (listen(sock->sock, backlog) == SOCKET_ERROR) - return WSAGetLastError(); + int backlog_val; + + if (apr_os_level >= APR_WIN_8) { + /* Starting from Windows 8, listen() accepts a special SOMAXCONN_HINT() + * arg that allows setting the listen backlog value to a larger + * value than the predefined Winsock 2 limit (several hundred). + * https://blogs.msdn.microsoft.com/winsdk/2015/06/01/winsocks-listen-backlog-offers-more-flexibility-in-windows-8/ + */ + backlog_val = SOMAXCONN_HINT(backlog); + } + else { + backlog_val = backlog; + } + + if (listen(sock->socketdes, backlog_val) == SOCKET_ERROR) + return apr_get_netos_error(); else return APR_SUCCESS; } -ap_status_t ap_accept(ap_socket_t **new, const ap_socket_t *sock, ap_pool_t *connection_context) +APR_DECLARE(apr_status_t) apr_socket_accept(apr_socket_t **new, + apr_socket_t *sock, apr_pool_t *p) { - (*new) = (ap_socket_t *)ap_palloc(connection_context, - sizeof(ap_socket_t)); + SOCKET s; +#if APR_HAVE_IPV6 + struct sockaddr_storage sa; +#else + struct sockaddr sa; +#endif + int salen = sizeof(sock->remote_addr->sa); - (*new)->cntxt = connection_context; - (*new)->local_addr = (struct sockaddr_in *)ap_palloc((*new)->cntxt, - sizeof(struct sockaddr_in)); - (*new)->remote_addr = (struct sockaddr_in *)ap_palloc((*new)->cntxt, - sizeof(struct sockaddr_in)); - memcpy((*new)->local_addr, sock->local_addr, sizeof(struct sockaddr_in)); + /* Don't allocate the memory until after we call accept. This allows + us to work with nonblocking sockets. */ + s = accept(sock->socketdes, (struct sockaddr *)&sa, &salen); + if (s == INVALID_SOCKET) { + return apr_get_netos_error(); + } + + alloc_socket(new, p); + set_socket_vars(*new, sock->local_addr->sa.sin.sin_family, SOCK_STREAM, + sock->protocol); + + (*new)->timeout = -1; + (*new)->disconnected = 0; + + (*new)->socketdes = s; + /* XXX next line looks bogus w.r.t. AF_INET6 support */ + (*new)->remote_addr->salen = sizeof((*new)->remote_addr->sa); + memcpy (&(*new)->remote_addr->sa, &sa, salen); + (*new)->remote_addr_unknown = 0; - (*new)->addr_len = sizeof(struct sockaddr_in); + *(*new)->local_addr = *sock->local_addr; - (*new)->sock = accept(sock->sock, (struct sockaddr *)(*new)->local_addr, - &(*new)->addr_len); + /* The above assignment just overwrote the pool entry. Setting the local_addr + pool for the accepted socket back to what it should be. Otherwise all + allocations for this socket will come from a server pool that is not + freed until the process goes down.*/ + (*new)->local_addr->pool = p; - if ((*new)->sock == INVALID_SOCKET) { - return WSAGetLastError(); + /* fix up any pointers which are no longer valid */ + if (sock->local_addr->sa.sin.sin_family == AF_INET) { + (*new)->local_addr->ipaddr_ptr = &(*new)->local_addr->sa.sin.sin_addr; } - - ap_register_cleanup((*new)->cntxt, (void *)(*new), - socket_cleanup, ap_null_cleanup); +#if APR_HAVE_IPV6 + else if (sock->local_addr->sa.sin.sin_family == AF_INET6) { + (*new)->local_addr->ipaddr_ptr = &(*new)->local_addr->sa.sin6.sin6_addr; + } +#endif + (*new)->remote_addr->port = ntohs((*new)->remote_addr->sa.sin.sin_port); + if (sock->local_port_unknown) { + /* not likely for a listening socket, but theoretically possible :) */ + (*new)->local_port_unknown = 1; + } + +#if APR_TCP_NODELAY_INHERITED + if (apr_is_option_set(sock, APR_TCP_NODELAY) == 1) { + apr_set_option(*new, APR_TCP_NODELAY, 1); + } +#endif /* TCP_NODELAY_INHERITED */ +#if APR_O_NONBLOCK_INHERITED + if (apr_is_option_set(sock, APR_SO_NONBLOCK) == 1) { + apr_set_option(*new, APR_SO_NONBLOCK, 1); + } +#endif /* APR_O_NONBLOCK_INHERITED */ + + if (sock->local_interface_unknown || + !memcmp(sock->local_addr->ipaddr_ptr, + generic_inaddr_any, + sock->local_addr->ipaddr_len)) { + /* If the interface address inside the listening socket's local_addr wasn't + * up-to-date, we don't know local interface of the connected socket either. + * + * If the listening socket was not bound to a specific interface, we + * don't know the local_addr of the connected socket. + */ + (*new)->local_interface_unknown = 1; + } + + apr_pool_cleanup_register((*new)->pool, (void *)(*new), + socket_cleanup, apr_pool_cleanup_null); return APR_SUCCESS; } -ap_status_t ap_connect(ap_socket_t *sock, char *hostname) +static apr_status_t wait_for_connect(apr_socket_t *sock) { - struct hostent *hp; - int lasterror; - fd_set temp; + int rc; + struct timeval tv, *tvptr; + fd_set wfdset, efdset; - if ((sock->sock == INVALID_SOCKET) || (!sock->local_addr)) { - return APR_ENOTSOCK; - } + /* wait for the connect to complete or timeout */ + FD_ZERO(&wfdset); + FD_SET(sock->socketdes, &wfdset); + FD_ZERO(&efdset); + FD_SET(sock->socketdes, &efdset); - if (*hostname >= '0' && *hostname <= '9' && - strspn(hostname, "0123456789.") == strlen(hostname)) { - sock->remote_addr->sin_addr.s_addr = inet_addr(hostname); + if (sock->timeout < 0) { + tvptr = NULL; } else { - hp = gethostbyname(hostname); - if (!hp) { - return WSAGetLastError(); + /* casts for winsock/timeval definition */ + tv.tv_sec = (long)apr_time_sec(sock->timeout); + tv.tv_usec = (int)apr_time_usec(sock->timeout); + tvptr = &tv; + } + rc = select(FD_SETSIZE+1, NULL, &wfdset, &efdset, tvptr); + if (rc == SOCKET_ERROR) { + return apr_get_netos_error(); + } + else if (!rc) { + return APR_FROM_OS_ERROR(WSAETIMEDOUT); + } + /* Evaluate the efdset */ + if (FD_ISSET(sock->socketdes, &efdset)) { + /* The connect failed. */ + int rclen = sizeof(rc); + if (getsockopt(sock->socketdes, SOL_SOCKET, SO_ERROR, (char*) &rc, &rclen)) { + return apr_get_netos_error(); } - memcpy((char *)&sock->remote_addr->sin_addr, hp->h_addr_list[0], hp->h_length); - sock->addr_len = sizeof(*sock->remote_addr); + return APR_FROM_OS_ERROR(rc); } - - sock->remote_addr->sin_family = AF_INET; - if (connect(sock->sock, (const struct sockaddr *)sock->remote_addr, - sock->addr_len) == 0) { - return APR_SUCCESS; + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_socket_connect(apr_socket_t *sock, + apr_sockaddr_t *sa) +{ + apr_status_t rv; + + if ((sock->socketdes == INVALID_SOCKET) || (!sock->local_addr)) { + return APR_ENOTSOCK; + } + + if (connect(sock->socketdes, (const struct sockaddr *)&sa->sa.sin, + sa->salen) == SOCKET_ERROR) { + rv = apr_get_netos_error(); } else { - lasterror = WSAGetLastError(); - if (lasterror == WSAEWOULDBLOCK) { - FD_ZERO(&temp); - FD_SET(sock->sock, &temp); - if (select(sock->sock+1, NULL, &temp, NULL, NULL) == 1) { - return APR_SUCCESS; + rv = APR_SUCCESS; + } + + if (rv == APR_FROM_OS_ERROR(WSAEWOULDBLOCK)) { + if (sock->timeout == 0) { + /* Tell the app that the connect is in progress... + * Gotta play some games here. connect on Unix will return + * EINPROGRESS under the same circumstances that Windows + * returns WSAEWOULDBLOCK. Do some adhoc canonicalization... + */ + rv = APR_FROM_OS_ERROR(WSAEINPROGRESS); + } + else { + rv = wait_for_connect(sock); + if (rv != APR_SUCCESS) { + return rv; } } - return lasterror; } + + if (memcmp(sa->ipaddr_ptr, generic_inaddr_any, sa->ipaddr_len)) { + /* A real remote address was passed in. If the unspecified + * address was used, the actual remote addr will have to be + * determined using getpeername() if required. */ + sock->remote_addr_unknown = 0; + + /* Copy the address structure details in. */ + sock->remote_addr = sa; + } + + if (sock->local_addr->sa.sin.sin_port == 0) { + /* connect() got us an ephemeral port */ + sock->local_port_unknown = 1; + } + if (!memcmp(sock->local_addr->ipaddr_ptr, + generic_inaddr_any, + sock->local_addr->ipaddr_len)) { + /* not bound to specific local interface; connect() had to assign + * one for the socket + */ + sock->local_interface_unknown = 1; + } + + if (rv != APR_SUCCESS && rv != APR_FROM_OS_ERROR(WSAEISCONN)) { + return rv; + } + + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_socket_type_get(apr_socket_t *sock, int *type) +{ + *type = sock->type; + return APR_SUCCESS; } -ap_status_t ap_get_socketdata(void **data, char *key, ap_socket_t *socket) +APR_DECLARE(apr_status_t) apr_socket_data_get(void **data, const char *key, + apr_socket_t *sock) { - return ap_get_userdata(data, key, socket->cntxt); + sock_userdata_t *cur = sock->userdata; + + *data = NULL; + + while (cur) { + if (!strcmp(cur->key, key)) { + *data = cur->data; + break; + } + cur = cur->next; + } + + return APR_SUCCESS; } -ap_status_t ap_set_socketdata(ap_socket_t *socket, void *data, char *key, - ap_status_t (*cleanup) (void *)) +APR_DECLARE(apr_status_t) apr_socket_data_set(apr_socket_t *sock, void *data, + const char *key, + apr_status_t (*cleanup)(void *)) { - return ap_set_userdata(data, key, cleanup, socket->cntxt); + sock_userdata_t *new = apr_palloc(sock->pool, sizeof(sock_userdata_t)); + + new->key = apr_pstrdup(sock->pool, key); + new->data = data; + new->next = sock->userdata; + sock->userdata = new; + + if (cleanup) { + apr_pool_cleanup_register(sock->pool, data, cleanup, cleanup); + } + + return APR_SUCCESS; } -ap_status_t ap_get_os_sock(ap_os_sock_t *thesock, ap_socket_t *sock) +APR_DECLARE(apr_status_t) apr_os_sock_get(apr_os_sock_t *thesock, + apr_socket_t *sock) { - *thesock = sock->sock; + *thesock = sock->socketdes; return APR_SUCCESS; } -ap_status_t ap_put_os_sock(ap_socket_t **sock, ap_os_sock_t *thesock, - ap_pool_t *cont) +APR_DECLARE(apr_status_t) apr_os_sock_make(apr_socket_t **apr_sock, + apr_os_sock_info_t *os_sock_info, + apr_pool_t *cont) { - if (cont == NULL) { - return APR_ENOPOOL; + alloc_socket(apr_sock, cont); + set_socket_vars(*apr_sock, os_sock_info->family, os_sock_info->type, os_sock_info->protocol); + (*apr_sock)->timeout = -1; + (*apr_sock)->disconnected = 0; + (*apr_sock)->socketdes = *os_sock_info->os_sock; + if (os_sock_info->local) { + memcpy(&(*apr_sock)->local_addr->sa.sin, + os_sock_info->local, + (*apr_sock)->local_addr->salen); + (*apr_sock)->local_addr->pool = cont; + /* XXX IPv6 - this assumes sin_port and sin6_port at same offset */ + (*apr_sock)->local_addr->port = ntohs((*apr_sock)->local_addr->sa.sin.sin_port); } + else { + (*apr_sock)->local_port_unknown = (*apr_sock)->local_interface_unknown = 1; + } + if (os_sock_info->remote) { + memcpy(&(*apr_sock)->remote_addr->sa.sin, + os_sock_info->remote, + (*apr_sock)->remote_addr->salen); + (*apr_sock)->remote_addr->pool = cont; + /* XXX IPv6 - this assumes sin_port and sin6_port at same offset */ + (*apr_sock)->remote_addr->port = ntohs((*apr_sock)->remote_addr->sa.sin.sin_port); + (*apr_sock)->remote_addr_unknown = 0; + } + + apr_pool_cleanup_register((*apr_sock)->pool, (void *)(*apr_sock), + socket_cleanup, apr_pool_cleanup_null); + + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_os_sock_put(apr_socket_t **sock, + apr_os_sock_t *thesock, + apr_pool_t *cont) +{ if ((*sock) == NULL) { - (*sock) = (ap_socket_t *)ap_palloc(cont, sizeof(ap_socket_t)); - (*sock)->cntxt = cont; - (*sock)->local_addr = (struct sockaddr_in *)ap_palloc((*sock)->cntxt, - sizeof(struct sockaddr_in)); - (*sock)->remote_addr = (struct sockaddr_in *)ap_palloc((*sock)->cntxt, - sizeof(struct sockaddr_in)); - - if ((*sock)->local_addr == NULL || (*sock)->remote_addr == NULL) { - return APR_ENOMEM; - } - - (*sock)->addr_len = sizeof(*(*sock)->local_addr); + alloc_socket(sock, cont); + /* XXX figure out the actual socket type here */ + /* *or* just decide that apr_os_sock_put() has to be told the family and type */ + set_socket_vars(*sock, AF_INET, SOCK_STREAM, 0); (*sock)->timeout = -1; + (*sock)->disconnected = 0; } - (*sock)->sock = *thesock; + (*sock)->local_port_unknown = (*sock)->local_interface_unknown = 1; + (*sock)->remote_addr_unknown = 1; + (*sock)->socketdes = *thesock; return APR_SUCCESS; } + + +/* Sockets cannot be inherited through the standard sockets + * inheritence. WSADuplicateSocket must be used. + * This is not trivial to implement. + */ + +APR_DECLARE(apr_status_t) apr_socket_inherit_set(apr_socket_t *socket) +{ + return APR_ENOTIMPL; +} + +APR_DECLARE(apr_status_t) apr_socket_inherit_unset(apr_socket_t *socket) +{ + return APR_ENOTIMPL; +} + +APR_POOL_IMPLEMENT_ACCESSOR(socket); diff --git a/network_io/win32/sockopt.c b/network_io/win32/sockopt.c index d269b64e6a2..463eeebf55c 100644 --- a/network_io/win32/sockopt.c +++ b/network_io/win32/sockopt.c @@ -1,186 +1,302 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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 "networkio.h" +#include "apr_arch_networkio.h" +#include "apr_arch_misc.h" /* apr_os_level */ #include "apr_network_io.h" #include "apr_general.h" -#include "apr_lib.h" +#include "apr_strings.h" #include <string.h> -#include <winsock2.h> -ap_status_t soblock(SOCKET sd) +/* IPV6_V6ONLY is missing from pre-Windows 2008 SDK as well as MinGW + * (at least up through 1.0.16). + * Runtime support is a separate issue. + */ +#ifndef IPV6_V6ONLY +#define IPV6_V6ONLY 27 +#endif + +static apr_status_t soblock(SOCKET sd) { - int one = 1; + u_long zero = 0; - if (ioctlsocket(sd, FIONBIO, &one) == SOCKET_ERROR) { - return APR_EEXIST; + if (ioctlsocket(sd, FIONBIO, &zero) == SOCKET_ERROR) { + return apr_get_netos_error(); } return APR_SUCCESS; } -ap_status_t sononblock(SOCKET sd) +static apr_status_t sononblock(SOCKET sd) { - int zero = 0; + u_long one = 1; - if (ioctlsocket(sd, FIONBIO, &zero) == SOCKET_ERROR) { - return APR_EEXIST; + if (ioctlsocket(sd, FIONBIO, &one) == SOCKET_ERROR) { + return apr_get_netos_error(); } return APR_SUCCESS; } -ap_status_t ap_setsocketopt(ap_socket_t *sock, ap_int32_t opt, ap_int32_t on) + +APR_DECLARE(apr_status_t) apr_socket_timeout_set(apr_socket_t *sock, apr_interval_time_t t) { - int one; - struct linger li; - ap_status_t stat; - - if (on) - one = 1; - else - one = 0; - - if (opt & APR_SO_TIMEOUT) { - int timeout; - sock->timeout = on; - timeout = on / 1000; /* Windows needs timeout in mSeconds */ - if (setsockopt(sock->sock, SOL_SOCKET, SO_RCVTIMEO, (char*) &timeout, - sizeof(timeout)) == SOCKET_ERROR) { - return WSAGetLastError(); - } - } - if (opt & APR_SO_KEEPALIVE) { - if (setsockopt(sock->sock, SOL_SOCKET, SO_KEEPALIVE, (void *)&one, sizeof(int)) == -1) { - return WSAGetLastError(); - } - } - if (opt & APR_SO_DEBUG) { - if (setsockopt(sock->sock, SOL_SOCKET, SO_DEBUG, (void *)&one, sizeof(int)) == -1) { - return WSAGetLastError(); - } - } - if (opt & APR_SO_REUSEADDR) { - if (setsockopt(sock->sock, SOL_SOCKET, SO_REUSEADDR, (void *)&one, sizeof(int)) == -1) { - return WSAGetLastError(); + apr_status_t stat; + + if (t == 0) { + /* Set the socket non-blocking if it was previously blocking */ + if (sock->timeout != 0) { + if ((stat = sononblock(sock->socketdes)) != APR_SUCCESS) + return stat; } } - if (opt & APR_SO_NONBLOCK) { - if (on) { - if ((stat = soblock(sock->sock)) != APR_SUCCESS) + else if (t > 0) { + /* Set the socket to blocking if it was previously non-blocking */ + if (sock->timeout == 0 || apr_is_option_set(sock, APR_SO_NONBLOCK)) { + if ((stat = soblock(sock->socketdes)) != APR_SUCCESS) return stat; + apr_set_option(sock, APR_SO_NONBLOCK, 0); } - else { - if ((stat = sononblock(sock->sock)) != APR_SUCCESS) - return stat; + /* Reset socket timeouts if the new timeout differs from the old timeout */ + if (sock->timeout != t) + { + /* Win32 timeouts are in msec, represented as int */ + sock->timeout_ms = (int)apr_time_as_msec(t); + setsockopt(sock->socketdes, SOL_SOCKET, SO_RCVTIMEO, + (char *) &sock->timeout_ms, + sizeof(sock->timeout_ms)); + setsockopt(sock->socketdes, SOL_SOCKET, SO_SNDTIMEO, + (char *) &sock->timeout_ms, + sizeof(sock->timeout_ms)); } } - if (opt & APR_SO_LINGER) { - li.l_onoff = on; - li.l_linger = MAX_SECS_TO_LINGER; - if (setsockopt(sock->sock, SOL_SOCKET, SO_LINGER, (char *) &li, sizeof(struct linger)) == -1) { - return APR_EEXIST; - } + else if (t < 0) { + int zero = 0; + /* Set the socket to blocking with infinite timeouts */ + if ((stat = soblock(sock->socketdes)) != APR_SUCCESS) + return stat; + setsockopt(sock->socketdes, SOL_SOCKET, SO_RCVTIMEO, + (char *) &zero, sizeof(zero)); + setsockopt(sock->socketdes, SOL_SOCKET, SO_SNDTIMEO, + (char *) &zero, sizeof(zero)); } + sock->timeout = t; return APR_SUCCESS; } -ap_status_t ap_gethostname(char *buf, int len, ap_pool_t *cont) -{ - if (gethostname(buf, len) == -1) - return APR_EEXIST; - else - return APR_SUCCESS; -} -ap_status_t ap_get_remote_hostname(char **name, ap_socket_t *sock) +APR_DECLARE(apr_status_t) apr_socket_opt_set(apr_socket_t *sock, + apr_int32_t opt, apr_int32_t on) { - struct hostent *hptr; + int one; + apr_status_t stat; - hptr = gethostbyaddr((char *)&(sock->local_addr->sin_addr), - sizeof(struct in_addr), AF_INET); + one = on ? 1 : 0; - if (hptr != NULL) { - *name = ap_pstrdup(sock->cntxt, hptr->h_name); - if (*name) { - return APR_SUCCESS; + switch (opt) { + case APR_SO_KEEPALIVE: + if (on != apr_is_option_set(sock, APR_SO_KEEPALIVE)) { + if (setsockopt(sock->socketdes, SOL_SOCKET, SO_KEEPALIVE, + (void *)&one, sizeof(int)) == -1) { + return apr_get_netos_error(); + } + apr_set_option(sock, APR_SO_KEEPALIVE, on); } - return APR_ENOMEM; + break; + case APR_SO_DEBUG: + if (on != apr_is_option_set(sock, APR_SO_DEBUG)) { + if (setsockopt(sock->socketdes, SOL_SOCKET, SO_DEBUG, + (void *)&one, sizeof(int)) == -1) { + return apr_get_netos_error(); + } + apr_set_option(sock, APR_SO_DEBUG, on); + } + break; + case APR_SO_SNDBUF: + if (setsockopt(sock->socketdes, SOL_SOCKET, SO_SNDBUF, + (void *)&on, sizeof(int)) == -1) { + return apr_get_netos_error(); + } + break; + case APR_SO_RCVBUF: + if (setsockopt(sock->socketdes, SOL_SOCKET, SO_RCVBUF, + (void *)&on, sizeof(int)) == -1) { + return apr_get_netos_error(); + } + break; + case APR_SO_BROADCAST: + if (on != apr_is_option_set(sock, APR_SO_BROADCAST)) { + if (setsockopt(sock->socketdes, SOL_SOCKET, SO_BROADCAST, + (void *)&one, sizeof(int)) == -1) { + return apr_get_netos_error(); + } + apr_set_option(sock, APR_SO_BROADCAST, on); + } + break; + case APR_SO_REUSEADDR: + if (on != apr_is_option_set(sock, APR_SO_REUSEADDR)) { + if (setsockopt(sock->socketdes, SOL_SOCKET, SO_REUSEADDR, + (void *)&one, sizeof(int)) == -1) { + return apr_get_netos_error(); + } + apr_set_option(sock, APR_SO_REUSEADDR, on); + } + break; + case APR_SO_NONBLOCK: + if (apr_is_option_set(sock, APR_SO_NONBLOCK) != on) { + if (on) { + if ((stat = sononblock(sock->socketdes)) != APR_SUCCESS) + return stat; + } + else { + if ((stat = soblock(sock->socketdes)) != APR_SUCCESS) + return stat; + } + apr_set_option(sock, APR_SO_NONBLOCK, on); + } + break; + case APR_SO_LINGER: + { + if (apr_is_option_set(sock, APR_SO_LINGER) != on) { + struct linger li; + li.l_onoff = on; + li.l_linger = APR_MAX_SECS_TO_LINGER; + if (setsockopt(sock->socketdes, SOL_SOCKET, SO_LINGER, + (char *) &li, sizeof(struct linger)) == -1) { + return apr_get_netos_error(); + } + apr_set_option(sock, APR_SO_LINGER, on); + } + break; } + case APR_TCP_DEFER_ACCEPT: +#if defined(TCP_DEFER_ACCEPT) + if (apr_is_option_set(sock, APR_TCP_DEFER_ACCEPT) != on) { + int optlevel = IPPROTO_TCP; + int optname = TCP_DEFER_ACCEPT; - return (WSAGetLastError() + APR_OS_START_SYSERR); -} -#if 0 -ap_status_t status_from_res_error(int reserr) -{ - ap_status_t status; - switch(reserr) { - case WSAHOST_NOT_FOUND: - status = APR_EHOSTNOTFOUND; + if (setsockopt(sock->socketdes, optlevel, optname, + (void *)&on, sizeof(int)) == -1) { + return apr_get_netos_error(); + } + apr_set_option(sock, APR_TCP_DEFER_ACCEPT, on); + } +#else + return APR_ENOTIMPL; +#endif + case APR_TCP_NODELAY: + if (apr_is_option_set(sock, APR_TCP_NODELAY) != on) { + int optlevel = IPPROTO_TCP; + int optname = TCP_NODELAY; + +#if APR_HAVE_SCTP + if (sock->protocol == IPPROTO_SCTP) { + optlevel = IPPROTO_SCTP; + optname = SCTP_NODELAY; + } +#endif + if (setsockopt(sock->socketdes, optlevel, optname, + (void *)&on, sizeof(int)) == -1) { + return apr_get_netos_error(); + } + apr_set_option(sock, APR_TCP_NODELAY, on); + } break; - case WSATRY_AGAIN: - status = APR_EAGAIN; + case APR_IPV6_V6ONLY: +#if APR_HAVE_IPV6 + if (apr_os_level < APR_WIN_VISTA && + sock->local_addr->family == AF_INET6) { + /* apr_set_option() called at socket creation */ + if (on) { + return APR_SUCCESS; + } + else { + return APR_ENOTIMPL; + } + } + /* we don't know the initial setting of this option, + * so don't check sock->options since that optimization + * won't work + */ + if (setsockopt(sock->socketdes, IPPROTO_IPV6, IPV6_V6ONLY, + (void *)&on, sizeof(int)) == -1) { + return apr_get_netos_error(); + } + apr_set_option(sock, APR_IPV6_V6ONLY, on); +#else + return APR_ENOTIMPL; +#endif break; - case WSANO_RECOVERY: - status = APR_ENORECOVERY; + default: + return APR_EINVAL; break; - case WSANO_DATA: - status = APR_ENODATA; + } + return APR_SUCCESS; +} + + +APR_DECLARE(apr_status_t) apr_socket_timeout_get(apr_socket_t *sock, apr_interval_time_t *t) +{ + *t = sock->timeout; + return APR_SUCCESS; +} + + +APR_DECLARE(apr_status_t) apr_socket_opt_get(apr_socket_t *sock, + apr_int32_t opt, apr_int32_t *on) +{ + switch (opt) { + case APR_SO_DISCONNECTED: + *on = sock->disconnected; break; + case APR_SO_KEEPALIVE: + case APR_SO_DEBUG: + case APR_SO_REUSEADDR: + case APR_SO_NONBLOCK: + case APR_SO_LINGER: default: - status = APR_ENORECOVERY; + *on = apr_is_option_set(sock, opt); + break; } - return status; + return APR_SUCCESS; } -#endif +APR_DECLARE(apr_status_t) apr_socket_atmark(apr_socket_t *sock, int *atmark) +{ + u_long oobmark; + + if (ioctlsocket(sock->socketdes, SIOCATMARK, (void*) &oobmark) < 0) + return apr_get_netos_error(); + + *atmark = (oobmark != 0); + + return APR_SUCCESS; +} + + +APR_DECLARE(apr_status_t) apr_gethostname(char *buf, int len, + apr_pool_t *cont) +{ + if (gethostname(buf, len) == -1) { + buf[0] = '\0'; + return apr_get_netos_error(); + } + else if (!memchr(buf, '\0', len)) { /* buffer too small */ + buf[0] = '\0'; + return APR_ENAMETOOLONG; + } + return APR_SUCCESS; +} + diff --git a/passwd/apr_getpass.c b/passwd/apr_getpass.c new file mode 100644 index 00000000000..6e4cbef3af8 --- /dev/null +++ b/passwd/apr_getpass.c @@ -0,0 +1,256 @@ +/* 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. + */ + +/* apr_password_get.c: abstraction to provide for obtaining a password from the + * command line in whatever way the OS supports. In the best case, it's a + * wrapper for the system library's getpass() routine; otherwise, we + * use one we define ourselves. + */ +#include "apr_private.h" +#include "apr_strings.h" +#include "apr_lib.h" +#include "apr_errno.h" +#if APR_HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#if APR_HAVE_ERRNO_H +#include <errno.h> +#endif + +#if APR_HAVE_UNISTD_H +#include <unistd.h> +#endif +#if APR_HAVE_CONIO_H +#ifdef _MSC_VER +#pragma warning(disable: 4032) +#include <conio.h> +#pragma warning(default: 4032) +#else +#include <conio.h> +#endif +#endif +#if APR_HAVE_STDLIB_H +#include <stdlib.h> +#endif +#if APR_HAVE_STRING_H +#include <string.h> +#endif +#if APR_HAVE_STRINGS_H +#include <strings.h> +#endif +#if APR_HAVE_STDIO_H +#include <stdio.h> +#endif + +/* Disable getpass() support when PASS_MAX is defined and is "small", + * for an arbitrary definition of "small". + * HP-UX truncates passwords (PR49496) so we disable getpass() for + * this platform too. + */ +#if defined(HAVE_GETPASS) && \ + (defined(PASS_MAX) && PASS_MAX < 32) || defined(__hpux) || defined(__hpux__) +#undef HAVE_GETPASS +#endif + +#if defined(HAVE_TERMIOS_H) && !defined(HAVE_GETPASS) +#include <termios.h> +#endif + +#if !APR_CHARSET_EBCDIC +#define LF 10 +#define CR 13 +#else /* APR_CHARSET_EBCDIC */ +#define LF '\n' +#define CR '\r' +#endif /* APR_CHARSET_EBCDIC */ + +#define MAX_STRING_LEN 256 + +#define ERR_OVERFLOW 5 + +#if !defined(HAVE_GETPASS) && !defined(HAVE_GETPASSPHRASE) && !defined(HAVE_GETPASS_R) + +/* MPE, Win32, and BeOS all lack a native getpass() */ + +#if !defined(HAVE_TERMIOS_H) && !defined(WIN32) +/* + * MPE lacks getpass() and a way to suppress stdin echo. So for now, just + * issue the prompt and read the results with echo. (Ugh). + */ + +static char *get_password(const char *prompt) +{ + static char password[MAX_STRING_LEN]; + + fputs(prompt, stderr); + fgets((char *) &password, sizeof(password), stdin); + + return (char *) &password; +} + +#elif defined(WIN32) + +/* + * Windows lacks getpass(). So we'll re-implement it here. + */ + +static char *get_password(const char *prompt) +{ +/* WCE lacks console. So the getpass is unsuported + * The only way is to use the GUI so the getpass should be implemented + * on per-application basis. + */ +#ifdef _WIN32_WCE + return NULL; +#else + static char password[128]; + int n = 0; + int ch; + + fputs(prompt, stderr); + + while ((ch = _getch()) != '\r') { + if (ch == EOF) /* EOF */ { + fputs("[EOF]\n", stderr); + return NULL; + } + else if (ch == 0 || ch == 0xE0) { + /* FN Keys (0 or E0) are a sentinal for a FN code */ + ch = (ch << 4) | _getch(); + /* Catch {DELETE}, {<--}, Num{DEL} and Num{<--} */ + if ((ch == 0xE53 || ch == 0xE4B || ch == 0x053 || ch == 0x04b) && n) { + password[--n] = '\0'; + fputs("\b \b", stderr); + } + else { + fputc('\a', stderr); + } + } + else if ((ch == '\b' || ch == 127) && n) /* BS/DEL */ { + password[--n] = '\0'; + fputs("\b \b", stderr); + } + else if (ch == 3) /* CTRL+C */ { + /* _getch() bypasses Ctrl+C but not Ctrl+Break detection! */ + fputs("^C\n", stderr); + exit(-1); + } + else if (ch == 26) /* CTRL+Z */ { + fputs("^Z\n", stderr); + return NULL; + } + else if (ch == 27) /* ESC */ { + fputc('\n', stderr); + fputs(prompt, stderr); + n = 0; + } + else if ((n < sizeof(password) - 1) && !apr_iscntrl(ch)) { + password[n++] = ch; + fputc('*', stderr); + } + else { + fputc('\a', stderr); + } + } + + fputc('\n', stderr); + password[n] = '\0'; + return password; +#endif +} + +#elif defined (HAVE_TERMIOS_H) + +static char *get_password(const char *prompt) +{ + struct termios attr; + static char password[MAX_STRING_LEN]; + int n=0; + fputs(prompt, stderr); + fflush(stderr); + + if (tcgetattr(STDIN_FILENO, &attr) != 0) + return NULL; + attr.c_lflag &= ~(ECHO); + + if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &attr) != 0) + return NULL; + while ((password[n] = getchar()) != '\n') { + if (n < sizeof(password) - 1 && password[n] >= ' ' && password[n] <= '~') { + n++; + } else { + fprintf(stderr,"\n"); + fputs(prompt, stderr); + fflush(stderr); + n = 0; + } + } + + password[n] = '\0'; + printf("\n"); + if (n > (MAX_STRING_LEN - 1)) { + password[MAX_STRING_LEN - 1] = '\0'; + } + + attr.c_lflag |= ECHO; + tcsetattr(STDIN_FILENO, TCSANOW, &attr); + return (char*) &password; +} + +#endif /* no getchar or _getch */ + +#endif /* no getpass or getpassphrase or getpass_r */ + +/* + * Use the OS getpass() routine (or our own) to obtain a password from + * the input stream. + * + * Exit values: + * 0: Success + * 5: Partial success; entered text truncated to the size of the + * destination buffer + * + * Restrictions: Truncation also occurs according to the host system's + * getpass() semantics, or at position 255 if our own version is used, + * but the caller is *not* made aware of it unless their own buffer is + * smaller than our own. + */ + +APR_DECLARE(apr_status_t) apr_password_get(const char *prompt, char *pwbuf, apr_size_t *bufsiz) +{ + apr_status_t rv = APR_SUCCESS; +#if defined(HAVE_GETPASS_R) + if (getpass_r(prompt, pwbuf, *bufsiz) == NULL) + return APR_EINVAL; +#else +#if defined(HAVE_GETPASSPHRASE) + char *pw_got = getpassphrase(prompt); +#elif defined(HAVE_GETPASS) + char *pw_got = getpass(prompt); +#else /* use the replacement implementation above */ + char *pw_got = get_password(prompt); +#endif + + if (!pw_got) + return APR_EINVAL; + if (strlen(pw_got) >= *bufsiz) { + rv = APR_ENAMETOOLONG; + } + apr_cpystrn(pwbuf, pw_got, *bufsiz); + memset(pw_got, 0, strlen(pw_got)); +#endif /* HAVE_GETPASS_R */ + return rv; +} diff --git a/poll/os2/poll.c b/poll/os2/poll.c new file mode 100644 index 00000000000..3c36e5e688e --- /dev/null +++ b/poll/os2/poll.c @@ -0,0 +1,105 @@ +/* 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_poll.h" +#include "apr_arch_networkio.h" + +APR_DECLARE(apr_status_t) apr_poll(apr_pollfd_t *aprset, apr_int32_t num, + apr_int32_t *nsds, apr_interval_time_t timeout) +{ + int *pollset; + int i; + int num_read = 0, num_write = 0, num_except = 0, num_total; + int pos_read, pos_write, pos_except; + + for (i = 0; i < num; i++) { + if (aprset[i].desc_type == APR_POLL_SOCKET) { + num_read += (aprset[i].reqevents & APR_POLLIN) != 0; + num_write += (aprset[i].reqevents & APR_POLLOUT) != 0; + num_except += (aprset[i].reqevents & APR_POLLPRI) != 0; + } + } + + num_total = num_read + num_write + num_except; + pollset = alloca(sizeof(int) * num_total); + memset(pollset, 0, sizeof(int) * num_total); + + pos_read = 0; + pos_write = num_read; + pos_except = pos_write + num_write; + + for (i = 0; i < num; i++) { + if (aprset[i].desc_type == APR_POLL_SOCKET) { + if (aprset[i].reqevents & APR_POLLIN) { + pollset[pos_read++] = aprset[i].desc.s->socketdes; + } + + if (aprset[i].reqevents & APR_POLLOUT) { + pollset[pos_write++] = aprset[i].desc.s->socketdes; + } + + if (aprset[i].reqevents & APR_POLLPRI) { + pollset[pos_except++] = aprset[i].desc.s->socketdes; + } + + aprset[i].rtnevents = 0; + } + } + + if (timeout > 0) { + timeout /= 1000; /* convert microseconds to milliseconds */ + } + + i = select(pollset, num_read, num_write, num_except, timeout); + (*nsds) = i; + + if ((*nsds) < 0) { + return APR_FROM_OS_ERROR(sock_errno()); + } + + if ((*nsds) == 0) { + return APR_TIMEUP; + } + + pos_read = 0; + pos_write = num_read; + pos_except = pos_write + num_write; + + for (i = 0; i < num; i++) { + if (aprset[i].desc_type == APR_POLL_SOCKET) { + if (aprset[i].reqevents & APR_POLLIN) { + if (pollset[pos_read++] > 0) { + aprset[i].rtnevents |= APR_POLLIN; + } + } + + if (aprset[i].reqevents & APR_POLLOUT) { + if (pollset[pos_write++] > 0) { + aprset[i].rtnevents |= APR_POLLOUT; + } + } + + if (aprset[i].reqevents & APR_POLLPRI) { + if (pollset[pos_except++] > 0) { + aprset[i].rtnevents |= APR_POLLPRI; + } + } + } + } + + return APR_SUCCESS; +} diff --git a/poll/os2/pollcb.c b/poll/os2/pollcb.c new file mode 100644 index 00000000000..63b33cb169f --- /dev/null +++ b/poll/os2/pollcb.c @@ -0,0 +1,96 @@ +/* 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_poll.h" + +struct apr_pollcb_t { + apr_pool_t *pool; + apr_pollset_t *pollset; +}; + + + +APR_DECLARE(apr_status_t) apr_pollcb_create(apr_pollcb_t **pollcb, + apr_uint32_t size, + apr_pool_t *p, + apr_uint32_t flags) +{ + return apr_pollcb_create_ex(pollcb, size, p, flags, APR_POLLSET_DEFAULT); +} + + + +APR_DECLARE(apr_status_t) apr_pollcb_create_ex(apr_pollcb_t **ret_pollcb, + apr_uint32_t size, + apr_pool_t *p, + apr_uint32_t flags, + apr_pollset_method_e method) +{ + apr_pollcb_t *pollcb = apr_palloc(p, sizeof(apr_pollcb_t)); + pollcb->pool = p; + *ret_pollcb = pollcb; + return apr_pollset_create_ex(&pollcb->pollset, size, p, flags, method); +} + + + +APR_DECLARE(apr_status_t) apr_pollcb_add(apr_pollcb_t *pollcb, + apr_pollfd_t *descriptor) +{ + return apr_pollset_add(pollcb->pollset, descriptor); +} + + + +APR_DECLARE(apr_status_t) apr_pollcb_remove(apr_pollcb_t *pollcb, + apr_pollfd_t *descriptor) +{ + return apr_pollset_remove(pollcb->pollset, descriptor); +} + + + +APR_DECLARE(apr_status_t) apr_pollcb_poll(apr_pollcb_t *pollcb, + apr_interval_time_t timeout, + apr_pollcb_cb_t func, + void *baton) +{ + int c; + int num_signaled = 0; + const apr_pollfd_t *signalled_descriptors; + apr_status_t rc = apr_pollset_poll(pollcb->pollset, timeout, &num_signaled, &signalled_descriptors); + + for (c = 0; rc == APR_SUCCESS && c < num_signaled; c++) { + rc = func(baton, signalled_descriptors + c); + } + + return rc; +} + + + +APR_DECLARE(const char *) apr_pollcb_method_name(apr_pollcb_t *pollcb) +{ + return "poll"; +} + + + +APR_DECLARE(apr_status_t) apr_pollcb_wakeup(apr_pollcb_t *pollcb) +{ + return apr_pollset_wakeup(pollcb->pollset); +} diff --git a/poll/os2/pollset.c b/poll/os2/pollset.c new file mode 100644 index 00000000000..2ec848105be --- /dev/null +++ b/poll/os2/pollset.c @@ -0,0 +1,321 @@ +/* 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_poll.h" +#include "apr_arch_networkio.h" + +#ifndef MSG_DONTWAIT +#define MSG_DONTWAIT 0x100 +#endif + +struct apr_pollset_t { + apr_pool_t *pool; + apr_uint32_t nelts; + apr_uint32_t nalloc; + int *pollset; + int num_read; + int num_write; + int num_except; + int num_total; + apr_pollfd_t *query_set; + apr_pollfd_t *result_set; + apr_socket_t *wake_listen; + apr_socket_t *wake_sender; + apr_sockaddr_t *wake_address; +}; + + + +APR_DECLARE(apr_status_t) apr_pollset_create(apr_pollset_t **pollset, + apr_uint32_t size, + apr_pool_t *p, + apr_uint32_t flags) +{ + apr_status_t rc = APR_SUCCESS; + + if (flags & APR_POLLSET_WAKEABLE) { + size++; + } + + *pollset = apr_palloc(p, sizeof(**pollset)); + (*pollset)->pool = p; + (*pollset)->nelts = 0; + (*pollset)->nalloc = size; + (*pollset)->pollset = apr_palloc(p, size * sizeof(int) * 3); + (*pollset)->query_set = apr_palloc(p, size * sizeof(apr_pollfd_t)); + (*pollset)->result_set = apr_palloc(p, size * sizeof(apr_pollfd_t)); + (*pollset)->num_read = -1; + (*pollset)->wake_listen = NULL; + (*pollset)->wake_sender = NULL; + + if (flags & APR_POLLSET_WAKEABLE) { + rc = apr_socket_create(&(*pollset)->wake_listen, APR_UNIX, SOCK_DGRAM, 0, p); + + if (rc == APR_SUCCESS) { + apr_sockaddr_t *listen_address; + apr_socket_timeout_set((*pollset)->wake_listen, 0); + apr_sockaddr_info_get(&listen_address, "", APR_UNIX, 0, 0, p); + rc = apr_socket_bind((*pollset)->wake_listen, listen_address); + + if (rc == APR_SUCCESS) { + apr_pollfd_t wake_poll_fd; + wake_poll_fd.p = p; + wake_poll_fd.desc_type = APR_POLL_SOCKET; + wake_poll_fd.reqevents = APR_POLLIN; + wake_poll_fd.desc.s = (*pollset)->wake_listen; + wake_poll_fd.client_data = NULL; + apr_pollset_add(*pollset, &wake_poll_fd); + apr_socket_addr_get(&(*pollset)->wake_address, APR_LOCAL, (*pollset)->wake_listen); + + rc = apr_socket_create(&(*pollset)->wake_sender, APR_UNIX, SOCK_DGRAM, 0, p); + } + } + } + + return rc; +} + +APR_DECLARE(apr_status_t) apr_pollset_create_ex(apr_pollset_t **pollset, + apr_uint32_t size, + apr_pool_t *p, + apr_uint32_t flags, + apr_pollset_method_e method) +{ + /* Only one method is supported */ + if (flags & APR_POLLSET_NODEFAULT) { + if (method != APR_POLLSET_DEFAULT && method != APR_POLLSET_POLL) { + return APR_ENOTIMPL; + } + } + + return apr_pollset_create(pollset, size, p, flags); +} + +APR_DECLARE(apr_status_t) apr_pollset_destroy(apr_pollset_t *pollset) +{ + /* A no-op function for now. If we later implement /dev/poll + * support, we'll need to close the /dev/poll fd here + */ + return APR_SUCCESS; +} + + + +APR_DECLARE(apr_status_t) apr_pollset_add(apr_pollset_t *pollset, + const apr_pollfd_t *descriptor) +{ + if (pollset->nelts == pollset->nalloc) { + return APR_ENOMEM; + } + + pollset->query_set[pollset->nelts] = *descriptor; + + if (descriptor->desc_type != APR_POLL_SOCKET) { + return APR_EBADF; + } + + pollset->nelts++; + pollset->num_read = -1; + return APR_SUCCESS; +} + + + +APR_DECLARE(apr_status_t) apr_pollset_remove(apr_pollset_t *pollset, + const apr_pollfd_t *descriptor) +{ + apr_uint32_t i; + + for (i = 0; i < pollset->nelts; i++) { + if (descriptor->desc.s == pollset->query_set[i].desc.s) { + /* Found an instance of the fd: remove this and any other copies */ + apr_uint32_t dst = i; + apr_uint32_t old_nelts = pollset->nelts; + pollset->nelts--; + + for (i++; i < old_nelts; i++) { + if (descriptor->desc.s == pollset->query_set[i].desc.s) { + pollset->nelts--; + } + else { + pollset->pollset[dst] = pollset->pollset[i]; + pollset->query_set[dst] = pollset->query_set[i]; + dst++; + } + } + + pollset->num_read = -1; + return APR_SUCCESS; + } + } + + return APR_NOTFOUND; +} + + + +static void make_pollset(apr_pollset_t *pollset) +{ + int i; + int pos = 0; + + pollset->num_read = 0; + pollset->num_write = 0; + pollset->num_except = 0; + + for (i = 0; i < pollset->nelts; i++) { + if (pollset->query_set[i].reqevents & APR_POLLIN) { + pollset->pollset[pos++] = pollset->query_set[i].desc.s->socketdes; + pollset->num_read++; + } + } + + for (i = 0; i < pollset->nelts; i++) { + if (pollset->query_set[i].reqevents & APR_POLLOUT) { + pollset->pollset[pos++] = pollset->query_set[i].desc.s->socketdes; + pollset->num_write++; + } + } + + for (i = 0; i < pollset->nelts; i++) { + if (pollset->query_set[i].reqevents & APR_POLLPRI) { + pollset->pollset[pos++] = pollset->query_set[i].desc.s->socketdes; + pollset->num_except++; + } + } + + pollset->num_total = pollset->num_read + pollset->num_write + pollset->num_except; +} + + + +APR_DECLARE(apr_status_t) apr_pollset_poll(apr_pollset_t *pollset, + apr_interval_time_t timeout, + apr_int32_t *num, + const apr_pollfd_t **descriptors) +{ + int rv; + apr_uint32_t i; + int *pollresult; + int read_pos, write_pos, except_pos; + apr_status_t rc = APR_SUCCESS; + + if (pollset->num_read < 0) { + make_pollset(pollset); + } + + pollresult = alloca(sizeof(int) * pollset->num_total); + memcpy(pollresult, pollset->pollset, sizeof(int) * pollset->num_total); + (*num) = 0; + + if (timeout > 0) { + timeout /= 1000; + } + + rv = select(pollresult, pollset->num_read, pollset->num_write, pollset->num_except, timeout); + + if (rv < 0) { + return APR_FROM_OS_ERROR(sock_errno()); + } + + if (rv == 0) { + return APR_TIMEUP; + } + + read_pos = 0; + write_pos = pollset->num_read; + except_pos = pollset->num_read + pollset->num_write; + + for (i = 0; i < pollset->nelts; i++) { + int rtnevents = 0; + + if (pollset->query_set[i].reqevents & APR_POLLIN) { + if (pollresult[read_pos++] != -1) { + rtnevents |= APR_POLLIN; + } + } + + if (pollset->query_set[i].reqevents & APR_POLLOUT) { + if (pollresult[write_pos++] != -1) { + rtnevents |= APR_POLLOUT; + } + } + + if (pollset->query_set[i].reqevents & APR_POLLPRI) { + if (pollresult[except_pos++] != -1) { + rtnevents |= APR_POLLPRI; + } + } + + if (rtnevents) { + if (i == 0 && pollset->wake_listen != NULL) { + struct apr_sockaddr_t from_addr; + char buffer[16]; + apr_size_t buflen; + for (;;) { + buflen = sizeof(buffer); + rv = apr_socket_recvfrom(&from_addr, pollset->wake_listen, + MSG_DONTWAIT, buffer, &buflen); + if (rv != APR_SUCCESS) { + break; + } + /* Woken up, drain the pipe still. */ + rc = APR_EINTR; + } + } + else { + pollset->result_set[*num] = pollset->query_set[i]; + pollset->result_set[*num].rtnevents = rtnevents; + /* Event(s) besides wakeup pipe. */ + rc = APR_SUCCESS; + (*num)++; + } + } + } + + if (descriptors) { + *descriptors = pollset->result_set; + } + + return rc; +} + + + +APR_DECLARE(apr_status_t) apr_pollset_wakeup(apr_pollset_t *pollset) +{ + if (pollset->wake_sender) { + apr_size_t len = 1; + return apr_socket_sendto(pollset->wake_sender, pollset->wake_address, 0, "", &len); + } + + return APR_EINIT; +} + + + +APR_DECLARE(const char *) apr_poll_method_defname() +{ + return "select"; +} + + + +APR_DECLARE(const char *) apr_pollset_method_name(apr_pollset_t *pollset) +{ + return "select"; +} diff --git a/poll/unix/epoll.c b/poll/unix/epoll.c new file mode 100644 index 00000000000..4ab03f67ccc --- /dev/null +++ b/poll/unix/epoll.c @@ -0,0 +1,490 @@ +/* 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_poll.h" +#include "apr_time.h" +#include "apr_portable.h" +#include "apr_arch_file_io.h" +#include "apr_arch_networkio.h" +#include "apr_arch_poll_private.h" +#include "apr_arch_inherit.h" + +#if defined(HAVE_EPOLL) + +static apr_int16_t get_epoll_event(apr_int16_t event) +{ + apr_int16_t rv = 0; + + if (event & APR_POLLIN) + rv |= EPOLLIN; + if (event & APR_POLLPRI) + rv |= EPOLLPRI; + if (event & APR_POLLOUT) + rv |= EPOLLOUT; + /* APR_POLLNVAL is not handled by epoll. EPOLLERR and EPOLLHUP are return-only */ + + return rv; +} + +static apr_int16_t get_epoll_revent(apr_int16_t event) +{ + apr_int16_t rv = 0; + + if (event & EPOLLIN) + rv |= APR_POLLIN; + if (event & EPOLLPRI) + rv |= APR_POLLPRI; + if (event & EPOLLOUT) + rv |= APR_POLLOUT; + if (event & EPOLLERR) + rv |= APR_POLLERR; + if (event & EPOLLHUP) + rv |= APR_POLLHUP; + /* APR_POLLNVAL is not handled by epoll. */ + + return rv; +} + +struct apr_pollset_private_t +{ + int epoll_fd; + struct epoll_event *pollset; + apr_pollfd_t *result_set; +#if APR_HAS_THREADS + /* A thread mutex to protect operations on the rings */ + apr_thread_mutex_t *ring_lock; +#endif + /* A ring containing all of the pollfd_t that are active */ + APR_RING_HEAD(pfd_query_ring_t, pfd_elem_t) query_ring; + /* A ring of pollfd_t that have been used, and then _remove()'d */ + APR_RING_HEAD(pfd_free_ring_t, pfd_elem_t) free_ring; + /* A ring of pollfd_t where rings that have been _remove()`ed but + might still be inside a _poll() */ + APR_RING_HEAD(pfd_dead_ring_t, pfd_elem_t) dead_ring; +}; + +static apr_status_t impl_pollset_cleanup(apr_pollset_t *pollset) +{ + close(pollset->p->epoll_fd); + return APR_SUCCESS; +} + + +static apr_status_t impl_pollset_create(apr_pollset_t *pollset, + apr_uint32_t size, + apr_pool_t *p, + apr_uint32_t flags) +{ + apr_status_t rv; + int fd; + +#ifdef HAVE_EPOLL_CREATE1 + fd = epoll_create1(EPOLL_CLOEXEC); +#else + fd = epoll_create(size); +#endif + if (fd < 0) { + pollset->p = NULL; + return apr_get_netos_error(); + } + +#ifndef HAVE_EPOLL_CREATE1 + { + int fd_flags; + + if ((fd_flags = fcntl(fd, F_GETFD)) == -1) { + rv = errno; + close(fd); + pollset->p = NULL; + return rv; + } + + fd_flags |= FD_CLOEXEC; + if (fcntl(fd, F_SETFD, fd_flags) == -1) { + rv = errno; + close(fd); + pollset->p = NULL; + return rv; + } + } +#endif + + pollset->p = apr_palloc(p, sizeof(apr_pollset_private_t)); +#if APR_HAS_THREADS + if ((flags & APR_POLLSET_THREADSAFE) && + !(flags & APR_POLLSET_NOCOPY) && + ((rv = apr_thread_mutex_create(&pollset->p->ring_lock, + APR_THREAD_MUTEX_DEFAULT, + p)) != APR_SUCCESS)) { + close(fd); + pollset->p = NULL; + return rv; + } +#else + if (flags & APR_POLLSET_THREADSAFE) { + close(fd); + pollset->p = NULL; + return APR_ENOTIMPL; + } +#endif + pollset->p->epoll_fd = fd; + pollset->p->pollset = apr_palloc(p, size * sizeof(struct epoll_event)); + pollset->p->result_set = apr_palloc(p, size * sizeof(apr_pollfd_t)); + + if (!(flags & APR_POLLSET_NOCOPY)) { + APR_RING_INIT(&pollset->p->query_ring, pfd_elem_t, link); + APR_RING_INIT(&pollset->p->free_ring, pfd_elem_t, link); + APR_RING_INIT(&pollset->p->dead_ring, pfd_elem_t, link); + } + return APR_SUCCESS; +} + +static apr_status_t impl_pollset_add(apr_pollset_t *pollset, + const apr_pollfd_t *descriptor) +{ + struct epoll_event ev = {0}; + int ret; + pfd_elem_t *elem = NULL; + apr_status_t rv = APR_SUCCESS; + + ev.events = get_epoll_event(descriptor->reqevents); + + if (pollset->flags & APR_POLLSET_NOCOPY) { + ev.data.ptr = (void *)descriptor; + } + else { + pollset_lock_rings(); + + if (!APR_RING_EMPTY(&(pollset->p->free_ring), pfd_elem_t, link)) { + elem = APR_RING_FIRST(&(pollset->p->free_ring)); + APR_RING_REMOVE(elem, link); + } + else { + elem = (pfd_elem_t *) apr_palloc(pollset->pool, sizeof(pfd_elem_t)); + APR_RING_ELEM_INIT(elem, link); + } + elem->pfd = *descriptor; + ev.data.ptr = elem; + } + if (descriptor->desc_type == APR_POLL_SOCKET) { + ret = epoll_ctl(pollset->p->epoll_fd, EPOLL_CTL_ADD, + descriptor->desc.s->socketdes, &ev); + } + else { + ret = epoll_ctl(pollset->p->epoll_fd, EPOLL_CTL_ADD, + descriptor->desc.f->filedes, &ev); + } + + if (0 != ret) { + rv = apr_get_netos_error(); + } + + if (!(pollset->flags & APR_POLLSET_NOCOPY)) { + if (rv != APR_SUCCESS) { + APR_RING_INSERT_TAIL(&(pollset->p->free_ring), elem, pfd_elem_t, link); + } + else { + APR_RING_INSERT_TAIL(&(pollset->p->query_ring), elem, pfd_elem_t, link); + } + pollset_unlock_rings(); + } + + return rv; +} + +static apr_status_t impl_pollset_remove(apr_pollset_t *pollset, + const apr_pollfd_t *descriptor) +{ + pfd_elem_t *ep; + apr_status_t rv = APR_SUCCESS; + struct epoll_event ev = {0}; /* ignored, but must be passed with + * kernel < 2.6.9 + */ + int ret; + + if (descriptor->desc_type == APR_POLL_SOCKET) { + ret = epoll_ctl(pollset->p->epoll_fd, EPOLL_CTL_DEL, + descriptor->desc.s->socketdes, &ev); + } + else { + ret = epoll_ctl(pollset->p->epoll_fd, EPOLL_CTL_DEL, + descriptor->desc.f->filedes, &ev); + } + if (ret < 0) { + rv = APR_NOTFOUND; + } + + if (!(pollset->flags & APR_POLLSET_NOCOPY)) { + pollset_lock_rings(); + + for (ep = APR_RING_FIRST(&(pollset->p->query_ring)); + ep != APR_RING_SENTINEL(&(pollset->p->query_ring), + pfd_elem_t, link); + ep = APR_RING_NEXT(ep, link)) { + + if (descriptor->desc.s == ep->pfd.desc.s) { + APR_RING_REMOVE(ep, link); + APR_RING_INSERT_TAIL(&(pollset->p->dead_ring), + ep, pfd_elem_t, link); + break; + } + } + + pollset_unlock_rings(); + } + + return rv; +} + +static apr_status_t impl_pollset_poll(apr_pollset_t *pollset, + apr_interval_time_t timeout, + apr_int32_t *num, + const apr_pollfd_t **descriptors) +{ + int ret; + apr_status_t rv = APR_SUCCESS; + + *num = 0; + + if (timeout > 0) { + timeout /= 1000; + } + + ret = epoll_wait(pollset->p->epoll_fd, pollset->p->pollset, pollset->nalloc, + timeout); + if (ret < 0) { + rv = apr_get_netos_error(); + } + else if (ret == 0) { + rv = APR_TIMEUP; + } + else { + int i, j; + const apr_pollfd_t *fdptr; + + for (i = 0, j = 0; i < ret; i++) { + if (pollset->flags & APR_POLLSET_NOCOPY) { + fdptr = (apr_pollfd_t *)(pollset->p->pollset[i].data.ptr); + } + else { + fdptr = &(((pfd_elem_t *) (pollset->p->pollset[i].data.ptr))->pfd); + } + /* Check if the polled descriptor is our + * wakeup pipe. In that case do not put it result set. + */ + if ((pollset->flags & APR_POLLSET_WAKEABLE) && + fdptr->desc_type == APR_POLL_FILE && + fdptr->desc.f == pollset->wakeup_pipe[0]) { + apr_poll_drain_wakeup_pipe(pollset->wakeup_pipe); + rv = APR_EINTR; + } + else { + pollset->p->result_set[j] = *fdptr; + pollset->p->result_set[j].rtnevents = + get_epoll_revent(pollset->p->pollset[i].events); + j++; + } + } + if (((*num) = j)) { /* any event besides wakeup pipe? */ + rv = APR_SUCCESS; + + if (descriptors) { + *descriptors = pollset->p->result_set; + } + } + } + + if (!(pollset->flags & APR_POLLSET_NOCOPY)) { + pollset_lock_rings(); + + /* Shift all PFDs in the Dead Ring to the Free Ring */ + APR_RING_CONCAT(&(pollset->p->free_ring), &(pollset->p->dead_ring), pfd_elem_t, link); + + pollset_unlock_rings(); + } + + return rv; +} + +static const apr_pollset_provider_t impl = { + impl_pollset_create, + impl_pollset_add, + impl_pollset_remove, + impl_pollset_poll, + impl_pollset_cleanup, + "epoll" +}; + +const apr_pollset_provider_t *const apr_pollset_provider_epoll = &impl; + +static apr_status_t impl_pollcb_cleanup(apr_pollcb_t *pollcb) +{ + close(pollcb->fd); + return APR_SUCCESS; +} + +static apr_status_t impl_pollcb_create(apr_pollcb_t *pollcb, + apr_uint32_t size, + apr_pool_t *p, + apr_uint32_t flags) +{ + int fd; + +#ifdef HAVE_EPOLL_CREATE1 + fd = epoll_create1(EPOLL_CLOEXEC); +#else + fd = epoll_create(size); +#endif + + if (fd < 0) { + return apr_get_netos_error(); + } + +#ifndef HAVE_EPOLL_CREATE1 + { + int fd_flags; + apr_status_t rv; + + if ((fd_flags = fcntl(fd, F_GETFD)) == -1) { + rv = errno; + close(fd); + pollcb->fd = -1; + return rv; + } + + fd_flags |= FD_CLOEXEC; + if (fcntl(fd, F_SETFD, fd_flags) == -1) { + rv = errno; + close(fd); + pollcb->fd = -1; + return rv; + } + } +#endif + + pollcb->fd = fd; + pollcb->pollset.epoll = apr_palloc(p, size * sizeof(struct epoll_event)); + + return APR_SUCCESS; +} + +static apr_status_t impl_pollcb_add(apr_pollcb_t *pollcb, + apr_pollfd_t *descriptor) +{ + struct epoll_event ev = { 0 }; + int ret; + + ev.events = get_epoll_event(descriptor->reqevents); + ev.data.ptr = (void *) descriptor; + + if (descriptor->desc_type == APR_POLL_SOCKET) { + ret = epoll_ctl(pollcb->fd, EPOLL_CTL_ADD, + descriptor->desc.s->socketdes, &ev); + } + else { + ret = epoll_ctl(pollcb->fd, EPOLL_CTL_ADD, + descriptor->desc.f->filedes, &ev); + } + + if (ret == -1) { + return apr_get_netos_error(); + } + + return APR_SUCCESS; +} + +static apr_status_t impl_pollcb_remove(apr_pollcb_t *pollcb, + apr_pollfd_t *descriptor) +{ + apr_status_t rv = APR_SUCCESS; + struct epoll_event ev = {0}; /* ignored, but must be passed with + * kernel < 2.6.9 + */ + int ret; + + if (descriptor->desc_type == APR_POLL_SOCKET) { + ret = epoll_ctl(pollcb->fd, EPOLL_CTL_DEL, + descriptor->desc.s->socketdes, &ev); + } + else { + ret = epoll_ctl(pollcb->fd, EPOLL_CTL_DEL, + descriptor->desc.f->filedes, &ev); + } + + if (ret < 0) { + rv = APR_NOTFOUND; + } + + return rv; +} + + +static apr_status_t impl_pollcb_poll(apr_pollcb_t *pollcb, + apr_interval_time_t timeout, + apr_pollcb_cb_t func, + void *baton) +{ + int ret, i; + apr_status_t rv = APR_SUCCESS; + + if (timeout > 0) { + timeout /= 1000; + } + + ret = epoll_wait(pollcb->fd, pollcb->pollset.epoll, pollcb->nalloc, + timeout); + if (ret < 0) { + rv = apr_get_netos_error(); + } + else if (ret == 0) { + rv = APR_TIMEUP; + } + else { + for (i = 0; i < ret; i++) { + apr_pollfd_t *pollfd = (apr_pollfd_t *)(pollcb->pollset.epoll[i].data.ptr); + + if ((pollcb->flags & APR_POLLSET_WAKEABLE) && + pollfd->desc_type == APR_POLL_FILE && + pollfd->desc.f == pollcb->wakeup_pipe[0]) { + apr_poll_drain_wakeup_pipe(pollcb->wakeup_pipe); + return APR_EINTR; + } + + pollfd->rtnevents = get_epoll_revent(pollcb->pollset.epoll[i].events); + + rv = func(baton, pollfd); + if (rv) { + return rv; + } + } + } + + return rv; +} + +static const apr_pollcb_provider_t impl_cb = { + impl_pollcb_create, + impl_pollcb_add, + impl_pollcb_remove, + impl_pollcb_poll, + impl_pollcb_cleanup, + "epoll" +}; + +const apr_pollcb_provider_t *const apr_pollcb_provider_epoll = &impl_cb; + +#endif /* HAVE_EPOLL */ diff --git a/poll/unix/kqueue.c b/poll/unix/kqueue.c new file mode 100644 index 00000000000..548464db148 --- /dev/null +++ b/poll/unix/kqueue.c @@ -0,0 +1,505 @@ +/* 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_poll.h" +#include "apr_time.h" +#include "apr_portable.h" +#include "apr_arch_file_io.h" +#include "apr_arch_networkio.h" +#include "apr_arch_poll_private.h" +#include "apr_arch_inherit.h" + +#ifdef HAVE_KQUEUE + +static apr_int16_t get_kqueue_revent(apr_int16_t event, apr_int16_t flags) +{ + apr_int16_t rv = 0; + + if (event == EVFILT_READ) + rv |= APR_POLLIN; + else if (event == EVFILT_WRITE) + rv |= APR_POLLOUT; + if (flags & EV_EOF) + rv |= APR_POLLHUP; + /* APR_POLLPRI, APR_POLLERR, and APR_POLLNVAL are not handled by this + * implementation. + * TODO: See if EV_ERROR + certain system errors in the returned data field + * should map to APR_POLLNVAL. + */ + return rv; +} + +struct apr_pollset_private_t +{ + int kqueue_fd; + struct kevent kevent; + apr_uint32_t setsize; + struct kevent *ke_set; + apr_pollfd_t *result_set; +#if APR_HAS_THREADS + /* A thread mutex to protect operations on the rings */ + apr_thread_mutex_t *ring_lock; +#endif + /* A ring containing all of the pollfd_t that are active */ + APR_RING_HEAD(pfd_query_ring_t, pfd_elem_t) query_ring; + /* A ring of pollfd_t that have been used, and then _remove'd */ + APR_RING_HEAD(pfd_free_ring_t, pfd_elem_t) free_ring; + /* A ring of pollfd_t where rings that have been _remove'd but + might still be inside a _poll */ + APR_RING_HEAD(pfd_dead_ring_t, pfd_elem_t) dead_ring; +}; + +static apr_status_t impl_pollset_cleanup(apr_pollset_t *pollset) +{ + close(pollset->p->kqueue_fd); + return APR_SUCCESS; +} + +static apr_status_t impl_pollset_create(apr_pollset_t *pollset, + apr_uint32_t size, + apr_pool_t *p, + apr_uint32_t flags) +{ + apr_status_t rv; + pollset->p = apr_palloc(p, sizeof(apr_pollset_private_t)); +#if APR_HAS_THREADS + if (flags & APR_POLLSET_THREADSAFE && + ((rv = apr_thread_mutex_create(&pollset->p->ring_lock, + APR_THREAD_MUTEX_DEFAULT, + p)) != APR_SUCCESS)) { + pollset->p = NULL; + return rv; + } +#else + if (flags & APR_POLLSET_THREADSAFE) { + pollset->p = NULL; + return APR_ENOTIMPL; + } +#endif + + /* POLLIN and POLLOUT are represented in different returned + * events, so we need 2 entries per descriptor in the result set, + * both for what is returned by kevent() and what is returned to + * the caller of apr_pollset_poll() (since it doesn't spend the + * CPU to coalesce separate APR_POLLIN and APR_POLLOUT events + * for the same descriptor) + */ + pollset->p->setsize = 2 * size; + + pollset->p->ke_set = + (struct kevent *) apr_palloc(p, pollset->p->setsize * sizeof(struct kevent)); + + memset(pollset->p->ke_set, 0, pollset->p->setsize * sizeof(struct kevent)); + + pollset->p->kqueue_fd = kqueue(); + + if (pollset->p->kqueue_fd == -1) { + pollset->p = NULL; + return apr_get_netos_error(); + } + + { + int flags; + + if ((flags = fcntl(pollset->p->kqueue_fd, F_GETFD)) == -1) { + rv = errno; + close(pollset->p->kqueue_fd); + pollset->p = NULL; + return rv; + } + + flags |= FD_CLOEXEC; + if (fcntl(pollset->p->kqueue_fd, F_SETFD, flags) == -1) { + rv = errno; + close(pollset->p->kqueue_fd); + pollset->p = NULL; + return rv; + } + } + + pollset->p->result_set = apr_palloc(p, pollset->p->setsize * sizeof(apr_pollfd_t)); + + APR_RING_INIT(&pollset->p->query_ring, pfd_elem_t, link); + APR_RING_INIT(&pollset->p->free_ring, pfd_elem_t, link); + APR_RING_INIT(&pollset->p->dead_ring, pfd_elem_t, link); + + return APR_SUCCESS; +} + +static apr_status_t impl_pollset_add(apr_pollset_t *pollset, + const apr_pollfd_t *descriptor) +{ + apr_os_sock_t fd; + pfd_elem_t *elem; + apr_status_t rv = APR_SUCCESS; + + pollset_lock_rings(); + + if (!APR_RING_EMPTY(&(pollset->p->free_ring), pfd_elem_t, link)) { + elem = APR_RING_FIRST(&(pollset->p->free_ring)); + APR_RING_REMOVE(elem, link); + } + else { + elem = (pfd_elem_t *) apr_palloc(pollset->pool, sizeof(pfd_elem_t)); + APR_RING_ELEM_INIT(elem, link); + } + elem->pfd = *descriptor; + + if (descriptor->desc_type == APR_POLL_SOCKET) { + fd = descriptor->desc.s->socketdes; + } + else { + fd = descriptor->desc.f->filedes; + } + + if (descriptor->reqevents & APR_POLLIN) { + EV_SET(&pollset->p->kevent, fd, EVFILT_READ, EV_ADD, 0, 0, elem); + + if (kevent(pollset->p->kqueue_fd, &pollset->p->kevent, 1, NULL, 0, + NULL) == -1) { + rv = apr_get_netos_error(); + } + } + + if (descriptor->reqevents & APR_POLLOUT && rv == APR_SUCCESS) { + EV_SET(&pollset->p->kevent, fd, EVFILT_WRITE, EV_ADD, 0, 0, elem); + + if (kevent(pollset->p->kqueue_fd, &pollset->p->kevent, 1, NULL, 0, + NULL) == -1) { + rv = apr_get_netos_error(); + } + } + + if (rv == APR_SUCCESS) { + APR_RING_INSERT_TAIL(&(pollset->p->query_ring), elem, pfd_elem_t, link); + } + else { + APR_RING_INSERT_TAIL(&(pollset->p->free_ring), elem, pfd_elem_t, link); + } + + pollset_unlock_rings(); + + return rv; +} + +static apr_status_t impl_pollset_remove(apr_pollset_t *pollset, + const apr_pollfd_t *descriptor) +{ + pfd_elem_t *ep; + apr_status_t rv; + apr_os_sock_t fd; + + pollset_lock_rings(); + + if (descriptor->desc_type == APR_POLL_SOCKET) { + fd = descriptor->desc.s->socketdes; + } + else { + fd = descriptor->desc.f->filedes; + } + + rv = APR_NOTFOUND; /* unless at least one of the specified conditions is */ + if (descriptor->reqevents & APR_POLLIN) { + EV_SET(&pollset->p->kevent, fd, EVFILT_READ, EV_DELETE, 0, 0, NULL); + + if (kevent(pollset->p->kqueue_fd, &pollset->p->kevent, 1, NULL, 0, + NULL) != -1) { + rv = APR_SUCCESS; + } + } + + if (descriptor->reqevents & APR_POLLOUT) { + EV_SET(&pollset->p->kevent, fd, EVFILT_WRITE, EV_DELETE, 0, 0, NULL); + + if (kevent(pollset->p->kqueue_fd, &pollset->p->kevent, 1, NULL, 0, + NULL) != -1) { + rv = APR_SUCCESS; + } + } + + for (ep = APR_RING_FIRST(&(pollset->p->query_ring)); + ep != APR_RING_SENTINEL(&(pollset->p->query_ring), + pfd_elem_t, link); + ep = APR_RING_NEXT(ep, link)) { + + if (descriptor->desc.s == ep->pfd.desc.s) { + APR_RING_REMOVE(ep, link); + APR_RING_INSERT_TAIL(&(pollset->p->dead_ring), + ep, pfd_elem_t, link); + break; + } + } + + pollset_unlock_rings(); + + return rv; +} + +static apr_status_t impl_pollset_poll(apr_pollset_t *pollset, + apr_interval_time_t timeout, + apr_int32_t *num, + const apr_pollfd_t **descriptors) +{ + int ret; + struct timespec tv, *tvptr; + apr_status_t rv = APR_SUCCESS; + + *num = 0; + + if (timeout < 0) { + tvptr = NULL; + } + else { + tv.tv_sec = (long) apr_time_sec(timeout); + tv.tv_nsec = (long) apr_time_usec(timeout) * 1000; + tvptr = &tv; + } + + ret = kevent(pollset->p->kqueue_fd, NULL, 0, pollset->p->ke_set, + pollset->p->setsize, tvptr); + if (ret < 0) { + rv = apr_get_netos_error(); + } + else if (ret == 0) { + rv = APR_TIMEUP; + } + else { + int i, j; + const apr_pollfd_t *fd; + + for (i = 0, j = 0; i < ret; i++) { + fd = &((pfd_elem_t *)pollset->p->ke_set[i].udata)->pfd; + if ((pollset->flags & APR_POLLSET_WAKEABLE) && + fd->desc_type == APR_POLL_FILE && + fd->desc.f == pollset->wakeup_pipe[0]) { + apr_poll_drain_wakeup_pipe(pollset->wakeup_pipe); + rv = APR_EINTR; + } + else { + pollset->p->result_set[j] = *fd; + pollset->p->result_set[j].rtnevents = + get_kqueue_revent(pollset->p->ke_set[i].filter, + pollset->p->ke_set[i].flags); + j++; + } + } + if ((*num = j)) { /* any event besides wakeup pipe? */ + rv = APR_SUCCESS; + if (descriptors) { + *descriptors = pollset->p->result_set; + } + } + } + + pollset_lock_rings(); + + /* Shift all PFDs in the Dead Ring to the Free Ring */ + APR_RING_CONCAT(&(pollset->p->free_ring), &(pollset->p->dead_ring), + pfd_elem_t, link); + + pollset_unlock_rings(); + + return rv; +} + +static const apr_pollset_provider_t impl = { + impl_pollset_create, + impl_pollset_add, + impl_pollset_remove, + impl_pollset_poll, + impl_pollset_cleanup, + "kqueue" +}; + +const apr_pollset_provider_t *apr_pollset_provider_kqueue = &impl; + +static apr_status_t impl_pollcb_cleanup(apr_pollcb_t *pollcb) +{ + close(pollcb->fd); + return APR_SUCCESS; +} + +static apr_status_t impl_pollcb_create(apr_pollcb_t *pollcb, + apr_uint32_t size, + apr_pool_t *p, + apr_uint32_t flags) +{ + int fd; + + fd = kqueue(); + if (fd < 0) { + return apr_get_netos_error(); + } + + { + int flags; + apr_status_t rv; + + if ((flags = fcntl(fd, F_GETFD)) == -1) { + rv = errno; + close(fd); + pollcb->fd = -1; + return rv; + } + + flags |= FD_CLOEXEC; + if (fcntl(fd, F_SETFD, flags) == -1) { + rv = errno; + close(fd); + pollcb->fd = -1; + return rv; + } + } + + pollcb->fd = fd; + pollcb->pollset.ke = (struct kevent *) apr_pcalloc(p, 2 * size * sizeof(struct kevent)); + + return APR_SUCCESS; +} + +static apr_status_t impl_pollcb_add(apr_pollcb_t *pollcb, + apr_pollfd_t *descriptor) +{ + apr_os_sock_t fd; + struct kevent ev; + apr_status_t rv = APR_SUCCESS; + + if (descriptor->desc_type == APR_POLL_SOCKET) { + fd = descriptor->desc.s->socketdes; + } + else { + fd = descriptor->desc.f->filedes; + } + + if (descriptor->reqevents & APR_POLLIN) { + EV_SET(&ev, fd, EVFILT_READ, EV_ADD, 0, 0, descriptor); + + if (kevent(pollcb->fd, &ev, 1, NULL, 0, NULL) == -1) { + rv = apr_get_netos_error(); + } + } + + if (descriptor->reqevents & APR_POLLOUT && rv == APR_SUCCESS) { + EV_SET(&ev, fd, EVFILT_WRITE, EV_ADD, 0, 0, descriptor); + + if (kevent(pollcb->fd, &ev, 1, NULL, 0, NULL) == -1) { + rv = apr_get_netos_error(); + } + } + + return rv; +} + +static apr_status_t impl_pollcb_remove(apr_pollcb_t *pollcb, + apr_pollfd_t *descriptor) +{ + apr_status_t rv; + struct kevent ev; + apr_os_sock_t fd; + + if (descriptor->desc_type == APR_POLL_SOCKET) { + fd = descriptor->desc.s->socketdes; + } + else { + fd = descriptor->desc.f->filedes; + } + + rv = APR_NOTFOUND; /* unless at least one of the specified conditions is */ + if (descriptor->reqevents & APR_POLLIN) { + EV_SET(&ev, fd, EVFILT_READ, EV_DELETE, 0, 0, NULL); + + if (kevent(pollcb->fd, &ev, 1, NULL, 0, NULL) != -1) { + rv = APR_SUCCESS; + } + } + + if (descriptor->reqevents & APR_POLLOUT) { + EV_SET(&ev, fd, EVFILT_WRITE, EV_DELETE, 0, 0, NULL); + + if (kevent(pollcb->fd, &ev, 1, NULL, 0, NULL) != -1) { + rv = APR_SUCCESS; + } + } + + return rv; +} + + +static apr_status_t impl_pollcb_poll(apr_pollcb_t *pollcb, + apr_interval_time_t timeout, + apr_pollcb_cb_t func, + void *baton) +{ + int ret, i; + struct timespec tv, *tvptr; + apr_status_t rv = APR_SUCCESS; + + if (timeout < 0) { + tvptr = NULL; + } + else { + tv.tv_sec = (long) apr_time_sec(timeout); + tv.tv_nsec = (long) apr_time_usec(timeout) * 1000; + tvptr = &tv; + } + + ret = kevent(pollcb->fd, NULL, 0, pollcb->pollset.ke, 2 * pollcb->nalloc, + tvptr); + + if (ret < 0) { + rv = apr_get_netos_error(); + } + else if (ret == 0) { + rv = APR_TIMEUP; + } + else { + for (i = 0; i < ret; i++) { + apr_pollfd_t *pollfd = (apr_pollfd_t *)(pollcb->pollset.ke[i].udata); + + if ((pollcb->flags & APR_POLLSET_WAKEABLE) && + pollfd->desc_type == APR_POLL_FILE && + pollfd->desc.f == pollcb->wakeup_pipe[0]) { + apr_poll_drain_wakeup_pipe(pollcb->wakeup_pipe); + return APR_EINTR; + } + + pollfd->rtnevents = get_kqueue_revent(pollcb->pollset.ke[i].filter, + pollcb->pollset.ke[i].flags); + + rv = func(baton, pollfd); + + if (rv) { + return rv; + } + } + } + + return rv; +} + +static const apr_pollcb_provider_t impl_cb = { + impl_pollcb_create, + impl_pollcb_add, + impl_pollcb_remove, + impl_pollcb_poll, + impl_pollcb_cleanup, + "kqueue" +}; + +const apr_pollcb_provider_t *apr_pollcb_provider_kqueue = &impl_cb; + +#endif /* HAVE_KQUEUE */ diff --git a/poll/unix/poll.c b/poll/unix/poll.c new file mode 100644 index 00000000000..f148f5e50d3 --- /dev/null +++ b/poll/unix/poll.c @@ -0,0 +1,460 @@ +/* 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_poll.h" +#include "apr_time.h" +#include "apr_portable.h" +#include "apr_arch_file_io.h" +#include "apr_arch_networkio.h" +#include "apr_arch_misc.h" +#include "apr_arch_poll_private.h" + +#if defined(HAVE_POLL) + +#ifdef HAVE_ALLOCA_H +#include <alloca.h> +#endif + +static apr_int16_t get_event(apr_int16_t event) +{ + apr_int16_t rv = 0; + + if (event & APR_POLLIN) + rv |= POLLIN; + if (event & APR_POLLPRI) + rv |= POLLPRI; + if (event & APR_POLLOUT) + rv |= POLLOUT; + /* POLLERR, POLLHUP, and POLLNVAL aren't valid as requested events */ + + return rv; +} + +static apr_int16_t get_revent(apr_int16_t event) +{ + apr_int16_t rv = 0; + + if (event & POLLIN) + rv |= APR_POLLIN; + if (event & POLLPRI) + rv |= APR_POLLPRI; + if (event & POLLOUT) + rv |= APR_POLLOUT; + if (event & POLLERR) + rv |= APR_POLLERR; + if (event & POLLHUP) + rv |= APR_POLLHUP; + if (event & POLLNVAL) + rv |= APR_POLLNVAL; + + return rv; +} + +#ifdef POLL_USES_POLL + +#define SMALL_POLLSET_LIMIT 8 + +APR_DECLARE(apr_status_t) apr_poll(apr_pollfd_t *aprset, apr_int32_t num, + apr_int32_t *nsds, + apr_interval_time_t timeout) +{ + int i, num_to_poll; +#ifdef HAVE_VLA + /* XXX: I trust that this is a segv when insufficient stack exists? */ + struct pollfd pollset[num]; +#elif defined(HAVE_ALLOCA) + struct pollfd *pollset = alloca(sizeof(struct pollfd) * num); + if (!pollset) + return APR_ENOMEM; +#else + struct pollfd tmp_pollset[SMALL_POLLSET_LIMIT]; + struct pollfd *pollset; + + if (num <= SMALL_POLLSET_LIMIT) { + pollset = tmp_pollset; + } + else { + /* This does require O(n) to copy the descriptors to the internal + * mapping. + */ + pollset = malloc(sizeof(struct pollfd) * num); + /* The other option is adding an apr_pool_abort() fn to invoke + * the pool's out of memory handler + */ + if (!pollset) + return APR_ENOMEM; + } +#endif + for (i = 0; i < num; i++) { + if (aprset[i].desc_type == APR_POLL_SOCKET) { + pollset[i].fd = aprset[i].desc.s->socketdes; + } + else if (aprset[i].desc_type == APR_POLL_FILE) { + pollset[i].fd = aprset[i].desc.f->filedes; + } + else { + break; + } + pollset[i].events = get_event(aprset[i].reqevents); + } + num_to_poll = i; + + if (timeout > 0) { + timeout /= 1000; /* convert microseconds to milliseconds */ + } + + i = poll(pollset, num_to_poll, timeout); + (*nsds) = i; + + if (i > 0) { /* poll() sets revents only if an event was signalled; + * we don't promise to set rtnevents unless an event + * was signalled + */ + for (i = 0; i < num; i++) { + aprset[i].rtnevents = get_revent(pollset[i].revents); + } + } + +#if !defined(HAVE_VLA) && !defined(HAVE_ALLOCA) + if (num > SMALL_POLLSET_LIMIT) { + free(pollset); + } +#endif + + if ((*nsds) < 0) { + return apr_get_netos_error(); + } + if ((*nsds) == 0) { + return APR_TIMEUP; + } + return APR_SUCCESS; +} + + +#endif /* POLL_USES_POLL */ + +struct apr_pollset_private_t +{ + struct pollfd *pollset; + apr_pollfd_t *query_set; + apr_pollfd_t *result_set; +}; + +static apr_status_t impl_pollset_create(apr_pollset_t *pollset, + apr_uint32_t size, + apr_pool_t *p, + apr_uint32_t flags) +{ + if (flags & APR_POLLSET_THREADSAFE) { + return APR_ENOTIMPL; + } +#ifdef WIN32 + if (!APR_HAVE_LATE_DLL_FUNC(WSAPoll)) { + return APR_ENOTIMPL; + } +#endif + pollset->p = apr_palloc(p, sizeof(apr_pollset_private_t)); + pollset->p->pollset = apr_palloc(p, size * sizeof(struct pollfd)); + pollset->p->query_set = apr_palloc(p, size * sizeof(apr_pollfd_t)); + pollset->p->result_set = apr_palloc(p, size * sizeof(apr_pollfd_t)); + + return APR_SUCCESS; +} + +static apr_status_t impl_pollset_add(apr_pollset_t *pollset, + const apr_pollfd_t *descriptor) +{ + if (pollset->nelts == pollset->nalloc) { + return APR_ENOMEM; + } + + pollset->p->query_set[pollset->nelts] = *descriptor; + + if (descriptor->desc_type == APR_POLL_SOCKET) { + pollset->p->pollset[pollset->nelts].fd = descriptor->desc.s->socketdes; + } + else { +#if APR_FILES_AS_SOCKETS + pollset->p->pollset[pollset->nelts].fd = descriptor->desc.f->filedes; +#else + if ((pollset->flags & APR_POLLSET_WAKEABLE) && + descriptor->desc.f == pollset->wakeup_pipe[0]) + pollset->p->pollset[pollset->nelts].fd = (SOCKET)descriptor->desc.f->filedes; + else + return APR_EBADF; +#endif + } + pollset->p->pollset[pollset->nelts].events = + get_event(descriptor->reqevents); + pollset->nelts++; + + return APR_SUCCESS; +} + +static apr_status_t impl_pollset_remove(apr_pollset_t *pollset, + const apr_pollfd_t *descriptor) +{ + apr_uint32_t i; + + for (i = 0; i < pollset->nelts; i++) { + if (descriptor->desc.s == pollset->p->query_set[i].desc.s) { + /* Found an instance of the fd: remove this and any other copies */ + apr_uint32_t dst = i; + apr_uint32_t old_nelts = pollset->nelts; + pollset->nelts--; + for (i++; i < old_nelts; i++) { + if (descriptor->desc.s == pollset->p->query_set[i].desc.s) { + pollset->nelts--; + } + else { + pollset->p->pollset[dst] = pollset->p->pollset[i]; + pollset->p->query_set[dst] = pollset->p->query_set[i]; + dst++; + } + } + return APR_SUCCESS; + } + } + + return APR_NOTFOUND; +} + +static apr_status_t impl_pollset_poll(apr_pollset_t *pollset, + apr_interval_time_t timeout, + apr_int32_t *num, + const apr_pollfd_t **descriptors) +{ + int ret; + apr_status_t rv = APR_SUCCESS; + + *num = 0; + +#ifdef WIN32 + /* WSAPoll() requires at least one socket. */ + if (pollset->nelts == 0) { + if (timeout > 0) { + apr_sleep(timeout); + return APR_TIMEUP; + } + return APR_SUCCESS; + } + if (timeout > 0) { + timeout /= 1000; + } + ret = WSAPoll(pollset->p->pollset, pollset->nelts, (int)timeout); +#else + if (timeout > 0) { + timeout /= 1000; + } + ret = poll(pollset->p->pollset, pollset->nelts, timeout); +#endif + if (ret < 0) { + return apr_get_netos_error(); + } + else if (ret == 0) { + return APR_TIMEUP; + } + else { + apr_uint32_t i, j; + + for (i = 0, j = 0; i < pollset->nelts; i++) { + if (pollset->p->pollset[i].revents != 0) { + /* Check if the polled descriptor is our + * wakeup pipe. In that case do not put it result set. + */ + if ((pollset->flags & APR_POLLSET_WAKEABLE) && + pollset->p->query_set[i].desc_type == APR_POLL_FILE && + pollset->p->query_set[i].desc.f == pollset->wakeup_pipe[0]) { + apr_poll_drain_wakeup_pipe(pollset->wakeup_pipe); + rv = APR_EINTR; + } + else { + pollset->p->result_set[j] = pollset->p->query_set[i]; + pollset->p->result_set[j].rtnevents = + get_revent(pollset->p->pollset[i].revents); + j++; + } + } + } + if ((*num = j)) { /* any event besides wakeup pipe? */ + rv = APR_SUCCESS; + } + } + if (descriptors && (*num)) + *descriptors = pollset->p->result_set; + return rv; +} + +static const apr_pollset_provider_t impl = { + impl_pollset_create, + impl_pollset_add, + impl_pollset_remove, + impl_pollset_poll, + NULL, + "poll" +}; + +const apr_pollset_provider_t *apr_pollset_provider_poll = &impl; + +/* Poll method pollcb. + * This is probably usable only for WIN32 having WSAPoll + */ +static apr_status_t impl_pollcb_create(apr_pollcb_t *pollcb, + apr_uint32_t size, + apr_pool_t *p, + apr_uint32_t flags) +{ +#if APR_HAS_THREADS + return APR_ENOTIMPL; +#else + pollcb->fd = -1; +#ifdef WIN32 + if (!APR_HAVE_LATE_DLL_FUNC(WSAPoll)) { + return APR_ENOTIMPL; + } +#endif + + pollcb->pollset.ps = apr_palloc(p, size * sizeof(struct pollfd)); + pollcb->copyset = apr_palloc(p, size * sizeof(apr_pollfd_t *)); + + return APR_SUCCESS; +#endif +} + +static apr_status_t impl_pollcb_add(apr_pollcb_t *pollcb, + apr_pollfd_t *descriptor) +{ + if (pollcb->nelts == pollcb->nalloc) { + return APR_ENOMEM; + } + + if (descriptor->desc_type == APR_POLL_SOCKET) { + pollcb->pollset.ps[pollcb->nelts].fd = descriptor->desc.s->socketdes; + } + else { +#if APR_FILES_AS_SOCKETS + pollcb->pollset.ps[pollcb->nelts].fd = descriptor->desc.f->filedes; +#else + return APR_EBADF; +#endif + } + + pollcb->pollset.ps[pollcb->nelts].events = + get_event(descriptor->reqevents); + pollcb->copyset[pollcb->nelts] = descriptor; + pollcb->nelts++; + + return APR_SUCCESS; +} + +static apr_status_t impl_pollcb_remove(apr_pollcb_t *pollcb, + apr_pollfd_t *descriptor) +{ + apr_uint32_t i; + + for (i = 0; i < pollcb->nelts; i++) { + if (descriptor->desc.s == pollcb->copyset[i]->desc.s) { + /* Found an instance of the fd: remove this and any other copies */ + apr_uint32_t dst = i; + apr_uint32_t old_nelts = pollcb->nelts; + pollcb->nelts--; + for (i++; i < old_nelts; i++) { + if (descriptor->desc.s == pollcb->copyset[i]->desc.s) { + pollcb->nelts--; + } + else { + pollcb->pollset.ps[dst] = pollcb->pollset.ps[i]; + pollcb->copyset[dst] = pollcb->copyset[i]; + dst++; + } + } + return APR_SUCCESS; + } + } + + return APR_NOTFOUND; +} + +static apr_status_t impl_pollcb_poll(apr_pollcb_t *pollcb, + apr_interval_time_t timeout, + apr_pollcb_cb_t func, + void *baton) +{ + int ret; + apr_status_t rv = APR_SUCCESS; + apr_uint32_t i; + +#ifdef WIN32 + /* WSAPoll() requires at least one socket. */ + if (pollcb->nelts == 0) { + if (timeout > 0) { + apr_sleep(timeout); + return APR_TIMEUP; + } + return APR_SUCCESS; + } + if (timeout > 0) { + timeout /= 1000; + } + ret = WSAPoll(pollcb->pollset.ps, pollcb->nelts, (int)timeout); +#else + if (timeout > 0) { + timeout /= 1000; + } + ret = poll(pollcb->pollset.ps, pollcb->nelts, timeout); +#endif + if (ret < 0) { + return apr_get_netos_error(); + } + else if (ret == 0) { + return APR_TIMEUP; + } + else { + for (i = 0; i < pollcb->nelts; i++) { + if (pollcb->pollset.ps[i].revents != 0) { + apr_pollfd_t *pollfd = pollcb->copyset[i]; + + if ((pollcb->flags & APR_POLLSET_WAKEABLE) && + pollfd->desc_type == APR_POLL_FILE && + pollfd->desc.f == pollcb->wakeup_pipe[0]) { + apr_poll_drain_wakeup_pipe(pollcb->wakeup_pipe); + return APR_EINTR; + } + + pollfd->rtnevents = get_revent(pollcb->pollset.ps[i].revents); + rv = func(baton, pollfd); + if (rv) { + return rv; + } + } + } + } + return rv; +} + +static const apr_pollcb_provider_t impl_cb = { + impl_pollcb_create, + impl_pollcb_add, + impl_pollcb_remove, + impl_pollcb_poll, + NULL, + "poll" +}; + +const apr_pollcb_provider_t *apr_pollcb_provider_poll = &impl_cb; + +#endif /* HAVE_POLL */ diff --git a/poll/unix/pollcb.c b/poll/unix/pollcb.c new file mode 100644 index 00000000000..a63ad5c9cad --- /dev/null +++ b/poll/unix/pollcb.c @@ -0,0 +1,224 @@ +/* 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. + */ + +#ifdef WIN32 +/* POSIX defines 1024 for the FD_SETSIZE */ +#define FD_SETSIZE 1024 +#endif + +#include "apr.h" +#include "apr_poll.h" +#include "apr_time.h" +#include "apr_portable.h" +#include "apr_arch_file_io.h" +#include "apr_arch_networkio.h" +#include "apr_arch_poll_private.h" + +static apr_pollset_method_e pollset_default_method = POLLSET_DEFAULT_METHOD; +#if defined(HAVE_KQUEUE) +extern const apr_pollcb_provider_t *apr_pollcb_provider_kqueue; +#endif +#if defined(HAVE_PORT_CREATE) +extern const apr_pollcb_provider_t *apr_pollcb_provider_port; +#endif +#if defined(HAVE_EPOLL) +extern const apr_pollcb_provider_t *apr_pollcb_provider_epoll; +#endif +#if defined(HAVE_POLL) +extern const apr_pollcb_provider_t *apr_pollcb_provider_poll; +#endif + +static const apr_pollcb_provider_t *pollcb_provider(apr_pollset_method_e method) +{ + const apr_pollcb_provider_t *provider = NULL; + switch (method) { + case APR_POLLSET_KQUEUE: +#if defined(HAVE_KQUEUE) + provider = apr_pollcb_provider_kqueue; +#endif + break; + case APR_POLLSET_PORT: +#if defined(HAVE_PORT_CREATE) + provider = apr_pollcb_provider_port; +#endif + break; + case APR_POLLSET_EPOLL: +#if defined(HAVE_EPOLL) + provider = apr_pollcb_provider_epoll; +#endif + break; + case APR_POLLSET_POLL: +#if defined(HAVE_POLL) + provider = apr_pollcb_provider_poll; +#endif + break; + case APR_POLLSET_SELECT: + case APR_POLLSET_AIO_MSGQ: + case APR_POLLSET_DEFAULT: + break; + } + return provider; +} + +static apr_status_t pollcb_cleanup(void *p) +{ + apr_pollcb_t *pollcb = (apr_pollcb_t *) p; + + if (pollcb->provider->cleanup) { + (*pollcb->provider->cleanup)(pollcb); + } + if (pollcb->flags & APR_POLLSET_WAKEABLE) { + apr_poll_close_wakeup_pipe(pollcb->wakeup_pipe); + } + + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_pollcb_create_ex(apr_pollcb_t **ret_pollcb, + apr_uint32_t size, + apr_pool_t *p, + apr_uint32_t flags, + apr_pollset_method_e method) +{ + apr_status_t rv; + apr_pollcb_t *pollcb; + const apr_pollcb_provider_t *provider = NULL; + + *ret_pollcb = NULL; + + #ifdef WIN32 + /* This will work only if ws2_32.dll has WSAPoll funtion. + * We could check the presence of the function here, + * but someone might implement other pollcb method in + * the future. + */ + if (method == APR_POLLSET_DEFAULT) { + method = APR_POLLSET_POLL; + } + #endif + + if (method == APR_POLLSET_DEFAULT) + method = pollset_default_method; + while (provider == NULL) { + provider = pollcb_provider(method); + if (!provider) { + if ((flags & APR_POLLSET_NODEFAULT) == APR_POLLSET_NODEFAULT) + return APR_ENOTIMPL; + if (method == pollset_default_method) + return APR_ENOTIMPL; + method = pollset_default_method; + } + } + + if (flags & APR_POLLSET_WAKEABLE) { + /* Add room for wakeup descriptor */ + size++; + } + + pollcb = apr_palloc(p, sizeof(*pollcb)); + pollcb->nelts = 0; + pollcb->nalloc = size; + pollcb->flags = flags; + pollcb->pool = p; + pollcb->provider = provider; + + rv = (*provider->create)(pollcb, size, p, flags); + if (rv == APR_ENOTIMPL) { + if (method == pollset_default_method) { + return rv; + } + + if ((flags & APR_POLLSET_NODEFAULT) == APR_POLLSET_NODEFAULT) { + return rv; + } + + /* Try with default provider */ + provider = pollcb_provider(pollset_default_method); + if (!provider) { + return APR_ENOTIMPL; + } + rv = (*provider->create)(pollcb, size, p, flags); + if (rv != APR_SUCCESS) { + return rv; + } + pollcb->provider = provider; + } + else if (rv != APR_SUCCESS) { + return rv; + } + + if (flags & APR_POLLSET_WAKEABLE) { + /* Create wakeup pipe */ + if ((rv = apr_poll_create_wakeup_pipe(pollcb->pool, &pollcb->wakeup_pfd, + pollcb->wakeup_pipe)) + != APR_SUCCESS) { + return rv; + } + + if ((rv = apr_pollcb_add(pollcb, &pollcb->wakeup_pfd)) != APR_SUCCESS) { + return rv; + } + } + if ((flags & APR_POLLSET_WAKEABLE) || provider->cleanup) + apr_pool_cleanup_register(p, pollcb, pollcb_cleanup, + apr_pool_cleanup_null); + + *ret_pollcb = pollcb; + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_pollcb_create(apr_pollcb_t **pollcb, + apr_uint32_t size, + apr_pool_t *p, + apr_uint32_t flags) +{ + apr_pollset_method_e method = APR_POLLSET_DEFAULT; + return apr_pollcb_create_ex(pollcb, size, p, flags, method); +} + +APR_DECLARE(apr_status_t) apr_pollcb_add(apr_pollcb_t *pollcb, + apr_pollfd_t *descriptor) +{ + return (*pollcb->provider->add)(pollcb, descriptor); +} + +APR_DECLARE(apr_status_t) apr_pollcb_remove(apr_pollcb_t *pollcb, + apr_pollfd_t *descriptor) +{ + return (*pollcb->provider->remove)(pollcb, descriptor); +} + + +APR_DECLARE(apr_status_t) apr_pollcb_poll(apr_pollcb_t *pollcb, + apr_interval_time_t timeout, + apr_pollcb_cb_t func, + void *baton) +{ + return (*pollcb->provider->poll)(pollcb, timeout, func, baton); +} + +APR_DECLARE(apr_status_t) apr_pollcb_wakeup(apr_pollcb_t *pollcb) +{ + if (pollcb->flags & APR_POLLSET_WAKEABLE) + return apr_file_putc(1, pollcb->wakeup_pipe[1]); + else + return APR_EINIT; +} + +APR_DECLARE(const char *) apr_pollcb_method_name(apr_pollcb_t *pollcb) +{ + return pollcb->provider->name; +} diff --git a/poll/unix/pollset.c b/poll/unix/pollset.c new file mode 100644 index 00000000000..8fa817330f6 --- /dev/null +++ b/poll/unix/pollset.c @@ -0,0 +1,247 @@ +/* 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. + */ + +#ifdef WIN32 +/* POSIX defines 1024 for the FD_SETSIZE */ +#define FD_SETSIZE 1024 +#endif + +#include "apr.h" +#include "apr_poll.h" +#include "apr_time.h" +#include "apr_portable.h" +#include "apr_arch_file_io.h" +#include "apr_arch_networkio.h" +#include "apr_arch_poll_private.h" +#include "apr_arch_inherit.h" + +static apr_pollset_method_e pollset_default_method = POLLSET_DEFAULT_METHOD; + +static apr_status_t pollset_cleanup(void *p) +{ + apr_pollset_t *pollset = (apr_pollset_t *) p; + if (pollset->provider->cleanup) { + (*pollset->provider->cleanup)(pollset); + } + if (pollset->flags & APR_POLLSET_WAKEABLE) { + apr_poll_close_wakeup_pipe(pollset->wakeup_pipe); + } + + return APR_SUCCESS; +} + +#if defined(HAVE_KQUEUE) +extern const apr_pollset_provider_t *apr_pollset_provider_kqueue; +#endif +#if defined(HAVE_PORT_CREATE) +extern const apr_pollset_provider_t *apr_pollset_provider_port; +#endif +#if defined(HAVE_EPOLL) +extern const apr_pollset_provider_t *apr_pollset_provider_epoll; +#endif +#if defined(HAVE_AIO_MSGQ) +extern const apr_pollset_provider_t *apr_pollset_provider_aio_msgq; +#endif +#if defined(HAVE_POLL) +extern const apr_pollset_provider_t *apr_pollset_provider_poll; +#endif +extern const apr_pollset_provider_t *apr_pollset_provider_select; + +static const apr_pollset_provider_t *pollset_provider(apr_pollset_method_e method) +{ + const apr_pollset_provider_t *provider = NULL; + switch (method) { + case APR_POLLSET_KQUEUE: +#if defined(HAVE_KQUEUE) + provider = apr_pollset_provider_kqueue; +#endif + break; + case APR_POLLSET_PORT: +#if defined(HAVE_PORT_CREATE) + provider = apr_pollset_provider_port; +#endif + break; + case APR_POLLSET_EPOLL: +#if defined(HAVE_EPOLL) + provider = apr_pollset_provider_epoll; +#endif + break; + case APR_POLLSET_AIO_MSGQ: +#if defined(HAVE_AIO_MSGQ) + provider = apr_pollset_provider_aio_msgq; +#endif + break; + case APR_POLLSET_POLL: +#if defined(HAVE_POLL) + provider = apr_pollset_provider_poll; +#endif + break; + case APR_POLLSET_SELECT: + provider = apr_pollset_provider_select; + break; + case APR_POLLSET_DEFAULT: + break; + } + return provider; +} + +APR_DECLARE(apr_status_t) apr_pollset_create_ex(apr_pollset_t **ret_pollset, + apr_uint32_t size, + apr_pool_t *p, + apr_uint32_t flags, + apr_pollset_method_e method) +{ + apr_status_t rv; + apr_pollset_t *pollset; + const apr_pollset_provider_t *provider = NULL; + + *ret_pollset = NULL; + + #ifdef WIN32 + /* Favor WSAPoll if supported. + * This will work only if ws2_32.dll has WSAPoll funtion. + * In other cases it will fall back to select() method unless + * the APR_POLLSET_NODEFAULT is added to the flags. + */ + if (method == APR_POLLSET_DEFAULT) { + method = APR_POLLSET_POLL; + } + #endif + + if (method == APR_POLLSET_DEFAULT) + method = pollset_default_method; + while (provider == NULL) { + provider = pollset_provider(method); + if (!provider) { + if ((flags & APR_POLLSET_NODEFAULT) == APR_POLLSET_NODEFAULT) + return APR_ENOTIMPL; + if (method == pollset_default_method) + return APR_ENOTIMPL; + method = pollset_default_method; + } + } + if (flags & APR_POLLSET_WAKEABLE) { + /* Add room for wakeup descriptor */ + size++; + } + + pollset = apr_palloc(p, sizeof(*pollset)); + pollset->nelts = 0; + pollset->nalloc = size; + pollset->pool = p; + pollset->flags = flags; + pollset->provider = provider; + + rv = (*provider->create)(pollset, size, p, flags); + if (rv == APR_ENOTIMPL) { + if (method == pollset_default_method) { + return rv; + } + provider = pollset_provider(pollset_default_method); + if (!provider) { + return APR_ENOTIMPL; + } + rv = (*provider->create)(pollset, size, p, flags); + if (rv != APR_SUCCESS) { + return rv; + } + pollset->provider = provider; + } + else if (rv != APR_SUCCESS) { + return rv; + } + if (flags & APR_POLLSET_WAKEABLE) { + /* Create wakeup pipe */ + if ((rv = apr_poll_create_wakeup_pipe(pollset->pool, &pollset->wakeup_pfd, + pollset->wakeup_pipe)) + != APR_SUCCESS) { + return rv; + } + + if ((rv = apr_pollset_add(pollset, &pollset->wakeup_pfd)) != APR_SUCCESS) { + return rv; + } + } + if ((flags & APR_POLLSET_WAKEABLE) || provider->cleanup) + apr_pool_cleanup_register(p, pollset, pollset_cleanup, + apr_pool_cleanup_null); + + *ret_pollset = pollset; + return APR_SUCCESS; +} + +APR_DECLARE(const char *) apr_pollset_method_name(apr_pollset_t *pollset) +{ + return pollset->provider->name; +} + +APR_DECLARE(const char *) apr_poll_method_defname() +{ + const apr_pollset_provider_t *provider = NULL; + + provider = pollset_provider(pollset_default_method); + if (provider) + return provider->name; + else + return "unknown"; +} + +APR_DECLARE(apr_status_t) apr_pollset_create(apr_pollset_t **pollset, + apr_uint32_t size, + apr_pool_t *p, + apr_uint32_t flags) +{ + apr_pollset_method_e method = APR_POLLSET_DEFAULT; + return apr_pollset_create_ex(pollset, size, p, flags, method); +} + +APR_DECLARE(apr_status_t) apr_pollset_destroy(apr_pollset_t * pollset) +{ + if (pollset->flags & APR_POLLSET_WAKEABLE || + pollset->provider->cleanup) + return apr_pool_cleanup_run(pollset->pool, pollset, + pollset_cleanup); + else + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_pollset_wakeup(apr_pollset_t *pollset) +{ + if (pollset->flags & APR_POLLSET_WAKEABLE) + return apr_file_putc(1, pollset->wakeup_pipe[1]); + else + return APR_EINIT; +} + +APR_DECLARE(apr_status_t) apr_pollset_add(apr_pollset_t *pollset, + const apr_pollfd_t *descriptor) +{ + return (*pollset->provider->add)(pollset, descriptor); +} + +APR_DECLARE(apr_status_t) apr_pollset_remove(apr_pollset_t *pollset, + const apr_pollfd_t *descriptor) +{ + return (*pollset->provider->remove)(pollset, descriptor); +} + +APR_DECLARE(apr_status_t) apr_pollset_poll(apr_pollset_t *pollset, + apr_interval_time_t timeout, + apr_int32_t *num, + const apr_pollfd_t **descriptors) +{ + return (*pollset->provider->poll)(pollset, timeout, num, descriptors); +} diff --git a/poll/unix/port.c b/poll/unix/port.c new file mode 100644 index 00000000000..c1e599412ec --- /dev/null +++ b/poll/unix/port.c @@ -0,0 +1,594 @@ +/* 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_poll.h" +#include "apr_time.h" +#include "apr_portable.h" +#include "apr_atomic.h" +#include "apr_arch_file_io.h" +#include "apr_arch_networkio.h" +#include "apr_arch_poll_private.h" +#include "apr_arch_inherit.h" + +#if defined(HAVE_PORT_CREATE) + +static apr_int16_t get_event(apr_int16_t event) +{ + apr_int16_t rv = 0; + + if (event & APR_POLLIN) + rv |= POLLIN; + if (event & APR_POLLPRI) + rv |= POLLPRI; + if (event & APR_POLLOUT) + rv |= POLLOUT; + /* POLLERR, POLLHUP, and POLLNVAL aren't valid as requested events */ + + return rv; +} + +static apr_int16_t get_revent(apr_int16_t event) +{ + apr_int16_t rv = 0; + + if (event & POLLIN) + rv |= APR_POLLIN; + if (event & POLLPRI) + rv |= APR_POLLPRI; + if (event & POLLOUT) + rv |= APR_POLLOUT; + if (event & POLLERR) + rv |= APR_POLLERR; + if (event & POLLHUP) + rv |= APR_POLLHUP; + if (event & POLLNVAL) + rv |= APR_POLLNVAL; + + return rv; +} + + +struct apr_pollset_private_t +{ + int port_fd; + port_event_t *port_set; + apr_pollfd_t *result_set; +#if APR_HAS_THREADS + /* A thread mutex to protect operations on the rings */ + apr_thread_mutex_t *ring_lock; +#endif + /* A ring containing all of the pollfd_t that are active */ + APR_RING_HEAD(pfd_query_ring_t, pfd_elem_t) query_ring; + /* A ring containing the pollfd_t that will be added on the + * next call to apr_pollset_poll(). + */ + APR_RING_HEAD(pfd_add_ring_t, pfd_elem_t) add_ring; + /* A ring of pollfd_t that have been used, and then _remove'd */ + APR_RING_HEAD(pfd_free_ring_t, pfd_elem_t) free_ring; + /* A ring of pollfd_t where rings that have been _remove'd but + might still be inside a _poll */ + APR_RING_HEAD(pfd_dead_ring_t, pfd_elem_t) dead_ring; + /* number of threads in poll */ + volatile apr_uint32_t waiting; +}; + +static apr_status_t call_port_getn(int port, port_event_t list[], + unsigned int max, unsigned int *nget, + apr_interval_time_t timeout) +{ + struct timespec tv, *tvptr; + int ret; + apr_status_t rv = APR_SUCCESS; + + if (timeout < 0) { + tvptr = NULL; + } + else { + tv.tv_sec = (long) apr_time_sec(timeout); + tv.tv_nsec = (long) apr_time_usec(timeout) * 1000; + tvptr = &tv; + } + + list[0].portev_user = (void *)-1; /* so we can double check that an + * event was returned + */ + + ret = port_getn(port, list, max, nget, tvptr); + /* Note: 32-bit port_getn() on Solaris 10 x86 returns large negative + * values instead of 0 when returning immediately. + */ + + if (ret == -1) { + rv = apr_get_netos_error(); + + switch(rv) { + case EINTR: + case ETIME: + if (*nget > 0 && list[0].portev_user != (void *)-1) { + /* This confusing API can return an event at the same time + * that it reports EINTR or ETIME. If that occurs, just + * report the event. With EINTR, nget can be > 0 without + * any event, so check that portev_user was filled in. + * + * (Maybe it will be simplified; see thread + * http://mail.opensolaris.org + * /pipermail/networking-discuss/2009-August/011979.html + * This code will still work afterwards.) + */ + rv = APR_SUCCESS; + break; + } + if (rv == ETIME) { + rv = APR_TIMEUP; + } + /* fall-through */ + default: + *nget = 0; + } + } + else if (*nget == 0) { + rv = APR_TIMEUP; + } + + return rv; +} + +static apr_status_t impl_pollset_cleanup(apr_pollset_t *pollset) +{ + close(pollset->p->port_fd); + return APR_SUCCESS; +} + +static apr_status_t impl_pollset_create(apr_pollset_t *pollset, + apr_uint32_t size, + apr_pool_t *p, + apr_uint32_t flags) +{ + apr_status_t rv = APR_SUCCESS; + pollset->p = apr_palloc(p, sizeof(apr_pollset_private_t)); +#if APR_HAS_THREADS + if (flags & APR_POLLSET_THREADSAFE && + ((rv = apr_thread_mutex_create(&pollset->p->ring_lock, + APR_THREAD_MUTEX_DEFAULT, + p)) != APR_SUCCESS)) { + pollset->p = NULL; + return rv; + } +#else + if (flags & APR_POLLSET_THREADSAFE) { + pollset->p = NULL; + return APR_ENOTIMPL; + } +#endif + pollset->p->waiting = 0; + + pollset->p->port_set = apr_palloc(p, size * sizeof(port_event_t)); + + pollset->p->port_fd = port_create(); + + if (pollset->p->port_fd < 0) { + pollset->p = NULL; + return apr_get_netos_error(); + } + + { + int flags; + + if ((flags = fcntl(pollset->p->port_fd, F_GETFD)) == -1) { + rv = errno; + close(pollset->p->port_fd); + pollset->p = NULL; + return rv; + } + + flags |= FD_CLOEXEC; + if (fcntl(pollset->p->port_fd, F_SETFD, flags) == -1) { + rv = errno; + close(pollset->p->port_fd); + pollset->p = NULL; + return rv; + } + } + + pollset->p->result_set = apr_palloc(p, size * sizeof(apr_pollfd_t)); + + APR_RING_INIT(&pollset->p->query_ring, pfd_elem_t, link); + APR_RING_INIT(&pollset->p->add_ring, pfd_elem_t, link); + APR_RING_INIT(&pollset->p->free_ring, pfd_elem_t, link); + APR_RING_INIT(&pollset->p->dead_ring, pfd_elem_t, link); + + return rv; +} + +static apr_status_t impl_pollset_add(apr_pollset_t *pollset, + const apr_pollfd_t *descriptor) +{ + apr_os_sock_t fd; + pfd_elem_t *elem; + int res; + apr_status_t rv = APR_SUCCESS; + + pollset_lock_rings(); + + if (!APR_RING_EMPTY(&(pollset->p->free_ring), pfd_elem_t, link)) { + elem = APR_RING_FIRST(&(pollset->p->free_ring)); + APR_RING_REMOVE(elem, link); + } + else { + elem = (pfd_elem_t *) apr_palloc(pollset->pool, sizeof(pfd_elem_t)); + APR_RING_ELEM_INIT(elem, link); + elem->on_query_ring = 0; + } + elem->pfd = *descriptor; + + if (descriptor->desc_type == APR_POLL_SOCKET) { + fd = descriptor->desc.s->socketdes; + } + else { + fd = descriptor->desc.f->filedes; + } + + /* If another thread is polling, notify the kernel immediately; otherwise, + * wait until the next call to apr_pollset_poll(). + */ + if (apr_atomic_read32(&pollset->p->waiting)) { + res = port_associate(pollset->p->port_fd, PORT_SOURCE_FD, fd, + get_event(descriptor->reqevents), (void *)elem); + + if (res < 0) { + rv = apr_get_netos_error(); + APR_RING_INSERT_TAIL(&(pollset->p->free_ring), elem, pfd_elem_t, link); + } + else { + elem->on_query_ring = 1; + APR_RING_INSERT_TAIL(&(pollset->p->query_ring), elem, pfd_elem_t, link); + } + } + else { + APR_RING_INSERT_TAIL(&(pollset->p->add_ring), elem, pfd_elem_t, link); + } + + pollset_unlock_rings(); + + return rv; +} + +static apr_status_t impl_pollset_remove(apr_pollset_t *pollset, + const apr_pollfd_t *descriptor) +{ + apr_os_sock_t fd; + pfd_elem_t *ep; + apr_status_t rv = APR_SUCCESS; + int res; + int err = 0; + int found; + + pollset_lock_rings(); + + if (descriptor->desc_type == APR_POLL_SOCKET) { + fd = descriptor->desc.s->socketdes; + } + else { + fd = descriptor->desc.f->filedes; + } + + /* Search the add ring first. This ring is often shorter, + * and it often contains the descriptor being removed. + * (For the common scenario where apr_pollset_poll() + * returns activity for the descriptor and the descriptor + * is then removed from the pollset, it will have just + * been moved to the add ring by apr_pollset_poll().) + * + * If it is on the add ring, it isn't associated with the + * event port yet/anymore. + */ + found = 0; + for (ep = APR_RING_FIRST(&(pollset->p->add_ring)); + ep != APR_RING_SENTINEL(&(pollset->p->add_ring), + pfd_elem_t, link); + ep = APR_RING_NEXT(ep, link)) { + + if (descriptor->desc.s == ep->pfd.desc.s) { + found = 1; + APR_RING_REMOVE(ep, link); + APR_RING_INSERT_TAIL(&(pollset->p->free_ring), + ep, pfd_elem_t, link); + break; + } + } + + if (!found) { + res = port_dissociate(pollset->p->port_fd, PORT_SOURCE_FD, fd); + + if (res < 0) { + /* The expected case for this failure is that another + * thread's call to port_getn() returned this fd and + * disassociated the fd from the event port, and + * impl_pollset_poll() is blocked on the ring lock, + * which this thread holds. + */ + err = errno; + rv = APR_NOTFOUND; + } + + for (ep = APR_RING_FIRST(&(pollset->p->query_ring)); + ep != APR_RING_SENTINEL(&(pollset->p->query_ring), + pfd_elem_t, link); + ep = APR_RING_NEXT(ep, link)) { + + if (descriptor->desc.s == ep->pfd.desc.s) { + APR_RING_REMOVE(ep, link); + ep->on_query_ring = 0; + APR_RING_INSERT_TAIL(&(pollset->p->dead_ring), + ep, pfd_elem_t, link); + if (ENOENT == err) { + rv = APR_SUCCESS; + } + break; + } + } + } + + pollset_unlock_rings(); + + return rv; +} + +static apr_status_t impl_pollset_poll(apr_pollset_t *pollset, + apr_interval_time_t timeout, + apr_int32_t *num, + const apr_pollfd_t **descriptors) +{ + apr_os_sock_t fd; + int ret; + unsigned int nget, i; + apr_int32_t j; + pfd_elem_t *ep; + apr_status_t rv = APR_SUCCESS; + + *num = 0; + nget = 1; + + pollset_lock_rings(); + + apr_atomic_inc32(&pollset->p->waiting); + + while (!APR_RING_EMPTY(&(pollset->p->add_ring), pfd_elem_t, link)) { + ep = APR_RING_FIRST(&(pollset->p->add_ring)); + APR_RING_REMOVE(ep, link); + + if (ep->pfd.desc_type == APR_POLL_SOCKET) { + fd = ep->pfd.desc.s->socketdes; + } + else { + fd = ep->pfd.desc.f->filedes; + } + + ret = port_associate(pollset->p->port_fd, PORT_SOURCE_FD, + fd, get_event(ep->pfd.reqevents), ep); + if (ret < 0) { + rv = apr_get_netos_error(); + APR_RING_INSERT_TAIL(&(pollset->p->free_ring), ep, pfd_elem_t, link); + break; + } + + ep->on_query_ring = 1; + APR_RING_INSERT_TAIL(&(pollset->p->query_ring), ep, pfd_elem_t, link); + } + + pollset_unlock_rings(); + + if (rv != APR_SUCCESS) { + apr_atomic_dec32(&pollset->p->waiting); + return rv; + } + + rv = call_port_getn(pollset->p->port_fd, pollset->p->port_set, + pollset->nalloc, &nget, timeout); + + /* decrease the waiting ASAP to reduce the window for calling + port_associate within apr_pollset_add() */ + apr_atomic_dec32(&pollset->p->waiting); + + pollset_lock_rings(); + + for (i = 0, j = 0; i < nget; i++) { + ep = (pfd_elem_t *)pollset->p->port_set[i].portev_user; + if ((pollset->flags & APR_POLLSET_WAKEABLE) && + ep->pfd.desc_type == APR_POLL_FILE && + ep->pfd.desc.f == pollset->wakeup_pipe[0]) { + apr_poll_drain_wakeup_pipe(pollset->wakeup_pipe); + rv = APR_EINTR; + } + else { + pollset->p->result_set[j] = ep->pfd; + pollset->p->result_set[j].rtnevents = + get_revent(pollset->p->port_set[i].portev_events); + j++; + } + /* If the ring element is still on the query ring, move it + * to the add ring for re-association with the event port + * later. (It may have already been moved to the dead ring + * by a call to pollset_remove on another thread.) + */ + if (ep->on_query_ring) { + APR_RING_REMOVE(ep, link); + ep->on_query_ring = 0; + APR_RING_INSERT_TAIL(&(pollset->p->add_ring), ep, + pfd_elem_t, link); + } + } + if ((*num = j)) { /* any event besides wakeup pipe? */ + rv = APR_SUCCESS; + if (descriptors) { + *descriptors = pollset->p->result_set; + } + } + + /* Shift all PFDs in the Dead Ring to the Free Ring */ + APR_RING_CONCAT(&(pollset->p->free_ring), &(pollset->p->dead_ring), pfd_elem_t, link); + + pollset_unlock_rings(); + + return rv; +} + +static const apr_pollset_provider_t impl = { + impl_pollset_create, + impl_pollset_add, + impl_pollset_remove, + impl_pollset_poll, + impl_pollset_cleanup, + "port" +}; + +const apr_pollset_provider_t *apr_pollset_provider_port = &impl; + +static apr_status_t impl_pollcb_cleanup(apr_pollcb_t *pollcb) +{ + close(pollcb->fd); + return APR_SUCCESS; +} + +static apr_status_t impl_pollcb_create(apr_pollcb_t *pollcb, + apr_uint32_t size, + apr_pool_t *p, + apr_uint32_t flags) +{ + pollcb->fd = port_create(); + + if (pollcb->fd < 0) { + return apr_get_netos_error(); + } + + { + int flags; + apr_status_t rv; + + if ((flags = fcntl(pollcb->fd, F_GETFD)) == -1) { + rv = errno; + close(pollcb->fd); + pollcb->fd = -1; + return rv; + } + + flags |= FD_CLOEXEC; + if (fcntl(pollcb->fd, F_SETFD, flags) == -1) { + rv = errno; + close(pollcb->fd); + pollcb->fd = -1; + return rv; + } + } + + pollcb->pollset.port = apr_palloc(p, size * sizeof(port_event_t)); + + return APR_SUCCESS; +} + +static apr_status_t impl_pollcb_add(apr_pollcb_t *pollcb, + apr_pollfd_t *descriptor) +{ + int ret, fd; + + if (descriptor->desc_type == APR_POLL_SOCKET) { + fd = descriptor->desc.s->socketdes; + } + else { + fd = descriptor->desc.f->filedes; + } + + ret = port_associate(pollcb->fd, PORT_SOURCE_FD, fd, + get_event(descriptor->reqevents), descriptor); + + if (ret == -1) { + return apr_get_netos_error(); + } + + return APR_SUCCESS; +} + +static apr_status_t impl_pollcb_remove(apr_pollcb_t *pollcb, + apr_pollfd_t *descriptor) +{ + int fd, ret; + + if (descriptor->desc_type == APR_POLL_SOCKET) { + fd = descriptor->desc.s->socketdes; + } + else { + fd = descriptor->desc.f->filedes; + } + + ret = port_dissociate(pollcb->fd, PORT_SOURCE_FD, fd); + + if (ret < 0) { + return APR_NOTFOUND; + } + + return APR_SUCCESS; +} + +static apr_status_t impl_pollcb_poll(apr_pollcb_t *pollcb, + apr_interval_time_t timeout, + apr_pollcb_cb_t func, + void *baton) +{ + apr_status_t rv; + unsigned int nget = 1; + + rv = call_port_getn(pollcb->fd, pollcb->pollset.port, pollcb->nalloc, + &nget, timeout); + + if (nget) { + unsigned int i; + + for (i = 0; i < nget; i++) { + apr_pollfd_t *pollfd = (apr_pollfd_t *)(pollcb->pollset.port[i].portev_user); + + if ((pollcb->flags & APR_POLLSET_WAKEABLE) && + pollfd->desc_type == APR_POLL_FILE && + pollfd->desc.f == pollcb->wakeup_pipe[0]) { + apr_poll_drain_wakeup_pipe(pollcb->wakeup_pipe); + return APR_EINTR; + } + + pollfd->rtnevents = get_revent(pollcb->pollset.port[i].portev_events); + + rv = func(baton, pollfd); + if (rv) { + return rv; + } + rv = apr_pollcb_add(pollcb, pollfd); + } + } + + return rv; +} + +static const apr_pollcb_provider_t impl_cb = { + impl_pollcb_create, + impl_pollcb_add, + impl_pollcb_remove, + impl_pollcb_poll, + impl_pollcb_cleanup, + "port" +}; + +const apr_pollcb_provider_t *apr_pollcb_provider_port = &impl_cb; + +#endif /* HAVE_PORT_CREATE */ diff --git a/poll/unix/select.c b/poll/unix/select.c new file mode 100644 index 00000000000..51be3c1cd5f --- /dev/null +++ b/poll/unix/select.c @@ -0,0 +1,449 @@ +/* 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. + */ + +#ifdef WIN32 +/* POSIX defines 1024 for the FD_SETSIZE */ +#define FD_SETSIZE 1024 +#endif + +#include "apr.h" +#include "apr_poll.h" +#include "apr_time.h" +#include "apr_portable.h" +#include "apr_arch_file_io.h" +#include "apr_arch_networkio.h" +#include "apr_arch_poll_private.h" + +#ifdef POLL_USES_SELECT + +APR_DECLARE(apr_status_t) apr_poll(apr_pollfd_t *aprset, int num, + apr_int32_t *nsds, + apr_interval_time_t timeout) +{ + fd_set readset, writeset, exceptset; + int rv, i; + int maxfd = -1; + struct timeval tv, *tvptr; +#ifdef NETWARE + apr_datatype_e set_type = APR_NO_DESC; +#endif + +#ifdef WIN32 + /* On Win32, select() must be presented with at least one socket to + * poll on, or select() will return WSAEINVAL. So, we'll just + * short-circuit and bail now. + */ + if (num == 0) { + (*nsds) = 0; + if (timeout > 0) { + apr_sleep(timeout); + return APR_TIMEUP; + } + return APR_SUCCESS; + } +#endif + + if (timeout < 0) { + tvptr = NULL; + } + else { + tv.tv_sec = (long) apr_time_sec(timeout); + tv.tv_usec = (long) apr_time_usec(timeout); + tvptr = &tv; + } + + FD_ZERO(&readset); + FD_ZERO(&writeset); + FD_ZERO(&exceptset); + + for (i = 0; i < num; i++) { + apr_os_sock_t fd; + + aprset[i].rtnevents = 0; + + if (aprset[i].desc_type == APR_POLL_SOCKET) { +#ifdef NETWARE + if (HAS_PIPES(set_type)) { + return APR_EBADF; + } + else { + set_type = APR_POLL_SOCKET; + } +#endif + fd = aprset[i].desc.s->socketdes; + } + else if (aprset[i].desc_type == APR_POLL_FILE) { +#if !APR_FILES_AS_SOCKETS + return APR_EBADF; +#else +#ifdef NETWARE + if (aprset[i].desc.f->is_pipe && !HAS_SOCKETS(set_type)) { + set_type = APR_POLL_FILE; + } + else + return APR_EBADF; +#endif /* NETWARE */ + + fd = aprset[i].desc.f->filedes; + +#endif /* APR_FILES_AS_SOCKETS */ + } + else { + break; + } +#if !defined(WIN32) && !defined(NETWARE) /* socket sets handled with array of handles */ + if (fd >= FD_SETSIZE) { + /* XXX invent new error code so application has a clue */ + return APR_EBADF; + } +#endif + if (aprset[i].reqevents & APR_POLLIN) { + FD_SET(fd, &readset); + } + if (aprset[i].reqevents & APR_POLLOUT) { + FD_SET(fd, &writeset); + } + if (aprset[i].reqevents & + (APR_POLLPRI | APR_POLLERR | APR_POLLHUP | APR_POLLNVAL)) { + FD_SET(fd, &exceptset); + } + if ((int) fd > maxfd) { + maxfd = (int) fd; + } + } + +#ifdef NETWARE + if (HAS_PIPES(set_type)) { + rv = pipe_select(maxfd + 1, &readset, &writeset, &exceptset, tvptr); + } + else { +#endif + + rv = select(maxfd + 1, &readset, &writeset, &exceptset, tvptr); + +#ifdef NETWARE + } +#endif + + (*nsds) = rv; + if ((*nsds) == 0) { + return APR_TIMEUP; + } + if ((*nsds) < 0) { + return apr_get_netos_error(); + } + + (*nsds) = 0; + for (i = 0; i < num; i++) { + apr_os_sock_t fd; + + if (aprset[i].desc_type == APR_POLL_SOCKET) { + fd = aprset[i].desc.s->socketdes; + } + else if (aprset[i].desc_type == APR_POLL_FILE) { +#if !APR_FILES_AS_SOCKETS + return APR_EBADF; +#else + fd = aprset[i].desc.f->filedes; +#endif + } + else { + break; + } + if (FD_ISSET(fd, &readset)) { + aprset[i].rtnevents |= APR_POLLIN; + } + if (FD_ISSET(fd, &writeset)) { + aprset[i].rtnevents |= APR_POLLOUT; + } + if (FD_ISSET(fd, &exceptset)) { + aprset[i].rtnevents |= APR_POLLERR; + } + if (aprset[i].rtnevents) { + (*nsds)++; + } + } + + return APR_SUCCESS; +} + +#endif /* POLL_USES_SELECT */ + +struct apr_pollset_private_t +{ + fd_set readset, writeset, exceptset; + int maxfd; + apr_pollfd_t *query_set; + apr_pollfd_t *result_set; + apr_uint32_t flags; +#ifdef NETWARE + int set_type; +#endif +}; + +static apr_status_t impl_pollset_create(apr_pollset_t *pollset, + apr_uint32_t size, + apr_pool_t *p, + apr_uint32_t flags) +{ + if (flags & APR_POLLSET_THREADSAFE) { + pollset->p = NULL; + return APR_ENOTIMPL; + } +#ifdef FD_SETSIZE + if (size > FD_SETSIZE) { + pollset->p = NULL; + return APR_EINVAL; + } +#endif + pollset->p = apr_palloc(p, sizeof(apr_pollset_private_t)); + FD_ZERO(&(pollset->p->readset)); + FD_ZERO(&(pollset->p->writeset)); + FD_ZERO(&(pollset->p->exceptset)); + pollset->p->maxfd = 0; +#ifdef NETWARE + pollset->p->set_type = APR_NO_DESC; +#endif + pollset->p->query_set = apr_palloc(p, size * sizeof(apr_pollfd_t)); + pollset->p->result_set = apr_palloc(p, size * sizeof(apr_pollfd_t)); + + return APR_SUCCESS; +} + +static apr_status_t impl_pollset_add(apr_pollset_t *pollset, + const apr_pollfd_t *descriptor) +{ + apr_os_sock_t fd; + + if (pollset->nelts == pollset->nalloc) { + return APR_ENOMEM; + } + + pollset->p->query_set[pollset->nelts] = *descriptor; + + if (descriptor->desc_type == APR_POLL_SOCKET) { +#ifdef NETWARE + /* NetWare can't handle mixed descriptor types in select() */ + if (HAS_PIPES(pollset->p->set_type)) { + return APR_EBADF; + } + else { + pollset->p->set_type = APR_POLL_SOCKET; + } +#endif + fd = descriptor->desc.s->socketdes; + } + else { +#if !APR_FILES_AS_SOCKETS + if ((pollset->flags & APR_POLLSET_WAKEABLE) && + descriptor->desc.f == pollset->wakeup_pipe[0]) + fd = (apr_os_sock_t)descriptor->desc.f->filedes; + else + return APR_EBADF; +#else +#ifdef NETWARE + /* NetWare can't handle mixed descriptor types in select() */ + if (descriptor->desc.f->is_pipe && !HAS_SOCKETS(pollset->p->set_type)) { + pollset->p->set_type = APR_POLL_FILE; + fd = descriptor->desc.f->filedes; + } + else { + return APR_EBADF; + } +#else + fd = descriptor->desc.f->filedes; +#endif +#endif + } +#if !defined(WIN32) && !defined(NETWARE) /* socket sets handled with array of handles */ + if (fd >= FD_SETSIZE) { + /* XXX invent new error code so application has a clue */ + return APR_EBADF; + } +#endif + if (descriptor->reqevents & APR_POLLIN) { + FD_SET(fd, &(pollset->p->readset)); + } + if (descriptor->reqevents & APR_POLLOUT) { + FD_SET(fd, &(pollset->p->writeset)); + } + if (descriptor->reqevents & + (APR_POLLPRI | APR_POLLERR | APR_POLLHUP | APR_POLLNVAL)) { + FD_SET(fd, &(pollset->p->exceptset)); + } + if ((int) fd > pollset->p->maxfd) { + pollset->p->maxfd = (int) fd; + } + pollset->nelts++; + return APR_SUCCESS; +} + +static apr_status_t impl_pollset_remove(apr_pollset_t * pollset, + const apr_pollfd_t * descriptor) +{ + apr_uint32_t i; + apr_os_sock_t fd; + + if (descriptor->desc_type == APR_POLL_SOCKET) { + fd = descriptor->desc.s->socketdes; + } + else { +#if !APR_FILES_AS_SOCKETS + return APR_EBADF; +#else + fd = descriptor->desc.f->filedes; +#endif + } + + for (i = 0; i < pollset->nelts; i++) { + if (descriptor->desc.s == pollset->p->query_set[i].desc.s) { + /* Found an instance of the fd: remove this and any other copies */ + apr_uint32_t dst = i; + apr_uint32_t old_nelts = pollset->nelts; + pollset->nelts--; + for (i++; i < old_nelts; i++) { + if (descriptor->desc.s == pollset->p->query_set[i].desc.s) { + pollset->nelts--; + } + else { + pollset->p->query_set[dst] = pollset->p->query_set[i]; + dst++; + } + } + FD_CLR(fd, &(pollset->p->readset)); + FD_CLR(fd, &(pollset->p->writeset)); + FD_CLR(fd, &(pollset->p->exceptset)); + if (((int) fd == pollset->p->maxfd) && (pollset->p->maxfd > 0)) { + pollset->p->maxfd--; + } + return APR_SUCCESS; + } + } + + return APR_NOTFOUND; +} + +static apr_status_t impl_pollset_poll(apr_pollset_t *pollset, + apr_interval_time_t timeout, + apr_int32_t *num, + const apr_pollfd_t **descriptors) +{ + int rs; + apr_uint32_t i, j; + struct timeval tv, *tvptr; + fd_set readset, writeset, exceptset; + apr_status_t rv = APR_SUCCESS; + + *num = 0; + +#ifdef WIN32 + /* On Win32, select() must be presented with at least one socket to + * poll on, or select() will return WSAEINVAL. So, we'll just + * short-circuit and bail now. + */ + if (pollset->nelts == 0) { + if (timeout > 0) { + apr_sleep(timeout); + return APR_TIMEUP; + } + return APR_SUCCESS; + } +#endif + + if (timeout < 0) { + tvptr = NULL; + } + else { + tv.tv_sec = (long) apr_time_sec(timeout); + tv.tv_usec = (long) apr_time_usec(timeout); + tvptr = &tv; + } + + memcpy(&readset, &(pollset->p->readset), sizeof(fd_set)); + memcpy(&writeset, &(pollset->p->writeset), sizeof(fd_set)); + memcpy(&exceptset, &(pollset->p->exceptset), sizeof(fd_set)); + +#ifdef NETWARE + if (HAS_PIPES(pollset->p->set_type)) { + rs = pipe_select(pollset->p->maxfd + 1, &readset, &writeset, &exceptset, + tvptr); + } + else +#endif + rs = select(pollset->p->maxfd + 1, &readset, &writeset, &exceptset, + tvptr); + + if (rs < 0) { + return apr_get_netos_error(); + } + if (rs == 0) { + return APR_TIMEUP; + } + j = 0; + for (i = 0; i < pollset->nelts; i++) { + apr_os_sock_t fd; + if (pollset->p->query_set[i].desc_type == APR_POLL_SOCKET) { + fd = pollset->p->query_set[i].desc.s->socketdes; + } + else { + if ((pollset->flags & APR_POLLSET_WAKEABLE) && + pollset->p->query_set[i].desc.f == pollset->wakeup_pipe[0]) { + apr_poll_drain_wakeup_pipe(pollset->wakeup_pipe); + rv = APR_EINTR; + continue; + } + else { +#if !APR_FILES_AS_SOCKETS + return APR_EBADF; +#else + fd = pollset->p->query_set[i].desc.f->filedes; +#endif + } + } + if (FD_ISSET(fd, &readset) || FD_ISSET(fd, &writeset) || + FD_ISSET(fd, &exceptset)) { + pollset->p->result_set[j] = pollset->p->query_set[i]; + pollset->p->result_set[j].rtnevents = 0; + if (FD_ISSET(fd, &readset)) { + pollset->p->result_set[j].rtnevents |= APR_POLLIN; + } + if (FD_ISSET(fd, &writeset)) { + pollset->p->result_set[j].rtnevents |= APR_POLLOUT; + } + if (FD_ISSET(fd, &exceptset)) { + pollset->p->result_set[j].rtnevents |= APR_POLLERR; + } + j++; + } + } + if (((*num) = j) != 0) + rv = APR_SUCCESS; + + if (descriptors) + *descriptors = pollset->p->result_set; + return rv; +} + +static const apr_pollset_provider_t impl = { + impl_pollset_create, + impl_pollset_add, + impl_pollset_remove, + impl_pollset_poll, + NULL, + "select" +}; + +const apr_pollset_provider_t *apr_pollset_provider_select = &impl; diff --git a/poll/unix/wakeup.c b/poll/unix/wakeup.c new file mode 100644 index 00000000000..f8ea0604842 --- /dev/null +++ b/poll/unix/wakeup.c @@ -0,0 +1,151 @@ +/* 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_poll.h" +#include "apr_time.h" +#include "apr_portable.h" +#include "apr_arch_file_io.h" +#include "apr_arch_networkio.h" +#include "apr_arch_poll_private.h" +#include "apr_arch_inherit.h" + +#if !APR_FILES_AS_SOCKETS + +#ifdef WIN32 + +apr_status_t apr_poll_create_wakeup_pipe(apr_pool_t *pool, apr_pollfd_t *pfd, + apr_file_t **wakeup_pipe) +{ + apr_status_t rv; + + if ((rv = file_socket_pipe_create(&wakeup_pipe[0], &wakeup_pipe[1], + pool)) != APR_SUCCESS) + return rv; + + pfd->reqevents = APR_POLLIN; + pfd->desc_type = APR_POLL_FILE; + pfd->desc.f = wakeup_pipe[0]; + return APR_SUCCESS; +} + +apr_status_t apr_poll_close_wakeup_pipe(apr_file_t **wakeup_pipe) +{ + apr_status_t rv0 = APR_SUCCESS; + apr_status_t rv1 = APR_SUCCESS; + + /* Close both sides of the wakeup pipe */ + if (wakeup_pipe[0]) { + rv0 = file_socket_pipe_close(wakeup_pipe[0]); + wakeup_pipe[0] = NULL; + } + if (wakeup_pipe[1]) { + rv1 = file_socket_pipe_close(wakeup_pipe[1]); + wakeup_pipe[1] = NULL; + } + return rv0 ? rv0 : rv1; +} + +#else /* !WIN32 */ + +apr_status_t apr_poll_create_wakeup_pipe(apr_pollfd_t *pfd, apr_file_t **wakeup_pipe) +{ + return APR_ENOTIMPL; +} + +apr_status_t apr_poll_close_wakeup_pipe(apr_file_t **wakeup_pipe) +{ + return APR_ENOTIMPL; +} + +#endif /* !WIN32 */ + +#else /* APR_FILES_AS_SOCKETS */ + +apr_status_t apr_poll_create_wakeup_pipe(apr_pool_t *pool, apr_pollfd_t *pfd, + apr_file_t **wakeup_pipe) +{ + apr_status_t rv; + + if ((rv = apr_file_pipe_create(&wakeup_pipe[0], &wakeup_pipe[1], + pool)) != APR_SUCCESS) + return rv; + + pfd->p = pool; + pfd->reqevents = APR_POLLIN; + pfd->desc_type = APR_POLL_FILE; + pfd->desc.f = wakeup_pipe[0]; + + { + int flags; + + if ((flags = fcntl(wakeup_pipe[0]->filedes, F_GETFD)) == -1) + return errno; + + flags |= FD_CLOEXEC; + if (fcntl(wakeup_pipe[0]->filedes, F_SETFD, flags) == -1) + return errno; + } + { + int flags; + + if ((flags = fcntl(wakeup_pipe[1]->filedes, F_GETFD)) == -1) + return errno; + + flags |= FD_CLOEXEC; + if (fcntl(wakeup_pipe[1]->filedes, F_SETFD, flags) == -1) + return errno; + } + + return APR_SUCCESS; +} + +apr_status_t apr_poll_close_wakeup_pipe(apr_file_t **wakeup_pipe) +{ + apr_status_t rv0 = APR_SUCCESS; + apr_status_t rv1 = APR_SUCCESS; + + /* Close both sides of the wakeup pipe */ + if (wakeup_pipe[0]) { + rv0 = apr_file_close(wakeup_pipe[0]); + wakeup_pipe[0] = NULL; + } + if (wakeup_pipe[1]) { + rv1 = apr_file_close(wakeup_pipe[1]); + wakeup_pipe[1] = NULL; + } + return rv0 ? rv0 : rv1; +} + +#endif /* APR_FILES_AS_SOCKETS */ + +/* Read and discard whatever is in the wakeup pipe. + */ +void apr_poll_drain_wakeup_pipe(apr_file_t **wakeup_pipe) +{ + char rb[512]; + apr_size_t nr = sizeof(rb); + + while (apr_file_read(wakeup_pipe[0], rb, &nr) == APR_SUCCESS) { + /* Although we write just one byte to the other end of the pipe + * during wakeup, multiple threads could call the wakeup. + * So simply drain out from the input side of the pipe all + * the data. + */ + if (nr != sizeof(rb)) + break; + } +} diff --git a/poll/unix/z_asio.c b/poll/unix/z_asio.c new file mode 100644 index 00000000000..48b531cc8c7 --- /dev/null +++ b/poll/unix/z_asio.c @@ -0,0 +1,782 @@ +/* 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. + * + * + ****************************************************************************** + * + * This implementation is based on a design by John Brooks (IBM Pok) which uses + * the z/OS sockets async i/o facility. When a + * socket is added to the pollset, an async poll is issued for that individual + * socket. It specifies that the kernel should send an IPC message when the + * socket becomes ready. The IPC messages are sent to a single message queue + * that is part of the pollset. apr_pollset_poll waits on the arrival of IPC + * messages or the specified timeout. + * + * Since z/OS does not support async i/o for pipes or files at present, this + * implementation falls back to using ordinary poll() when + * APR_POLLSET_THREADSAFE is unset. + * + * Greg Ames + * April 2012 + */ + +#include "apr.h" +#include "apr_hash.h" +#include "apr_poll.h" +#include "apr_time.h" +#include "apr_portable.h" +#include "apr_arch_inherit.h" +#include "apr_arch_file_io.h" +#include "apr_arch_networkio.h" +#include "apr_arch_poll_private.h" + +#ifdef HAVE_AIO_MSGQ + +#include <sys/msg.h> /* msgget etc */ +#include <time.h> /* timestruct */ +#include <poll.h> /* pollfd */ +#include <limits.h> /* MAX_INT */ + +struct apr_pollset_private_t +{ + int msg_q; /* IPC message queue. The z/OS kernel sends messages + * to this queue when our async polls on individual + * file descriptors complete + */ + apr_pollfd_t *result_set; + apr_uint32_t size; + +#if APR_HAS_THREADS + /* A thread mutex to protect operations on the rings and the hash */ + apr_thread_mutex_t *ring_lock; +#endif + + /* A hash of all active elements used for O(1) _remove operations */ + apr_hash_t *elems; + + APR_RING_HEAD(ready_ring_t, asio_elem_t) ready_ring; + APR_RING_HEAD(prior_ready_ring_t, asio_elem_t) prior_ready_ring; + APR_RING_HEAD(free_ring_t, asio_elem_t) free_ring; + + /* for pipes etc with no asio */ + struct pollfd *pollset; + apr_pollfd_t *query_set; +}; + +typedef enum { + ASIO_INIT = 0, + ASIO_REMOVED, + ASIO_COMPLETE +} asio_state_e; + +typedef struct asio_elem_t asio_elem_t; + +struct asio_msgbuf_t { + long msg_type; /* must be > 0 */ + asio_elem_t *msg_elem; +}; + +struct asio_elem_t +{ + APR_RING_ENTRY(asio_elem_t) link; + apr_pollfd_t pfd; + struct pollfd os_pfd; + struct aiocb a; + asio_state_e state; + struct asio_msgbuf_t msg; +}; + +#define DEBUG 0 + +/* DEBUG settings: 0 - no debug messages at all, + * 1 - should not occur messages, + * 2 - apr_pollset_* entry and exit messages, + * 3 - state changes, memory usage, + * 4 - z/OS, APR, and internal calls, + * 5 - everything else except the timer pop path, + * 6 - everything, including the Event 1 sec timer pop path + * + * each DEBUG level includes all messages produced by lower numbered levels + */ + +#if DEBUG + +#include <assert.h> +#include <unistd.h> /* getpid */ + +#define DBG_BUFF char dbg_msg_buff[256]; + +#define DBG_TEST(lvl) if (lvl <= DEBUG) { + +#define DBG_CORE(msg) sprintf(dbg_msg_buff, "% 8d " __FUNCTION__ \ + " " msg, getpid()), \ + fprintf(stderr, "%s", dbg_msg_buff); +#define DBG_CORE1(msg, var1) sprintf(dbg_msg_buff, "% 8d " __FUNCTION__ \ + " " msg, getpid(), var1), \ + fprintf(stderr, "%s", dbg_msg_buff); +#define DBG_CORE2(msg, var1, var2) sprintf(dbg_msg_buff, "% 8d " __FUNCTION__ \ + " " msg, getpid(), var1, var2), \ + fprintf(stderr, "%s", dbg_msg_buff); +#define DBG_CORE3(msg, var1, var2, var3) \ + sprintf(dbg_msg_buff, "% 8d " __FUNCTION__ \ + " " msg, getpid(), var1, var2, var3), \ + fprintf(stderr, "%s", dbg_msg_buff); +#define DBG_CORE4(msg, var1, var2, var3, var4) \ + sprintf(dbg_msg_buff, "% 8d " __FUNCTION__ \ + " " msg, getpid(), var1, var2, var3, var4),\ + fprintf(stderr, "%s", dbg_msg_buff); + +#define DBG_END } + +#define DBG(lvl, msg) DBG_TEST(lvl) \ + DBG_CORE(msg) \ + DBG_END + +#define DBG1(lvl, msg, var1) DBG_TEST(lvl) \ + DBG_CORE1(msg, var1) \ + DBG_END + +#define DBG2(lvl, msg, var1, var2) DBG_TEST(lvl) \ + DBG_CORE2(msg, var1, var2) \ + DBG_END + +#define DBG3(lvl, msg, var1, var2, var3) \ + DBG_TEST(lvl) \ + DBG_CORE3(msg, var1, var2, var3) \ + DBG_END + +#define DBG4(lvl, msg, var1, var2, var3, var4) \ + DBG_TEST(lvl) \ + DBG_CORE4(msg, var1, var2, var3, var4) \ + DBG_END + +#else /* DEBUG is 0 */ +#define DBG_BUFF +#define DBG(lvl, msg) ((void)0) +#define DBG1(lvl, msg, var1) ((void)0) +#define DBG2(lvl, msg, var1, var2) ((void)0) +#define DBG3(lvl, msg, var1, var2, var3) ((void)0) +#define DBG4(lvl, msg, var1, var2, var3, var4) ((void)0) + +#endif /* DEBUG */ + +static int asyncio(struct aiocb *a) +{ + DBG_BUFF + int rv; + +#ifdef _LP64 +#define AIO BPX4AIO +#else +#define AIO BPX1AIO +#endif + + AIO(sizeof(struct aiocb), a, &rv, &errno, __err2ad()); + DBG2(4, "BPX4AIO aiocb %p rv %d\n", + a, rv); +#ifdef DEBUG + if (rv < 0) { + DBG2(4, "errno %d errnojr %08x\n", + errno, *__err2ad()); + } +#endif + return rv; +} + +static apr_int16_t get_event(apr_int16_t event) +{ + DBG_BUFF + apr_int16_t rv = 0; + DBG(4, "entered\n"); + + if (event & APR_POLLIN) + rv |= POLLIN; + if (event & APR_POLLPRI) + rv |= POLLPRI; + if (event & APR_POLLOUT) + rv |= POLLOUT; + if (event & APR_POLLERR) + rv |= POLLERR; + if (event & APR_POLLHUP) + rv |= POLLHUP; + if (event & APR_POLLNVAL) + rv |= POLLNVAL; + + DBG(4, "exiting\n"); + return rv; +} + +static apr_int16_t get_revent(apr_int16_t event) +{ + DBG_BUFF + apr_int16_t rv = 0; + DBG(4, "entered\n"); + + if (event & POLLIN) + rv |= APR_POLLIN; + if (event & POLLPRI) + rv |= APR_POLLPRI; + if (event & POLLOUT) + rv |= APR_POLLOUT; + if (event & POLLERR) + rv |= APR_POLLERR; + if (event & POLLHUP) + rv |= APR_POLLHUP; + if (event & POLLNVAL) + rv |= APR_POLLNVAL; + + DBG(4, "exiting\n"); + return rv; +} + +static apr_status_t asio_pollset_cleanup(apr_pollset_t *pollset) +{ + DBG_BUFF + int rv; + + DBG(4, "entered\n"); + if (pollset->flags & APR_POLLSET_THREADSAFE) { + rv = msgctl(pollset->p->msg_q, IPC_RMID, NULL); + DBG1(4, "asio_pollset_cleanup: msgctl(IPC_RMID) returned %d\n", rv); + } + + return rv; +} + +static apr_status_t asio_pollset_create(apr_pollset_t *pollset, + apr_uint32_t size, + apr_pool_t *p, + apr_uint32_t flags) +{ + DBG_BUFF + apr_status_t rv; + apr_pollset_private_t *priv; + + DBG1(2, "entered, flags: %x\n", flags); + + priv = pollset->p = apr_pcalloc(p, sizeof(*priv)); + + if (flags & APR_POLLSET_THREADSAFE) { +#if APR_HAS_THREADS + if ((rv = apr_thread_mutex_create(&(priv->ring_lock), + APR_THREAD_MUTEX_DEFAULT, + p)) != APR_SUCCESS) { + DBG1(1, "apr_thread_mutex_create returned %d\n", rv); + pollset->p = NULL; + return rv; + } + rv = msgget(IPC_PRIVATE, S_IWUSR+S_IRUSR); /* user r/w perms */ + if (rv < 0) { +#if DEBUG + perror(__FUNCTION__ " msgget returned < 0 "); +#endif + pollset->p = NULL; + return rv; + } + + DBG2(4, "pollset %p msgget was OK, rv=%d\n", pollset, rv); + priv->msg_q = rv; + priv->elems = apr_hash_make(p); + + APR_RING_INIT(&priv->free_ring, asio_elem_t, link); + APR_RING_INIT(&priv->prior_ready_ring, asio_elem_t, link); + +#else /* APR doesn't have threads but caller wants a threadsafe pollset */ + pollset->p = NULL; + return APR_ENOTIMPL; +#endif + + } else { /* APR_POLLSET_THREADSAFE not set, i.e. no async i/o, + * init fields only needed in old style pollset + */ + + priv->pollset = apr_palloc(p, size * sizeof(struct pollfd)); + priv->query_set = apr_palloc(p, size * sizeof(apr_pollfd_t)); + + if ((!priv->pollset) || (!priv->query_set)) { + pollset->p = NULL; + return APR_ENOMEM; + } + } + + pollset->nelts = 0; + pollset->flags = flags; + pollset->pool = p; + priv->size = size; + priv->result_set = apr_palloc(p, size * sizeof(apr_pollfd_t)); + if (!priv->result_set) { + if (flags & APR_POLLSET_THREADSAFE) { + msgctl(priv->msg_q, IPC_RMID, NULL); + } + pollset->p = NULL; + return APR_ENOMEM; + } + + DBG2(2, "exiting, pollset: %p, type: %s\n", + pollset, + flags & APR_POLLSET_THREADSAFE ? "async" : "POSIX"); + + + return APR_SUCCESS; + +} /* end of asio_pollset_create */ + +static apr_status_t posix_add(apr_pollset_t *pollset, + const apr_pollfd_t *descriptor) +{ + DBG_BUFF + int fd; + apr_pool_t *p = pollset->pool; + apr_pollset_private_t *priv = pollset->p; + + DBG(4, "entered\n"); + + if (pollset->nelts == priv->size) { + return APR_ENOMEM; + } + + priv->query_set[pollset->nelts] = *descriptor; + if (descriptor->desc_type == APR_POLL_SOCKET) { + fd = descriptor->desc.s->socketdes; + } + else { + fd = descriptor->desc.f->filedes; + } + + priv->pollset[pollset->nelts].fd = fd; + + priv->pollset[pollset->nelts].events = + get_event(descriptor->reqevents); + + pollset->nelts++; + + DBG2(4, "exiting, fd %d added to pollset %p\n", fd, pollset); + + return APR_SUCCESS; +} /* end of posix_add */ + + +static apr_status_t asio_pollset_add(apr_pollset_t *pollset, + const apr_pollfd_t *descriptor) +{ + DBG_BUFF + asio_elem_t *elem; + apr_status_t rv = APR_SUCCESS; + apr_pollset_private_t *priv = pollset->p; + + pollset_lock_rings(); + DBG(2, "entered\n"); + + if (pollset->flags & APR_POLLSET_THREADSAFE) { + + if (!APR_RING_EMPTY(&(priv->free_ring), asio_elem_t, link)) { + elem = APR_RING_FIRST(&(priv->free_ring)); + APR_RING_REMOVE(elem, link); + DBG1(3, "used recycled memory at %08p\n", elem); + elem->state = ASIO_INIT; + elem->a.aio_cflags = 0; + } + else { + elem = (asio_elem_t *) apr_pcalloc(pollset->pool, sizeof(asio_elem_t)); + DBG1(3, "alloced new memory at %08p\n", elem); + + elem->a.aio_notifytype = AIO_MSGQ; + elem->a.aio_msgev_qid = priv->msg_q; + DBG1(5, "aio_msgev_quid = %d \n", elem->a.aio_msgev_qid); + elem->a.aio_msgev_size = sizeof(asio_elem_t *); + elem->a.aio_msgev_flag = 0; /* wait if queue is full */ + elem->a.aio_msgev_addr = &(elem->msg); + elem->a.aio_buf = &(elem->os_pfd); + elem->a.aio_nbytes = 1; /* number of pfds to poll */ + elem->msg.msg_type = 1; + elem->msg.msg_elem = elem; + } + + /* z/OS only supports async I/O for sockets for now */ + elem->os_pfd.fd = descriptor->desc.s->socketdes; + + APR_RING_ELEM_INIT(elem, link); + elem->a.aio_cmd = AIO_SELPOLL; + elem->a.aio_cflags &= ~AIO_OK2COMPIMD; /* not OK to complete inline*/ + elem->pfd = *descriptor; + elem->os_pfd.events = get_event(descriptor->reqevents); + + if (0 != asyncio(&elem->a)) { + rv = errno; + DBG3(4, "pollset %p asio failed fd %d, errno %p\n", + pollset, elem->os_pfd.fd, rv); +#if DEBUG + perror(__FUNCTION__ " asio failure"); +#endif + } + else { + DBG2(4, "good asio call, adding fd %d to pollset %p\n", + elem->os_pfd.fd, pollset); + + pollset->nelts++; + apr_hash_set(priv->elems, &(elem->os_pfd.fd), sizeof(int), elem); + } + } + else { + /* APR_POLLSET_THREADSAFE isn't set. use POSIX poll in case + * pipes or files are used with this pollset + */ + + rv = posix_add(pollset, descriptor); + } + + DBG1(2, "exiting, rv = %d\n", rv); + + pollset_unlock_rings(); + return rv; +} /* end of asio_pollset_add */ + +static posix_remove(apr_pollset_t *pollset, const apr_pollfd_t *descriptor) +{ + DBG_BUFF + apr_uint32_t i; + apr_pollset_private_t *priv = pollset->p; + + DBG(4, "entered\n"); + for (i = 0; i < pollset->nelts; i++) { + if (descriptor->desc.s == priv->query_set[i].desc.s) { + /* Found an instance of the fd: remove this and any other copies */ + apr_uint32_t dst = i; + apr_uint32_t old_nelts = pollset->nelts; + pollset->nelts--; + for (i++; i < old_nelts; i++) { + if (descriptor->desc.s == priv->query_set[i].desc.s) { + pollset->nelts--; + } + else { + priv->pollset[dst] = priv->pollset[i]; + priv->query_set[dst] = priv->query_set[i]; + dst++; + } + } + DBG(4, "returning OK\n"); + return APR_SUCCESS; + } + } + + DBG(1, "returning APR_NOTFOUND\n"); + return APR_NOTFOUND; + +} /* end of posix_remove */ + +static apr_status_t asio_pollset_remove(apr_pollset_t *pollset, + const apr_pollfd_t *descriptor) +{ + DBG_BUFF + asio_elem_t *elem; + apr_status_t rv = APR_SUCCESS; + apr_pollset_private_t *priv = pollset->p; + /* AIO_CANCEL is synchronous, so autodata works fine. */ + struct aiocb cancel_a = {0}; + + int fd; + + DBG(2, "entered\n"); + + if (!(pollset->flags & APR_POLLSET_THREADSAFE)) { + return posix_remove(pollset, descriptor); + } + + pollset_lock_rings(); + +#if DEBUG + assert(descriptor->desc_type == APR_POLL_SOCKET); +#endif + /* zOS 1.12 doesn't support files for async i/o */ + fd = descriptor->desc.s->socketdes; + + elem = apr_hash_get(priv->elems, &(fd), sizeof(int)); + if (elem == NULL) { + DBG1(1, "couldn't find fd %d\n", fd); + rv = APR_NOTFOUND; + } else { + DBG1(5, "hash found fd %d\n", fd); + /* delete this fd from the hash */ + apr_hash_set(priv->elems, &(fd), sizeof(int), NULL); + + if (elem->state == ASIO_INIT) { + /* asyncio call to cancel */ + cancel_a.aio_cmd = AIO_CANCEL; + cancel_a.aio_buf = &elem->a; /* point to original aiocb */ + + cancel_a.aio_cflags = 0; + cancel_a.aio_cflags2 = 0; + + /* we want the original aiocb to show up on the pollset message queue + * before recycling its memory to eliminate race conditions + */ + + rv = asyncio(&cancel_a); + DBG1(4, "asyncio returned %d\n", rv); + +#if DEBUG + assert(rv == 1); +#endif + } + elem->state = ASIO_REMOVED; + rv = APR_SUCCESS; + } + + DBG1(2, "exiting, rv: %d\n", rv); + + pollset_unlock_rings(); + + return rv; +} /* end of asio_pollset_remove */ + +static posix_poll(apr_pollset_t *pollset, + apr_interval_time_t timeout, + apr_int32_t *num, + const apr_pollfd_t **descriptors) +{ + DBG_BUFF + int rv; + apr_uint32_t i, j; + apr_pollset_private_t *priv = pollset->p; + + DBG(4, "entered\n"); + + if (timeout > 0) { + timeout /= 1000; + } + rv = poll(priv->pollset, pollset->nelts, timeout); + (*num) = rv; + if (rv < 0) { + return apr_get_netos_error(); + } + if (rv == 0) { + return APR_TIMEUP; + } + j = 0; + for (i = 0; i < pollset->nelts; i++) { + if (priv->pollset[i].revents != 0) { + priv->result_set[j] = priv->query_set[i]; + priv->result_set[j].rtnevents = + get_revent(priv->pollset[i].revents); + j++; + } + } + if (descriptors) + *descriptors = priv->result_set; + + DBG(4, "exiting ok\n"); + return APR_SUCCESS; + +} /* end of posix_poll */ + +static process_msg(apr_pollset_t *pollset, struct asio_msgbuf_t *msg) +{ + DBG_BUFF + asio_elem_t *elem = msg->msg_elem; + + switch(elem->state) { + case ASIO_REMOVED: + DBG2(5, "for cancelled elem, recycling memory - elem %08p, fd %d\n", + elem, elem->os_pfd.fd); + APR_RING_INSERT_TAIL(&(pollset->p->free_ring), elem, + asio_elem_t, link); + break; + case ASIO_INIT: + DBG2(4, "adding to ready ring: elem %08p, fd %d\n", + elem, elem->os_pfd.fd); + elem->state = ASIO_COMPLETE; + APR_RING_INSERT_TAIL(&(pollset->p->ready_ring), elem, + asio_elem_t, link); + break; + default: + DBG3(1, "unexpected state: elem %08p, fd %d, state %d\n", + elem, elem->os_pfd.fd, elem->state); +#if DEBUG + assert(0); +#endif + } +} + +static apr_status_t asio_pollset_poll(apr_pollset_t *pollset, + apr_interval_time_t timeout, + apr_int32_t *num, + const apr_pollfd_t **descriptors) +{ + DBG_BUFF + int i, ret; + asio_elem_t *elem, *next_elem; + struct asio_msgbuf_t msg_buff; + struct timespec tv; + apr_status_t rv = APR_SUCCESS; + apr_pollset_private_t *priv = pollset->p; + + DBG(6, "entered\n"); /* chatty - traces every second w/Event */ + + if ((pollset->flags & APR_POLLSET_THREADSAFE) == 0 ) { + return posix_poll(pollset, timeout, num, descriptors); + } + + pollset_lock_rings(); + APR_RING_INIT(&(priv->ready_ring), asio_elem_t, link); + + while (!APR_RING_EMPTY(&(priv->prior_ready_ring), asio_elem_t, link)) { + elem = APR_RING_FIRST(&(priv->prior_ready_ring)); + DBG3(5, "pollset %p elem %p fd %d on prior ready ring\n", + pollset, + elem, + elem->os_pfd.fd); + + APR_RING_REMOVE(elem, link); + + /* + * since USS does not remember what's in our pollset, we have + * to re-add fds which have not been apr_pollset_remove'd + * + * there may have been too many ready fd's to return in the + * result set last time. re-poll inline for both cases + */ + + if (elem->state == ASIO_REMOVED) { + + /* + * async i/o is done since it was found on prior_ready + * the state says the caller is done with it too + * so recycle the elem + */ + + APR_RING_INSERT_TAIL(&(priv->free_ring), elem, + asio_elem_t, link); + continue; /* do not re-add if it has been _removed */ + } + + elem->state = ASIO_INIT; + elem->a.aio_cflags = AIO_OK2COMPIMD; + + if (0 != (ret = asyncio(&elem->a))) { + if (ret == 1) { + DBG(4, "asyncio() completed inline\n"); + /* it's ready now */ + elem->state = ASIO_COMPLETE; + APR_RING_INSERT_TAIL(&(priv->ready_ring), elem, asio_elem_t, + link); + } + else { + DBG2(1, "asyncio() failed, ret: %d, errno: %d\n", + ret, errno); + pollset_unlock_rings(); + return errno; + } + } + DBG1(4, "asyncio() completed rc %d\n", ret); + } + + DBG(6, "after prior ready loop\n"); /* chatty w/timeouts, hence 6 */ + + /* Gather async poll completions that have occurred since the last call */ + while (0 < msgrcv(priv->msg_q, &msg_buff, sizeof(asio_elem_t *), 0, + IPC_NOWAIT)) { + process_msg(pollset, &msg_buff); + } + + /* Suspend if nothing is ready yet. */ + if (APR_RING_EMPTY(&(priv->ready_ring), asio_elem_t, link)) { + + if (timeout >= 0) { + tv.tv_sec = apr_time_sec(timeout); + tv.tv_nsec = apr_time_usec(timeout) * 1000; + } else { + tv.tv_sec = INT_MAX; /* block until something is ready */ + } + + DBG2(6, "nothing on the ready ring " + "- blocking for %d seconds %d ns\n", + tv.tv_sec, tv.tv_nsec); + + pollset_unlock_rings(); /* allow other apr_pollset_* calls while blocked */ + + if (0 >= (ret = __msgrcv_timed(priv->msg_q, &msg_buff, + sizeof(asio_elem_t *), 0, NULL, &tv))) { +#if DEBUG + if (errno == EAGAIN) { + DBG(6, "__msgrcv_timed timed out\n"); /* timeout path, so 6 */ + } + else { + DBG(1, "__msgrcv_timed failed!\n"); + } +#endif + return (errno == EAGAIN) ? APR_TIMEUP : errno; + } + + pollset_lock_rings(); + + process_msg(pollset, &msg_buff); + } + + APR_RING_INIT(&priv->prior_ready_ring, asio_elem_t, link); + + (*num) = 0; + elem = APR_RING_FIRST(&(priv->ready_ring)); + + for (i = 0; + + i < priv->size + && elem != APR_RING_SENTINEL(&(priv->ready_ring), asio_elem_t, link); + i++) { + DBG2(5, "ready ring: elem %08p, fd %d\n", elem, elem->os_pfd.fd); + + priv->result_set[i] = elem->pfd; + priv->result_set[i].rtnevents + = get_revent(elem->os_pfd.revents); + (*num)++; + + elem = APR_RING_NEXT(elem, link); + +#if DEBUG + if (elem == APR_RING_SENTINEL(&(priv->ready_ring), asio_elem_t, link)) { + DBG(5, "end of ready ring reached\n"); + } +#endif + } + + if (descriptors) { + *descriptors = priv->result_set; + } + + /* if the result size is too small, remember which descriptors + * haven't had results reported yet. we will look + * at these descriptors on the next apr_pollset_poll call + */ + + APR_RING_CONCAT(&priv->prior_ready_ring, &(priv->ready_ring), asio_elem_t, link); + + DBG1(2, "exiting, rv = %d\n", rv); + + pollset_unlock_rings(); + + return rv; +} /* end of asio_pollset_poll */ + +static const apr_pollset_provider_t impl = { + asio_pollset_create, + asio_pollset_add, + asio_pollset_remove, + asio_pollset_poll, + asio_pollset_cleanup, + "asio" +}; + +const apr_pollset_provider_t *apr_pollset_provider_aio_msgq = &impl; + +#endif /* HAVE_AIO_MSGQ */ diff --git a/random/unix/apr_random.c b/random/unix/apr_random.c new file mode 100644 index 00000000000..b042b66bdf5 --- /dev/null +++ b/random/unix/apr_random.c @@ -0,0 +1,326 @@ +/* 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. + */ +/* + * See the paper "On Randomness" by Ben Laurie for an explanation of this PRNG. + * http://www.apache-ssl.org/randomness.pdf + * XXX: Is there a formal proof of this PRNG? Couldn't we use the more popular + * Mersenne Twister PRNG (and BSD licensed)? + */ + +#include "apr.h" +#include "apr_pools.h" +#include "apr_random.h" +#include "apr_thread_proc.h" +#include <assert.h> + +#ifdef min +#undef min +#endif +#define min(a,b) ((a) < (b) ? (a) : (b)) + +#define APR_RANDOM_DEFAULT_POOLS 32 +#define APR_RANDOM_DEFAULT_REHASH_SIZE 1024 +#define APR_RANDOM_DEFAULT_RESEED_SIZE 32 +#define APR_RANDOM_DEFAULT_HASH_SECRET_SIZE 32 +#define APR_RANDOM_DEFAULT_G_FOR_INSECURE 32 +#define APR_RANDOM_DEFAULT_G_FOR_SECURE 320 + +typedef struct apr_random_pool_t { + unsigned char *pool; + unsigned int bytes; + unsigned int pool_size; +} apr_random_pool_t; + +#define hash_init(h) (h)->init(h) +#define hash_add(h,b,n) (h)->add(h,b,n) +#define hash_finish(h,r) (h)->finish(h,r) + +#define hash(h,r,b,n) hash_init(h),hash_add(h,b,n),hash_finish(h,r) + +#define crypt_setkey(c,k) (c)->set_key((c)->data,k) +#define crypt_crypt(c,out,in) (c)->crypt((c)->date,out,in) + +struct apr_random_t { + apr_pool_t *apr_pool; + apr_crypto_hash_t *pool_hash; + unsigned int npools; + apr_random_pool_t *pools; + unsigned int next_pool; + unsigned int generation; + apr_size_t rehash_size; + apr_size_t reseed_size; + apr_crypto_hash_t *key_hash; +#define K_size(g) ((g)->key_hash->size) + apr_crypto_hash_t *prng_hash; +#define B_size(g) ((g)->prng_hash->size) + + unsigned char *H; + unsigned char *H_waiting; +#define H_size(g) (B_size(g)+K_size(g)) +#define H_current(g) (((g)->insecure_started && !(g)->secure_started) \ + ? (g)->H_waiting : (g)->H) + + unsigned char *randomness; + apr_size_t random_bytes; + unsigned int g_for_insecure; + unsigned int g_for_secure; + unsigned int secure_base; + unsigned int insecure_started:1; + unsigned int secure_started:1; + + apr_random_t *next; +}; + +static apr_random_t *all_random; + +static apr_status_t random_cleanup(void *data) +{ + apr_random_t *remove_this = data, + *cur = all_random, + **prev_ptr = &all_random; + while (cur) { + if (cur == remove_this) { + *prev_ptr = cur->next; + break; + } + prev_ptr = &cur->next; + cur = cur->next; + } + return APR_SUCCESS; +} + + +APR_DECLARE(void) apr_random_init(apr_random_t *g,apr_pool_t *p, + apr_crypto_hash_t *pool_hash, + apr_crypto_hash_t *key_hash, + apr_crypto_hash_t *prng_hash) +{ + unsigned int n; + + g->apr_pool = p; + + g->pool_hash = pool_hash; + g->key_hash = key_hash; + g->prng_hash = prng_hash; + + g->npools = APR_RANDOM_DEFAULT_POOLS; + g->pools = apr_palloc(p,g->npools*sizeof *g->pools); + for (n = 0; n < g->npools; ++n) { + g->pools[n].bytes = g->pools[n].pool_size = 0; + g->pools[n].pool = NULL; + } + g->next_pool = 0; + + g->generation = 0; + + g->rehash_size = APR_RANDOM_DEFAULT_REHASH_SIZE; + /* Ensure that the rehash size is twice the size of the pool hasher */ + g->rehash_size = ((g->rehash_size+2*g->pool_hash->size-1)/g->pool_hash->size + /2)*g->pool_hash->size*2; + g->reseed_size = APR_RANDOM_DEFAULT_RESEED_SIZE; + + g->H = apr_pcalloc(p,H_size(g)); + g->H_waiting = apr_pcalloc(p,H_size(g)); + + g->randomness = apr_palloc(p,B_size(g)); + g->random_bytes = 0; + + g->g_for_insecure = APR_RANDOM_DEFAULT_G_FOR_INSECURE; + g->secure_base = 0; + g->g_for_secure = APR_RANDOM_DEFAULT_G_FOR_SECURE; + g->secure_started = g->insecure_started = 0; + + g->next = all_random; + all_random = g; + apr_pool_cleanup_register(p, g, random_cleanup, apr_pool_cleanup_null); +} + +static void mix_pid(apr_random_t *g,unsigned char *H,pid_t pid) +{ + hash_init(g->key_hash); + hash_add(g->key_hash,H,H_size(g)); + hash_add(g->key_hash,&pid,sizeof pid); + hash_finish(g->key_hash,H); +} + +static void mixer(apr_random_t *g,pid_t pid) +{ + unsigned char *H = H_current(g); + + /* mix the PID into the current H */ + mix_pid(g,H,pid); + /* if we are in waiting, then also mix into main H */ + if (H != g->H) + mix_pid(g,g->H,pid); + /* change order of pool mixing for good measure - note that going + backwards is much better than going forwards */ + --g->generation; + /* blow away any lingering randomness */ + g->random_bytes = 0; +} + +APR_DECLARE(void) apr_random_after_fork(apr_proc_t *proc) +{ + apr_random_t *r; + + for (r = all_random; r; r = r->next) + /* + * XXX Note: the pid does not provide sufficient entropy to + * actually call this secure. See Ben's paper referenced at + * the top of this file. + */ + mixer(r,proc->pid); +} + +APR_DECLARE(apr_random_t *) apr_random_standard_new(apr_pool_t *p) +{ + apr_random_t *r = apr_palloc(p,sizeof *r); + + apr_random_init(r,p,apr_crypto_sha256_new(p),apr_crypto_sha256_new(p), + apr_crypto_sha256_new(p)); + return r; +} + +static void rekey(apr_random_t *g) +{ + unsigned int n; + unsigned char *H = H_current(g); + + hash_init(g->key_hash); + hash_add(g->key_hash,H,H_size(g)); + for (n = 0 ; n < g->npools && (n == 0 || g->generation&(1 << (n-1))) + ; ++n) { + hash_add(g->key_hash,g->pools[n].pool,g->pools[n].bytes); + g->pools[n].bytes = 0; + } + hash_finish(g->key_hash,H+B_size(g)); + + ++g->generation; + if (!g->insecure_started && g->generation > g->g_for_insecure) { + g->insecure_started = 1; + if (!g->secure_started) { + memcpy(g->H_waiting,g->H,H_size(g)); + g->secure_base = g->generation; + } + } + + if (!g->secure_started && g->generation > g->secure_base+g->g_for_secure) { + g->secure_started = 1; + memcpy(g->H,g->H_waiting,H_size(g)); + } +} + +APR_DECLARE(void) apr_random_add_entropy(apr_random_t *g,const void *entropy_, + apr_size_t bytes) +{ + unsigned int n; + const unsigned char *entropy = entropy_; + + for (n = 0; n < bytes; ++n) { + apr_random_pool_t *p = &g->pools[g->next_pool]; + + if (++g->next_pool == g->npools) + g->next_pool = 0; + + if (p->pool_size < p->bytes+1) { + unsigned char *np = apr_palloc(g->apr_pool,(p->bytes+1)*2); + + memcpy(np,p->pool,p->bytes); + p->pool = np; + p->pool_size = (p->bytes+1)*2; + } + p->pool[p->bytes++] = entropy[n]; + + if (p->bytes == g->rehash_size) { + apr_size_t r; + + for (r = 0; r < p->bytes/2; r+=g->pool_hash->size) + hash(g->pool_hash,p->pool+r,p->pool+r*2,g->pool_hash->size*2); + p->bytes/=2; + } + assert(p->bytes < g->rehash_size); + } + + if (g->pools[0].bytes >= g->reseed_size) + rekey(g); +} + +/* This will give g->B_size bytes of randomness */ +static void apr_random_block(apr_random_t *g,unsigned char *random) +{ + /* FIXME: in principle, these are different hashes */ + hash(g->prng_hash,g->H,g->H,H_size(g)); + hash(g->prng_hash,random,g->H,B_size(g)); +} + +static void apr_random_bytes(apr_random_t *g,unsigned char *random, + apr_size_t bytes) +{ + apr_size_t n; + + for (n = 0; n < bytes; ) { + apr_size_t l; + + if (g->random_bytes == 0) { + apr_random_block(g,g->randomness); + g->random_bytes = B_size(g); + } + l = min(bytes-n,g->random_bytes); + memcpy(&random[n],g->randomness+B_size(g)-g->random_bytes,l); + g->random_bytes-=l; + n+=l; + } +} + +APR_DECLARE(apr_status_t) apr_random_secure_bytes(apr_random_t *g, + void *random, + apr_size_t bytes) +{ + if (!g->secure_started) + return APR_ENOTENOUGHENTROPY; + apr_random_bytes(g,random,bytes); + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_random_insecure_bytes(apr_random_t *g, + void *random, + apr_size_t bytes) +{ + if (!g->insecure_started) + return APR_ENOTENOUGHENTROPY; + apr_random_bytes(g,random,bytes); + return APR_SUCCESS; +} + +APR_DECLARE(void) apr_random_barrier(apr_random_t *g) +{ + g->secure_started = 0; + g->secure_base = g->generation; +} + +APR_DECLARE(apr_status_t) apr_random_secure_ready(apr_random_t *r) +{ + if (!r->secure_started) + return APR_ENOTENOUGHENTROPY; + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_random_insecure_ready(apr_random_t *r) +{ + if (!r->insecure_started) + return APR_ENOTENOUGHENTROPY; + return APR_SUCCESS; +} diff --git a/random/unix/sha2.c b/random/unix/sha2.c new file mode 100644 index 00000000000..12c257d1fa1 --- /dev/null +++ b/random/unix/sha2.c @@ -0,0 +1,528 @@ +/* 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. + */ +/* + * FILE: sha2.c + * AUTHOR: Aaron D. Gifford <me@aarongifford.com> + * + * A licence was granted to the ASF by Aaron on 4 November 2003. + */ + +#include <string.h> /* memcpy()/memset() or bcopy()/bzero() */ +#include <assert.h> /* assert() */ +#include "sha2.h" + +/* + * ASSERT NOTE: + * Some sanity checking code is included using assert(). On my FreeBSD + * system, this additional code can be removed by compiling with NDEBUG + * defined. Check your own systems manpage on assert() to see how to + * compile WITHOUT the sanity checking code on your system. + * + * UNROLLED TRANSFORM LOOP NOTE: + * You can define SHA2_UNROLL_TRANSFORM to use the unrolled transform + * loop version for the hash transform rounds (defined using macros + * later in this file). Either define on the command line, for example: + * + * cc -DSHA2_UNROLL_TRANSFORM -o sha2 sha2.c sha2prog.c + * + * or define below: + * + * #define SHA2_UNROLL_TRANSFORM + * + */ + +/*** SHA-256/384/512 Machine Architecture Definitions *****************/ +typedef apr_byte_t sha2_byte; /* Exactly 1 byte */ +typedef apr_uint32_t sha2_word32; /* Exactly 4 bytes */ +typedef apr_uint64_t sha2_word64; /* Exactly 8 bytes */ + +/*** SHA-256/384/512 Various Length Definitions ***********************/ +/* NOTE: Most of these are in sha2.h */ +#define SHA256_SHORT_BLOCK_LENGTH (SHA256_BLOCK_LENGTH - 8) + + +/*** ENDIAN REVERSAL MACROS *******************************************/ +#if !APR_IS_BIGENDIAN +#define REVERSE32(w,x) { \ + sha2_word32 tmp = (w); \ + tmp = (tmp >> 16) | (tmp << 16); \ + (x) = ((tmp & 0xff00ff00UL) >> 8) | ((tmp & 0x00ff00ffUL) << 8); \ +} +#define REVERSE64(w,x) { \ + sha2_word64 tmp = (w); \ + tmp = (tmp >> 32) | (tmp << 32); \ + tmp = ((tmp & APR_UINT64_C(0xff00ff00ff00ff00)) >> 8) | \ + ((tmp & APR_UINT64_C(0x00ff00ff00ff00ff)) << 8); \ + (x) = ((tmp & APR_UINT64_C(0xffff0000ffff0000)) >> 16) | \ + ((tmp & APR_UINT64_C(0x0000ffff0000ffff)) << 16); \ +} +#endif /* !APR_IS_BIGENDIAN */ + +/* + * Macro for incrementally adding the unsigned 64-bit integer n to the + * unsigned 128-bit integer (represented using a two-element array of + * 64-bit words): + */ +#define ADDINC128(w,n) { \ + (w)[0] += (sha2_word64)(n); \ + if ((w)[0] < (n)) { \ + (w)[1]++; \ + } \ +} + +/* + * Macros for copying blocks of memory and for zeroing out ranges + * of memory. Using these macros makes it easy to switch from + * using memset()/memcpy() and using bzero()/bcopy(). + * + * Please define either SHA2_USE_MEMSET_MEMCPY or define + * SHA2_USE_BZERO_BCOPY depending on which function set you + * choose to use: + */ +#if !defined(SHA2_USE_MEMSET_MEMCPY) && !defined(SHA2_USE_BZERO_BCOPY) +/* Default to memset()/memcpy() if no option is specified */ +#define SHA2_USE_MEMSET_MEMCPY 1 +#endif +#if defined(SHA2_USE_MEMSET_MEMCPY) && defined(SHA2_USE_BZERO_BCOPY) +/* Abort with an error if BOTH options are defined */ +#error Define either SHA2_USE_MEMSET_MEMCPY or SHA2_USE_BZERO_BCOPY, not both! +#endif + +#ifdef SHA2_USE_MEMSET_MEMCPY +#define MEMSET_BZERO(p,l) memset((p), 0, (l)) +#define MEMCPY_BCOPY(d,s,l) memcpy((d), (s), (l)) +#endif +#ifdef SHA2_USE_BZERO_BCOPY +#define MEMSET_BZERO(p,l) bzero((p), (l)) +#define MEMCPY_BCOPY(d,s,l) bcopy((s), (d), (l)) +#endif + + +/*** THE SIX LOGICAL FUNCTIONS ****************************************/ +/* + * Bit shifting and rotation (used by the six SHA-XYZ logical functions: + * + * NOTE: The naming of R and S appears backwards here (R is a SHIFT and + * S is a ROTATION) because the SHA-256/384/512 description document + * (see http://csrc.nist.gov/cryptval/shs/sha256-384-512.pdf) uses this + * same "backwards" definition. + */ +/* Shift-right (used in SHA-256, SHA-384, and SHA-512): */ +#define R(b,x) ((x) >> (b)) +/* 32-bit Rotate-right (used in SHA-256): */ +#define S32(b,x) (((x) >> (b)) | ((x) << (32 - (b)))) +/* 64-bit Rotate-right (used in SHA-384 and SHA-512): */ +#define S64(b,x) (((x) >> (b)) | ((x) << (64 - (b)))) + +/* Two of six logical functions used in SHA-256, SHA-384, and SHA-512: */ +#define Ch(x,y,z) (((x) & (y)) ^ ((~(x)) & (z))) +#define Maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) + +/* Four of six logical functions used in SHA-256: */ +#define Sigma0_256(x) (S32(2, (x)) ^ S32(13, (x)) ^ S32(22, (x))) +#define Sigma1_256(x) (S32(6, (x)) ^ S32(11, (x)) ^ S32(25, (x))) +#define sigma0_256(x) (S32(7, (x)) ^ S32(18, (x)) ^ R(3 , (x))) +#define sigma1_256(x) (S32(17, (x)) ^ S32(19, (x)) ^ R(10, (x))) + +/* Four of six logical functions used in SHA-384 and SHA-512: */ +#define Sigma0_512(x) (S64(28, (x)) ^ S64(34, (x)) ^ S64(39, (x))) +#define Sigma1_512(x) (S64(14, (x)) ^ S64(18, (x)) ^ S64(41, (x))) +#define sigma0_512(x) (S64( 1, (x)) ^ S64( 8, (x)) ^ R( 7, (x))) +#define sigma1_512(x) (S64(19, (x)) ^ S64(61, (x)) ^ R( 6, (x))) + +/*** INTERNAL FUNCTION PROTOTYPES *************************************/ +/* NOTE: These should not be accessed directly from outside this + * library -- they are intended for private internal visibility/use + * only. + */ +void apr__SHA256_Transform(SHA256_CTX*, const sha2_word32*); + + +/*** SHA-XYZ INITIAL HASH VALUES AND CONSTANTS ************************/ +/* Hash constant words K for SHA-256: */ +static const sha2_word32 K256[64] = { + 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, + 0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, + 0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL, + 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL, + 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL, + 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, + 0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, + 0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL, + 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL, + 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL, + 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, + 0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, + 0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL, + 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL, + 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL, + 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL +}; + +/* Initial hash value H for SHA-256: */ +static const sha2_word32 sha256_initial_hash_value[8] = { + 0x6a09e667UL, + 0xbb67ae85UL, + 0x3c6ef372UL, + 0xa54ff53aUL, + 0x510e527fUL, + 0x9b05688cUL, + 0x1f83d9abUL, + 0x5be0cd19UL +}; + +/* + * Constant used by SHA256/384/512_End() functions for converting the + * digest to a readable hexadecimal character string: + */ +static const char *sha2_hex_digits = "0123456789abcdef"; + + +/*** SHA-256: *********************************************************/ +void apr__SHA256_Init(SHA256_CTX* context) { + if (context == (SHA256_CTX*)0) { + return; + } + MEMCPY_BCOPY(context->state, sha256_initial_hash_value, SHA256_DIGEST_LENGTH); + MEMSET_BZERO(context->buffer, SHA256_BLOCK_LENGTH); + context->bitcount = 0; +} + +#ifdef SHA2_UNROLL_TRANSFORM + +/* Unrolled SHA-256 round macros: */ + +#if !APR_IS_BIGENDIAN + +#define ROUND256_0_TO_15(a,b,c,d,e,f,g,h) \ + REVERSE32(*data++, W256[j]); \ + T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + \ + K256[j] + W256[j]; \ + (d) += T1; \ + (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \ + j++ + + +#else /* APR_IS_BIGENDIAN */ + +#define ROUND256_0_TO_15(a,b,c,d,e,f,g,h) \ + T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + \ + K256[j] + (W256[j] = *data++); \ + (d) += T1; \ + (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \ + j++ + +#endif /* APR_IS_BIGENDIAN */ + +#define ROUND256(a,b,c,d,e,f,g,h) \ + s0 = W256[(j+1)&0x0f]; \ + s0 = sigma0_256(s0); \ + s1 = W256[(j+14)&0x0f]; \ + s1 = sigma1_256(s1); \ + T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + K256[j] + \ + (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0); \ + (d) += T1; \ + (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \ + j++ + +void apr__SHA256_Transform(SHA256_CTX* context, const sha2_word32* data) { + sha2_word32 a, b, c, d, e, f, g, h, s0, s1; + sha2_word32 T1, *W256; + int j; + + W256 = (sha2_word32*)context->buffer; + + /* Initialize registers with the prev. intermediate value */ + a = context->state[0]; + b = context->state[1]; + c = context->state[2]; + d = context->state[3]; + e = context->state[4]; + f = context->state[5]; + g = context->state[6]; + h = context->state[7]; + + j = 0; + do { + /* Rounds 0 to 15 (unrolled): */ + ROUND256_0_TO_15(a,b,c,d,e,f,g,h); + ROUND256_0_TO_15(h,a,b,c,d,e,f,g); + ROUND256_0_TO_15(g,h,a,b,c,d,e,f); + ROUND256_0_TO_15(f,g,h,a,b,c,d,e); + ROUND256_0_TO_15(e,f,g,h,a,b,c,d); + ROUND256_0_TO_15(d,e,f,g,h,a,b,c); + ROUND256_0_TO_15(c,d,e,f,g,h,a,b); + ROUND256_0_TO_15(b,c,d,e,f,g,h,a); + } while (j < 16); + + /* Now for the remaining rounds to 64: */ + do { + ROUND256(a,b,c,d,e,f,g,h); + ROUND256(h,a,b,c,d,e,f,g); + ROUND256(g,h,a,b,c,d,e,f); + ROUND256(f,g,h,a,b,c,d,e); + ROUND256(e,f,g,h,a,b,c,d); + ROUND256(d,e,f,g,h,a,b,c); + ROUND256(c,d,e,f,g,h,a,b); + ROUND256(b,c,d,e,f,g,h,a); + } while (j < 64); + + /* Compute the current intermediate hash value */ + context->state[0] += a; + context->state[1] += b; + context->state[2] += c; + context->state[3] += d; + context->state[4] += e; + context->state[5] += f; + context->state[6] += g; + context->state[7] += h; + + /* Clean up */ + a = b = c = d = e = f = g = h = T1 = 0; +} + +#else /* SHA2_UNROLL_TRANSFORM */ + +void apr__SHA256_Transform(SHA256_CTX* context, const sha2_word32* data) { + sha2_word32 a, b, c, d, e, f, g, h, s0, s1; + sha2_word32 T1, T2, *W256; + int j; + + W256 = (sha2_word32*)context->buffer; + + /* Initialize registers with the prev. intermediate value */ + a = context->state[0]; + b = context->state[1]; + c = context->state[2]; + d = context->state[3]; + e = context->state[4]; + f = context->state[5]; + g = context->state[6]; + h = context->state[7]; + + j = 0; + do { +#if !APR_IS_BIGENDIAN + /* Copy data while converting to host byte order */ + REVERSE32(*data++,W256[j]); + /* Apply the SHA-256 compression function to update a..h */ + T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + W256[j]; +#else /* APR_IS_BIGENDIAN */ + /* Apply the SHA-256 compression function to update a..h with copy */ + T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + (W256[j] = *data++); +#endif /* APR_IS_BIGENDIAN */ + T2 = Sigma0_256(a) + Maj(a, b, c); + h = g; + g = f; + f = e; + e = d + T1; + d = c; + c = b; + b = a; + a = T1 + T2; + + j++; + } while (j < 16); + + do { + /* Part of the message block expansion: */ + s0 = W256[(j+1)&0x0f]; + s0 = sigma0_256(s0); + s1 = W256[(j+14)&0x0f]; + s1 = sigma1_256(s1); + + /* Apply the SHA-256 compression function to update a..h */ + T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + + (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0); + T2 = Sigma0_256(a) + Maj(a, b, c); + h = g; + g = f; + f = e; + e = d + T1; + d = c; + c = b; + b = a; + a = T1 + T2; + + j++; + } while (j < 64); + + /* Compute the current intermediate hash value */ + context->state[0] += a; + context->state[1] += b; + context->state[2] += c; + context->state[3] += d; + context->state[4] += e; + context->state[5] += f; + context->state[6] += g; + context->state[7] += h; + + /* Clean up */ + a = b = c = d = e = f = g = h = T1 = T2 = 0; +} + +#endif /* SHA2_UNROLL_TRANSFORM */ + +void apr__SHA256_Update(SHA256_CTX* context, const sha2_byte *data, size_t len) { + unsigned int freespace, usedspace; + + if (len == 0) { + /* Calling with no data is valid - we do nothing */ + return; + } + + /* Sanity check: */ + assert(context != (SHA256_CTX*)0 && data != (sha2_byte*)0); + + usedspace = (unsigned int)((context->bitcount >> 3) + % SHA256_BLOCK_LENGTH); + if (usedspace > 0) { + /* Calculate how much free space is available in the buffer */ + freespace = SHA256_BLOCK_LENGTH - usedspace; + + if (len >= freespace) { + /* Fill the buffer completely and process it */ + MEMCPY_BCOPY(&context->buffer[usedspace], data, freespace); + context->bitcount += freespace << 3; + len -= freespace; + data += freespace; + apr__SHA256_Transform(context, (sha2_word32*)context->buffer); + } else { + /* The buffer is not yet full */ + MEMCPY_BCOPY(&context->buffer[usedspace], data, len); + context->bitcount += len << 3; + /* Clean up: */ + usedspace = freespace = 0; + return; + } + } + while (len >= SHA256_BLOCK_LENGTH) { + /* Process as many complete blocks as we can */ + apr__SHA256_Transform(context, (sha2_word32*)data); + context->bitcount += SHA256_BLOCK_LENGTH << 3; + len -= SHA256_BLOCK_LENGTH; + data += SHA256_BLOCK_LENGTH; + } + if (len > 0) { + /* There's left-overs, so save 'em */ + MEMCPY_BCOPY(context->buffer, data, len); + context->bitcount += len << 3; + } + /* Clean up: */ + usedspace = freespace = 0; +} + +void apr__SHA256_Final(sha2_byte digest[], SHA256_CTX* context) { + sha2_word32 *d = (sha2_word32*)digest; + unsigned int usedspace; + + /* Sanity check: */ + assert(context != (SHA256_CTX*)0); + + /* If no digest buffer is passed, we don't bother doing this: */ + if (digest != (sha2_byte*)0) { + usedspace = (unsigned int)((context->bitcount >> 3) + % SHA256_BLOCK_LENGTH); +#if !APR_IS_BIGENDIAN + /* Convert FROM host byte order */ + REVERSE64(context->bitcount,context->bitcount); +#endif + if (usedspace > 0) { + /* Begin padding with a 1 bit: */ + context->buffer[usedspace++] = 0x80; + + if (usedspace <= SHA256_SHORT_BLOCK_LENGTH) { + /* Set-up for the last transform: */ + MEMSET_BZERO(&context->buffer[usedspace], SHA256_SHORT_BLOCK_LENGTH - usedspace); + } else { + if (usedspace < SHA256_BLOCK_LENGTH) { + MEMSET_BZERO(&context->buffer[usedspace], SHA256_BLOCK_LENGTH - usedspace); + } + /* Do second-to-last transform: */ + apr__SHA256_Transform(context, (sha2_word32*)context->buffer); + + /* And set-up for the last transform: */ + MEMSET_BZERO(context->buffer, SHA256_SHORT_BLOCK_LENGTH); + } + } else { + /* Set-up for the last transform: */ + MEMSET_BZERO(context->buffer, SHA256_SHORT_BLOCK_LENGTH); + + /* Begin padding with a 1 bit: */ + *context->buffer = 0x80; + } + /* Set the bit count: */ + { + union dummy { + apr_uint64_t bitcount; + apr_byte_t bytes[8]; + } bitcount; + bitcount.bitcount = context->bitcount; + MEMCPY_BCOPY(&context->buffer[SHA256_SHORT_BLOCK_LENGTH], bitcount.bytes, 8); + } + + /* Final transform: */ + apr__SHA256_Transform(context, (sha2_word32*)context->buffer); + +#if !APR_IS_BIGENDIAN + { + /* Convert TO host byte order */ + int j; + for (j = 0; j < 8; j++) { + REVERSE32(context->state[j],context->state[j]); + *d++ = context->state[j]; + } + } +#else + MEMCPY_BCOPY(d, context->state, SHA256_DIGEST_LENGTH); +#endif + } + + /* Clean up state data: */ + MEMSET_BZERO(context, sizeof(*context)); + usedspace = 0; +} + +char *apr__SHA256_End(SHA256_CTX* context, char buffer[]) { + sha2_byte digest[SHA256_DIGEST_LENGTH], *d = digest; + int i; + + /* Sanity check: */ + assert(context != (SHA256_CTX*)0); + + if (buffer != (char*)0) { + apr__SHA256_Final(digest, context); + + for (i = 0; i < SHA256_DIGEST_LENGTH; i++) { + *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4]; + *buffer++ = sha2_hex_digits[*d & 0x0f]; + d++; + } + *buffer = (char)0; + } else { + MEMSET_BZERO(context, sizeof(*context)); + } + MEMSET_BZERO(digest, SHA256_DIGEST_LENGTH); + return buffer; +} + +char* apr__SHA256_Data(const sha2_byte* data, size_t len, char digest[SHA256_DIGEST_STRING_LENGTH]) { + SHA256_CTX context; + + apr__SHA256_Init(&context); + apr__SHA256_Update(&context, data, len); + return apr__SHA256_End(&context, digest); +} diff --git a/random/unix/sha2.h b/random/unix/sha2.h new file mode 100644 index 00000000000..0a030d7dbae --- /dev/null +++ b/random/unix/sha2.h @@ -0,0 +1,59 @@ +/* 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. + */ +/* + * FILE: sha2.h + * AUTHOR: Aaron D. Gifford <me@aarongifford.com> + * + * A licence was granted to the ASF by Aaron on 4 November 2003. + */ + +#ifndef __SHA2_H__ +#define __SHA2_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "apr.h" + +/*** SHA-256 Various Length Definitions ***********************/ +#define SHA256_BLOCK_LENGTH 64 +#define SHA256_DIGEST_LENGTH 32 +#define SHA256_DIGEST_STRING_LENGTH (SHA256_DIGEST_LENGTH * 2 + 1) + + +/*** SHA-256/384/512 Context Structures *******************************/ +typedef struct _SHA256_CTX { + apr_uint32_t state[8]; + apr_uint64_t bitcount; + apr_byte_t buffer[SHA256_BLOCK_LENGTH]; +} SHA256_CTX; + + +/*** SHA-256/384/512 Function Prototypes ******************************/ +void apr__SHA256_Init(SHA256_CTX *); +void apr__SHA256_Update(SHA256_CTX *, const apr_byte_t *, size_t); +void apr__SHA256_Final(apr_byte_t [SHA256_DIGEST_LENGTH], SHA256_CTX *); +char* apr__SHA256_End(SHA256_CTX *, char [SHA256_DIGEST_STRING_LENGTH]); +char* apr__SHA256_Data(const apr_byte_t *, size_t, + char [SHA256_DIGEST_STRING_LENGTH]); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __SHA2_H__ */ + diff --git a/random/unix/sha2_glue.c b/random/unix/sha2_glue.c new file mode 100644 index 00000000000..cb6e897802f --- /dev/null +++ b/random/unix/sha2_glue.c @@ -0,0 +1,49 @@ +/* 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_random.h> +#include <apr_pools.h> +#include "sha2.h" + +static void sha256_init(apr_crypto_hash_t *h) +{ + apr__SHA256_Init(h->data); +} + +static void sha256_add(apr_crypto_hash_t *h,const void *data, + apr_size_t bytes) +{ + apr__SHA256_Update(h->data,data,bytes); +} + +static void sha256_finish(apr_crypto_hash_t *h,unsigned char *result) +{ + apr__SHA256_Final(result,h->data); +} + +APR_DECLARE(apr_crypto_hash_t *) apr_crypto_sha256_new(apr_pool_t *p) +{ + apr_crypto_hash_t *h=apr_palloc(p,sizeof *h); + + h->data=apr_palloc(p,sizeof(SHA256_CTX)); + h->init=sha256_init; + h->add=sha256_add; + h->finish=sha256_finish; + h->size=256/8; + + return h; +} diff --git a/redis/apr_redis.c b/redis/apr_redis.c new file mode 100644 index 00000000000..77692736619 --- /dev/null +++ b/redis/apr_redis.c @@ -0,0 +1,1548 @@ +/* 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_redis.h" +#include "apr_poll.h" +#include "apr_version.h" +#include <stdlib.h> +#include <string.h> + +#define BUFFER_SIZE 512 +#define LILBUFF_SIZE 64 +struct apr_redis_conn_t +{ + char *buffer; + apr_size_t blen; + apr_pool_t *p; + apr_pool_t *tp; + apr_socket_t *sock; + apr_bucket_brigade *bb; + apr_bucket_brigade *tb; + apr_redis_server_t *rs; +}; + +/* Strings for Client Commands */ + +#define RC_EOL "\r\n" +#define RC_EOL_LEN (sizeof(RC_EOL)-1) + +#define RC_WS " " +#define RC_WS_LEN (sizeof(RC_WS)-1) + +#define RC_RESP_1 "*1\r\n" +#define RC_RESP_1_LEN (sizeof(RC_RESP_1)-1) + +#define RC_RESP_2 "*2\r\n" +#define RC_RESP_2_LEN (sizeof(RC_RESP_2)-1) + +#define RC_RESP_3 "*3\r\n" +#define RC_RESP_3_LEN (sizeof(RC_RESP_3)-1) + +#define RC_RESP_4 "*4\r\n" +#define RC_RESP_4_LEN (sizeof(RC_RESP_4)-1) + +#define RC_GET "GET\r\n" +#define RC_GET_LEN (sizeof(RC_GET)-1) + +#define RC_GET_SIZE "$3\r\n" +#define RC_GET_SIZE_LEN (sizeof(RC_GET_SIZE)-1) + +#define RC_SET "SET\r\n" +#define RC_SET_LEN (sizeof(RC_SET)-1) + +#define RC_SET_SIZE "$3\r\n" +#define RC_SET_SIZE_LEN (sizeof(RC_SET_SIZE)-1) + +#define RC_SETEX "SETEX\r\n" +#define RC_SETEX_LEN (sizeof(RC_SETEX)-1) + +#define RC_SETEX_SIZE "$5\r\n" +#define RC_SETEX_SIZE_LEN (sizeof(RC_SETEX_SIZE)-1) + +#define RC_DEL "DEL\r\n" +#define RC_DEL_LEN (sizeof(RC_DEL)-1) + +#define RC_DEL_SIZE "$3\r\n" +#define RC_DEL_SIZE_LEN (sizeof(RC_DEL_SIZE)-1) + +#define RC_QUIT "QUIT\r\n" +#define RC_QUIT_LEN (sizeof(RC_QUIT)-1) + +#define RC_QUIT_SIZE "$4\r\n" +#define RC_QUIT_SIZE_LEN (sizeof(RC_QUIT_SIZE)-1) + +#define RC_PING "PING\r\n" +#define RC_PING_LEN (sizeof(RC_PING)-1) + +#define RC_PING_SIZE "$4\r\n" +#define RC_PING_SIZE_LEN (sizeof(RC_PING_SIZE)-1) + +#define RC_INFO "INFO\r\n" +#define RC_INFO_LEN (sizeof(RC_INFO)-1) + +#define RC_INFO_SIZE "$4\r\n" +#define RC_INFO_SIZE_LEN (sizeof(RC_INFO_SIZE)-1) + +/* Strings for Server Replies */ + +#define RS_STORED "+OK" +#define RS_STORED_LEN (sizeof(RS_STORED)-1) + +#define RS_NOT_STORED "$-1" +#define RS_NOT_STORED_LEN (sizeof(RS_NOT_STORED)-1) + +#define RS_DELETED ":1" +#define RS_DELETED_LEN (sizeof(RS_DELETED)-1) + +#define RS_NOT_FOUND_GET "$-1" +#define RS_NOT_FOUND_GET_LEN (sizeof(RS_NOT_FOUND_GET)-1) + +#define RS_NOT_FOUND_DEL ":0" +#define RS_NOT_FOUND_DEL_LEN (sizeof(RS_NOT_FOUND_DEL)-1) + +#define RS_TYPE_STRING "$" +#define RS_TYPE_STRING_LEN (sizeof(RS_TYPE_STRING)-1) + +#define RS_END "\r\n" +#define RS_END_LEN (sizeof(RS_END)-1) + +static apr_status_t make_server_dead(apr_redis_t *rc, + apr_redis_server_t *rs) +{ +#if APR_HAS_THREADS + apr_thread_mutex_lock(rs->lock); +#endif + rs->status = APR_RC_SERVER_DEAD; + rs->btime = apr_time_now(); +#if APR_HAS_THREADS + apr_thread_mutex_unlock(rs->lock); +#endif + return APR_SUCCESS; +} + +static apr_status_t make_server_live(apr_redis_t *rc, + apr_redis_server_t *rs) +{ + rs->status = APR_RC_SERVER_LIVE; + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_redis_add_server(apr_redis_t *rc, + apr_redis_server_t *rs) +{ + apr_status_t rv = APR_SUCCESS; + + if (rc->ntotal >= rc->nalloc) { + return APR_ENOMEM; + } + rc->live_servers[rc->ntotal] = rs; + rc->ntotal++; + make_server_live(rc, rs); + return rv; +} + +APR_DECLARE(apr_redis_server_t *) +apr_redis_find_server_hash(apr_redis_t *rc, const apr_uint32_t hash) +{ + if (rc->server_func) { + return rc->server_func(rc->server_baton, rc, hash); + } + else { + return apr_redis_find_server_hash_default(NULL, rc, hash); + } +} + +APR_DECLARE(apr_redis_server_t *) +apr_redis_find_server_hash_default(void *baton, apr_redis_t *rc, + const apr_uint32_t hash) +{ + apr_redis_server_t *rs = NULL; + apr_uint32_t h = hash ? hash : 1; + apr_uint32_t i = 0; + apr_time_t curtime = 0; + + if (rc->ntotal == 0) { + return NULL; + } + + do { + rs = rc->live_servers[h % rc->ntotal]; + if (rs->status == APR_RC_SERVER_LIVE) { + break; + } + else { + if (curtime == 0) { + curtime = apr_time_now(); + } +#if APR_HAS_THREADS + apr_thread_mutex_lock(rs->lock); +#endif + /* Try the dead server, every 5 seconds */ + if (curtime - rs->btime > apr_time_from_sec(5)) { + rs->btime = curtime; + if (apr_redis_ping(rs) == APR_SUCCESS) { + make_server_live(rc, rs); +#if APR_HAS_THREADS + apr_thread_mutex_unlock(rs->lock); +#endif + break; + } + } +#if APR_HAS_THREADS + apr_thread_mutex_unlock(rs->lock); +#endif + } + h++; + i++; + } while (i < rc->ntotal); + + if (i == rc->ntotal) { + rs = NULL; + } + + return rs; +} + +APR_DECLARE(apr_redis_server_t *) apr_redis_find_server(apr_redis_t *rc, + const char *host, + apr_port_t port) +{ + int i; + + for (i = 0; i < rc->ntotal; i++) { + if (strcmp(rc->live_servers[i]->host, host) == 0 + && rc->live_servers[i]->port == port) { + + return rc->live_servers[i]; + } + } + + return NULL; +} + +static apr_status_t rs_find_conn(apr_redis_server_t *rs, + apr_redis_conn_t ** conn) +{ + apr_status_t rv; + apr_bucket_alloc_t *balloc; + apr_bucket *e; + +#if APR_HAS_THREADS + rv = apr_reslist_acquire(rs->conns, (void **) conn); +#else + *conn = rs->conn; + rv = APR_SUCCESS; +#endif + + if (rv != APR_SUCCESS) { + return rv; + } + + balloc = apr_bucket_alloc_create((*conn)->tp); + (*conn)->bb = apr_brigade_create((*conn)->tp, balloc); + (*conn)->tb = apr_brigade_create((*conn)->tp, balloc); + + e = apr_bucket_socket_create((*conn)->sock, balloc); + APR_BRIGADE_INSERT_TAIL((*conn)->bb, e); + + return rv; +} + +static apr_status_t rs_bad_conn(apr_redis_server_t *rs, + apr_redis_conn_t *conn) +{ +#if APR_HAS_THREADS + return apr_reslist_invalidate(rs->conns, conn); +#else + return APR_SUCCESS; +#endif +} + +static apr_status_t rs_release_conn(apr_redis_server_t *rs, + apr_redis_conn_t *conn) +{ + apr_pool_clear(conn->tp); +#if APR_HAS_THREADS + return apr_reslist_release(rs->conns, conn); +#else + return APR_SUCCESS; +#endif +} + +APR_DECLARE(apr_status_t) apr_redis_enable_server(apr_redis_t *rc, + apr_redis_server_t *rs) +{ + apr_status_t rv = APR_SUCCESS; + + if (rs->status == APR_RC_SERVER_LIVE) { + return rv; + } + rv = make_server_live(rc, rs); + return rv; +} + +APR_DECLARE(apr_status_t) apr_redis_disable_server(apr_redis_t *rc, + apr_redis_server_t *rs) +{ + return make_server_dead(rc, rs); +} + +static apr_status_t conn_connect(apr_redis_conn_t *conn) +{ + apr_status_t rv = APR_SUCCESS; + apr_sockaddr_t *sa; +#if APR_HAVE_SOCKADDR_UN + apr_int32_t family = conn->rs->host[0] != '/' ? APR_INET : APR_UNIX; +#else + apr_int32_t family = APR_INET; +#endif + + rv = apr_sockaddr_info_get(&sa, conn->rs->host, family, conn->rs->port, 0, + conn->p); + if (rv != APR_SUCCESS) { + return rv; + } + + rv = apr_socket_timeout_set(conn->sock, 1 * APR_USEC_PER_SEC); + if (rv != APR_SUCCESS) { + return rv; + } + + rv = apr_socket_connect(conn->sock, sa); + if (rv != APR_SUCCESS) { + return rv; + } + + rv = apr_socket_timeout_set(conn->sock, + conn->rs->rwto * APR_USEC_PER_SEC); + if (rv != APR_SUCCESS) { + return rv; + } + + return rv; +} + +static apr_status_t +rc_conn_construct(void **conn_, void *params, apr_pool_t *pool) +{ + apr_status_t rv = APR_SUCCESS; + apr_redis_conn_t *conn; + apr_pool_t *np; + apr_pool_t *tp; + apr_redis_server_t *rs = params; +#if APR_HAVE_SOCKADDR_UN + apr_int32_t family = rs->host[0] != '/' ? APR_INET : APR_UNIX; +#else + apr_int32_t family = APR_INET; +#endif + + rv = apr_pool_create(&np, pool); + if (rv != APR_SUCCESS) { + return rv; + } + + rv = apr_pool_create(&tp, np); + if (rv != APR_SUCCESS) { + apr_pool_destroy(np); + return rv; + } + + conn = apr_palloc(np, sizeof(apr_redis_conn_t)); + + conn->p = np; + conn->tp = tp; + + rv = apr_socket_create(&conn->sock, family, SOCK_STREAM, 0, np); + + if (rv != APR_SUCCESS) { + apr_pool_destroy(np); + return rv; + } + + conn->buffer = apr_palloc(conn->p, BUFFER_SIZE + 1); + conn->blen = 0; + conn->rs = rs; + + rv = conn_connect(conn); + if (rv != APR_SUCCESS) { + apr_pool_destroy(np); + } + else { + *conn_ = conn; + } + + return rv; +} + +#if APR_HAS_THREADS +static apr_status_t +rc_conn_destruct(void *conn_, void *params, apr_pool_t *pool) +{ + apr_redis_conn_t *conn = (apr_redis_conn_t *) conn_; + struct iovec vec[3]; + apr_size_t written; + + /* send a quit message to the Redis server to be nice about it. */ + + /* + * RESP Command: + * *1 + * $4 + * QUIT + */ + vec[0].iov_base = RC_RESP_1; + vec[0].iov_len = RC_RESP_1_LEN; + + vec[1].iov_base = RC_QUIT_SIZE; + vec[1].iov_len = RC_QUIT_SIZE_LEN; + + vec[2].iov_base = RC_QUIT; + vec[2].iov_len = RC_QUIT_LEN; + + /* Return values not checked, since we just want to make it go away. */ + apr_socket_sendv(conn->sock, vec, 3, &written); + apr_socket_close(conn->sock); + + apr_pool_destroy(conn->p); + + return APR_SUCCESS; +} +#endif + +APR_DECLARE(apr_status_t) apr_redis_server_create(apr_pool_t *p, + const char *host, + apr_port_t port, + apr_uint32_t min, + apr_uint32_t smax, + apr_uint32_t max, + apr_uint32_t ttl, + apr_uint32_t rwto, + apr_redis_server_t **rs) +{ + apr_status_t rv = APR_SUCCESS; + apr_redis_server_t *server; + apr_pool_t *np; + + rv = apr_pool_create(&np, p); + + server = apr_palloc(np, sizeof(apr_redis_server_t)); + + server->p = np; + server->host = apr_pstrdup(np, host); + server->port = port; + server->status = APR_RC_SERVER_DEAD; + server->rwto = rwto; + server->version.major = 0; + server->version.minor = 0; + server->version.patch = 0; + +#if APR_HAS_THREADS + rv = apr_thread_mutex_create(&server->lock, APR_THREAD_MUTEX_DEFAULT, np); + if (rv != APR_SUCCESS) { + return rv; + } + + rv = apr_reslist_create(&server->conns, + min, /* hard minimum */ + smax, /* soft maximum */ + max, /* hard maximum */ + ttl, /* Time to live */ + rc_conn_construct, /* Make a New Connection */ + rc_conn_destruct, /* Kill Old Connection */ + server, np); + if (rv != APR_SUCCESS) { + return rv; + } + + apr_reslist_cleanup_order_set(server->conns, APR_RESLIST_CLEANUP_FIRST); +#else + rv = rc_conn_construct((void **) &(server->conn), server, np); + if (rv != APR_SUCCESS) { + return rv; + } +#endif + + *rs = server; + + return rv; +} + +APR_DECLARE(apr_status_t) apr_redis_create(apr_pool_t *p, + apr_uint16_t max_servers, + apr_uint32_t flags, + apr_redis_t **redis) +{ + apr_status_t rv = APR_SUCCESS; + apr_redis_t *rc; + + rc = apr_palloc(p, sizeof(apr_redis_t)); + rc->p = p; + rc->nalloc = max_servers; + rc->ntotal = 0; + rc->live_servers = + apr_palloc(p, rc->nalloc * sizeof(struct apr_redis_server_t *)); + rc->hash_func = NULL; + rc->hash_baton = NULL; + rc->server_func = NULL; + rc->server_baton = NULL; + *redis = rc; + return rv; +} + + +/* The crc32 functions and data was originally written by Spencer + * Garrett <srg@quick.com> and was gleaned from the PostgreSQL source + * tree via the files contrib/ltree/crc32.[ch] and from FreeBSD at + * src/usr.bin/cksum/crc32.c. + */ + +static const apr_uint32_t crc32tab[256] = { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, + 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, + 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, + 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, + 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, + 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, + 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, + 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, + 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, + 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, + 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, + 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, + 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, + 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, + 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, + 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, + 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, + 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, + 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, + 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, + 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, + 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, + 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, + 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, + 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, + 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, + 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, + 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, + 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, + 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, + 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, + 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, + 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, + 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, + 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, + 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, + 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, + 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, + 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, + 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, + 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, + 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, + 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, + 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, + 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, + 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, + 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, + 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d, +}; + +APR_DECLARE(apr_uint32_t) apr_redis_hash_crc32(void *baton, + const char *data, + const apr_size_t data_len) +{ + apr_uint32_t i; + apr_uint32_t crc; + crc = ~0; + + for (i = 0; i < data_len; i++) + crc = (crc >> 8) ^ crc32tab[(crc ^ (data[i])) & 0xff]; + + return ~crc; +} + +APR_DECLARE(apr_uint32_t) apr_redis_hash_default(void *baton, + const char *data, + const apr_size_t data_len) +{ + /* The default Perl Client doesn't actually use just crc32 -- it shifts it again + * like this.... + */ + return ((apr_redis_hash_crc32(baton, data, data_len) >> 16) & 0x7fff); +} + +APR_DECLARE(apr_uint32_t) apr_redis_hash(apr_redis_t *rc, + const char *data, + const apr_size_t data_len) +{ + if (rc->hash_func) { + return rc->hash_func(rc->hash_baton, data, data_len); + } + else { + return apr_redis_hash_default(NULL, data, data_len); + } +} + +static apr_status_t get_server_line(apr_redis_conn_t *conn) +{ + apr_size_t bsize = BUFFER_SIZE; + apr_status_t rv = APR_SUCCESS; + + rv = apr_brigade_split_line(conn->tb, conn->bb, APR_BLOCK_READ, + BUFFER_SIZE); + + if (rv != APR_SUCCESS) { + return rv; + } + + rv = apr_brigade_flatten(conn->tb, conn->buffer, &bsize); + + if (rv != APR_SUCCESS) { + return rv; + } + + conn->blen = bsize; + conn->buffer[bsize] = '\0'; + + return apr_brigade_cleanup(conn->tb); +} + +APR_DECLARE(apr_status_t) apr_redis_set(apr_redis_t *rc, + const char *key, + char *data, + const apr_size_t data_size, + apr_uint16_t flags) +{ + apr_uint32_t hash; + apr_redis_server_t *rs; + apr_redis_conn_t *conn; + apr_status_t rv; + apr_size_t written; + struct iovec vec[9]; + char keysize_str[LILBUFF_SIZE]; + char datasize_str[LILBUFF_SIZE]; + apr_size_t len, klen; + + klen = strlen(key); + hash = apr_redis_hash(rc, key, klen); + + rs = apr_redis_find_server_hash(rc, hash); + + if (rs == NULL) + return APR_NOTFOUND; + + rv = rs_find_conn(rs, &conn); + + if (rv != APR_SUCCESS) { + apr_redis_disable_server(rc, rs); + return rv; + } + + /* + * RESP Command: + * *3 + * $3 + * SET + * $<keylen> + * key + * $<datalen> + * data + */ + + vec[0].iov_base = RC_RESP_3; + vec[0].iov_len = RC_RESP_3_LEN; + + vec[1].iov_base = RC_SET_SIZE; + vec[1].iov_len = RC_SET_SIZE_LEN; + + vec[2].iov_base = RC_SET; + vec[2].iov_len = RC_SET_LEN; + + len = apr_snprintf(keysize_str, LILBUFF_SIZE, "$%" APR_SIZE_T_FMT "\r\n", klen); + vec[3].iov_base = keysize_str; + vec[3].iov_len = len; + + vec[4].iov_base = (void *) key; + vec[4].iov_len = klen; + + vec[5].iov_base = RC_EOL; + vec[5].iov_len = RC_EOL_LEN; + + len = apr_snprintf(datasize_str, LILBUFF_SIZE, "$%" APR_SIZE_T_FMT "\r\n", + data_size); + vec[6].iov_base = datasize_str; + vec[6].iov_len = len; + + vec[7].iov_base = data; + vec[7].iov_len = data_size; + + vec[8].iov_base = RC_EOL; + vec[8].iov_len = RC_EOL_LEN; + + rv = apr_socket_sendv(conn->sock, vec, 9, &written); + + if (rv != APR_SUCCESS) { + rs_bad_conn(rs, conn); + apr_redis_disable_server(rc, rs); + return rv; + } + + rv = get_server_line(conn); + if (rv != APR_SUCCESS) { + rs_bad_conn(rs, conn); + apr_redis_disable_server(rc, rs); + return rv; + } + + if (strcmp(conn->buffer, RS_STORED RC_EOL) == 0) { + rv = APR_SUCCESS; + } + else if (strcmp(conn->buffer, RS_NOT_STORED RC_EOL) == 0) { + rv = APR_EEXIST; + } + else { + rv = APR_EGENERAL; + } + + rs_release_conn(rs, conn); + return rv; +} + +APR_DECLARE(apr_status_t) apr_redis_setex(apr_redis_t *rc, + const char *key, + char *data, + const apr_size_t data_size, + apr_uint32_t timeout, + apr_uint16_t flags) +{ + apr_uint32_t hash; + apr_redis_server_t *rs; + apr_redis_conn_t *conn; + apr_status_t rv; + apr_size_t written; + struct iovec vec[11]; + char keysize_str[LILBUFF_SIZE]; + char expire_str[LILBUFF_SIZE]; + char expiresize_str[LILBUFF_SIZE]; + char datasize_str[LILBUFF_SIZE]; + apr_size_t len, klen, expire_len; + + + klen = strlen(key); + hash = apr_redis_hash(rc, key, klen); + + rs = apr_redis_find_server_hash(rc, hash); + + if (rs == NULL) + return APR_NOTFOUND; + + rv = rs_find_conn(rs, &conn); + + if (rv != APR_SUCCESS) { + apr_redis_disable_server(rc, rs); + return rv; + } + + /* + * RESP Command: + * *4 + * $5 + * SETEX + * $<keylen> + * key + * $<expirelen> + * expirey + * $<datalen> + * data + */ + + vec[0].iov_base = RC_RESP_4; + vec[0].iov_len = RC_RESP_4_LEN; + + vec[1].iov_base = RC_SETEX_SIZE; + vec[1].iov_len = RC_SETEX_SIZE_LEN; + + vec[2].iov_base = RC_SETEX; + vec[2].iov_len = RC_SETEX_LEN; + + len = apr_snprintf(keysize_str, LILBUFF_SIZE, "$%" APR_SIZE_T_FMT "\r\n", klen); + vec[3].iov_base = keysize_str; + vec[3].iov_len = len; + + vec[4].iov_base = (void *) key; + vec[4].iov_len = klen; + + vec[5].iov_base = RC_EOL; + vec[5].iov_len = RC_EOL_LEN; + + expire_len = apr_snprintf(expire_str, LILBUFF_SIZE, "%u\r\n", timeout); + len = apr_snprintf(expiresize_str, LILBUFF_SIZE, "$%" APR_SIZE_T_FMT "\r\n", + expire_len - 2); + vec[6].iov_base = (void *) expiresize_str; + vec[6].iov_len = len; + + vec[7].iov_base = (void *) expire_str; + vec[7].iov_len = expire_len; + + len = apr_snprintf(datasize_str, LILBUFF_SIZE, "$%" APR_SIZE_T_FMT "\r\n", + data_size); + vec[8].iov_base = datasize_str; + vec[8].iov_len = len; + + vec[9].iov_base = data; + vec[9].iov_len = data_size; + + vec[10].iov_base = RC_EOL; + vec[10].iov_len = RC_EOL_LEN; + + rv = apr_socket_sendv(conn->sock, vec, 11, &written); + + if (rv != APR_SUCCESS) { + rs_bad_conn(rs, conn); + apr_redis_disable_server(rc, rs); + return rv; + } + + rv = get_server_line(conn); + if (rv != APR_SUCCESS) { + rs_bad_conn(rs, conn); + apr_redis_disable_server(rc, rs); + return rv; + } + + if (strcmp(conn->buffer, RS_STORED RC_EOL) == 0) { + rv = APR_SUCCESS; + } + else if (strcmp(conn->buffer, RS_NOT_STORED RC_EOL) == 0) { + rv = APR_EEXIST; + } + else { + rv = APR_EGENERAL; + } + + rs_release_conn(rs, conn); + return rv; +} + +static apr_status_t grab_bulk_resp(apr_redis_server_t *rs, apr_redis_t *rc, + apr_redis_conn_t *conn, apr_pool_t *p, + char **baton, apr_size_t *new_length) +{ + char *length; + char *last; + apr_status_t rv; + apr_size_t len = 0; + *new_length = 0; + + length = apr_strtok(conn->buffer + 1, " ", &last); + if (length) { + len = strtol(length, (char **) NULL, 10); + } + + if (len == 0) { + *new_length = 0; + *baton = NULL; + } + else { + apr_bucket_brigade *bbb; + apr_bucket *e; + + /* eat the trailing \r\n */ + rv = apr_brigade_partition(conn->bb, len + 2, &e); + + if (rv != APR_SUCCESS) { + rs_bad_conn(rs, conn); + if (rc) + apr_redis_disable_server(rc, rs); + return rv; + } + + bbb = apr_brigade_split(conn->bb, e); + + rv = apr_brigade_pflatten(conn->bb, baton, &len, p); + + if (rv != APR_SUCCESS) { + rs_bad_conn(rs, conn); + if (rc) + apr_redis_disable_server(rc, rs); + return rv; + } + + rv = apr_brigade_destroy(conn->bb); + if (rv != APR_SUCCESS) { + rs_bad_conn(rs, conn); + if (rc) + apr_redis_disable_server(rc, rs); + return rv; + } + + conn->bb = bbb; + + *new_length = len - 2; + (*baton)[*new_length] = '\0'; + } + return APR_SUCCESS; + +} + +APR_DECLARE(apr_status_t) apr_redis_getp(apr_redis_t *rc, + apr_pool_t *p, + const char *key, + char **baton, + apr_size_t *new_length, + apr_uint16_t *flags) +{ + apr_status_t rv; + apr_redis_server_t *rs; + apr_redis_conn_t *conn; + apr_uint32_t hash; + apr_size_t written; + apr_size_t len, klen; + struct iovec vec[6]; + char keysize_str[LILBUFF_SIZE]; + + klen = strlen(key); + hash = apr_redis_hash(rc, key, klen); + rs = apr_redis_find_server_hash(rc, hash); + + if (rs == NULL) + return APR_NOTFOUND; + + rv = rs_find_conn(rs, &conn); + + if (rv != APR_SUCCESS) { + apr_redis_disable_server(rc, rs); + return rv; + } + + /* + * RESP Command: + * *2 + * $3 + * GET + * $<keylen> + * key + */ + vec[0].iov_base = RC_RESP_2; + vec[0].iov_len = RC_RESP_2_LEN; + + vec[1].iov_base = RC_GET_SIZE; + vec[1].iov_len = RC_GET_SIZE_LEN; + + vec[2].iov_base = RC_GET; + vec[2].iov_len = RC_GET_LEN; + + len = apr_snprintf(keysize_str, LILBUFF_SIZE, "$%" APR_SIZE_T_FMT "\r\n", + klen); + vec[3].iov_base = keysize_str; + vec[3].iov_len = len; + + vec[4].iov_base = (void *) key; + vec[4].iov_len = klen; + + vec[5].iov_base = RC_EOL; + vec[5].iov_len = RC_EOL_LEN; + + rv = apr_socket_sendv(conn->sock, vec, 6, &written); + + + if (rv != APR_SUCCESS) { + rs_bad_conn(rs, conn); + apr_redis_disable_server(rc, rs); + return rv; + } + + rv = get_server_line(conn); + if (rv != APR_SUCCESS) { + rs_bad_conn(rs, conn); + apr_redis_disable_server(rc, rs); + return rv; + } + if (strncmp(RS_NOT_FOUND_GET, conn->buffer, RS_NOT_FOUND_GET_LEN) == 0) { + rv = APR_NOTFOUND; + } + else if (strncmp(RS_TYPE_STRING, conn->buffer, RS_TYPE_STRING_LEN) == 0) { + rv = grab_bulk_resp(rs, rc, conn, p, baton, new_length); + } + else { + rv = APR_EGENERAL; + } + + rs_release_conn(rs, conn); + return rv; +} + +APR_DECLARE(apr_status_t) + apr_redis_delete(apr_redis_t *rc, const char *key, apr_uint32_t timeout) +{ + apr_status_t rv; + apr_redis_server_t *rs; + apr_redis_conn_t *conn; + apr_uint32_t hash; + apr_size_t written; + struct iovec vec[6]; + apr_size_t len, klen; + char keysize_str[LILBUFF_SIZE]; + + klen = strlen(key); + hash = apr_redis_hash(rc, key, klen); + rs = apr_redis_find_server_hash(rc, hash); + if (rs == NULL) + return APR_NOTFOUND; + + rv = rs_find_conn(rs, &conn); + + if (rv != APR_SUCCESS) { + apr_redis_disable_server(rc, rs); + return rv; + } + + /* + * RESP Command: + * *2 + * $3 + * DEL + * $<keylen> + * key + */ + vec[0].iov_base = RC_RESP_2; + vec[0].iov_len = RC_RESP_2_LEN; + + vec[1].iov_base = RC_DEL_SIZE; + vec[1].iov_len = RC_DEL_SIZE_LEN; + + vec[2].iov_base = RC_DEL; + vec[2].iov_len = RC_DEL_LEN; + + len = apr_snprintf(keysize_str, LILBUFF_SIZE, "$%" APR_SIZE_T_FMT "\r\n", + klen); + vec[3].iov_base = keysize_str; + vec[3].iov_len = len; + + vec[4].iov_base = (void *) key; + vec[4].iov_len = klen; + + vec[5].iov_base = RC_EOL; + vec[5].iov_len = RC_EOL_LEN; + + rv = apr_socket_sendv(conn->sock, vec, 6, &written); + + if (rv != APR_SUCCESS) { + rs_bad_conn(rs, conn); + apr_redis_disable_server(rc, rs); + return rv; + } + + rv = get_server_line(conn); + if (rv != APR_SUCCESS) { + rs_bad_conn(rs, conn); + apr_redis_disable_server(rc, rs); + return rv; + } + + if (strncmp(RS_DELETED, conn->buffer, RS_DELETED_LEN) == 0) { + rv = APR_SUCCESS; + } + else if (strncmp(RS_NOT_FOUND_DEL, conn->buffer, RS_NOT_FOUND_DEL_LEN) == 0) { + rv = APR_NOTFOUND; + } + else { + rv = APR_EGENERAL; + } + + rs_release_conn(rs, conn); + return rv; +} + +APR_DECLARE(apr_status_t) +apr_redis_ping(apr_redis_server_t *rs) +{ + apr_status_t rv; + apr_size_t written; + struct iovec vec[3]; + apr_redis_conn_t *conn; + + rv = rs_find_conn(rs, &conn); + + if (rv != APR_SUCCESS) { + return rv; + } + + /* + * RESP Command: + * *1 + * $4 + * PING + */ + vec[0].iov_base = RC_RESP_1; + vec[0].iov_len = RC_RESP_1_LEN; + + vec[1].iov_base = RC_PING_SIZE; + vec[1].iov_len = RC_PING_SIZE_LEN; + + vec[2].iov_base = RC_PING; + vec[2].iov_len = RC_PING_LEN; + + rv = apr_socket_sendv(conn->sock, vec, 3, &written); + + if (rv != APR_SUCCESS) { + rs_bad_conn(rs, conn); + return rv; + } + + rv = get_server_line(conn); + if (rv == APR_SUCCESS) { + /* we got *something*. Was it Redis? */ + if (strncmp(conn->buffer, "+PONG", sizeof("+PONG")-1) != 0) { + rv = APR_EGENERAL; + } + } + rs_release_conn(rs, conn); + return rv; +} + +APR_DECLARE(apr_status_t) +apr_redis_info(apr_redis_server_t *rs, apr_pool_t *p, char **baton) +{ + apr_status_t rv; + apr_redis_conn_t *conn; + apr_size_t written; + struct iovec vec[3]; + + rv = rs_find_conn(rs, &conn); + + if (rv != APR_SUCCESS) { + return rv; + } + + /* + * RESP Command: + * *1 + * $4 + * INFO + */ + vec[0].iov_base = RC_RESP_1; + vec[0].iov_len = RC_RESP_1_LEN; + + vec[1].iov_base = RC_INFO_SIZE; + vec[1].iov_len = RC_INFO_SIZE_LEN; + + vec[2].iov_base = RC_INFO; + vec[2].iov_len = RC_INFO_LEN; + + rv = apr_socket_sendv(conn->sock, vec, 3, &written); + + if (rv != APR_SUCCESS) { + rs_bad_conn(rs, conn); + return rv; + } + + rv = get_server_line(conn); + if (rv != APR_SUCCESS) { + rs_bad_conn(rs, conn); + return rv; + } + + if (strncmp(RS_TYPE_STRING, conn->buffer, RS_TYPE_STRING_LEN) == 0) { + apr_size_t nl; + rv = grab_bulk_resp(rs, NULL, conn, p, baton, &nl); + } else { + rs_bad_conn(rs, conn); + rv = APR_EGENERAL; + } + + rs_release_conn(rs, conn); + return rv; +} + +#define RV_FIELD "redis_version:" +APR_DECLARE(apr_status_t) +apr_redis_version(apr_redis_server_t *rs, apr_pool_t *p, char **baton) +{ + apr_status_t rv; + char *ptr, *eptr; + apr_pool_t *subpool; + + /* Have we already obtained the version number? */ + if (rs->version.minor != 0) { + if (baton) + *baton = apr_pstrdup(p, rs->version.number); + return APR_SUCCESS; + } + if (apr_pool_create(&subpool, p) != APR_SUCCESS) { + /* well, we tried */ + subpool = p; + } + rv = apr_redis_info(rs, subpool, baton); + + if (rv != APR_SUCCESS) { + if (subpool != p) { + apr_pool_destroy(subpool); + } + return rv; + } + + ptr = strstr(*baton, RV_FIELD); + if (ptr) { + rs->version.major = strtol(ptr + sizeof(RV_FIELD) - 1, &eptr, 10); + ptr = eptr + 1; + rs->version.minor = strtol(ptr, &eptr, 10); + ptr = eptr + 1; + rs->version.patch = strtol(ptr, &eptr, 10); + rs->version.number = apr_psprintf(rs->p, "%d.%d.%d", + rs->version.major, rs->version.minor, + rs->version.patch); + } + if (baton) + *baton = apr_pstrdup(p, rs->version.number); + if (subpool != p) { + apr_pool_destroy(subpool); + } + return APR_SUCCESS; +} + +static apr_status_t plus_minus(apr_redis_t *rc, + int incr, + const char *key, + apr_int32_t inc, + apr_uint32_t *new_value) +{ + apr_status_t rv; + apr_redis_server_t *rs; + apr_redis_conn_t *conn; + apr_uint32_t hash; + apr_size_t written; + apr_size_t len, klen; + struct iovec vec[12]; + char keysize_str[LILBUFF_SIZE]; + char inc_str[LILBUFF_SIZE]; + char inc_str_len[LILBUFF_SIZE]; + int i = 0; + + klen = strlen(key); + hash = apr_redis_hash(rc, key, klen); + rs = apr_redis_find_server_hash(rc, hash); + if (rs == NULL) + return APR_NOTFOUND; + + rv = rs_find_conn(rs, &conn); + + if (rv != APR_SUCCESS) { + apr_redis_disable_server(rc, rs); + return rv; + } + + /* + * RESP Command: + * *2|*3 + * $4|$6 + * INCR/DECR|INCRBY/DECRBY + * $<keylen> + * key + * <:inc> + */ + if (inc == 1) { + vec[i].iov_base = RC_RESP_2; + vec[i].iov_len = RC_RESP_2_LEN; + i++; + + vec[i].iov_base = "$4\r\n"; + vec[i].iov_len = sizeof("$4\r\n")-1; + i++; + + if (incr) + vec[i].iov_base = "INCR\r\n"; + else + vec[i].iov_base = "DECR\r\n"; + vec[i].iov_len = sizeof("INCR\r\n")-1; + i++; + } + else { + vec[i].iov_base = RC_RESP_3; + vec[i].iov_len = RC_RESP_3_LEN; + i++; + + vec[i].iov_base = "$6\r\n"; + vec[i].iov_len = sizeof("$6\r\n")-1; + i++; + + if (incr) + vec[i].iov_base = "INCRBY\r\n"; + else + vec[i].iov_base = "DECRBY\r\n"; + vec[i].iov_len = sizeof("INCRBY\r\n")-1; + i++; + } + + len = apr_snprintf(keysize_str, LILBUFF_SIZE, "$%" APR_SIZE_T_FMT "\r\n", + klen); + vec[i].iov_base = keysize_str; + vec[i].iov_len = len; + i++; + + vec[i].iov_base = (void *) key; + vec[i].iov_len = klen; + i++; + + vec[i].iov_base = RC_EOL; + vec[i].iov_len = RC_EOL_LEN; + i++; + + if (inc != 1) { + len = apr_snprintf(inc_str, LILBUFF_SIZE, "%d\r\n", inc); + klen = apr_snprintf(inc_str_len, LILBUFF_SIZE, "$%d\r\n", (int)(len-2)); + vec[i].iov_base = inc_str_len; + vec[i].iov_len = klen; + i++; + + vec[i].iov_base = inc_str; + vec[i].iov_len = len; + i++; + + vec[i].iov_base = RC_EOL; + vec[i].iov_len = RC_EOL_LEN; + i++; + } + + rv = apr_socket_sendv(conn->sock, vec, i, &written); + + if (rv != APR_SUCCESS) { + rs_bad_conn(rs, conn); + apr_redis_disable_server(rc, rs); + return rv; + } + + rv = get_server_line(conn); + if (rv != APR_SUCCESS) { + rs_bad_conn(rs, conn); + apr_redis_disable_server(rc, rs); + return rv; + } + if (strncmp(RS_NOT_FOUND_GET, conn->buffer, RS_NOT_FOUND_GET_LEN) == 0) { + rv = APR_NOTFOUND; + } + else if (*conn->buffer == ':') { + *new_value = atoi((const char *)(conn->buffer + 1)); + rv = APR_SUCCESS; + } + else { + rv = APR_EGENERAL; + } + rs_release_conn(rs, conn); + return rv; +} + +APR_DECLARE(apr_status_t) +apr_redis_incr(apr_redis_t *rc, const char *key, apr_int32_t inc, apr_uint32_t *new_value) +{ + return plus_minus(rc, 1, key, inc, new_value); +} + +APR_DECLARE(apr_status_t) +apr_redis_decr(apr_redis_t *rc, const char *key, apr_int32_t inc, apr_uint32_t *new_value) +{ + return plus_minus(rc, 0, key, inc, new_value); +} + +APR_DECLARE(apr_status_t) +apr_redis_multgetp(apr_redis_t *rc, + apr_pool_t *temp_pool, + apr_pool_t *data_pool, + apr_hash_t *values) +{ + return APR_ENOTIMPL; +} + +/** + * Define all of the strings for stats + */ + +#define STAT_process_id "process_id:" +#define STAT_process_id_LEN (sizeof(STAT_process_id)-1) + +#define STAT_uptime_in_seconds "uptime_in_seconds:" +#define STAT_uptime_in_seconds_LEN (sizeof(STAT_uptime_in_seconds)-1) + +#define STAT_arch_bits "arch_bits:" +#define STAT_arch_bits_LEN (sizeof(STAT_arch_bits)-1) + +#define STAT_connected_clients "connected_clients:" +#define STAT_connected_clients_LEN (sizeof(STAT_connected_clients)-1) + +#define STAT_blocked_clients "blocked_clients:" +#define STAT_blocked_clients_LEN (sizeof(STAT_blocked_clients)-1) + +#define STAT_maxmemory "maxmemory:" +#define STAT_maxmemory_LEN (sizeof(STAT_maxmemory)-1) + +#define STAT_used_memory "used_memory:" +#define STAT_used_memory_LEN (sizeof(STAT_used_memory)-1) + +#define STAT_total_system_memory "total_system_memory:" +#define STAT_total_system_memory_LEN (sizeof(STAT_total_system_memory)-1) + +#define STAT_total_connections_received "total_connections_received:" +#define STAT_total_connections_received_LEN (sizeof(STAT_total_connections_received)-1) + +#define STAT_total_commands_processed "total_commands_processed:" +#define STAT_total_commands_processed_LEN (sizeof(STAT_total_commands_processed)-1) + +#define STAT_rejected_connections "rejected_connections:" +#define STAT_rejected_connections_LEN (sizeof(STAT_rejected_connections)-1) + +#define STAT_total_net_input_bytes "total_net_input_bytes:" +#define STAT_total_net_input_bytes_LEN (sizeof(STAT_total_net_input_bytes)-1) + +#define STAT_total_net_output_bytes "total_net_output_bytes:" +#define STAT_total_net_output_bytes_LEN (sizeof(STAT_total_net_output_bytes)-1) + +#define STAT_keyspace_hits "keyspace_hits:" +#define STAT_keyspace_hits_LEN (sizeof(STAT_keyspace_hits)-1) + +#define STAT_keyspace_misses "keyspace_misses:" +#define STAT_keyspace_misses_LEN (sizeof(STAT_keyspace_misses)-1) + +#define STAT_connected_slaves "connected_slaves:" +#define STAT_connected_slaves_LEN (sizeof(STAT_connected_slaves)-1) + +#define STAT_used_cpu_sys "used_cpu_sys:" +#define STAT_used_cpu_sys_LEN (sizeof(STAT_used_cpu_sys)-1) + +#define STAT_used_cpu_user "used_cpu_user:" +#define STAT_used_cpu_user_LEN (sizeof(STAT_used_cpu_user)-1) + +#define STAT_cluster_enabled "cluster_enabled:" +#define STAT_cluster_enabled_LEN (sizeof(STAT_cluster_enabled)-1) + +static apr_uint32_t stat_read_uint32( char *buf) +{ + return atoi(buf); +} + +static apr_uint64_t stat_read_uint64(char *buf) +{ + return apr_atoi64(buf); +} + +#define rc_do_stat(name, type) \ + if ((ptr = strstr(info , STAT_ ## name )) != NULL ) { \ + char *str = ptr + (STAT_ ## name ## _LEN ); \ + stats-> name = stat_read_ ## type (str); \ + } + +static void update_stats(char *info, apr_redis_stats_t *stats) +{ + char *ptr; + + rc_do_stat(process_id, uint32); + rc_do_stat(uptime_in_seconds, uint32); + rc_do_stat(arch_bits, uint32); + rc_do_stat(connected_clients, uint32); + rc_do_stat(blocked_clients, uint32); + rc_do_stat(maxmemory, uint64); + rc_do_stat(used_memory, uint64); + rc_do_stat(total_system_memory, uint64); + rc_do_stat(total_connections_received, uint64); + rc_do_stat(total_commands_processed, uint64); + rc_do_stat(rejected_connections, uint64); + rc_do_stat(total_net_input_bytes, uint64); + rc_do_stat(total_net_output_bytes, uint64); + rc_do_stat(keyspace_hits, uint64); + rc_do_stat(keyspace_misses, uint64); + rc_do_stat(connected_slaves, uint32); + rc_do_stat(used_cpu_sys, uint32); + rc_do_stat(used_cpu_user, uint32); + rc_do_stat(cluster_enabled, uint32); +} + +APR_DECLARE(apr_status_t) +apr_redis_stats(apr_redis_server_t *rs, + apr_pool_t *p, + apr_redis_stats_t **stats) +{ + apr_status_t rv; + char *info; + apr_pool_t *subpool; + apr_redis_stats_t *ret; + char *ptr; + + if (apr_pool_create(&subpool, p) != APR_SUCCESS) { + /* well, we tried */ + subpool = p; + } + rv = apr_redis_info(rs, subpool, &info); + + if (rv != APR_SUCCESS) { + if (subpool != p) { + apr_pool_destroy(subpool); + } + return rv; + } + ret = apr_pcalloc(p, sizeof(apr_redis_stats_t)); + /* Get the bulk of the stats */ + update_stats(info, ret); + + /* Now the version number */ + if (rs->version.major != 0) { + ret->major = rs->version.major; + ret->minor = rs->version.minor; + ret->patch = rs->version.patch; + } + else { + char *eptr; + ptr = strstr(info, RV_FIELD); + if (ptr) { + ret->major = rs->version.major = strtol(ptr + sizeof(RV_FIELD) - 1, &eptr, 10); + ptr = eptr + 1; + ret->minor = rs->version.minor = strtol(ptr, &eptr, 10); + ptr = eptr + 1; + ret->patch = rs->version.patch = strtol(ptr, &eptr, 10); + } + } + + /* Finally, the role */ + ptr = strstr(info, "role:"); + if (!ptr) { + ret->role = APR_RS_SERVER_UNKNOWN; + } + else if (!strncmp("master", ptr + sizeof("role:") - 1, sizeof("master")-1)) { + ret->role = APR_RS_SERVER_MASTER; + } + else { + ret->role = APR_RS_SERVER_SLAVE; + } + if (stats) { + *stats = ret; + } + + return APR_SUCCESS; +} diff --git a/shmem/beos/shm.c b/shmem/beos/shm.c new file mode 100644 index 00000000000..fcd7c84d1e6 --- /dev/null +++ b/shmem/beos/shm.c @@ -0,0 +1,195 @@ +/* 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_general.h" +#include "apr_shm.h" +#include "apr_errno.h" +#include "apr_lib.h" +#include "apr_strings.h" +#include <stdio.h> +#include <stdlib.h> +#include <kernel/OS.h> +#include "apr_portable.h" + +struct apr_shm_t { + apr_pool_t *pool; + void *memblock; + void *ptr; + apr_size_t reqsize; + apr_size_t avail; + area_id aid; +}; + +APR_DECLARE(apr_status_t) apr_shm_create(apr_shm_t **m, + apr_size_t reqsize, + const char *filename, + apr_pool_t *p) +{ + apr_size_t pagesize; + area_id newid; + char *addr; + char shname[B_OS_NAME_LENGTH]; + + (*m) = (apr_shm_t *)apr_pcalloc(p, sizeof(apr_shm_t)); + /* we MUST allocate in pages, so calculate how big an area we need... */ + pagesize = ((reqsize + B_PAGE_SIZE - 1) / B_PAGE_SIZE) * B_PAGE_SIZE; + + if (!filename) { + int num = 0; + snprintf(shname, B_OS_NAME_LENGTH, "apr_shmem_%ld", find_thread(NULL)); + while (find_area(shname) >= 0) + snprintf(shname, B_OS_NAME_LENGTH, "apr_shmem_%ld_%d", + find_thread(NULL), num++); + } + newid = create_area(filename ? filename : shname, + (void*)&addr, B_ANY_ADDRESS, + pagesize, B_LAZY_LOCK, B_READ_AREA|B_WRITE_AREA); + + if (newid < 0) + return errno; + + (*m)->pool = p; + (*m)->aid = newid; + (*m)->memblock = addr; + (*m)->ptr = (void*)addr; + (*m)->avail = pagesize; /* record how big an area we actually created... */ + (*m)->reqsize = reqsize; + + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_shm_create_ex(apr_shm_t **m, + apr_size_t reqsize, + const char *filename, + apr_pool_t *p, + apr_int32_t flags) +{ + return apr_shm_create(m, reqsize, filename, p); +} + +APR_DECLARE(apr_status_t) apr_shm_destroy(apr_shm_t *m) +{ + delete_area(m->aid); + m->avail = 0; + m->memblock = NULL; + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_shm_remove(const char *filename, + apr_pool_t *pool) +{ + area_id deleteme = find_area(filename); + + if (deleteme == B_NAME_NOT_FOUND) + return APR_EINVAL; + + delete_area(deleteme); + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_shm_delete(apr_shm_t *m) +{ + if (m->filename) { + return apr_shm_remove(m->filename, m->pool); + } + else { + return APR_ENOTIMPL; + } +} + +APR_DECLARE(apr_status_t) apr_shm_attach(apr_shm_t **m, + const char *filename, + apr_pool_t *pool) +{ + area_info ai; + thread_info ti; + apr_shm_t *new_m; + area_id deleteme = find_area(filename); + + if (deleteme == B_NAME_NOT_FOUND) + return APR_EINVAL; + + new_m = (apr_shm_t*)apr_palloc(pool, sizeof(apr_shm_t*)); + if (new_m == NULL) + return APR_ENOMEM; + new_m->pool = pool; + + get_area_info(deleteme, &ai); + get_thread_info(find_thread(NULL), &ti); + + if (ti.team != ai.team) { + area_id narea; + + narea = clone_area(ai.name, &(ai.address), B_CLONE_ADDRESS, + B_READ_AREA|B_WRITE_AREA, ai.area); + + if (narea < B_OK) + return narea; + + get_area_info(narea, &ai); + new_m->aid = narea; + new_m->memblock = ai.address; + new_m->ptr = (void*)ai.address; + new_m->avail = ai.size; + new_m->reqsize = ai.size; + } + + (*m) = new_m; + + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_shm_attach_ex(apr_shm_t **m, + const char *filename, + apr_pool_t *pool, + apr_int32_t flags) +{ + return apr_shm_attach(m, filename, pool); +} + +APR_DECLARE(apr_status_t) apr_shm_detach(apr_shm_t *m) +{ + delete_area(m->aid); + return APR_SUCCESS; +} + +APR_DECLARE(void *) apr_shm_baseaddr_get(const apr_shm_t *m) +{ + return m->memblock; +} + +APR_DECLARE(apr_size_t) apr_shm_size_get(const apr_shm_t *m) +{ + return m->reqsize; +} + +APR_PERMS_SET_ENOTIMPL(shm) + +APR_POOL_IMPLEMENT_ACCESSOR(shm) + +APR_DECLARE(apr_status_t) apr_os_shm_get(apr_os_shm_t *osshm, + apr_shm_t *shm) +{ + return APR_ENOTIMPL; +} + +APR_DECLARE(apr_status_t) apr_os_shm_put(apr_shm_t **m, + apr_os_shm_t *osshm, + apr_pool_t *pool) +{ + return APR_ENOTIMPL; +} + diff --git a/shmem/os2/.cvsignore b/shmem/os2/.cvsignore deleted file mode 100644 index f3c7a7c5da6..00000000000 --- a/shmem/os2/.cvsignore +++ /dev/null @@ -1 +0,0 @@ -Makefile diff --git a/shmem/os2/Makefile.in b/shmem/os2/Makefile.in deleted file mode 100644 index 5e25e40384e..00000000000 --- a/shmem/os2/Makefile.in +++ /dev/null @@ -1,58 +0,0 @@ -#CFLAGS=$(OPTIM) $(CFLAGS1) $(EXTRA_CFLAGS) -#LIBS=$(EXTRA_LIBS) $(LIBS1) -#INCLUDES=$(INCLUDES1) $(INCLUDES0) $(EXTRA_INCLUDES) -#LDFLAGS=$(LDFLAGS1) $(EXTRA_LDFLAGS) - -CC=@CC@ -RANLIB=@RANLIB@ -CFLAGS=@CFLAGS@ @OPTIM@ -LIBS=@LIBS@ -LDFLAGS=@LDFLAGS@ $(LIBS) -INCDIR=../../inc -INCDIR1=../../include -INCDIR2=../../file_io/os2 -INCLUDES=-I$(INCDIR) -I$(INCDIR1) -I$(INCDIR2) -I. - -LIB=shmem.a - -OBJS=shmem.o - -.c.o: - $(CC) $(CFLAGS) -c $(INCLUDES) $< - -all: $(LIB) - -clean: - $(RM) -f *.o *.a *.so - -distclean: clean - -$(RM) -f Makefile - -$(OBJS): Makefile - -$(LIB): $(OBJS) - $(RM) -f $@ - $(AR) cr $@ $(OBJS) - $(RANLIB) $@ - -# -# We really don't expect end users to use this rule. It works only with -# gcc, and rebuilds Makefile.tmpl. You have to re-run Configure after -# using it. -# -depend: - cp Makefile.in Makefile.in.bak \ - && sed -ne '1,/^# DO NOT REMOVE/p' Makefile.in > Makefile.new \ - && gcc -MM $(INCLUDES) $(CFLAGS) *.c | sed -e "s%\\\\\(.\)%/\\1%g" >> Makefile.new \ - && sed -e '1,$$s: $(INCDIR)/: $$(INCDIR)/:g' \ - -e '1,$$s: $(INCDIR1)/: $$(INCDIR1)/:g' \ - -e '1,$$s: $(INCDIR2)/: $$(INCDIR2)/:g' \ - -e '1,$$s: $(OSDIR)/: $$(OSDIR)/:g' Makefile.new \ - > Makefile.in \ - && rm Makefile.new - -# DO NOT REMOVE -shmem.o: shmem.c $(INCDIR1)/apr_general.h $(INCDIR1)/apr.h \ - $(INCDIR1)/apr_errno.h $(INCDIR1)/apr_shmem.h \ - $(INCDIR1)/apr_lib.h $(INCDIR1)/apr_file_io.h \ - $(INCDIR1)/apr_time.h $(INCDIR1)/apr_thread_proc.h diff --git a/shmem/os2/shm.c b/shmem/os2/shm.c new file mode 100644 index 00000000000..b6ef7811aea --- /dev/null +++ b/shmem/os2/shm.c @@ -0,0 +1,168 @@ +/* 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_general.h" +#include "apr_shm.h" +#include "apr_errno.h" +#include "apr_lib.h" +#include "apr_strings.h" +#include "apr_portable.h" + +struct apr_shm_t { + apr_pool_t *pool; + void *memblock; +}; + +APR_DECLARE(apr_status_t) apr_shm_create(apr_shm_t **m, + apr_size_t reqsize, + const char *filename, + apr_pool_t *pool) +{ + int rc; + apr_shm_t *newm = (apr_shm_t *)apr_palloc(pool, sizeof(apr_shm_t)); + char *name = NULL; + ULONG flags = PAG_COMMIT|PAG_READ|PAG_WRITE; + + newm->pool = pool; + + if (filename) { + name = apr_pstrcat(pool, "\\SHAREMEM\\", filename, NULL); + } + + if (name == NULL) { + flags |= OBJ_GETTABLE; + } + + rc = DosAllocSharedMem(&(newm->memblock), name, reqsize, flags); + + if (rc) { + return APR_FROM_OS_ERROR(rc); + } + + *m = newm; + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_shm_create_ex(apr_shm_t **m, + apr_size_t reqsize, + const char *filename, + apr_pool_t *p, + apr_int32_t flags) +{ + return apr_shm_create(m, reqsize, filename, p); +} + +APR_DECLARE(apr_status_t) apr_shm_destroy(apr_shm_t *m) +{ + DosFreeMem(m->memblock); + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_shm_remove(const char *filename, + apr_pool_t *pool) +{ + return APR_ENOTIMPL; +} + +APR_DECLARE(apr_status_t) apr_shm_delete(apr_shm_t *m) +{ + return APR_ENOTIMPL; +} + +APR_DECLARE(apr_status_t) apr_shm_attach(apr_shm_t **m, + const char *filename, + apr_pool_t *pool) +{ + int rc; + apr_shm_t *newm = (apr_shm_t *)apr_palloc(pool, sizeof(apr_shm_t)); + char *name = NULL; + ULONG flags = PAG_READ|PAG_WRITE; + + newm->pool = pool; + name = apr_pstrcat(pool, "\\SHAREMEM\\", filename, NULL); + + rc = DosGetNamedSharedMem(&(newm->memblock), name, flags); + + if (rc) { + return APR_FROM_OS_ERROR(rc); + } + + *m = newm; + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_shm_attach_ex(apr_shm_t **m, + const char *filename, + apr_pool_t *pool, + apr_int32_t flags) +{ + return apr_shm_attach(m, filename, pool); +} + +APR_DECLARE(apr_status_t) apr_shm_detach(apr_shm_t *m) +{ + int rc = 0; + + if (m->memblock) { + rc = DosFreeMem(m->memblock); + } + + return APR_FROM_OS_ERROR(rc); +} + +APR_DECLARE(void *) apr_shm_baseaddr_get(const apr_shm_t *m) +{ + return m->memblock; +} + +APR_DECLARE(apr_size_t) apr_shm_size_get(const apr_shm_t *m) +{ + ULONG flags, size = 0x1000000; + DosQueryMem(m->memblock, &size, &flags); + return size; +} + +APR_PERMS_SET_ENOTIMPL(shm) + +APR_POOL_IMPLEMENT_ACCESSOR(shm) + +APR_DECLARE(apr_status_t) apr_os_shm_get(apr_os_shm_t *osshm, + apr_shm_t *shm) +{ + *osshm = shm->memblock; + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_os_shm_put(apr_shm_t **m, + apr_os_shm_t *osshm, + apr_pool_t *pool) +{ + int rc; + apr_shm_t *newm = (apr_shm_t *)apr_palloc(pool, sizeof(apr_shm_t)); + ULONG flags = PAG_COMMIT|PAG_READ|PAG_WRITE; + + newm->pool = pool; + + rc = DosGetSharedMem(&(newm->memblock), flags); + + if (rc) { + return APR_FROM_OS_ERROR(rc); + } + + *m = newm; + return APR_SUCCESS; +} + diff --git a/shmem/os2/shmem.c b/shmem/os2/shmem.c deleted file mode 100644 index 364f1941501..00000000000 --- a/shmem/os2/shmem.c +++ /dev/null @@ -1,158 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#include "apr_general.h" -#include "apr_shmem.h" -#include "apr_errno.h" -#include "apr_lib.h" -#include <umalloc.h> -#include <stdlib.h> -#define INCL_DOS -#include <os2.h> - -struct shmem_t { - void *memblock; - Heap_t heap; -}; - - - -ap_status_t ap_shm_init(struct shmem_t **m, ap_size_t reqsize, const char *file, ap_pool_t *cont) -{ - int rc; - struct shmem_t *newm = (struct shmem_t *)ap_palloc(cont, sizeof(struct shmem_t)); - char *name = NULL; - - if (file) - name = ap_pstrcat(cont, "\\SHAREMEM\\", file, NULL); - - rc = DosAllocSharedMem(&(newm->memblock), name, reqsize, PAG_COMMIT|OBJ_GETTABLE|PAG_READ|PAG_WRITE); - - if (rc) - return APR_OS2_STATUS(rc); - - newm->heap = _ucreate(newm->memblock, reqsize, !_BLOCK_CLEAN, _HEAP_REGULAR|_HEAP_SHARED, NULL, NULL); - _uopen(newm->heap); - *m = newm; - return APR_SUCCESS; -} - - - -ap_status_t ap_shm_destroy(struct shmem_t *m) -{ - _uclose(m->heap); - _udestroy(m->heap, _FORCE); - DosFreeMem(m->memblock); - return APR_SUCCESS; -} - - - -void *ap_shm_malloc(struct shmem_t *m, ap_size_t reqsize) -{ - return _umalloc(m->heap, reqsize); -} - - - -void *ap_shm_calloc(struct shmem_t *m, ap_size_t size) -{ - return _ucalloc(m->heap, size, 1); -} - - - -ap_status_t ap_shm_free(struct shmem_t *m, void *entity) -{ - free(entity); - return APR_SUCCESS; -} - - - -ap_status_t ap_get_shm_name(ap_shmem_t *c, ap_shm_name_t **name) -{ - return APR_ANONYMOUS; -} - - - -ap_status_t ap_set_shm_name(ap_shmem_t *c, ap_shm_name_t *name) -{ - return APR_ANONYMOUS; -} - - - -ap_status_t ap_open_shmem(struct shmem_t *m) -{ - int rc; - - rc = DosGetSharedMem(m->memblock, PAG_READ|PAG_WRITE); - - if (rc) - return APR_OS2_STATUS(rc); - - _uopen(m->heap); - return APR_SUCCESS; -} - - - -ap_status_t ap_shm_avail(struct shmem_t *c, ap_size_t *size) -{ - - return APR_ENOTIMPL; -} diff --git a/shmem/unix/.cvsignore b/shmem/unix/.cvsignore deleted file mode 100644 index f3c7a7c5da6..00000000000 --- a/shmem/unix/.cvsignore +++ /dev/null @@ -1 +0,0 @@ -Makefile diff --git a/shmem/unix/Makefile.in b/shmem/unix/Makefile.in deleted file mode 100644 index 085863ddb8c..00000000000 --- a/shmem/unix/Makefile.in +++ /dev/null @@ -1,60 +0,0 @@ -#CFLAGS=$(OPTIM) $(CFLAGS1) $(EXTRA_CFLAGS) -#LIBS=$(EXTRA_LIBS) $(LIBS1) -#INCLUDES=$(INCLUDES1) $(INCLUDES0) $(EXTRA_INCLUDES) -#LDFLAGS=$(LDFLAGS1) $(EXTRA_LDFLAGS) - -RM=@RM@ -CC=@CC@ -RANLIB=@RANLIB@ -CFLAGS=@CFLAGS@ @OPTIM@ -LIBS=@LIBS@ -LDFLAGS=@LDFLAGS@ $(LIBS) -INCDIR=../../inc -INCDIR1=../../include -INCDIR2=../../misc/@OSDIR@ -INCLUDES=-I$(INCDIR) -I$(INCDIR1) -I$(INCDIR2) -Imm -I. - -LIB=libshmem.a - -OBJS=shmem.o - -.c.o: - $(CC) $(CFLAGS) -c $(INCLUDES) $< - -all: $(LIB) - -clean: - $(RM) -f *.o *.a *.so - cd mm; make clean; cd .. - -distclean: clean - -$(RM) -f Makefile - cd mm; make distclean; cd .. - -$(OBJS): Makefile - -$(LIB): $(OBJS) - $(RM) -f $@ - cd mm; make; cd .. - cp mm/mm_global.o mm/mm_alloc.o mm/mm_core.o mm/mm_lib.o mm/mm_vers.o . - $(AR) cr $@ $(OBJS) - $(RANLIB) $@ - -# -# We really don't expect end users to use this rule. It works only with -# gcc, and rebuilds Makefile.tmpl. You have to re-run Configure after -# using it. -# -depend: - cp Makefile.in Makefile.in.bak \ - && sed -ne '1,/^# DO NOT REMOVE/p' Makefile.in > Makefile.new \ - && gcc -MM $(INCLUDES) $(CFLAGS) *.c >> Makefile.new \ - && sed -e '1,$$s: $(INCDIR)/: $$(INCDIR)/:g' \ - -e '1,$$s: $(OSDIR)/: $$(OSDIR)/:g' Makefile.new \ - > Makefile.in \ - && rm Makefile.new - -# DO NOT REMOVE -shmem.o: shmem.c mm/mm.h ../../include/apr_general.h \ - ../../include/apr.h ../../include/apr_errno.h \ - ../../include/apr_shmem.h diff --git a/shmem/unix/mm/.cvsignore b/shmem/unix/mm/.cvsignore deleted file mode 100644 index c147a43f370..00000000000 --- a/shmem/unix/mm/.cvsignore +++ /dev/null @@ -1,11 +0,0 @@ -config.log -mm_conf.h -libtool -config.status -.libs -Makefile -mm-config -*.lo -*.la -mm_test -configure diff --git a/shmem/unix/mm/CHANGES b/shmem/unix/mm/CHANGES deleted file mode 100644 index 4048a223cb2..00000000000 --- a/shmem/unix/mm/CHANGES +++ /dev/null @@ -1,162 +0,0 @@ - - MM CHANGES - ========== - - Changes between 1.0.10 and 1.0.11 (27-Aug-1999 to 06-Sep-1999) - - *) Cleaned up various file permission in source tree - *) Enhanced mm-config.in: new --all option and less newlines - *) Added support --silent to libtool glue code in aclocal.m4 - *) Upgraded to GNU Pth's more recent config.{guess,sub} - *) Upgraded to GNU shtool 1.4.6 - *) Fixed --section for mm-config in Makefile.in - *) Added `void *' casts to MAP_FAILED (= -1) values to avoid - warnings under some platforms. - *) Fixed a few typos in mm.pod - - Changes between 1.0.9 and 1.0.10 (02-Jul-1999 to 27-Aug-1999) - - *) Changed "make dist" and "make snap" to use "shtool tarball" - *) Added #define KERNEL for SunOS to get SHM_R und SHM_W values. - *) Upgraded to GNU libtool 1.3.3 - *) Upgraded to GNU shtool 1.4.5 - *) Downgraded required Autoconf version to 2.12 - *) Added MM version number to test report - *) Added --enable-batch - *) Moved mm_lock_mode in mm.h to top to avoid warnings - - Changes between 1.0.8 and 1.0.9 (24-Jun-1999 to 02-Jul-1999) - - *) Fixed a nasty bug related to {MM,mm}_[un]lock(): - an additional semicolon broke the semantics. - *) Upgraded to released shtool 1.4.0 - *) Fixed `make test' - - Changes between 1.0.7 and 1.0.8 (22-Jun-1999 to 24-Jun-1999) - - *) Added important MAP_FAILED fallback also to Autoconf stuff - *) Upgraded to latest shtool 1.3.0-dev to fix two Awk problems - - Changes between 1.0.6 and 1.0.7 (06-Jun-1999 to 22-Jun-1999) - - *) Upgraded to latest shtool 1.3.0-dev - *) Avoid -g under non-debugging situation - *) Complain with a fatal error message when MM_SHM_MAXSEGSIZE - couldn't be determined. - *) Updated config.guess/config.sub - *) Fixed a nasty permission bug for the lock files: - they were opened write-only, but at least fcntl() - requires them to be opened read-write. - *) Check return value of mm_core_lock() in mm_alloc.c - - Changes between 1.0.5 and 1.0.6 (02-Jun-1999 to 06-Jun-1999) - - *) Fixed mm_malloc() function: it returned the wrong pointer when a chunk - was reused and forgot to lock/unlock the data structures. - *) Fixed internal best-fit algorithm for finding a free memory chunk: - - things got inserted out of order in the list - - when chunk is found which matches size exactly it stops immediately - - lowered chunk splitting threshold to MIN(2*size,128) - *) Moved internal definitions in mm.h to private section - - Changes between 1.0.4 and 1.0.5 (21-May-1999 to 02-Jun-1999) - - *) Fixed output of mm-config.in - *) Fixed output of configure --help - *) Upgraded to GNU libtool 1.3.2 - *) Upgraded to shtool 1.2.9 - *) Made libtool calls visible but use --quiet - *) Hint user to send feedback only on errors or for new platform - *) Removed unnecessary "elf" hint for FreeBSD from config.guess - - Changes between 1.0.3 and 1.0.4 (15-May-1999 to 21-May-1999) - - *) Fixed maximum memory size determination and internal handling - *) Documented the mm_lib_xxx() functions. - - Changes between 1.0.2 and 1.0.3 (26-Apr-1999 to 15-May-1999) - - *) Added {MM,mm,mm_core}_permission() function - *) Fixed version information and mod_ssl URL in manual page - *) Upgraded config.{guess,sub} from libtool 1.3 distribution - *) Upgraded to GNU libtool 1.3 - *) Upgraded to shtool 1.2.7 - *) Fixed public includes for xx_t types - *) Fixed mm_vers.c and shtool type inside CVS - - Changes between 1.0.1 and 1.0.2 (18-Apr-1999 to 26-Apr-1999) - - *) Upgraded to GNU libtool 1.2f - *) Upgraded to shtool 1.1.0 - - Changes between 1.0.0 and 1.0.1 (18-Mar-1999 to 18-Apr-1999) - - *) Fixed "dist" Makefile target to not distribute CVS stuff - *) Upgraded lshtool to the latest version - *) Const'ification of the API - - Changes between 1.0b6 and 1.0.0 (18-Mar-1999 to 28-Mar-1999) - - *) Finally cleaned up and polished the mm.pod manual page. - *) Fixed mm-config program - - Changes between 1.0b5 and 1.0b6 (18-Mar-1999 to 18-Mar-1999) - - *) Added {MM,mm}_maxsize() to manual page - *) Changed MM_create() signature to match mm_create() - - Changes between 1.0b4 and 1.0b5 (15-Mar-1999 to 18-Mar-1999) - - *) Make sure the maximum allocateable size takes - the overhead of the memory pool into account. - *) Fixed lshtool and this way hex version string - *) Fixed Makefile for mm_test target dependecies - *) Added {MM,mm}_maxsize() function to let one - determine in advance the maximum allocateable pool - - Changes between 1.0b3 and 1.0b4 (15-Mar-1999 to 15-Mar-1999) - - *) Added mm-config.pod manpage - *) Split mm-config --ldflags into --ldflags and --libs - *) Removed TODO and fulltest files - - Changes between 1.0b2 and 1.0b3 (13-Mar-1999 to 15-Mar-1999) - - *) Added Autoconf check for determining max shared mem segment size - *) Changed -1 to MAP_FAILED when available - *) Replaced 8KB default shared memory segment size with max size - *) Added mm_core_maxsegsize() function - *) Use a remembered offset for mmap() on temporary files - *) Imported source tree into CVS - *) Added read-only locking support - *) Fixed MMFILE and MMZERO variants - - Changes between 1.0b1 and 1.0b2 (12-Mar-1999 to 13-Mar-1999) - - *) Updated the mm.pod manual page. - *) Split README into README and LICENSE files - *) Fixed becho problems - *) Added a test suite summary - *) Added INSTALL file - *) Reduced mm_test's memory size from 1MB to 512KB - *) Fixed unsigned long and %X related warnings - - Changes between 1.0b0 and 1.0b1 (11-Mar-1999 to 12-Mar-1999) - - *) Enhanced mm_test - *) Added {MM,mm}_available() function - *) Fixed MMZERO - *) Fixed IPC Semaphore initialization - *) Added --with-{sem,shm}=TYPE options - *) Fixed "make test" and mm_memory_display() function - *) Added mm_lib.c source with mm_lib_xx() functions - - Changes between 0.9.0 and 1.0b0 (10-Mar-1999 to 11-Mar-1999) - - *) Switched to GNU Autoconf and GNU Libtool - - Changes between GENESIS and 0.9.0 (Jan-1999 to 10-Mar-1999) - - *) Created initial version on FreeBSD - *) Ported to Linux and Solaris - diff --git a/shmem/unix/mm/INSTALL b/shmem/unix/mm/INSTALL deleted file mode 100644 index 1f42c1d4abd..00000000000 --- a/shmem/unix/mm/INSTALL +++ /dev/null @@ -1,19 +0,0 @@ - __ __ __ __ - | \/ | \/ | - | |\/| | |\/| | - | | | | | | | - |_| |_|_| |_| - - MM - Shared Memory Library - - To install the MM library into /path/to/mm/{bin,lib,include,man}/ perform - the following steps in your shell: - - $ ./configure --prefix=/path/to/mm - $ make - $ make test - $ make install - - This installs at least a static variant of the MM library and when your - platforms support it, also a shared library variant of the MM library. - diff --git a/shmem/unix/mm/LICENSE b/shmem/unix/mm/LICENSE deleted file mode 100644 index 3bd1c3d4131..00000000000 --- a/shmem/unix/mm/LICENSE +++ /dev/null @@ -1,40 +0,0 @@ - - ==================================================================== - Copyright (c) 1999 Ralf S. Engelschall. 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 acknowledgment: - "This product includes software developed by - Ralf S. Engelschall <rse@engelschall.com>." - - 4. Redistributions of any form whatsoever must retain the following - acknowledgment: - "This product includes software developed by - Ralf S. Engelschall <rse@engelschall.com>." - - THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``AS IS'' AND ANY - EXPRESSED 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 RALF S. ENGELSCHALL OR - ITS 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. - ==================================================================== - diff --git a/shmem/unix/mm/Makefile.in b/shmem/unix/mm/Makefile.in deleted file mode 100644 index 206580d2c05..00000000000 --- a/shmem/unix/mm/Makefile.in +++ /dev/null @@ -1,222 +0,0 @@ -## ==================================================================== -## Copyright (c) 1999 Ralf S. Engelschall. 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 acknowledgment: -## "This product includes software developed by -## Ralf S. Engelschall <rse@engelschall.com>." -## -## 4. Redistributions of any form whatsoever must retain the following -## acknowledgment: -## "This product includes software developed by -## Ralf S. Engelschall <rse@engelschall.com>." -## -## THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``AS IS'' AND ANY -## EXPRESSED 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 RALF S. ENGELSCHALL OR -## ITS 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. -## ==================================================================== - -## -## Makefile -## - -@SET_MAKE@ - -TOP = . -prefix = @prefix@ -exec_prefix = @exec_prefix@ -bindir = @bindir@ -libdir = @libdir@ -includedir = @includedir@ -mandir = @mandir@ - -SHELL = /bin/sh -CC = @CC@ -CFLAGS = @CFLAGS@ -LDFLAGS = @LDFLAGS@ -LIBS = @LIBS@ -RM = rm -f -LIBTOOL = @LIBTOOL@ -SHTOOL = @SHTOOL@ - -MAN = mm.3 mm-config.1 -OBJ = mm_global.o mm_alloc.o mm_core.o mm_lib.o mm_vers.o -LOBJ = mm_global.lo mm_alloc.lo mm_core.lo mm_lib.lo mm_vers.lo - -_VERSION_FILE = \ - mm_vers.c -_VERSION = \ - $(SHTOOL) version -l c -n MM -p MM $$OPT $(_VERSION_FILE);\ - V=`$(SHTOOL) version -l c -d long $(_VERSION_FILE)`;\ - sed -e "s/Version .*(.*)/Version $$V/g" <README >README.n && mv README.n README - -.SUFFIXES: .o .lo - -.c.o: - $(LIBTOOL) --quiet --mode=compile \ - $(CC) -c $(CFLAGS) $< - -.c.lo: - $(LIBTOOL) --quiet --mode=compile \ - $(CC) -c $(CFLAGS) $< - -all: libmm.la $(MAN) mm_test - -libmm.la: $(OBJ) $(LOBJ) - $(LIBTOOL) --quiet --mode=link \ - $(CC) -o libmm.la $(LOBJ) \ - -rpath $(libdir) -version-info `$(SHTOOL) version -l c -d libtool mm_vers.c` - -mm_alloc.c mm_core.c mm_global.c: mm_conf.h mm.h mm_vers.c - -test: mm_test - -@./mm_test; \ - if [ $$? -eq 0 ]; then \ - PLATFORM=`$(SHELL) ./config.guess`; \ - PLATFORM=`$(SHELL) ./config.sub $$PLATFORM`; \ - if [ ".`grep $$PLATFORM README`" = . ]; then \ - echo "Please send the following summary via Email to the author"; \ - echo "Ralf S. Engelschall <rse@engelschall.com> for inclusion into"; \ - echo "the list of successfully tested platforms (see README file):"; \ - echo ""; \ - echo "Ok" >.fbtool; \ - $(SHELL) ./fbtool -d; \ - fi; \ - else \ - echo "Please send the following summary together with as much other"; \ - echo "details about the configuration, build and test steps to the author"; \ - echo "Ralf S. Engelschall <rse@engelschall.com> to help him in tracking"; \ - echo "down your platform problem."; \ - echo ""; \ - echo "Failed" >.fbtool; \ - $(SHELL) ./fbtool -d; \ - fi; \ - exit 0 - -debug: mm_test - @$(LIBTOOL) --mode=execute gdb mm_test - -mm_test: mm_test.lo libmm.la - $(LIBTOOL) --quiet --mode=link \ - $(CC) -o $@ mm_test.lo libmm.la - -mm.3: mm.pod - V1=`$(SHTOOL) version -l c -d short $(_VERSION_FILE)`; \ - V2=`$(SHTOOL) version -l c -d long $(_VERSION_FILE)`; \ - D=`$(SHTOOL) version -l c -d long $(_VERSION_FILE) | sed -e 's;.*(;;' -e 's;).*;;'`; \ - pod2man --section=3 --center="Shared Memory Library" --release="$$D" --date="MM $$V1" mm.pod |\ - perl -p -e 's;^(\\\&\s+.+?)([Mm][Mm]_[a-zA-Z0-9_]+)(\(.+?)$$;$$1\\fB$$2\\fR$$3;' |\ - sed -e "s;MM_VERSION_STR;$$V2;" >mm.3 - -mm-config.1: mm-config.pod - V1=`$(SHTOOL) version -l c -d short $(_VERSION_FILE)`; \ - V2=`$(SHTOOL) version -l c -d long $(_VERSION_FILE)`; \ - D=`$(SHTOOL) version -l c -d long $(_VERSION_FILE) | sed -e 's;.*(;;' -e 's;).*;;'`; \ - pod2man --section=1 --center="Shared Memory Library" --release="$$D" --date="MM $$V1" mm-config.pod |\ - perl -p -e 's;^(\\\&\s+.+?)([Mm][Mm]_[a-zA-Z0-9_]+)(\(.+?)$$;$$1\\fB$$2\\fR$$3;' |\ - sed -e "s;MM_VERSION_STR;$$V2;" >mm-config.1 - -update: - @$(RM) ltmain.sh ltconfig shtool - @$(MAKE) $(MFLAGS) ltmain.sh ltconfig configure shtool - -configure: configure.in aclocal.m4 - $(RM) configure - autoconf - -ltmain.sh: - @F=`libtoolize -n -c -f | grep 'cp.*ltmain.sh' |\ - sed -e 's;[^/]*;;' -e 's; .*;;'`; \ - echo "ltmain.sh <-- $$F"; cat $$F |\ - sed -e 's:/bin/sh; then:/bin/sh || test "$$nonopt" = ./shtool;then:' \ - -e 's:exec \$$SHELL \$$0 --finish:exit 0 #:' >ltmain.sh - -ltconfig: - @F=`libtoolize -n -c -f | grep 'cp.*ltconfig' | sed -e 's;[^/]*;;' -e 's; .*;;'`; \ - echo "ltconfig <-- $$F"; cp $$F . - -shtool: - shtoolize -o shtool all - -install: all - $(SHTOOL) mkdir -f -p -m 755 $(bindir) - $(SHTOOL) mkdir -f -p -m 755 $(includedir) - $(SHTOOL) mkdir -f -p -m 755 $(libdir) - $(SHTOOL) mkdir -f -p -m 755 $(mandir)/man1 - $(SHTOOL) mkdir -f -p -m 755 $(mandir)/man3 - $(SHTOOL) install -c -m 755 mm-config $(bindir)/mm-config - $(SHTOOL) install -c -m 644 mm-config.1 $(mandir)/man1/mm-config.1 - $(SHTOOL) install -c -m 644 mm.3 $(mandir)/man3/mm.3 - $(SHTOOL) install -c -m 644 mm.h $(includedir)/mm.h - @$(LIBTOOL) --mode=install $(SHTOOL) install -c -m 644 libmm.la $(libdir)/libmm.la - -clean: - $(RM) mm_test mm_test.o mm_test.lo - $(RM) core *.core *.bak *~ - $(RM) $(LOBJ) - $(RM) $(OBJ) - $(RM) libmm.la - $(RM) -r .libs - -distclean: clean - $(RM) Makefile - $(RM) mm-config mm_conf.h - $(RM) config.h config.cache config.status config.log - $(RM) libtool - $(RM) .fbtool - -realclean: distclean - $(RM) $(MAN) - -dist: distclean - @$(SHTOOL) fixperm -v *; \ - V=`$(SHTOOL) version -l c -d short $(_VERSION_FILE)`; \ - $(SHTOOL) tarball -o mm-$${V}.tar.gz -d mm-$${V} -u rse -g mm \ - -e 'CVS,\.cvsignore,\.[ao],^\.' -c 'gzip --best' .; \ - ls -l mm-$${V}.tar.gz - -snap: distclean - @$(SHTOOL) fixperm *; \ - V=`$(SHTOOL) version -l c -d short $(_VERSION_FILE)`; \ - $(SHTOOL) tarball -o mm-$${V}-SNAP.tar.gz -d mm-$${V}-SNAP -u rse -g mm \ - -e 'CVS,\.cvsignore,\.[ao],^\.' -c 'gzip --best' .; \ - ls -l mm-$${V}-SNAP.tar.gz - -new-version: - OPT='-i v' && $(_VERSION) -new-revision: - OPT='-i r' && $(_VERSION) -new-patchlevel: - OPT='-i P' && $(_VERSION) -new-betalevel: - OPT='-i b' && $(_VERSION) -new-alphalevel: - OPT='-i a' && $(_VERSION) -new-snaplevel: - OPT='-i s' && $(_VERSION) -new-release: - OPT='-s $(R)' && $(_VERSION) -update-version: - OPT="-s `$(SHTOOL) version -l c -d short $(_VERSION_FILE)`" && $(_VERSION) - diff --git a/shmem/unix/mm/README b/shmem/unix/mm/README deleted file mode 100644 index 5a19d6c08ad..00000000000 --- a/shmem/unix/mm/README +++ /dev/null @@ -1,87 +0,0 @@ - __ __ __ __ - | \/ | \/ | - | |\/| | |\/| | - | | | | | | | - |_| |_|_| |_| - - MM - Shared Memory Library - Copyright (c) 1999 Ralf S. Engelschall, All rights reserved. - Version 1.0.8 (24-Jun-1999) - - The MM library is a 2-layer abstraction library which simplifies the usage - of shared memory between forked (and this way strongly related) processes - under Unix platforms. On the first (lower) layer it hides all platform - dependent implementation details (allocation and locking) when dealing with - shared memory segments and on the second (higher) layer it provides a - high-level malloc(3)-style API for a convenient and well known way to work - with data-structures inside those shared memory segments. - - This library was successfully tested on the following platforms (and - should automatically adjust to other platforms, of course): - - o i386-unknown-freebsd3.1 FreeBSD 3.1 - o i386-unknown-freebsd3.2 FreeBSD 3.2 - o i386-unknown-freebsd2.2.7 FreeBSD 2.2.7 - o i386-unknown-freebsd2.2.8 FreeBSD 2.2.8 - o i386-unknown-freebsd2.2.2 FreeBSD 2.2.2 - o i386-unknown-openbsd2.5 OpenBSD 2.5 - o i386-pc-bsdi4.0.1 BSDI 4.0.1 - o i586-pc-linux-gnu RedHat 5.2 - o i586-pc-linux-gnu RedHat 5.0 - o i686-pc-linux-gnu Redhat 6.0 - o i486-pc-linux-gnulibc1 Linux - o i686-pc-linux-gnulibc1 Slackware 4.0 - o i586-pc-linux-gnulibc1 Slackware 4.0 - o sparc-sun-solaris2.6 Solaris 2.6 - o sparc-sun-solaris2.7 Solaris 2.7 - o i386-pc-solaris2.7 Solaris 2.7 - o alphaev56-dec-osf4.0d Digital Unix v4.0D - o alphaev56-dec-osf4.0c Digital Unix v4.0C - o powerpc-ibm-aix4.2.0.0 AIX 4.2 - o powerpc-ibm-aix4.3.1.0 AIX 4.2 - o alphaev56-unknown-linux-gnu Linux/Alpha - o powerpc-unknown-linux-gnu LinuxPPC 4 - o m68k-apple-aux3.1.1 A/UX 3.1.1 - o hppa1.1-hp-hpux10.10 HP-UX 10.10 - o hppa1.1-hp-hpux10.20 HP-UX 10.20 - o hppa2.0-hp-hpux10.20 HP-UX 10.20 - o arm-unknown-linux-gnu Corel Netwinder SA110 - o mips-sni-sysv4 SIEMENS ReliantUNIX - o mips-sgi-irix6.2 IRIX 6.2 - o mips-sgi-irix6.3 IRIX 6.3 - o mips-sgi-irix6.4 IRIX 6.4 - o mips-sgi-irix6.5 IRIX 6.5.4 - - Credit has to be given to the following people who contributed ideas, - bugfixes, hints, gave platform feedback, etc. (in alphabetical order): - - o Ronald Appelfelder <ra@intraregio.net> - o Robert Belleman <robbel@wins.uva.nl> - o Jeff Clark <hotwire@hoser.com> - o Eric Cholet <cholet@logilune.com> - o Dean Gaudet <dgaudet@arctic.org> - o Ask Bjoern Hansen <ask@netcetera.dk> - o Jim Jagielski <jim@jagunet.com> - o Mats Josefsson <matjos@rsv.se> - o Sergey Kachanovsky <ranger@tversu.ru> - o Martin Kraemer <martin.kraemer@mch.sni.de> - o Rasmus Lerdorf <rasmus@lerdorf.on.ca> - o Dave Malhotra <davem@glue.umd.edu> - o Christophe Massiot <massiot@via.ecp.fr> - o Patrick <puzzled@symplex.net> - o Charles Randall <crandall@matchlogic.com> - o David Rees <drees@ucsd.edu> - o Christian Reiber <chrei@en.muc.de> - o Dan Sullivan <sullivan@epa.gov> - o Tom Vaughan <tvaughan@aventail.com> - o Rick Watson <rick@akbar.cc.utexas.edu> - o Mark Wilkie <mark@exceptionmedia.com> - o Cliff Woolley <jwoolley@wlu.edu> - - The documentation and latest release can be found on - http://www.engelschall.com/sw/mm/ - - Ralf S. Engelschall - rse@engelschall.com - www.engelschall.com - diff --git a/shmem/unix/mm/aclocal.m4 b/shmem/unix/mm/aclocal.m4 deleted file mode 100644 index ad9f0147d07..00000000000 --- a/shmem/unix/mm/aclocal.m4 +++ /dev/null @@ -1,362 +0,0 @@ -dnl ## -dnl ## -dnl ## -define(AC_PROG_LIBTOOL,[dnl -AC_ARG_ENABLE(static,dnl -[ --enable-static build static libraries (default=yes)], -enable_static="$enableval", -enable_static=yes -)dnl -AC_ARG_ENABLE(shared,dnl -[ --enable-shared build shared libraries (default=yes)], -enable_shared="$enableval", -enable_shared=yes -)dnl -libtool_flags='' -test ".$silent" = .yes && libtool_flags="$libtool_flags --silent" -test ".$enable_static" = .no && libtool_flags="$libtool_flags --disable-static" -test ".$enable_shared" = .no && libtool_flags="$libtool_flags --disable-shared" -test ".$ac_cv_prog_gcc" = .yes && libtool_flags="$libtool_flags --with-gcc" -test ".$ac_cv_prog_gnu_ld" = .yes && libtool_flags="$libtool_flags --with-gnu-ld" -CC="$CC" CFLAGS="$CFLAGS" CPPFLAGS="$CPPFLAGS" LD="$LD" \ -${CONFIG_SHELL-/bin/sh} ltconfig --no-reexec \ -$libtool_flags --no-verify ltmain.sh $PLATFORM ||\ -AC_MSG_ERROR([libtool configuration failed]) -LIBTOOL="\$(TOP)/libtool" -AC_SUBST(LIBTOOL) -])dnl -dnl ## -dnl ## -dnl ## -define(AC_CHECK_DEBUGGING,[dnl -AC_MSG_CHECKING(for compilation debug mode) -AC_ARG_ENABLE(debug,dnl -[ --enable-debug build for debugging (default=no)], -[dnl -if test ".$ac_cv_prog_gcc" = ".yes"; then - case "$CFLAGS" in - *-O2* ) ;; - * ) CFLAGS="$CFLAGS -O2" ;; - esac - case "$CFLAGS" in - *-g* ) ;; - * ) CFLAGS="$CFLAGS -g" ;; - esac - CFLAGS="$CFLAGS -ggdb3" - CFLAGS="$CFLAGS -Wall -Wshadow -Wpointer-arith -Wcast-align" - CFLAGS="$CFLAGS -Wmissing-prototypes -Wmissing-declarations -Wnested-externs -Winline" -else - case "$CFLAGS" in - *-g* ) ;; - * ) CFLAGS="$CFLAGS -g" ;; - esac -fi -msg="enabled" -AC_DEFINE(MM_DEBUG) -],[ -case "$CFLAGS" in - *-g* ) CFLAGS=`echo "$CFLAGS" |\ - sed -e 's/ -g //g' -e 's/ -g$//' -e 's/^-g //g' -e 's/^-g$//'` ;; -esac -msg=disabled -])dnl -AC_MSG_RESULT([$msg]) -]) -dnl ## -dnl ## -dnl ## -define(AC_CONFIGURE_PART,[dnl -AC_MSG_RESULT() -AC_MSG_RESULT(${T_MD}$1:${T_ME}) -])dnl -dnl ## -dnl ## -dnl ## -define(AC_CHECK_DEFINE,[dnl -AC_CACHE_CHECK(for $1 in $2, ac_cv_define_$1, -AC_EGREP_CPP([YES_IS_DEFINED], [ -#include <$2> -#ifdef $1 -YES_IS_DEFINED -#endif -], ac_cv_define_$1=yes; AC_DEFINE(HAVE_$1), ac_cv_define_$1=no) -)])dnl -dnl ## -dnl ## -dnl ## -define(AC_IFALLYES,[dnl -ac_rc=yes -for ac_spec in $1; do - ac_type=`echo "$ac_spec" | sed -e 's/:.*$//'` - ac_item=`echo "$ac_spec" | sed -e 's/^.*://'` - case $ac_type in - header ) - ac_item=`echo "$ac_item" | sed 'y%./+-%__p_%'` - ac_var="ac_cv_header_$ac_item" - ;; - file ) - ac_item=`echo "$ac_item" | sed 'y%./+-%__p_%'` - ac_var="ac_cv_file_$ac_item" - ;; - func ) ac_var="ac_cv_func_$ac_item" ;; - define ) ac_var="ac_cv_define_$ac_item" ;; - custom ) ac_var="$ac_item" ;; - esac - eval "ac_val=\$$ac_var" - if test ".$ac_val" != .yes; then - ac_rc=no - break - fi -done -if test ".$ac_rc" = .yes; then - : - $2 -else - : - $3 -fi -])dnl -dnl ## -dnl ## -dnl ## -define(AC_BEGIN_DECISION,[dnl -ac_decision_item='$1' -ac_decision_msg='FAILED' -ac_decision='' -])dnl -define(AC_DECIDE,[dnl -ac_decision='$1' -ac_decision_msg='$2' -ac_decision_$1=yes -ac_decision_$1_msg='$2' -])dnl -define(AC_DECISION_OVERRIDE,[dnl - ac_decision='' - for ac_item in $1; do - eval "ac_decision_this=\$ac_decision_${ac_item}" - if test ".$ac_decision_this" = .yes; then - ac_decision=$ac_item - eval "ac_decision_msg=\$ac_decision_${ac_item}_msg" - fi - done -])dnl -define(AC_DECISION_FORCE,[dnl -ac_decision="$1" -eval "ac_decision_msg=\"\$ac_decision_${ac_decision}_msg\"" -])dnl -define(AC_END_DECISION,[dnl -if test ".$ac_decision" = .; then - echo "[$]0:Error: decision on $ac_decision_item failed" 1>&2 - exit 1 -else - if test ".$ac_decision_msg" = .; then - ac_decision_msg="$ac_decision" - fi - AC_MSG_RESULT([decision on $ac_decision_item... $ac_decision_msg]) -fi -])dnl -dnl ## -dnl ## -dnl ## -AC_DEFUN(AC_TEST_FILE, -[AC_REQUIRE([AC_PROG_CC]) -ac_safe=`echo "$1" | sed 'y%./+-%__p_%'` -AC_MSG_CHECKING([for $1]) -AC_CACHE_VAL(ac_cv_file_$ac_safe, [ - if test -r $1; then - eval "ac_cv_file_$ac_safe=yes" - else - eval "ac_cv_file_$ac_safe=no" - fi -])dnl -if eval "test \"`echo '$ac_cv_file_'$ac_safe`\" = yes"; then - AC_MSG_RESULT(yes) - ifelse([$2], , :, [$2]) -else - AC_MSG_RESULT(no) -ifelse([$3], , , [$3]) -fi -]) -dnl ## -dnl ## AC_PROG_NM - find the path to a BSD-compatible name lister -dnl ## -AC_DEFUN(AC_PROG_NM, -[AC_MSG_CHECKING([for BSD-compatible nm]) -AC_CACHE_VAL(ac_cv_path_NM, -[if test -n "$NM"; then - # Let the user override the test. - ac_cv_path_NM="$NM" -else - IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" - for ac_dir in /usr/ucb /usr/ccs/bin $PATH /bin; do - test -z "$ac_dir" && ac_dir=. - if test -f $ac_dir/nm; then - # Check to see if the nm accepts a BSD-compat flag. - # Adding the `sed 1q' prevents false positives on HP-UX, which says: - # nm: unknown option "B" ignored - if ($ac_dir/nm -B /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then - ac_cv_path_NM="$ac_dir/nm -B" - elif ($ac_dir/nm -p /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then - ac_cv_path_NM="$ac_dir/nm -p" - else - ac_cv_path_NM="$ac_dir/nm" - fi - break - fi - done - IFS="$ac_save_ifs" - test -z "$ac_cv_path_NM" && ac_cv_path_NM=nm -fi]) -NM="$ac_cv_path_NM" -AC_MSG_RESULT([$NM]) -AC_SUBST(NM) -]) -dnl # -dnl # -dnl # -define(AC_CHECK_MAXSEGSIZE,[dnl -AC_MSG_CHECKING(for shared memory maximum segment size) -OCFLAGS="$CFLAGS" -case "$1" in - MM_SHMT_MM* ) CFLAGS="-DTEST_MMAP $CFLAGS" ;; - MM_SHMT_IPCSHM ) CFLAGS="-DTEST_SHMGET $CFLAGS" ;; -esac -cross_compile=no -AC_TRY_RUN( -changequote(<<, >>)dnl -<< -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <sys/file.h> -#include <sys/types.h> -#include <sys/stat.h> -#ifdef TEST_MMAP -#include <sys/mman.h> -#endif -#ifdef TEST_SHMGET -#include <sys/ipc.h> -#ifndef _OSD_POSIX -#include <sys/shm.h> -#else -#define _KMEMUSER 1 /* BS2000 needs this to enable SHM_[RW] */ -#include <sys/shm.h> -#undef _KMEMUSER -#endif -#endif -#if !defined(MAP_FAILED) -#define MAP_FAILED ((void *)-1) -#endif - -int testit(int size) -{ - int fd; - void *segment; -#ifdef TEST_MMAP - char file[] = "./ac_test.tmp"; - unlink(file); - if ((fd = open(file, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR)) == -1) - return 0; - if (ftruncate(fd, size) == -1) - return 0; - if ((segment = (void *)mmap(NULL, size, PROT_READ|PROT_WRITE, - MAP_SHARED, fd, 0)) == MAP_FAILED) { - close(fd); - return 0; - } - munmap((caddr_t)segment, size); - close(fd); - unlink(file); -#endif -#ifdef TEST_SHMGET - if ((fd = shmget(IPC_PRIVATE, size, SHM_R|SHM_W|IPC_CREAT)) == -1) - return 0; - if ((segment = (void *)shmat(fd, NULL, 0)) == ((void *)-1)) { - shmctl(fd, IPC_RMID, NULL); - return 0; - } - shmdt(segment); - shmctl(fd, IPC_RMID, NULL); -#endif - return 1; -} - -#define ABS(n) ((n) >= 0 ? (n) : (-(n))) - -int main(int argc, char *argv[]) -{ - int t, m, b; - int d; - int rc; - FILE *f; - - /* - * Find maximum possible allocation size by performing a - * binary search starting with a search space between 0 and - * 64MB of memory. - */ - t = 1024*1024*64 /* = 67108864 */; - if (testit(t)) - m = t; - else { - m = 1024*1024*32; - b = 0; - for (;;) { - /* fprintf(stderr, "t=%d, m=%d, b=%d\n", t, m, b); */ - rc = testit(m); - if (rc) { - d = ((t-m)/2); - b = m; - } - else { - d = -((m-b)/2); - t = m; - } - if (ABS(d) < 1024*1) { - if (!rc) - m = b; - break; - } - if (m < 1024*8) - break; - m += d; - } - if (m < 1024*8) - m = 0; - } - if ((f = fopen("conftestval", "w")) == NULL) - exit(1); - fprintf(f, "%d\n", m); - fclose(f); - exit(0); -} ->> -changequote([, ])dnl -,[ -MM_SHM_MAXSEGSIZE="`cat conftestval`" -msg="$MM_SHM_MAXSEGSIZE" -if test $msg -eq 67108864; then - msg="64MB (soft limit)" -elif test $msg -gt 1048576; then - msg="`expr $msg / 1024`" - msg="`expr $msg / 1024`" - msg="${msg}MB" -elif test $msg -gt 1024; then - msg="`expr $msg / 1024`" - msg="${msg}KB" -else - MM_SHM_MAXSEGSIZE=0 - msg=unknown -fi -], -MM_SHM_MAXSEGSIZE=0 -msg=unknown -, -MM_SHM_MAXSEGSIZE=0 -msg=unknown -)dnl -CFLAGS="$OCFLAGS" -test ".$msg" = .unknown && AC_MSG_ERROR([Unable to determine maximum shared memory segment size]) -AC_MSG_RESULT([$msg]) -AC_DEFINE_UNQUOTED(MM_SHM_MAXSEGSIZE, $MM_SHM_MAXSEGSIZE) -]) diff --git a/shmem/unix/mm/config.guess b/shmem/unix/mm/config.guess deleted file mode 100755 index 16942ccf63b..00000000000 --- a/shmem/unix/mm/config.guess +++ /dev/null @@ -1,1103 +0,0 @@ -#! /bin/sh -# Attempt to guess a canonical system name. -# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999 -# Free Software Foundation, Inc. -# -# This file is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# -# As a special exception to the GNU General Public License, if you -# distribute this file as part of a program that contains a -# configuration script generated by Autoconf, you may include it under -# the same distribution terms that you use for the rest of that program. - -# Written by Per Bothner <bothner@cygnus.com>. -# The master version of this file is at the FSF in /home/gd/gnu/lib. -# Please send patches to the Autoconf mailing list <autoconf@gnu.org>. -# -# This script attempts to guess a canonical system name similar to -# config.sub. If it succeeds, it prints the system name on stdout, and -# exits with 0. Otherwise, it exits with 1. -# -# The plan is that this can be called by configure scripts if you -# don't specify an explicit system type (host/target name). -# -# Only a few systems have been added to this list; please add others -# (but try to keep the structure clean). -# - -# Use $HOST_CC if defined. $CC may point to a cross-compiler -if test x"$CC_FOR_BUILD" = x; then - if test x"$HOST_CC" != x; then - CC_FOR_BUILD="$HOST_CC" - else - if test x"$CC" != x; then - CC_FOR_BUILD="$CC" - else - CC_FOR_BUILD=cc - fi - fi -fi - - -# This is needed to find uname on a Pyramid OSx when run in the BSD universe. -# (ghazi@noc.rutgers.edu 8/24/94.) -if (test -f /.attbin/uname) >/dev/null 2>&1 ; then - PATH=$PATH:/.attbin ; export PATH -fi - -UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown -UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown -UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown -UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown - -dummy=dummy-$$ -trap 'rm -f $dummy.c $dummy.o $dummy; exit 1' 1 2 15 - -# Note: order is significant - the case branches are not exclusive. - -case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in - alpha:OSF1:*:*) - if test $UNAME_RELEASE = "V4.0"; then - UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` - fi - # A Vn.n version is a released version. - # A Tn.n version is a released field test version. - # A Xn.n version is an unreleased experimental baselevel. - # 1.2 uses "1.2" for uname -r. - cat <<EOF >$dummy.s - .globl main - .ent main -main: - .frame \$30,0,\$26,0 - .prologue 0 - .long 0x47e03d80 # implver $0 - lda \$2,259 - .long 0x47e20c21 # amask $2,$1 - srl \$1,8,\$2 - sll \$2,2,\$2 - sll \$0,3,\$0 - addl \$1,\$0,\$0 - addl \$2,\$0,\$0 - ret \$31,(\$26),1 - .end main -EOF - $CC_FOR_BUILD $dummy.s -o $dummy 2>/dev/null - if test "$?" = 0 ; then - ./$dummy - case "$?" in - 7) - UNAME_MACHINE="alpha" - ;; - 15) - UNAME_MACHINE="alphaev5" - ;; - 14) - UNAME_MACHINE="alphaev56" - ;; - 10) - UNAME_MACHINE="alphapca56" - ;; - 16) - UNAME_MACHINE="alphaev6" - ;; - esac - fi - rm -f $dummy.s $dummy - echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` - exit 0 ;; - Alpha\ *:Windows_NT*:*) - # How do we know it's Interix rather than the generic POSIX subsystem? - # Should we change UNAME_MACHINE based on the output of uname instead - # of the specific Alpha model? - echo alpha-pc-interix - exit 0 ;; - 21064:Windows_NT:50:3) - echo alpha-dec-winnt3.5 - exit 0 ;; - Amiga*:UNIX_System_V:4.0:*) - echo m68k-cbm-sysv4 - exit 0;; - amiga:NetBSD:*:*) - echo m68k-cbm-netbsd${UNAME_RELEASE} - exit 0 ;; - amiga:OpenBSD:*:*) - echo m68k-unknown-openbsd${UNAME_RELEASE} - exit 0 ;; - *:[Aa]miga[Oo][Ss]:*:*) - echo ${UNAME_MACHINE}-unknown-amigaos - exit 0 ;; - arc64:OpenBSD:*:*) - echo mips64el-unknown-openbsd${UNAME_RELEASE} - exit 0 ;; - arc:OpenBSD:*:*) - echo mipsel-unknown-openbsd${UNAME_RELEASE} - exit 0 ;; - hkmips:OpenBSD:*:*) - echo mips-unknown-openbsd${UNAME_RELEASE} - exit 0 ;; - pmax:OpenBSD:*:*) - echo mipsel-unknown-openbsd${UNAME_RELEASE} - exit 0 ;; - sgi:OpenBSD:*:*) - echo mips-unknown-openbsd${UNAME_RELEASE} - exit 0 ;; - wgrisc:OpenBSD:*:*) - echo mipsel-unknown-openbsd${UNAME_RELEASE} - exit 0 ;; - arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) - echo arm-acorn-riscix${UNAME_RELEASE} - exit 0;; - arm32:NetBSD:*:*) - echo arm-unknown-netbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` - exit 0 ;; - SR2?01:HI-UX/MPP:*:*) - echo hppa1.1-hitachi-hiuxmpp - exit 0;; - Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) - # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. - if test "`(/bin/universe) 2>/dev/null`" = att ; then - echo pyramid-pyramid-sysv3 - else - echo pyramid-pyramid-bsd - fi - exit 0 ;; - NILE*:*:*:dcosx) - echo pyramid-pyramid-svr4 - exit 0 ;; - sun4H:SunOS:5.*:*) - echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` - exit 0 ;; - sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) - echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` - exit 0 ;; - i86pc:SunOS:5.*:*) - echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` - exit 0 ;; - sun4*:SunOS:6*:*) - # According to config.sub, this is the proper way to canonicalize - # SunOS6. Hard to guess exactly what SunOS6 will be like, but - # it's likely to be more like Solaris than SunOS4. - echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` - exit 0 ;; - sun4*:SunOS:*:*) - case "`/usr/bin/arch -k`" in - Series*|S4*) - UNAME_RELEASE=`uname -v` - ;; - esac - # Japanese Language versions have a version number like `4.1.3-JL'. - echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` - exit 0 ;; - sun3*:SunOS:*:*) - echo m68k-sun-sunos${UNAME_RELEASE} - exit 0 ;; - sun*:*:4.2BSD:*) - UNAME_RELEASE=`(head -1 /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` - test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 - case "`/bin/arch`" in - sun3) - echo m68k-sun-sunos${UNAME_RELEASE} - ;; - sun4) - echo sparc-sun-sunos${UNAME_RELEASE} - ;; - esac - exit 0 ;; - aushp:SunOS:*:*) - echo sparc-auspex-sunos${UNAME_RELEASE} - exit 0 ;; - atari*:NetBSD:*:*) - echo m68k-atari-netbsd${UNAME_RELEASE} - exit 0 ;; - atari*:OpenBSD:*:*) - echo m68k-unknown-openbsd${UNAME_RELEASE} - exit 0 ;; - # The situation for MiNT is a little confusing. The machine name - # can be virtually everything (everything which is not - # "atarist" or "atariste" at least should have a processor - # > m68000). The system name ranges from "MiNT" over "FreeMiNT" - # to the lowercase version "mint" (or "freemint"). Finally - # the system name "TOS" denotes a system which is actually not - # MiNT. But MiNT is downward compatible to TOS, so this should - # be no problem. - atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) - echo m68k-atari-mint${UNAME_RELEASE} - exit 0 ;; - atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) - echo m68k-atari-mint${UNAME_RELEASE} - exit 0 ;; - *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) - echo m68k-atari-mint${UNAME_RELEASE} - exit 0 ;; - milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) - echo m68k-milan-mint${UNAME_RELEASE} - exit 0 ;; - hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) - echo m68k-hades-mint${UNAME_RELEASE} - exit 0 ;; - *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) - echo m68k-unknown-mint${UNAME_RELEASE} - exit 0 ;; - sun3*:NetBSD:*:*) - echo m68k-sun-netbsd${UNAME_RELEASE} - exit 0 ;; - sun3*:OpenBSD:*:*) - echo m68k-unknown-openbsd${UNAME_RELEASE} - exit 0 ;; - mac68k:NetBSD:*:*) - echo m68k-apple-netbsd${UNAME_RELEASE} - exit 0 ;; - mac68k:OpenBSD:*:*) - echo m68k-unknown-openbsd${UNAME_RELEASE} - exit 0 ;; - mvme68k:OpenBSD:*:*) - echo m68k-unknown-openbsd${UNAME_RELEASE} - exit 0 ;; - mvme88k:OpenBSD:*:*) - echo m88k-unknown-openbsd${UNAME_RELEASE} - exit 0 ;; - powerpc:machten:*:*) - echo powerpc-apple-machten${UNAME_RELEASE} - exit 0 ;; - macppc:NetBSD:*:*) - echo powerpc-apple-netbsd${UNAME_RELEASE} - exit 0 ;; - RISC*:Mach:*:*) - echo mips-dec-mach_bsd4.3 - exit 0 ;; - RISC*:ULTRIX:*:*) - echo mips-dec-ultrix${UNAME_RELEASE} - exit 0 ;; - VAX*:ULTRIX*:*:*) - echo vax-dec-ultrix${UNAME_RELEASE} - exit 0 ;; - 2020:CLIX:*:* | 2430:CLIX:*:*) - echo clipper-intergraph-clix${UNAME_RELEASE} - exit 0 ;; - mips:*:*:UMIPS | mips:*:*:RISCos) - sed 's/^ //' << EOF >$dummy.c -#ifdef __cplusplus - int main (int argc, char *argv[]) { -#else - int main (argc, argv) int argc; char *argv[]; { -#endif - #if defined (host_mips) && defined (MIPSEB) - #if defined (SYSTYPE_SYSV) - printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); - #endif - #if defined (SYSTYPE_SVR4) - printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); - #endif - #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) - printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); - #endif - #endif - exit (-1); - } -EOF - $CC_FOR_BUILD $dummy.c -o $dummy \ - && ./$dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \ - && rm $dummy.c $dummy && exit 0 - rm -f $dummy.c $dummy - echo mips-mips-riscos${UNAME_RELEASE} - exit 0 ;; - Night_Hawk:Power_UNIX:*:*) - echo powerpc-harris-powerunix - exit 0 ;; - m88k:CX/UX:7*:*) - echo m88k-harris-cxux7 - exit 0 ;; - m88k:*:4*:R4*) - echo m88k-motorola-sysv4 - exit 0 ;; - m88k:*:3*:R3*) - echo m88k-motorola-sysv3 - exit 0 ;; - AViiON:dgux:*:*) - # DG/UX returns AViiON for all architectures - UNAME_PROCESSOR=`/usr/bin/uname -p` - if [ $UNAME_PROCESSOR = mc88100 -o $UNAME_PROCESSOR = mc88110 ] ; then - if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx \ - -o ${TARGET_BINARY_INTERFACE}x = x ] ; then - echo m88k-dg-dgux${UNAME_RELEASE} - else - echo m88k-dg-dguxbcs${UNAME_RELEASE} - fi - else echo i586-dg-dgux${UNAME_RELEASE} - fi - exit 0 ;; - M88*:DolphinOS:*:*) # DolphinOS (SVR3) - echo m88k-dolphin-sysv3 - exit 0 ;; - M88*:*:R3*:*) - # Delta 88k system running SVR3 - echo m88k-motorola-sysv3 - exit 0 ;; - XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) - echo m88k-tektronix-sysv3 - exit 0 ;; - Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) - echo m68k-tektronix-bsd - exit 0 ;; - *:IRIX*:*:*) - echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` - exit 0 ;; - ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. - echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id - exit 0 ;; # Note that: echo "'`uname -s`'" gives 'AIX ' - i?86:AIX:*:*) - echo i386-ibm-aix - exit 0 ;; - *:AIX:2:3) - if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then - sed 's/^ //' << EOF >$dummy.c - #include <sys/systemcfg.h> - - main() - { - if (!__power_pc()) - exit(1); - puts("powerpc-ibm-aix3.2.5"); - exit(0); - } -EOF - $CC_FOR_BUILD $dummy.c -o $dummy && ./$dummy && rm $dummy.c $dummy && exit 0 - rm -f $dummy.c $dummy - echo rs6000-ibm-aix3.2.5 - elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then - echo rs6000-ibm-aix3.2.4 - else - echo rs6000-ibm-aix3.2 - fi - exit 0 ;; - *:AIX:*:4) - IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | head -1 | awk '{ print $1 }'` - if /usr/sbin/lsattr -EHl ${IBM_CPU_ID} | grep POWER >/dev/null 2>&1; then - IBM_ARCH=rs6000 - else - IBM_ARCH=powerpc - fi - if [ -x /usr/bin/oslevel ] ; then - IBM_REV=`/usr/bin/oslevel` - else - IBM_REV=4.${UNAME_RELEASE} - fi - echo ${IBM_ARCH}-ibm-aix${IBM_REV} - exit 0 ;; - *:AIX:*:*) - echo rs6000-ibm-aix - exit 0 ;; - ibmrt:4.4BSD:*|romp-ibm:BSD:*) - echo romp-ibm-bsd4.4 - exit 0 ;; - ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC NetBSD and - echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to - exit 0 ;; # report: romp-ibm BSD 4.3 - *:BOSX:*:*) - echo rs6000-bull-bosx - exit 0 ;; - DPX/2?00:B.O.S.:*:*) - echo m68k-bull-sysv3 - exit 0 ;; - 9000/[34]??:4.3bsd:1.*:*) - echo m68k-hp-bsd - exit 0 ;; - hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) - echo m68k-hp-bsd4.4 - exit 0 ;; - 9000/[34678]??:HP-UX:*:*) - case "${UNAME_MACHINE}" in - 9000/31? ) HP_ARCH=m68000 ;; - 9000/[34]?? ) HP_ARCH=m68k ;; - 9000/[678][0-9][0-9]) - sed 's/^ //' << EOF >$dummy.c - #include <stdlib.h> - #include <unistd.h> - - int main () - { - #if defined(_SC_KERNEL_BITS) - long bits = sysconf(_SC_KERNEL_BITS); - #endif - long cpu = sysconf (_SC_CPU_VERSION); - - switch (cpu) - { - case CPU_PA_RISC1_0: puts ("hppa1.0"); break; - case CPU_PA_RISC1_1: puts ("hppa1.1"); break; - case CPU_PA_RISC2_0: - #if defined(_SC_KERNEL_BITS) - switch (bits) - { - case 64: puts ("hppa2.0w"); break; - case 32: puts ("hppa2.0n"); break; - default: puts ("hppa2.0"); break; - } break; - #else /* !defined(_SC_KERNEL_BITS) */ - puts ("hppa2.0"); break; - #endif - default: puts ("hppa1.0"); break; - } - exit (0); - } -EOF - ($CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null ) && HP_ARCH=`./$dummy` - rm -f $dummy.c $dummy - esac - HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` - echo ${HP_ARCH}-hp-hpux${HPUX_REV} - exit 0 ;; - 3050*:HI-UX:*:*) - sed 's/^ //' << EOF >$dummy.c - #include <unistd.h> - int - main () - { - long cpu = sysconf (_SC_CPU_VERSION); - /* The order matters, because CPU_IS_HP_MC68K erroneously returns - true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct - results, however. */ - if (CPU_IS_PA_RISC (cpu)) - { - switch (cpu) - { - case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; - case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; - case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; - default: puts ("hppa-hitachi-hiuxwe2"); break; - } - } - else if (CPU_IS_HP_MC68K (cpu)) - puts ("m68k-hitachi-hiuxwe2"); - else puts ("unknown-hitachi-hiuxwe2"); - exit (0); - } -EOF - $CC_FOR_BUILD $dummy.c -o $dummy && ./$dummy && rm $dummy.c $dummy && exit 0 - rm -f $dummy.c $dummy - echo unknown-hitachi-hiuxwe2 - exit 0 ;; - 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) - echo hppa1.1-hp-bsd - exit 0 ;; - 9000/8??:4.3bsd:*:*) - echo hppa1.0-hp-bsd - exit 0 ;; - *9??*:MPE/iX:*:*) - echo hppa1.0-hp-mpeix - exit 0 ;; - hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) - echo hppa1.1-hp-osf - exit 0 ;; - hp8??:OSF1:*:*) - echo hppa1.0-hp-osf - exit 0 ;; - i?86:OSF1:*:*) - if [ -x /usr/sbin/sysversion ] ; then - echo ${UNAME_MACHINE}-unknown-osf1mk - else - echo ${UNAME_MACHINE}-unknown-osf1 - fi - exit 0 ;; - parisc*:Lites*:*:*) - echo hppa1.1-hp-lites - exit 0 ;; - hppa*:OpenBSD:*:*) - echo hppa-unknown-openbsd - exit 0 ;; - C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) - echo c1-convex-bsd - exit 0 ;; - C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) - if getsysinfo -f scalar_acc - then echo c32-convex-bsd - else echo c2-convex-bsd - fi - exit 0 ;; - C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) - echo c34-convex-bsd - exit 0 ;; - C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) - echo c38-convex-bsd - exit 0 ;; - C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) - echo c4-convex-bsd - exit 0 ;; - CRAY*X-MP:*:*:*) - echo xmp-cray-unicos - exit 0 ;; - CRAY*Y-MP:*:*:*) - echo ymp-cray-unicos${UNAME_RELEASE} - exit 0 ;; - CRAY*[A-Z]90:*:*:*) - echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ - | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ - -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ - exit 0 ;; - CRAY*TS:*:*:*) - echo t90-cray-unicos${UNAME_RELEASE} - exit 0 ;; - CRAY*T3E:*:*:*) - echo t3e-cray-unicosmk${UNAME_RELEASE} - exit 0 ;; - CRAY-2:*:*:*) - echo cray2-cray-unicos - exit 0 ;; - F300:UNIX_System_V:*:*) - FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` - FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` - echo "f300-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" - exit 0 ;; - F301:UNIX_System_V:*:*) - echo f301-fujitsu-uxpv`echo $UNAME_RELEASE | sed 's/ .*//'` - exit 0 ;; - hp3[0-9][05]:NetBSD:*:*) - echo m68k-hp-netbsd${UNAME_RELEASE} - exit 0 ;; - hp300:OpenBSD:*:*) - echo m68k-unknown-openbsd${UNAME_RELEASE} - exit 0 ;; - i?86:BSD/386:*:* | i?86:BSD/OS:*:*) - echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} - exit 0 ;; - sparc*:BSD/OS:*:*) - echo sparc-unknown-bsdi${UNAME_RELEASE} - exit 0 ;; - *:BSD/OS:*:*) - echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} - exit 0 ;; - *:FreeBSD:*:*) - # echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` - VERS=`echo ${UNAME_RELEASE} | sed -e 's/[-(].*//'` - MACH=`sysctl -n hw.model` - ARCH='unknown' - case ${MACH} in - *386* ) MACH="i386" ;; - *486* ) MACH="i486" ;; - Pentium\ II*) MACH="i686" ;; - Pentium* ) MACH="i586" ;; - Alpha* ) MACH="alpha" ;; - * ) MACH="$UNAME_MACHINE" ;; - esac - case ${MACH} in - i[0-9]86 ) ARCH="pc" ;; - esac - echo "${MACH}-${ARCH}-freebsd${VERS}" - exit 0 ;; - *:NetBSD:*:*) - echo ${UNAME_MACHINE}-unknown-netbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` - exit 0 ;; - *:OpenBSD:*:*) - echo ${UNAME_MACHINE}-unknown-openbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` - exit 0 ;; - i*:CYGWIN*:*) - echo ${UNAME_MACHINE}-pc-cygwin - exit 0 ;; - i*:MINGW*:*) - echo ${UNAME_MACHINE}-pc-mingw32 - exit 0 ;; - i*:Windows_NT*:* | Pentium*:Windows_NT*:*) - # How do we know it's Interix rather than the generic POSIX subsystem? - # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we - # UNAME_MACHINE based on the output of uname instead of i386? - echo i386-pc-interix - exit 0 ;; - i*:UWIN*:*) - echo ${UNAME_MACHINE}-pc-uwin - exit 0 ;; - p*:CYGWIN*:*) - echo powerpcle-unknown-cygwin - exit 0 ;; - prep*:SunOS:5.*:*) - echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` - exit 0 ;; - *:GNU:*:*) - echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` - exit 0 ;; - *:Linux:*:*) - # uname on the ARM produces all sorts of strangeness, and we need to - # filter it out. - case "$UNAME_MACHINE" in - armv*) UNAME_MACHINE=$UNAME_MACHINE ;; - arm* | sa110*) UNAME_MACHINE="arm" ;; - esac - - # The BFD linker knows what the default object file format is, so - # first see if it will tell us. cd to the root directory to prevent - # problems with other programs or directories called `ld' in the path. - ld_help_string=`cd /; ld --help 2>&1` - ld_supported_emulations=`echo $ld_help_string \ - | sed -ne '/supported emulations:/!d - s/[ ][ ]*/ /g - s/.*supported emulations: *// - s/ .*// - p'` - case "$ld_supported_emulations" in - *ia64) echo "${UNAME_MACHINE}-unknown-linux" ; exit 0 ;; - i?86linux) echo "${UNAME_MACHINE}-pc-linux-gnuaout" ; exit 0 ;; - i?86coff) echo "${UNAME_MACHINE}-pc-linux-gnucoff" ; exit 0 ;; - sparclinux) echo "${UNAME_MACHINE}-unknown-linux-gnuaout" ; exit 0 ;; - armlinux) echo "${UNAME_MACHINE}-unknown-linux-gnuaout" ; exit 0 ;; - m68klinux) echo "${UNAME_MACHINE}-unknown-linux-gnuaout" ; exit 0 ;; - elf32ppc | elf32ppclinux) - # Determine Lib Version - cat >$dummy.c <<EOF -#include <features.h> -#if defined(__GLIBC__) -extern char __libc_version[]; -extern char __libc_release[]; -#endif -main(argc, argv) - int argc; - char *argv[]; -{ -#if defined(__GLIBC__) - printf("%s %s\n", __libc_version, __libc_release); -#else - printf("unkown\n"); -#endif - return 0; -} -EOF - LIBC="" - $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null - if test "$?" = 0 ; then - ./$dummy | grep 1\.99 > /dev/null - if test "$?" = 0 ; then - LIBC="libc1" - fi - fi - rm -f $dummy.c $dummy - echo powerpc-unknown-linux-gnu${LIBC} ; exit 0 ;; - esac - - if test "${UNAME_MACHINE}" = "alpha" ; then - sed 's/^ //' <<EOF >$dummy.s - .globl main - .ent main - main: - .frame \$30,0,\$26,0 - .prologue 0 - .long 0x47e03d80 # implver $0 - lda \$2,259 - .long 0x47e20c21 # amask $2,$1 - srl \$1,8,\$2 - sll \$2,2,\$2 - sll \$0,3,\$0 - addl \$1,\$0,\$0 - addl \$2,\$0,\$0 - ret \$31,(\$26),1 - .end main -EOF - LIBC="" - $CC_FOR_BUILD $dummy.s -o $dummy 2>/dev/null - if test "$?" = 0 ; then - ./$dummy - case "$?" in - 7) - UNAME_MACHINE="alpha" - ;; - 15) - UNAME_MACHINE="alphaev5" - ;; - 14) - UNAME_MACHINE="alphaev56" - ;; - 10) - UNAME_MACHINE="alphapca56" - ;; - 16) - UNAME_MACHINE="alphaev6" - ;; - esac - - objdump --private-headers $dummy | \ - grep ld.so.1 > /dev/null - if test "$?" = 0 ; then - LIBC="libc1" - fi - fi - rm -f $dummy.s $dummy - echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} ; exit 0 - elif test "${UNAME_MACHINE}" = "mips" ; then - cat >$dummy.c <<EOF -#ifdef __cplusplus - int main (int argc, char *argv[]) { -#else - int main (argc, argv) int argc; char *argv[]; { -#endif -#ifdef __MIPSEB__ - printf ("%s-unknown-linux-gnu\n", argv[1]); -#endif -#ifdef __MIPSEL__ - printf ("%sel-unknown-linux-gnu\n", argv[1]); -#endif - return 0; -} -EOF - $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy "${UNAME_MACHINE}" && rm $dummy.c $dummy && exit 0 - rm -f $dummy.c $dummy - else - # Either a pre-BFD a.out linker (linux-gnuoldld) - # or one that does not give us useful --help. - # GCC wants to distinguish between linux-gnuoldld and linux-gnuaout. - # If ld does not provide *any* "supported emulations:" - # that means it is gnuoldld. - echo "$ld_help_string" | grep >/dev/null 2>&1 "supported emulations:" - test $? != 0 && echo "${UNAME_MACHINE}-pc-linux-gnuoldld" && exit 0 - - case "${UNAME_MACHINE}" in - i?86) - VENDOR=pc; - ;; - *) - VENDOR=unknown; - ;; - esac - # Determine whether the default compiler is a.out or elf - cat >$dummy.c <<EOF -#include <features.h> -#ifdef __cplusplus - int main (int argc, char *argv[]) { -#else - int main (argc, argv) int argc; char *argv[]; { -#endif -#ifdef __ELF__ -# ifdef __GLIBC__ -# if __GLIBC__ >= 2 - printf ("%s-${VENDOR}-linux-gnu\n", argv[1]); -# else - printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]); -# endif -# else - printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]); -# endif -#else - printf ("%s-${VENDOR}-linux-gnuaout\n", argv[1]); -#endif - return 0; -} -EOF - $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy "${UNAME_MACHINE}" && rm $dummy.c $dummy && exit 0 - rm -f $dummy.c $dummy - fi ;; -# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. earlier versions -# are messed up and put the nodename in both sysname and nodename. - i?86:DYNIX/ptx:4*:*) - echo i386-sequent-sysv4 - exit 0 ;; - i?86:UnixWare:*:* ) - echo ${UNAME_MACHINE}-pc-sysv${UNAME_RELEASE}uw${UNAME_VERSION} - exit 0 ;; - i?86:UNIX_SV:4.2MP:2.*) - # Unixware is an offshoot of SVR4, but it has its own version - # number series starting with 2... - # I am not positive that other SVR4 systems won't match this, - # I just have to hope. -- rms. - # Use sysv4.2uw... so that sysv4* matches it. - echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} - exit 0 ;; - i?86:*:4.*:* | i?86:SYSTEM_V:4.*:*) - if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then - echo ${UNAME_MACHINE}-univel-sysv${UNAME_RELEASE} - else - echo ${UNAME_MACHINE}-pc-sysv${UNAME_RELEASE} - fi - exit 0 ;; - i?86:*:5:7*) - UNAME_REL=`(/bin/uname -X|egrep Release|sed -e 's/.*= //')` - (/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486 - (/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) && UNAME_MACHINE=i586 - (/bin/uname -X|egrep '^Machine.*Pent.*II' >/dev/null) && UNAME_MACHINE=i686 - (/bin/uname -X|egrep '^Machine.*Pentium Pro' >/dev/null) && UNAME_MACHINE=i585 - echo ${UNAME_MACHINE}-${UNAME_SYSTEM}${UNAME_VERSION}-sysv${UNAME_RELEASE} - exit 0 ;; - i?86:*:3.2:*) - if test -f /usr/options/cb.name; then - UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name` - echo ${UNAME_MACHINE}-pc-isc$UNAME_REL - elif /bin/uname -X 2>/dev/null >/dev/null ; then - UNAME_REL=`(/bin/uname -X|egrep Release|sed -e 's/.*= //')` - (/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486 - (/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) \ - && UNAME_MACHINE=i586 - (/bin/uname -X|egrep '^Machine.*Pent ?II' >/dev/null) \ - && UNAME_MACHINE=i686 - (/bin/uname -X|egrep '^Machine.*Pentium Pro' >/dev/null) \ - && UNAME_MACHINE=i686 - echo ${UNAME_MACHINE}-pc-sco$UNAME_REL - else - echo ${UNAME_MACHINE}-pc-sysv32 - fi - exit 0 ;; - pc:*:*:*) - # uname -m prints for DJGPP always 'pc', but it prints nothing about - # the processor, so we play safe by assuming i386. - echo i386-pc-msdosdjgpp - exit 0 ;; - Intel:Mach:3*:*) - echo i386-pc-mach3 - exit 0 ;; - paragon:*:*:*) - echo i860-intel-osf1 - exit 0 ;; - i860:*:4.*:*) # i860-SVR4 - if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then - echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 - else # Add other i860-SVR4 vendors below as they are discovered. - echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 - fi - exit 0 ;; - mini*:CTIX:SYS*5:*) - # "miniframe" - echo m68010-convergent-sysv - exit 0 ;; - M68*:*:R3V[567]*:*) - test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;; - 3[34]??:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 4850:*:4.0:3.0) - OS_REL='' - test -r /etc/.relid \ - && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` - /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ - && echo i486-ncr-sysv4.3${OS_REL} && exit 0 - /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ - && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;; - 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) - /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ - && echo i486-ncr-sysv4 && exit 0 ;; - m68*:LynxOS:2.*:*) - echo m68k-unknown-lynxos${UNAME_RELEASE} - exit 0 ;; - mc68030:UNIX_System_V:4.*:*) - echo m68k-atari-sysv4 - exit 0 ;; - i?86:LynxOS:2.*:* | i?86:LynxOS:3.[01]*:*) - echo i386-unknown-lynxos${UNAME_RELEASE} - exit 0 ;; - TSUNAMI:LynxOS:2.*:*) - echo sparc-unknown-lynxos${UNAME_RELEASE} - exit 0 ;; - rs6000:LynxOS:2.*:* | PowerPC:LynxOS:2.*:*) - echo rs6000-unknown-lynxos${UNAME_RELEASE} - exit 0 ;; - SM[BE]S:UNIX_SV:*:*) - echo mips-dde-sysv${UNAME_RELEASE} - exit 0 ;; - BS2000:POSIX-BC:*:*) - echo bs2000-siemens-sysv4 - exit 0 ;; - RM*:ReliantUNIX-*:*:*) - echo mips-sni-sysv4 - exit 0 ;; - RM*:SINIX-*:*:*) - echo mips-sni-sysv4 - exit 0 ;; - *:SINIX-*:*:*) - if uname -p 2>/dev/null >/dev/null ; then - UNAME_MACHINE=`(uname -p) 2>/dev/null` - echo ${UNAME_MACHINE}-sni-sysv4 - else - echo ns32k-sni-sysv - fi - exit 0 ;; - PENTIUM:CPunix:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort - # says <Richard.M.Bartel@ccMail.Census.GOV> - echo i586-unisys-sysv4 - exit 0 ;; - *:UNIX_System_V:4*:FTX*) - # From Gerald Hewes <hewes@openmarket.com>. - # How about differentiating between stratus architectures? -djm - echo hppa1.1-stratus-sysv4 - exit 0 ;; - *:*:*:FTX*) - # From seanf@swdc.stratus.com. - echo i860-stratus-sysv4 - exit 0 ;; - mc68*:A/UX:*:*) - echo m68k-apple-aux${UNAME_RELEASE} - exit 0 ;; - news*:NEWS-OS:*:6*) - echo mips-sony-newsos6 - exit 0 ;; - R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) - if [ -d /usr/nec ]; then - echo mips-nec-sysv${UNAME_RELEASE} - else - echo mips-unknown-sysv${UNAME_RELEASE} - fi - exit 0 ;; - BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. - echo powerpc-be-beos - exit 0 ;; - BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. - echo powerpc-apple-beos - exit 0 ;; - BePC:BeOS:*:*) # BeOS running on Intel PC compatible. - echo i586-pc-beos - exit 0 ;; - SX-4:SUPER-UX:*:*) - echo sx4-nec-superux${UNAME_RELEASE} - exit 0 ;; - SX-5:SUPER-UX:*:*) - echo sx5-nec-superux${UNAME_RELEASE} - exit 0 ;; - Power*:Rhapsody:*:*) - echo powerpc-apple-rhapsody${UNAME_RELEASE} - exit 0 ;; - *:Rhapsody:*:*) - echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} - exit 0 ;; -esac - -#echo '(No uname command or uname output not recognized.)' 1>&2 -#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 - -cat >$dummy.c <<EOF -#ifdef _SEQUENT_ -# include <sys/types.h> -# include <sys/utsname.h> -#endif -main () -{ -#if defined (sony) -#if defined (MIPSEB) - /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, - I don't know.... */ - printf ("mips-sony-bsd\n"); exit (0); -#else -#include <sys/param.h> - printf ("m68k-sony-newsos%s\n", -#ifdef NEWSOS4 - "4" -#else - "" -#endif - ); exit (0); -#endif -#endif - -#if defined (__arm) && defined (__acorn) && defined (__unix) - printf ("arm-acorn-riscix"); exit (0); -#endif - -#if defined (hp300) && !defined (hpux) - printf ("m68k-hp-bsd\n"); exit (0); -#endif - -#if defined (NeXT) -#if !defined (__ARCHITECTURE__) -#define __ARCHITECTURE__ "m68k" -#endif - int version; - version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; - if (version < 4) - printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); - else - printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); - exit (0); -#endif - -#if defined (MULTIMAX) || defined (n16) -#if defined (UMAXV) - printf ("ns32k-encore-sysv\n"); exit (0); -#else -#if defined (CMU) - printf ("ns32k-encore-mach\n"); exit (0); -#else - printf ("ns32k-encore-bsd\n"); exit (0); -#endif -#endif -#endif - -#if defined (__386BSD__) - printf ("i386-pc-bsd\n"); exit (0); -#endif - -#if defined (sequent) -#if defined (i386) - printf ("i386-sequent-dynix\n"); exit (0); -#endif -#if defined (ns32000) - printf ("ns32k-sequent-dynix\n"); exit (0); -#endif -#endif - -#if defined (_SEQUENT_) - struct utsname un; - - uname(&un); - - if (strncmp(un.version, "V2", 2) == 0) { - printf ("i386-sequent-ptx2\n"); exit (0); - } - if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ - printf ("i386-sequent-ptx1\n"); exit (0); - } - printf ("i386-sequent-ptx\n"); exit (0); - -#endif - -#if defined (vax) -#if !defined (ultrix) - printf ("vax-dec-bsd\n"); exit (0); -#else - printf ("vax-dec-ultrix\n"); exit (0); -#endif -#endif - -#if defined (alliant) && defined (i860) - printf ("i860-alliant-bsd\n"); exit (0); -#endif - - exit (1); -} -EOF - -$CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy && rm $dummy.c $dummy && exit 0 -rm -f $dummy.c $dummy - -# Apollos put the system type in the environment. - -test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; } - -# Convex versions that predate uname can use getsysinfo(1) - -if [ -x /usr/convex/getsysinfo ] -then - case `getsysinfo -f cpu_type` in - c1*) - echo c1-convex-bsd - exit 0 ;; - c2*) - if getsysinfo -f scalar_acc - then echo c32-convex-bsd - else echo c2-convex-bsd - fi - exit 0 ;; - c34*) - echo c34-convex-bsd - exit 0 ;; - c38*) - echo c38-convex-bsd - exit 0 ;; - c4*) - echo c4-convex-bsd - exit 0 ;; - esac -fi - -#echo '(Unable to guess system type)' 1>&2 - -exit 1 diff --git a/shmem/unix/mm/config.sub b/shmem/unix/mm/config.sub deleted file mode 100755 index 0fd1ade4a9c..00000000000 --- a/shmem/unix/mm/config.sub +++ /dev/null @@ -1,1219 +0,0 @@ -#! /bin/sh -# Configuration validation subroutine script, version 1.1. -# Copyright (C) 1991, 92-97, 1998, 1999 Free Software Foundation, Inc. -# This file is (in principle) common to ALL GNU software. -# The presence of a machine in this file suggests that SOME GNU software -# can handle that machine. It does not imply ALL GNU software can. -# -# This file is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, -# Boston, MA 02111-1307, USA. - -# As a special exception to the GNU General Public License, if you -# distribute this file as part of a program that contains a -# configuration script generated by Autoconf, you may include it under -# the same distribution terms that you use for the rest of that program. - -# Configuration subroutine to validate and canonicalize a configuration type. -# Supply the specified configuration type as an argument. -# If it is invalid, we print an error message on stderr and exit with code 1. -# Otherwise, we print the canonical config type on stdout and succeed. - -# This file is supposed to be the same for all GNU packages -# and recognize all the CPU types, system types and aliases -# that are meaningful with *any* GNU software. -# Each package is responsible for reporting which valid configurations -# it does not support. The user should be able to distinguish -# a failure to support a valid configuration from a meaningless -# configuration. - -# The goal of this file is to map all the various variations of a given -# machine specification into a single specification in the form: -# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM -# or in some cases, the newer four-part form: -# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM -# It is wrong to echo any other type of specification. - -if [ x$1 = x ] -then - echo Configuration name missing. 1>&2 - echo "Usage: $0 CPU-MFR-OPSYS" 1>&2 - echo "or $0 ALIAS" 1>&2 - echo where ALIAS is a recognized configuration type. 1>&2 - exit 1 -fi - -# First pass through any local machine types. -case $1 in - *local*) - echo $1 - exit 0 - ;; - *) - ;; -esac - -# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). -# Here we must recognize all the valid KERNEL-OS combinations. -maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` -case $maybe_os in - linux-gnu*) - os=-$maybe_os - basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` - ;; - *) - basic_machine=`echo $1 | sed 's/-[^-]*$//'` - if [ $basic_machine != $1 ] - then os=`echo $1 | sed 's/.*-/-/'` - else os=; fi - ;; -esac - -### Let's recognize common machines as not being operating systems so -### that things like config.sub decstation-3100 work. We also -### recognize some manufacturers as not being operating systems, so we -### can provide default operating systems below. -case $os in - -sun*os*) - # Prevent following clause from handling this invalid input. - ;; - -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ - -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ - -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ - -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ - -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ - -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ - -apple) - os= - basic_machine=$1 - ;; - -sim | -cisco | -oki | -wec | -winbond) - os= - basic_machine=$1 - ;; - -scout) - ;; - -wrs) - os=vxworks - basic_machine=$1 - ;; - -hiux*) - os=-hiuxwe2 - ;; - -sco5) - os=-sco3.2v5 - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -sco4) - os=-sco3.2v4 - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -sco3.2.[4-9]*) - os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -sco3.2v[4-9]*) - # Don't forget version if it is 3.2v4 or newer. - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -sco*) - os=-sco3.2v2 - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -udk*) - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -isc) - os=-isc2.2 - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -clix*) - basic_machine=clipper-intergraph - ;; - -isc*) - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -lynx*) - os=-lynxos - ;; - -ptx*) - basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` - ;; - -windowsnt*) - os=`echo $os | sed -e 's/windowsnt/winnt/'` - ;; - -psos*) - os=-psos - ;; -esac - -# Decode aliases for certain CPU-COMPANY combinations. -case $basic_machine in - # Recognize the basic CPU types without company name. - # Some are omitted here because they have special meanings below. - tahoe | i860 | ia64 | m32r | m68k | m68000 | m88k | ns32k | arc | arm \ - | arme[lb] | pyramid | mn10200 | mn10300 | tron | a29k \ - | 580 | i960 | h8300 \ - | hppa | hppa1.0 | hppa1.1 | hppa2.0 | hppa2.0w | hppa2.0n \ - | alpha | alphaev[4-7] | alphaev56 | alphapca5[67] \ - | we32k | ns16k | clipper | i370 | sh | powerpc | powerpcle \ - | 1750a | dsp16xx | pdp11 | mips16 | mips64 | mipsel | mips64el \ - | mips64orion | mips64orionel | mipstx39 | mipstx39el \ - | mips64vr4300 | mips64vr4300el | mips64vr4100 | mips64vr4100el \ - | mips64vr5000 | miprs64vr5000el | mcore \ - | sparc | sparclet | sparclite | sparc64 | sparcv9 | v850 | c4x \ - | thumb | d10v) - basic_machine=$basic_machine-unknown - ;; - m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | z8k | v70 | h8500 | w65) - ;; - - # We use `pc' rather than `unknown' - # because (1) that's what they normally are, and - # (2) the word "unknown" tends to confuse beginning users. - i[34567]86) - basic_machine=$basic_machine-pc - ;; - # Object if more than one company name word. - *-*-*) - echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 - exit 1 - ;; - # Recognize the basic CPU types with company name. - # FIXME: clean up the formatting here. - vax-* | tahoe-* | i[34567]86-* | i860-* | ia64-* | m32r-* | m68k-* | m68000-* \ - | m88k-* | sparc-* | ns32k-* | fx80-* | arc-* | arm-* | c[123]* \ - | mips-* | pyramid-* | tron-* | a29k-* | romp-* | rs6000-* \ - | power-* | none-* | 580-* | cray2-* | h8300-* | h8500-* | i960-* \ - | xmp-* | ymp-* \ - | hppa-* | hppa1.0-* | hppa1.1-* | hppa2.0-* | hppa2.0w-* | hppa2.0n-* \ - | alpha-* | alphaev[4-7]-* | alphaev56-* | alphapca5[67]-* \ - | we32k-* | cydra-* | ns16k-* | pn-* | np1-* | xps100-* \ - | clipper-* | orion-* \ - | sparclite-* | pdp11-* | sh-* | powerpc-* | powerpcle-* \ - | sparc64-* | sparcv9-* | sparc86x-* | mips16-* | mips64-* | mipsel-* \ - | mips64el-* | mips64orion-* | mips64orionel-* \ - | mips64vr4100-* | mips64vr4100el-* | mips64vr4300-* | mips64vr4300el-* \ - | mipstx39-* | mipstx39el-* | mcore-* \ - | f301-* | armv*-* | t3e-* \ - | m88110-* | m680[01234]0-* | m683?2-* | m68360-* | z8k-* | d10v-* \ - | thumb-* | v850-* | d30v-* | tic30-* | c30-* ) - ;; - # Recognize the various machine names and aliases which stand - # for a CPU type and a company and sometimes even an OS. - 386bsd) - basic_machine=i386-unknown - os=-bsd - ;; - 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) - basic_machine=m68000-att - ;; - 3b*) - basic_machine=we32k-att - ;; - a29khif) - basic_machine=a29k-amd - os=-udi - ;; - adobe68k) - basic_machine=m68010-adobe - os=-scout - ;; - alliant | fx80) - basic_machine=fx80-alliant - ;; - altos | altos3068) - basic_machine=m68k-altos - ;; - am29k) - basic_machine=a29k-none - os=-bsd - ;; - amdahl) - basic_machine=580-amdahl - os=-sysv - ;; - amiga | amiga-*) - basic_machine=m68k-cbm - ;; - amigaos | amigados) - basic_machine=m68k-cbm - os=-amigaos - ;; - amigaunix | amix) - basic_machine=m68k-cbm - os=-sysv4 - ;; - apollo68) - basic_machine=m68k-apollo - os=-sysv - ;; - apollo68bsd) - basic_machine=m68k-apollo - os=-bsd - ;; - aux) - basic_machine=m68k-apple - os=-aux - ;; - balance) - basic_machine=ns32k-sequent - os=-dynix - ;; - convex-c1) - basic_machine=c1-convex - os=-bsd - ;; - convex-c2) - basic_machine=c2-convex - os=-bsd - ;; - convex-c32) - basic_machine=c32-convex - os=-bsd - ;; - convex-c34) - basic_machine=c34-convex - os=-bsd - ;; - convex-c38) - basic_machine=c38-convex - os=-bsd - ;; - cray | ymp) - basic_machine=ymp-cray - os=-unicos - ;; - cray2) - basic_machine=cray2-cray - os=-unicos - ;; - [ctj]90-cray) - basic_machine=c90-cray - os=-unicos - ;; - crds | unos) - basic_machine=m68k-crds - ;; - da30 | da30-*) - basic_machine=m68k-da30 - ;; - decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) - basic_machine=mips-dec - ;; - delta | 3300 | motorola-3300 | motorola-delta \ - | 3300-motorola | delta-motorola) - basic_machine=m68k-motorola - ;; - delta88) - basic_machine=m88k-motorola - os=-sysv3 - ;; - dpx20 | dpx20-*) - basic_machine=rs6000-bull - os=-bosx - ;; - dpx2* | dpx2*-bull) - basic_machine=m68k-bull - os=-sysv3 - ;; - ebmon29k) - basic_machine=a29k-amd - os=-ebmon - ;; - elxsi) - basic_machine=elxsi-elxsi - os=-bsd - ;; - encore | umax | mmax) - basic_machine=ns32k-encore - ;; - es1800 | OSE68k | ose68k | ose | OSE) - basic_machine=m68k-ericsson - os=-ose - ;; - fx2800) - basic_machine=i860-alliant - ;; - genix) - basic_machine=ns32k-ns - ;; - gmicro) - basic_machine=tron-gmicro - os=-sysv - ;; - h3050r* | hiux*) - basic_machine=hppa1.1-hitachi - os=-hiuxwe2 - ;; - h8300hms) - basic_machine=h8300-hitachi - os=-hms - ;; - h8300xray) - basic_machine=h8300-hitachi - os=-xray - ;; - h8500hms) - basic_machine=h8500-hitachi - os=-hms - ;; - harris) - basic_machine=m88k-harris - os=-sysv3 - ;; - hp300-*) - basic_machine=m68k-hp - ;; - hp300bsd) - basic_machine=m68k-hp - os=-bsd - ;; - hp300hpux) - basic_machine=m68k-hp - os=-hpux - ;; - hp3k9[0-9][0-9] | hp9[0-9][0-9]) - basic_machine=hppa1.0-hp - ;; - hp9k2[0-9][0-9] | hp9k31[0-9]) - basic_machine=m68000-hp - ;; - hp9k3[2-9][0-9]) - basic_machine=m68k-hp - ;; - hp9k6[0-9][0-9] | hp6[0-9][0-9]) - basic_machine=hppa1.0-hp - ;; - hp9k7[0-79][0-9] | hp7[0-79][0-9]) - basic_machine=hppa1.1-hp - ;; - hp9k78[0-9] | hp78[0-9]) - # FIXME: really hppa2.0-hp - basic_machine=hppa1.1-hp - ;; - hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) - # FIXME: really hppa2.0-hp - basic_machine=hppa1.1-hp - ;; - hp9k8[0-9][13679] | hp8[0-9][13679]) - basic_machine=hppa1.1-hp - ;; - hp9k8[0-9][0-9] | hp8[0-9][0-9]) - basic_machine=hppa1.0-hp - ;; - hppa-next) - os=-nextstep3 - ;; - hppaosf) - basic_machine=hppa1.1-hp - os=-osf - ;; - hppro) - basic_machine=hppa1.1-hp - os=-proelf - ;; - i370-ibm* | ibm*) - basic_machine=i370-ibm - os=-mvs - ;; -# I'm not sure what "Sysv32" means. Should this be sysv3.2? - i[34567]86v32) - basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` - os=-sysv32 - ;; - i[34567]86v4*) - basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` - os=-sysv4 - ;; - i[34567]86v) - basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` - os=-sysv - ;; - i[34567]86sol2) - basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` - os=-solaris2 - ;; - i386mach) - basic_machine=i386-mach - os=-mach - ;; - i386-vsta | vsta) - basic_machine=i386-unknown - os=-vsta - ;; - i386-go32 | go32) - basic_machine=i386-unknown - os=-go32 - ;; - i386-mingw32 | mingw32) - basic_machine=i386-unknown - os=-mingw32 - ;; - iris | iris4d) - basic_machine=mips-sgi - case $os in - -irix*) - ;; - *) - os=-irix4 - ;; - esac - ;; - isi68 | isi) - basic_machine=m68k-isi - os=-sysv - ;; - m88k-omron*) - basic_machine=m88k-omron - ;; - magnum | m3230) - basic_machine=mips-mips - os=-sysv - ;; - merlin) - basic_machine=ns32k-utek - os=-sysv - ;; - miniframe) - basic_machine=m68000-convergent - ;; - *mint | *MiNT) - basic_machine=m68k-atari - os=-mint - ;; - mipsel*-linux*) - basic_machine=mipsel-unknown - os=-linux-gnu - ;; - mips*-linux*) - basic_machine=mips-unknown - os=-linux-gnu - ;; - mips3*-*) - basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` - ;; - mips3*) - basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown - ;; - monitor) - basic_machine=m68k-rom68k - os=-coff - ;; - msdos) - basic_machine=i386-unknown - os=-msdos - ;; - ncr3000) - basic_machine=i486-ncr - os=-sysv4 - ;; - netbsd386) - basic_machine=i386-unknown - os=-netbsd - ;; - netwinder) - basic_machine=armv4l-corel - os=-linux - ;; - news | news700 | news800 | news900) - basic_machine=m68k-sony - os=-newsos - ;; - news1000) - basic_machine=m68030-sony - os=-newsos - ;; - news-3600 | risc-news) - basic_machine=mips-sony - os=-newsos - ;; - necv70) - basic_machine=v70-nec - os=-sysv - ;; - next | m*-next ) - basic_machine=m68k-next - case $os in - -nextstep* ) - ;; - -ns2*) - os=-nextstep2 - ;; - *) - os=-nextstep3 - ;; - esac - ;; - nh3000) - basic_machine=m68k-harris - os=-cxux - ;; - nh[45]000) - basic_machine=m88k-harris - os=-cxux - ;; - nindy960) - basic_machine=i960-intel - os=-nindy - ;; - mon960) - basic_machine=i960-intel - os=-mon960 - ;; - np1) - basic_machine=np1-gould - ;; - op50n-* | op60c-*) - basic_machine=hppa1.1-oki - os=-proelf - ;; - OSE68000 | ose68000) - basic_machine=m68000-ericsson - os=-ose - ;; - os68k) - basic_machine=m68k-none - os=-os68k - ;; - pa-hitachi) - basic_machine=hppa1.1-hitachi - os=-hiuxwe2 - ;; - paragon) - basic_machine=i860-intel - os=-osf - ;; - pbd) - basic_machine=sparc-tti - ;; - pbb) - basic_machine=m68k-tti - ;; - pc532 | pc532-*) - basic_machine=ns32k-pc532 - ;; - pentium | p5 | k5 | k6 | nexen) - basic_machine=i586-pc - ;; - pentiumpro | p6 | 6x86) - basic_machine=i686-pc - ;; - pentiumii | pentium2) - basic_machine=i786-pc - ;; - pentium-* | p5-* | k5-* | k6-* | nexen-*) - basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - pentiumpro-* | p6-* | 6x86-*) - basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - pentiumii-* | pentium2-*) - basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - pn) - basic_machine=pn-gould - ;; - power) basic_machine=rs6000-ibm - ;; - ppc) basic_machine=powerpc-unknown - ;; - ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - ppcle | powerpclittle | ppc-le | powerpc-little) - basic_machine=powerpcle-unknown - ;; - ppcle-* | powerpclittle-*) - basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - ps2) - basic_machine=i386-ibm - ;; - rom68k) - basic_machine=m68k-rom68k - os=-coff - ;; - rm[46]00) - basic_machine=mips-siemens - ;; - rtpc | rtpc-*) - basic_machine=romp-ibm - ;; - sa29200) - basic_machine=a29k-amd - os=-udi - ;; - sequent) - basic_machine=i386-sequent - ;; - sh) - basic_machine=sh-hitachi - os=-hms - ;; - sparclite-wrs) - basic_machine=sparclite-wrs - os=-vxworks - ;; - sps7) - basic_machine=m68k-bull - os=-sysv2 - ;; - spur) - basic_machine=spur-unknown - ;; - st2000) - basic_machine=m68k-tandem - ;; - stratus) - basic_machine=i860-stratus - os=-sysv4 - ;; - sun2) - basic_machine=m68000-sun - ;; - sun2os3) - basic_machine=m68000-sun - os=-sunos3 - ;; - sun2os4) - basic_machine=m68000-sun - os=-sunos4 - ;; - sun3os3) - basic_machine=m68k-sun - os=-sunos3 - ;; - sun3os4) - basic_machine=m68k-sun - os=-sunos4 - ;; - sun4os3) - basic_machine=sparc-sun - os=-sunos3 - ;; - sun4os4) - basic_machine=sparc-sun - os=-sunos4 - ;; - sun4sol2) - basic_machine=sparc-sun - os=-solaris2 - ;; - sun3 | sun3-*) - basic_machine=m68k-sun - ;; - sun4) - basic_machine=sparc-sun - ;; - sun386 | sun386i | roadrunner) - basic_machine=i386-sun - ;; - symmetry) - basic_machine=i386-sequent - os=-dynix - ;; - t3e) - basic_machine=t3e-cray - os=-unicos - ;; - tx39) - basic_machine=mipstx39-unknown - ;; - tx39el) - basic_machine=mipstx39el-unknown - ;; - tower | tower-32) - basic_machine=m68k-ncr - ;; - udi29k) - basic_machine=a29k-amd - os=-udi - ;; - ultra3) - basic_machine=a29k-nyu - os=-sym1 - ;; - v810 | necv810) - basic_machine=v810-nec - os=-none - ;; - vaxv) - basic_machine=vax-dec - os=-sysv - ;; - vms) - basic_machine=vax-dec - os=-vms - ;; - vpp*|vx|vx-*) - basic_machine=f301-fujitsu - ;; - vxworks960) - basic_machine=i960-wrs - os=-vxworks - ;; - vxworks68) - basic_machine=m68k-wrs - os=-vxworks - ;; - vxworks29k) - basic_machine=a29k-wrs - os=-vxworks - ;; - w65*) - basic_machine=w65-wdc - os=-none - ;; - w89k-*) - basic_machine=hppa1.1-winbond - os=-proelf - ;; - xmp) - basic_machine=xmp-cray - os=-unicos - ;; - xps | xps100) - basic_machine=xps100-honeywell - ;; - z8k-*-coff) - basic_machine=z8k-unknown - os=-sim - ;; - none) - basic_machine=none-none - os=-none - ;; - -# Here we handle the default manufacturer of certain CPU types. It is in -# some cases the only manufacturer, in others, it is the most popular. - w89k) - basic_machine=hppa1.1-winbond - ;; - op50n) - basic_machine=hppa1.1-oki - ;; - op60c) - basic_machine=hppa1.1-oki - ;; - mips) - if [ x$os = x-linux-gnu ]; then - basic_machine=mips-unknown - else - basic_machine=mips-mips - fi - ;; - romp) - basic_machine=romp-ibm - ;; - rs6000) - basic_machine=rs6000-ibm - ;; - vax) - basic_machine=vax-dec - ;; - pdp11) - basic_machine=pdp11-dec - ;; - we32k) - basic_machine=we32k-att - ;; - sparc | sparcv9) - basic_machine=sparc-sun - ;; - cydra) - basic_machine=cydra-cydrome - ;; - orion) - basic_machine=orion-highlevel - ;; - orion105) - basic_machine=clipper-highlevel - ;; - mac | mpw | mac-mpw) - basic_machine=m68k-apple - ;; - pmac | pmac-mpw) - basic_machine=powerpc-apple - ;; - c4x*) - basic_machine=c4x-none - os=-coff - ;; - bs2000-siemens) - ;; - *) - echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 - exit 1 - ;; -esac - -# Here we canonicalize certain aliases for manufacturers. -case $basic_machine in - *-digital*) - basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` - ;; - *-commodore*) - basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` - ;; - *) - ;; -esac - -# Decode manufacturer-specific aliases for certain operating systems. - -if [ x"$os" != x"" ] -then -case $os in - # First match some system type aliases - # that might get confused with valid system types. - # -solaris* is a basic system type, with this one exception. - -solaris1 | -solaris1.*) - os=`echo $os | sed -e 's|solaris1|sunos4|'` - ;; - -solaris) - os=-solaris2 - ;; - -svr4*) - os=-sysv4 - ;; - -unixware*) - os=-sysv4.2uw - ;; - -gnu/linux*) - os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` - ;; - # First accept the basic system types. - # The portable systems comes first. - # Each alternative MUST END IN A *, to match a version number. - # -sysv* is not here because it comes later, after sysvr4. - -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ - | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ - | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ - | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ - | -aos* \ - | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ - | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ - | -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \ - | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ - | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ - | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ - | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ - | -mingw32* | -linux-gnu* | -uxpv* | -beos* | -mpeix* | -udk* \ - | -interix* | -uwin* | -rhapsody* | -openstep* | -oskit*) - # Remember, each alternative MUST END IN *, to match a version number. - ;; - -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ - | -windows* | -osx | -abug | -netware* | -os9* | -beos* \ - | -macos* | -mpw* | -magic* | -mon960* | -lnews*) - ;; - -mac*) - os=`echo $os | sed -e 's|mac|macos|'` - ;; - -linux*) - os=`echo $os | sed -e 's|linux|linux-gnu|'` - ;; - -sunos5*) - os=`echo $os | sed -e 's|sunos5|solaris2|'` - ;; - -sunos6*) - os=`echo $os | sed -e 's|sunos6|solaris3|'` - ;; - -osfrose*) - os=-osfrose - ;; - -osf*) - os=-osf - ;; - -utek*) - os=-bsd - ;; - -dynix*) - os=-bsd - ;; - -acis*) - os=-aos - ;; - -386bsd) - os=-bsd - ;; - -ctix* | -uts*) - os=-sysv - ;; - -ns2 ) - os=-nextstep2 - ;; - # Preserve the version number of sinix5. - -sinix5.*) - os=`echo $os | sed -e 's|sinix|sysv|'` - ;; - -sinix*) - os=-sysv4 - ;; - -triton*) - os=-sysv3 - ;; - -oss*) - os=-sysv3 - ;; - -svr4) - os=-sysv4 - ;; - -svr3) - os=-sysv3 - ;; - -sysvr4) - os=-sysv4 - ;; - # This must come after -sysvr4. - -sysv*) - ;; - -ose*) - os=-ose - ;; - -es1800*) - os=-ose - ;; - -xenix) - os=-xenix - ;; - -*mint | -*MiNT) - os=-mint - ;; - -none) - ;; - *) - # Get rid of the `-' at the beginning of $os. - os=`echo $os | sed 's/[^-]*-//'` - echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 - exit 1 - ;; -esac -else - -# Here we handle the default operating systems that come with various machines. -# The value should be what the vendor currently ships out the door with their -# machine or put another way, the most popular os provided with the machine. - -# Note that if you're going to try to match "-MANUFACTURER" here (say, -# "-sun"), then you have to tell the case statement up towards the top -# that MANUFACTURER isn't an operating system. Otherwise, code above -# will signal an error saying that MANUFACTURER isn't an operating -# system, and we'll never get to this point. - -case $basic_machine in - *-acorn) - os=-riscix1.2 - ;; - arm*-corel) - os=-linux - ;; - arm*-semi) - os=-aout - ;; - pdp11-*) - os=-none - ;; - *-dec | vax-*) - os=-ultrix4.2 - ;; - m68*-apollo) - os=-domain - ;; - i386-sun) - os=-sunos4.0.2 - ;; - m68000-sun) - os=-sunos3 - # This also exists in the configure program, but was not the - # default. - # os=-sunos4 - ;; - m68*-cisco) - os=-aout - ;; - mips*-cisco) - os=-elf - ;; - mips*-*) - os=-elf - ;; - *-tti) # must be before sparc entry or we get the wrong os. - os=-sysv3 - ;; - sparc-* | *-sun) - os=-sunos4.1.1 - ;; - *-be) - os=-beos - ;; - *-ibm) - os=-aix - ;; - *-wec) - os=-proelf - ;; - *-winbond) - os=-proelf - ;; - *-oki) - os=-proelf - ;; - *-hp) - os=-hpux - ;; - *-hitachi) - os=-hiux - ;; - i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) - os=-sysv - ;; - *-cbm) - os=-amigaos - ;; - *-dg) - os=-dgux - ;; - *-dolphin) - os=-sysv3 - ;; - m68k-ccur) - os=-rtu - ;; - m88k-omron*) - os=-luna - ;; - *-next ) - os=-nextstep - ;; - *-sequent) - os=-ptx - ;; - *-crds) - os=-unos - ;; - *-ns) - os=-genix - ;; - i370-*) - os=-mvs - ;; - *-next) - os=-nextstep3 - ;; - *-gould) - os=-sysv - ;; - *-highlevel) - os=-bsd - ;; - *-encore) - os=-bsd - ;; - *-sgi) - os=-irix - ;; - *-siemens) - os=-sysv4 - ;; - *-masscomp) - os=-rtu - ;; - f301-fujitsu) - os=-uxpv - ;; - *-rom68k) - os=-coff - ;; - *-*bug) - os=-coff - ;; - *-apple) - os=-macos - ;; - *-atari*) - os=-mint - ;; - *) - os=-none - ;; -esac -fi - -# Here we handle the case where we know the os, and the CPU type, but not the -# manufacturer. We pick the logical manufacturer. -vendor=unknown -case $basic_machine in - *-unknown) - case $os in - -riscix*) - vendor=acorn - ;; - -sunos*) - vendor=sun - ;; - -aix*) - vendor=ibm - ;; - -beos*) - vendor=be - ;; - -hpux*) - vendor=hp - ;; - -mpeix*) - vendor=hp - ;; - -hiux*) - vendor=hitachi - ;; - -unos*) - vendor=crds - ;; - -dgux*) - vendor=dg - ;; - -luna*) - vendor=omron - ;; - -genix*) - vendor=ns - ;; - -mvs*) - vendor=ibm - ;; - -ptx*) - vendor=sequent - ;; - -vxsim* | -vxworks*) - vendor=wrs - ;; - -aux*) - vendor=apple - ;; - -hms*) - vendor=hitachi - ;; - -mpw* | -macos*) - vendor=apple - ;; - -*mint | -*MiNT) - vendor=atari - ;; - esac - basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` - ;; -esac - -echo $basic_machine$os -exit 0 diff --git a/shmem/unix/mm/configure.in b/shmem/unix/mm/configure.in deleted file mode 100644 index e7de4dd965c..00000000000 --- a/shmem/unix/mm/configure.in +++ /dev/null @@ -1,219 +0,0 @@ -dnl ## -dnl ## Autoconf specification for MM library -dnl ## - -dnl # -dnl # standard Autoconf prolog -dnl # - -AC_PREREQ(2.12)dnl -AC_REVISION(1.0)dnl - -dnl # shtool bootstrap -SHTOOL="\$(TOP)/shtool" -AC_SUBST(SHTOOL) -ac_shtool="./shtool" -T_MD=`$ac_shtool echo -n -e %B` -T_ME=`$ac_shtool echo -n -e %b` -PLATFORM=`${CONFIG_SHELL-/bin/sh} ./config.guess` -PLATFORM=`${CONFIG_SHELL-/bin/sh} ./config.sub $PLATFORM` -MM_VERSION_STR="`$ac_shtool version -l c -d long mm_vers.c`" -AC_SUBST(MM_VERSION_STR) - -dnl # friendly header ;-) -echo "Configuring ${T_MD}MM${T_ME} (Shared Memory Library), Version ${T_MD}${MM_VERSION_STR}${T_ME}" -echo "Copyright (c) 1999 Ralf S. Engelschall, All Rights Reserved." -echo "Platform: ${T_MD}${PLATFORM}${T_ME}" - -dnl # autoconf initialization -AC_INIT(README) -AC_CONFIG_HEADER(mm_conf.h)dnl -AC_PREFIX_DEFAULT(/usr/local) - -dnl # determine build mode -AC_ARG_ENABLE(batch,dnl -[ --enable-batch build in batch mode (default=no)], -enable_batch="$enableval", -if test ".$enable_batch" = .; then - enable_batch=no -fi -)dnl - -dnl # -dnl # determine build tools and parameters -dnl # - -AC_CONFIGURE_PART(Build Tools) -AC_PROG_CC -AC_PROG_CPP -AC_CHECK_DEBUGGING -AC_SET_MAKE -AC_PROG_LIBTOOL - -dnl # support for some special platform/compiler options -case "$PLATFORM:$CC" in - *-hp-hpux*:cc ) CFLAGS="$CFLAGS -Ae +DAportable" ;; -esac - -dnl # -dnl # determine system parameters -dnl # - -AC_CONFIGURE_PART(Platform Environment) - -AC_HAVE_HEADERS(stdio.h stdlib.h string.h dnl - errno.h limits.h unistd.h fcntl.h dnl - sys/stat.h sys/types.h) -AC_BEGIN_DECISION([mandatory system headers]) -AC_IFALLYES(header:stdio.h header:stdlib.h header:string.h dnl - header:errno.h header:limits.h header:unistd.h header:fcntl.h dnl - header:sys/stat.h header:sys/types.h, - AC_DECIDE(fine, [all fine])) -AC_END_DECISION - -AC_HAVE_HEADERS(memory.h) -AC_CHECK_FUNCS(memcpy memset bcopy) -AC_CHECK_DEFINE(_POSIX_PATH_MAX, limits.h) -AC_CHECK_DEFINE(PATH_MAX, limits.h) -AC_CHECK_DEFINE(MAXPATHLEN, sys/param.h) -AC_CHECK_DEFINE(_POSIX_CHILD_MAX, limits.h) -AC_CHECK_DEFINE(CHILD_MAX, limits.h) - -dnl # some special defines for brain dead platforms -case $PLATFORM in - *-*-sunos* ) AC_DEFINE(MM_OS_SUNOS) ;; -esac - -dnl # -dnl # method to determine virtual memory page size -dnl # - -AC_CONFIGURE_PART(Virtual Memory Page Size) - -AC_HAVE_HEADERS(unistd.h) -AC_HAVE_FUNCS(getpagesize sysconf) -AC_CHECK_DEFINE(_SC_PAGESIZE, unistd.h) -AC_HAVE_HEADERS(kernel/OS.h) -AC_CHECK_DEFINE(B_PAGE_SIZE, kernel/OS.h) - -AC_BEGIN_DECISION([memory page size determination]) -AC_IFALLYES(header:unistd.h func:getpagesize, - AC_DECIDE(MM_VMPS_GETPAGESIZE, [4.2BSD getpagesize()])) -AC_IFALLYES(header:unistd.h func:sysconf define:_SC_PAGESIZE, - AC_DECIDE(MM_VMPS_SYSCONF, [POSIX.1 sysconf(_SC_PAGESIZE)])) -AC_IFALLYES(header:kernel/OS.h define:B_PAGE_SIZE, - AC_DECIDE(MM_VMPS_BEOS, [BeOS B_PAGE_SIZE])) -AC_END_DECISION -AC_DEFINE_UNQUOTED($ac_decision) - -dnl # -dnl # Shared Memory -dnl # - -AC_CONFIGURE_PART(Shared Memory Implementation) - -AC_HAVE_HEADERS(sys/mman.h) -AC_CHECK_DEFINE(MAP_ANON, sys/mman.h) -AC_HAVE_FUNCS(mmap munmap shm_open shm_unlink) -AC_TEST_FILE(/dev/zero) -AC_HAVE_HEADERS(sys/ipc.h sys/shm.h sys/file.h) -AC_HAVE_FUNCS(shmget shmat shmdt shmctl) -AC_HAVE_HEADERS(kernel/OS.h) -AC_HAVE_FUNCS(create_area) - -AC_BEGIN_DECISION([shared memory allocation method]) -AC_IFALLYES(header:sys/mman.h func:mmap func:munmap, - AC_DECIDE(MM_SHMT_MMFILE, [Classical mmap() on temporary file])) -AC_IFALLYES(header:sys/mman.h func:mmap func:munmap func:shm_open func:shm_unlink, - AC_DECIDE(MM_SHMT_MMPOSX, [mmap() via POSIX.1 shm_open() on temporary file])) -AC_IFALLYES(header:sys/mman.h func:mmap func:munmap file:/dev/zero, - AC_DECIDE(MM_SHMT_MMZERO, [SVR4-style mmap() on /dev/zero])) -AC_IFALLYES(header:sys/ipc.h header:sys/shm.h header:sys/file.h dnl - func:shmget func:shmat func:shmdt func:shmctl, - AC_DECIDE(MM_SHMT_IPCSHM, [SysV IPC shmget()])) -AC_IFALLYES(header:sys/mman.h func:mmap func:munmap define:MAP_ANON, - AC_DECIDE(MM_SHMT_MMANON, [4.4BSD-style mmap() via MAP_ANON])) -AC_IFALLYES(header:kernel/OS.h func:create_area, - AC_DECIDE(MM_SHMT_BEOS, [BeOS areas])) -case $PLATFORM in - *-*-linux* ) - # Linux has problems with MM_SHMT_MMANON - AC_DECISION_OVERRIDE(MM_SHMT_MMANON MM_SHMT_MMFILE MM_SHMT_MMZERO dnl - MM_SHMT_MMPOSX MM_SHMT_IPCSHM) - ;; -esac -AC_ARG_WITH(shm,dnl -[ --with-shm=TYPE force shared memory type: MMFILE MMZERO MMPOSX MMANON IPCSHM], -AC_DECISION_FORCE(MM_SHMT_$withval) -)dnl -AC_END_DECISION -AC_DEFINE_UNQUOTED($ac_decision) - -AC_CHECK_MAXSEGSIZE($ac_decision) - -dnl # -dnl # Mutex -dnl # - -AC_CONFIGURE_PART(Mutual Exclusion Implementation) - -AC_HAVE_HEADERS(sys/ipc.h sys/sem.h sys/file.h) -AC_HAVE_FUNCS(semget semctl) -AC_CHECK_DEFINE(LOCK_EX, sys/file.h) -AC_CHECK_DEFINE(F_SETLK, fcntl.h) -AC_CHECK_DEFINE(IPC_PRIVATE, sys/ipc.h) -AC_CHECK_DEFINE(SEM_UNDO, sys/sem.h) -AC_HAVE_HEADERS(kernel/OS.h) -AC_CHECK_FUNCS(create_sem, kernel/OS.h) - -AC_MSG_CHECKING(whether union semun is defined in sys/sem.h) -AC_TRY_COMPILE([ -#include <sys/types.h> -#include <sys/ipc.h> -#include <sys/sem.h> -],[ -union semun arg; -semctl(0, 0, 0, arg); -], -AC_DEFINE(HAVE_UNION_SEMUN) -msg=yes,dnl -msg=no) -AC_MSG_RESULT([$msg]) - -AC_BEGIN_DECISION([mutex implementation method]) -AC_IFALLYES(header:sys/file.h define:LOCK_EX, - AC_DECIDE(MM_SEMT_FLOCK, [4.2BSD-style flock() on temporary file])) -AC_IFALLYES(header:sys/ipc.h header:sys/sem.h header:sys/file.h dnl - func:semget func:semctl, - AC_DECIDE(MM_SEMT_IPCSEM, [SysV IPC semget()])) -AC_IFALLYES(header:fcntl.h define:F_SETLK, - AC_DECIDE(MM_SEMT_FCNTL, [SVR4-style fcntl() on temporary file])) -AC_IFALLYES(header:kernel/OS.h func:create_sem, - AC_DECIDE(MM_SEMT_BEOS, [BeOS semaphores/benaphores])) -AC_ARG_WITH(sem,dnl -[ --with-sem=TYPE force semaphore type: FLOCK FCNTL IPCSEM], -AC_DECISION_FORCE(MM_SEMT_$withval) -)dnl -AC_END_DECISION -AC_DEFINE_UNQUOTED($ac_decision) - -dnl # -dnl # finally: source file substitution... -dnl # - -AC_CONFIGURE_PART(Output Substitution) - -AC_OUTPUT(dnl -Makefile dnl -mm-config dnl -,dnl -chmod a+x mm-config -)dnl - -if test ".$enable_batch" != .yes; then - echo "" - echo "Now please type \`${T_MD}make${T_ME}' to compile. Good luck." - echo "" -fi - -dnl ##EOF## diff --git a/shmem/unix/mm/fbtool b/shmem/unix/mm/fbtool deleted file mode 100755 index 5b6b2231896..00000000000 --- a/shmem/unix/mm/fbtool +++ /dev/null @@ -1,42 +0,0 @@ -#!/bin/sh -## -## fbtool -- MM library feedback tool -## Copyright (c) 1999 Ralf S. Engelschall, All Rights Reserved. -## - -if [ ! -f .fbtool ]; then - echo "fbtool:Error: still no results known"; - exit 1 -fi -result=`cat .fbtool` - -VERSION=`./shtool version -l c -d long mm_vers.c` - -PLATFORM=`/bin/sh ./config.guess` -PLATFORM=`/bin/sh ./config.sub $PLATFORM` - -VMPS=`grep MM_VMPS_ mm_conf.h | grep define | sed -e 's;.*MM_;MM_;' -e 's; .*;;'`; \ -SHMT=`grep MM_SHMT_ mm_conf.h | grep define | sed -e 's;.*MM_;MM_;' -e 's; .*;;'`; \ -SEMT=`grep MM_SEMT_ mm_conf.h | grep define | sed -e 's;.*MM_;MM_;' -e 's; .*;;'`; \ -SEGS=`grep MM_SHM_MAXSEGSIZE mm_conf.h | grep define | sed -e 's;.*SIZE *;;' -e 's; .*;;'`; \ - -TMP=".fbsummary" -rm -f $TMP >/dev/null 2>&1 -touch $TMP -echo "+-MM-Library-Test-Suite-Summary---------------------------" >>$TMP -echo "| Library Version : MM $VERSION" >>$TMP -echo "| Platform : $PLATFORM" >>$TMP -echo "| Memory Page Size Type : $VMPS" >>$TMP -echo "| Shared Memory Type : $SHMT" >>$TMP -echo "| Semaphore Type : $SEMT" >>$TMP -echo "| Maximum Segment Size : $SEGS" >>$TMP -echo "| Test Suite : $result" >>$TMP -echo "+---------------------------------------------------------" >>$TMP - -case $1 in - -d ) cat $TMP ;; - -s ) ;; -esac - -rm -f $TMP >/dev/null 2>&1 - diff --git a/shmem/unix/mm/ltconfig b/shmem/unix/mm/ltconfig deleted file mode 100755 index 65ec6f65d0f..00000000000 --- a/shmem/unix/mm/ltconfig +++ /dev/null @@ -1,3017 +0,0 @@ -#! /bin/sh - -# ltconfig - Create a system-specific libtool. -# Copyright (C) 1996-1999 Free Software Foundation, Inc. -# Originally by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996 -# -# This file is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# -# As a special exception to the GNU General Public License, if you -# distribute this file as part of a program that contains a -# configuration script generated by Autoconf, you may include it under -# the same distribution terms that you use for the rest of that program. - -# A lot of this script is taken from autoconf-2.10. - -# Check that we are running under the correct shell. -SHELL=${CONFIG_SHELL-/bin/sh} -echo=echo -if test "X$1" = X--no-reexec; then - # Discard the --no-reexec flag, and continue. - shift -elif test "X$1" = X--fallback-echo; then - # Avoid inline document here, it may be left over - : -elif test "X`($echo '\t') 2>/dev/null`" = 'X\t'; then - # Yippee, $echo works! - : -else - # Restart under the correct shell. - exec "$SHELL" "$0" --no-reexec ${1+"$@"} -fi - -if test "X$1" = X--fallback-echo; then - # used as fallback echo - shift - cat <<EOF -$* -EOF - exit 0 -fi - -# Find the correct PATH separator. Usually this is `:', but -# DJGPP uses `;' like DOS. -if test "X${PATH_SEPARATOR+set}" != "Xset"; then - UNAME=${UNAME-`uname 2>/dev/null`} - case X$UNAME in - *-DOS) PATH_SEPARATOR=';' ;; - *) PATH_SEPARATOR=':' ;; - esac -fi - -# The HP-UX ksh and POSIX shell print the target directory to stdout -# if CDPATH is set. -if test "${CDPATH+set}" = set; then CDPATH=; export CDPATH; fi - -if test "X${echo_test_string+set}" != "Xset"; then - # find a string as large as possible, as long as the shell can cope with it - for cmd in 'sed 50q "$0"' 'sed 20q "$0"' 'sed 10q "$0"' 'sed 2q "$0"' 'echo test'; do - # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ... - if (echo_test_string="`eval $cmd`") 2>/dev/null && - echo_test_string="`eval $cmd`" && - (test "X$echo_test_string" = "X$echo_test_string") 2>/dev/null; then - break - fi - done -fi - -if test "X`($echo '\t') 2>/dev/null`" != 'X\t' || - test "X`($echo "$echo_test_string") 2>/dev/null`" != X"$echo_test_string"; then - # The Solaris, AIX, and Digital Unix default echo programs unquote - # backslashes. This makes it impossible to quote backslashes using - # echo "$something" | sed 's/\\/\\\\/g' - # - # So, first we look for a working echo in the user's PATH. - - IFS="${IFS= }"; save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR}" - for dir in $PATH /usr/ucb; do - if (test -f $dir/echo || test -f $dir/echo$ac_exeext) && - test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' && - test "X`($dir/echo "$echo_test_string") 2>/dev/null`" = X"$echo_test_string"; then - echo="$dir/echo" - break - fi - done - IFS="$save_ifs" - - if test "X$echo" = Xecho; then - # We didn't find a better echo, so look for alternatives. - if test "X`(print -r '\t') 2>/dev/null`" = 'X\t' && - test "X`(print -r "$echo_test_string") 2>/dev/null`" = X"$echo_test_string"; then - # This shell has a builtin print -r that does the trick. - echo='print -r' - elif (test -f /bin/ksh || test -f /bin/ksh$ac_exeext) && - test "X$CONFIG_SHELL" != X/bin/ksh; then - # If we have ksh, try running ltconfig again with it. - ORIGINAL_CONFIG_SHELL="${CONFIG_SHELL-/bin/sh}" - export ORIGINAL_CONFIG_SHELL - CONFIG_SHELL=/bin/ksh - export CONFIG_SHELL - exec "$CONFIG_SHELL" "$0" --no-reexec ${1+"$@"} - else - # Try using printf. - echo='printf "%s\n"' - if test "X`($echo '\t') 2>/dev/null`" = 'X\t' && - test "X`($echo "$echo_test_string") 2>/dev/null`" = X"$echo_test_string"; then - # Cool, printf works - : - elif test "X`("$ORIGINAL_CONFIG_SHELL" "$0" --fallback-echo '\t') 2>/dev/null`" = 'X\t' && - test "X`("$ORIGINAL_CONFIG_SHELL" "$0" --fallback-echo "$echo_test_string") 2>/dev/null`" = X"$echo_test_string"; then - CONFIG_SHELL="$ORIGINAL_CONFIG_SHELL" - export CONFIG_SHELL - SHELL="$CONFIG_SHELL" - export SHELL - echo="$CONFIG_SHELL $0 --fallback-echo" - elif test "X`("$CONFIG_SHELL" "$0" --fallback-echo '\t') 2>/dev/null`" = 'X\t' && - test "X`("$CONFIG_SHELL" "$0" --fallback-echo "$echo_test_string") 2>/dev/null`" = X"$echo_test_string"; then - echo="$CONFIG_SHELL $0 --fallback-echo" - else - # maybe with a smaller string... - prev=: - - for cmd in 'echo test' 'sed 2q "$0"' 'sed 10q "$0"' 'sed 20q "$0"' 'sed 50q "$0"'; do - if (test "X$echo_test_string" = "X`eval $cmd`") 2>/dev/null; then - break - fi - prev="$cmd" - done - - if test "$prev" != 'sed 50q "$0"'; then - echo_test_string=`eval $prev` - export echo_test_string - exec "${ORIGINAL_CONFIG_SHELL}" "$0" ${1+"$@"} - else - # Oops. We lost completely, so just stick with echo. - echo=echo - fi - fi - fi - fi -fi - -# Sed substitution that helps us do robust quoting. It backslashifies -# metacharacters that are still active within double-quoted strings. -Xsed='sed -e s/^X//' -sed_quote_subst='s/\([\\"\\`$\\\\]\)/\\\1/g' - -# Same as above, but do not quote variable references. -double_quote_subst='s/\([\\"\\`\\\\]\)/\\\1/g' - -# Sed substitution to delay expansion of an escaped shell variable in a -# double_quote_subst'ed string. -delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' - -# The name of this program. -progname=`$echo "X$0" | $Xsed -e 's%^.*/%%'` - -# Constants: -PROGRAM=ltconfig -PACKAGE=libtool -VERSION=1.3.3 -TIMESTAMP=" (1.385.2.181 1999/07/02 15:49:11)" -ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.c 1>&5' -ac_link='${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.c $LIBS 1>&5' -rm="rm -f" - -help="Try \`$progname --help' for more information." - -# Global variables: -default_ofile=libtool -can_build_shared=yes -enable_shared=yes -# All known linkers require a `.a' archive for static linking (except M$VC, -# which needs '.lib'). -enable_static=yes -enable_fast_install=yes -enable_dlopen=unknown -enable_win32_dll=no -ltmain= -silent= -srcdir= -ac_config_guess= -ac_config_sub= -host= -nonopt= -ofile="$default_ofile" -verify_host=yes -with_gcc=no -with_gnu_ld=no -need_locks=yes -ac_ext=c -objext=o -libext=a -exeext= -cache_file= - -old_AR="$AR" -old_CC="$CC" -old_CFLAGS="$CFLAGS" -old_CPPFLAGS="$CPPFLAGS" -old_LDFLAGS="$LDFLAGS" -old_LD="$LD" -old_LN_S="$LN_S" -old_LIBS="$LIBS" -old_NM="$NM" -old_RANLIB="$RANLIB" -old_DLLTOOL="$DLLTOOL" -old_OBJDUMP="$OBJDUMP" -old_AS="$AS" - -# Parse the command line options. -args= -prev= -for option -do - case "$option" in - -*=*) optarg=`echo "$option" | sed 's/[-_a-zA-Z0-9]*=//'` ;; - *) optarg= ;; - esac - - # If the previous option needs an argument, assign it. - if test -n "$prev"; then - eval "$prev=\$option" - prev= - continue - fi - - case "$option" in - --help) cat <<EOM -Usage: $progname [OPTION]... [HOST [LTMAIN]] - -Generate a system-specific libtool script. - - --debug enable verbose shell tracing - --disable-shared do not build shared libraries - --disable-static do not build static libraries - --disable-fast-install do not optimize for fast installation - --enable-dlopen enable dlopen support - --enable-win32-dll enable building dlls on win32 hosts - --help display this help and exit - --no-verify do not verify that HOST is a valid host type --o, --output=FILE specify the output file [default=$default_ofile] - --quiet same as \`--silent' - --silent do not print informational messages - --srcdir=DIR find \`config.guess' in DIR - --version output version information and exit - --with-gcc assume that the GNU C compiler will be used - --with-gnu-ld assume that the C compiler uses the GNU linker - --disable-lock disable file locking - --cache-file=FILE configure cache file - -LTMAIN is the \`ltmain.sh' shell script fragment or \`ltmain.c' program -that provides basic libtool functionality. - -HOST is the canonical host system name [default=guessed]. -EOM - exit 0 - ;; - - --debug) - echo "$progname: enabling shell trace mode" - set -x - ;; - - --disable-shared) enable_shared=no ;; - - --disable-static) enable_static=no ;; - - --disable-fast-install) enable_fast_install=no ;; - - --enable-dlopen) enable_dlopen=yes ;; - - --enable-win32-dll) enable_win32_dll=yes ;; - - --quiet | --silent) silent=yes ;; - - --srcdir) prev=srcdir ;; - --srcdir=*) srcdir="$optarg" ;; - - --no-verify) verify_host=no ;; - - --output | -o) prev=ofile ;; - --output=*) ofile="$optarg" ;; - - --version) echo "$PROGRAM (GNU $PACKAGE) $VERSION$TIMESTAMP"; exit 0 ;; - - --with-gcc) with_gcc=yes ;; - --with-gnu-ld) with_gnu_ld=yes ;; - - --disable-lock) need_locks=no ;; - - --cache-file=*) cache_file="$optarg" ;; - - -*) - echo "$progname: unrecognized option \`$option'" 1>&2 - echo "$help" 1>&2 - exit 1 - ;; - - *) - if test -z "$ltmain"; then - ltmain="$option" - elif test -z "$host"; then -# This generates an unnecessary warning for sparc-sun-solaris4.1.3_U1 -# if test -n "`echo $option| sed 's/[-a-z0-9.]//g'`"; then -# echo "$progname: warning \`$option' is not a valid host type" 1>&2 -# fi - host="$option" - else - echo "$progname: too many arguments" 1>&2 - echo "$help" 1>&2 - exit 1 - fi ;; - esac -done - -if test -z "$ltmain"; then - echo "$progname: you must specify a LTMAIN file" 1>&2 - echo "$help" 1>&2 - exit 1 -fi - -if test ! -f "$ltmain"; then - echo "$progname: \`$ltmain' does not exist" 1>&2 - echo "$help" 1>&2 - exit 1 -fi - -# Quote any args containing shell metacharacters. -ltconfig_args= -for arg -do - case "$arg" in - *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*) - ltconfig_args="$ltconfig_args '$arg'" ;; - *) ltconfig_args="$ltconfig_args $arg" ;; - esac -done - -# A relevant subset of AC_INIT. - -# File descriptor usage: -# 0 standard input -# 1 file creation -# 2 errors and warnings -# 3 some systems may open it to /dev/tty -# 4 used on the Kubota Titan -# 5 compiler messages saved in config.log -# 6 checking for... messages and results -if test "$silent" = yes; then - exec 6>/dev/null -else - exec 6>&1 -fi -exec 5>>./config.log - -# NLS nuisances. -# Only set LANG and LC_ALL to C if already set. -# These must not be set unconditionally because not all systems understand -# e.g. LANG=C (notably SCO). -if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi -if test "${LANG+set}" = set; then LANG=C; export LANG; fi - -if test -n "$cache_file" && test -r "$cache_file"; then - echo "loading cache $cache_file within ltconfig" - . $cache_file -fi - -if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then - # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu. - if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then - ac_n= ac_c=' -' ac_t=' ' - else - ac_n=-n ac_c= ac_t= - fi -else - ac_n= ac_c='\c' ac_t= -fi - -if test -z "$srcdir"; then - # Assume the source directory is the same one as the path to LTMAIN. - srcdir=`$echo "X$ltmain" | $Xsed -e 's%/[^/]*$%%'` - test "$srcdir" = "$ltmain" && srcdir=. -fi - -trap "$rm conftest*; exit 1" 1 2 15 -if test "$verify_host" = yes; then - # Check for config.guess and config.sub. - ac_aux_dir= - for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do - if test -f $ac_dir/config.guess; then - ac_aux_dir=$ac_dir - break - fi - done - if test -z "$ac_aux_dir"; then - echo "$progname: cannot find config.guess in $srcdir $srcdir/.. $srcdir/../.." 1>&2 - echo "$help" 1>&2 - exit 1 - fi - ac_config_guess=$ac_aux_dir/config.guess - ac_config_sub=$ac_aux_dir/config.sub - - # Make sure we can run config.sub. - if $SHELL $ac_config_sub sun4 >/dev/null 2>&1; then : - else - echo "$progname: cannot run $ac_config_sub" 1>&2 - echo "$help" 1>&2 - exit 1 - fi - - echo $ac_n "checking host system type""... $ac_c" 1>&6 - - host_alias=$host - case "$host_alias" in - "") - if host_alias=`$SHELL $ac_config_guess`; then : - else - echo "$progname: cannot guess host type; you must specify one" 1>&2 - echo "$help" 1>&2 - exit 1 - fi ;; - esac - host=`$SHELL $ac_config_sub $host_alias` - echo "$ac_t$host" 1>&6 - - # Make sure the host verified. - test -z "$host" && exit 1 - -elif test -z "$host"; then - echo "$progname: you must specify a host type if you use \`--no-verify'" 1>&2 - echo "$help" 1>&2 - exit 1 -else - host_alias=$host -fi - -# Transform linux* to *-*-linux-gnu*, to support old configure scripts. -case "$host_os" in -linux-gnu*) ;; -linux*) host=`echo $host | sed 's/^\(.*-.*-linux\)\(.*\)$/\1-gnu\2/'` -esac - -host_cpu=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` -host_vendor=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` -host_os=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` - -case "$host_os" in -aix3*) - # AIX sometimes has problems with the GCC collect2 program. For some - # reason, if we set the COLLECT_NAMES environment variable, the problems - # vanish in a puff of smoke. - if test "${COLLECT_NAMES+set}" != set; then - COLLECT_NAMES= - export COLLECT_NAMES - fi - ;; -esac - -# Determine commands to create old-style static archives. -old_archive_cmds='$AR cru $oldlib$oldobjs' -old_postinstall_cmds='chmod 644 $oldlib' -old_postuninstall_cmds= - -# Set a sane default for `AR'. -test -z "$AR" && AR=ar - -# Set a sane default for `OBJDUMP'. -test -z "$OBJDUMP" && OBJDUMP=objdump - -# If RANLIB is not set, then run the test. -if test "${RANLIB+set}" != "set"; then - result=no - - echo $ac_n "checking for ranlib... $ac_c" 1>&6 - IFS="${IFS= }"; save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR}" - for dir in $PATH; do - test -z "$dir" && dir=. - if test -f $dir/ranlib || test -f $dir/ranlib$ac_exeext; then - RANLIB="ranlib" - result="ranlib" - break - fi - done - IFS="$save_ifs" - - echo "$ac_t$result" 1>&6 -fi - -if test -n "$RANLIB"; then - old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib" - old_postinstall_cmds="\$RANLIB \$oldlib~$old_postinstall_cmds" -fi - -# Set sane defaults for `DLLTOOL', `OBJDUMP', and `AS', used on cygwin. -test -z "$DLLTOOL" && DLLTOOL=dlltool -test -z "$OBJDUMP" && OBJDUMP=objdump -test -z "$AS" && AS=as - -# Check to see if we are using GCC. -if test "$with_gcc" != yes || test -z "$CC"; then - # If CC is not set, then try to find GCC or a usable CC. - if test -z "$CC"; then - echo $ac_n "checking for gcc... $ac_c" 1>&6 - IFS="${IFS= }"; save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR}" - for dir in $PATH; do - test -z "$dir" && dir=. - if test -f $dir/gcc || test -f $dir/gcc$ac_exeext; then - CC="gcc" - break - fi - done - IFS="$save_ifs" - - if test -n "$CC"; then - echo "$ac_t$CC" 1>&6 - else - echo "$ac_t"no 1>&6 - fi - fi - - # Not "gcc", so try "cc", rejecting "/usr/ucb/cc". - if test -z "$CC"; then - echo $ac_n "checking for cc... $ac_c" 1>&6 - IFS="${IFS= }"; save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR}" - cc_rejected=no - for dir in $PATH; do - test -z "$dir" && dir=. - if test -f $dir/cc || test -f $dir/cc$ac_exeext; then - if test "$dir/cc" = "/usr/ucb/cc"; then - cc_rejected=yes - continue - fi - CC="cc" - break - fi - done - IFS="$save_ifs" - if test $cc_rejected = yes; then - # We found a bogon in the path, so make sure we never use it. - set dummy $CC - shift - if test $# -gt 0; then - # We chose a different compiler from the bogus one. - # However, it has the same name, so the bogon will be chosen - # first if we set CC to just the name; use the full file name. - shift - set dummy "$dir/cc" "$@" - shift - CC="$@" - fi - fi - - if test -n "$CC"; then - echo "$ac_t$CC" 1>&6 - else - echo "$ac_t"no 1>&6 - fi - - if test -z "$CC"; then - echo "$progname: error: no acceptable cc found in \$PATH" 1>&2 - exit 1 - fi - fi - - # Now see if the compiler is really GCC. - with_gcc=no - echo $ac_n "checking whether we are using GNU C... $ac_c" 1>&6 - echo "$progname:581: checking whether we are using GNU C" >&5 - - $rm conftest.c - cat > conftest.c <<EOF -#ifdef __GNUC__ - yes; -#endif -EOF - if { ac_try='${CC-cc} -E conftest.c'; { (eval echo $progname:589: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then - with_gcc=yes - fi - $rm conftest.c - echo "$ac_t$with_gcc" 1>&6 -fi - -# Allow CC to be a program name with arguments. -set dummy $CC -compiler="$2" - -echo $ac_n "checking for object suffix... $ac_c" 1>&6 -$rm conftest* -echo 'int i = 1;' > conftest.c -echo "$progname:603: checking for object suffix" >& 5 -if { (eval echo $progname:604: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>conftest.err; }; then - # Append any warnings to the config.log. - cat conftest.err 1>&5 - - for ac_file in conftest.*; do - case $ac_file in - *.c) ;; - *) objext=`echo $ac_file | sed -e s/conftest.//` ;; - esac - done -else - cat conftest.err 1>&5 - echo "$progname: failed program was:" >&5 - cat conftest.c >&5 -fi -$rm conftest* -echo "$ac_t$objext" 1>&6 - -echo $ac_n "checking for executable suffix... $ac_c" 1>&6 -if eval "test \"`echo '$''{'ac_cv_exeext'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - ac_cv_exeext="no" - $rm conftest* - echo 'main () { return 0; }' > conftest.c - echo "$progname:629: checking for executable suffix" >& 5 - if { (eval echo $progname:630: \"$ac_link\") 1>&5; (eval $ac_link) 2>conftest.err; }; then - # Append any warnings to the config.log. - cat conftest.err 1>&5 - - for ac_file in conftest.*; do - case $ac_file in - *.c | *.err | *.$objext ) ;; - *) ac_cv_exeext=.`echo $ac_file | sed -e s/conftest.//` ;; - esac - done - else - cat conftest.err 1>&5 - echo "$progname: failed program was:" >&5 - cat conftest.c >&5 - fi - $rm conftest* -fi -if test "X$ac_cv_exeext" = Xno; then - exeext="" -else - exeext="$ac_cv_exeext" -fi -echo "$ac_t$ac_cv_exeext" 1>&6 - -echo $ac_n "checking for $compiler option to produce PIC... $ac_c" 1>&6 -pic_flag= -special_shlib_compile_flags= -wl= -link_static_flag= -no_builtin_flag= - -if test "$with_gcc" = yes; then - wl='-Wl,' - link_static_flag='-static' - - case "$host_os" in - beos* | irix5* | irix6* | osf3* | osf4*) - # PIC is the default for these OSes. - ;; - aix*) - # Below there is a dirty hack to force normal static linking with -ldl - # The problem is because libdl dynamically linked with both libc and - # libC (AIX C++ library), which obviously doesn't included in libraries - # list by gcc. This cause undefined symbols with -static flags. - # This hack allows C programs to be linked with "-static -ldl", but - # we not sure about C++ programs. - link_static_flag="$link_static_flag ${wl}-lC" - ;; - cygwin* | mingw* | os2*) - # We can build DLLs from non-PIC. - ;; - amigaos*) - # FIXME: we need at least 68020 code to build shared libraries, but - # adding the `-m68020' flag to GCC prevents building anything better, - # like `-m68040'. - pic_flag='-m68020 -resident32 -malways-restore-a4' - ;; - sysv4*MP*) - if test -d /usr/nec; then - pic_flag=-Kconform_pic - fi - ;; - *) - pic_flag='-fPIC' - ;; - esac -else - # PORTME Check for PIC flags for the system compiler. - case "$host_os" in - aix3* | aix4*) - # All AIX code is PIC. - link_static_flag='-bnso -bI:/lib/syscalls.exp' - ;; - - hpux9* | hpux10* | hpux11*) - # Is there a better link_static_flag that works with the bundled CC? - wl='-Wl,' - link_static_flag="${wl}-a ${wl}archive" - pic_flag='+Z' - ;; - - irix5* | irix6*) - wl='-Wl,' - link_static_flag='-non_shared' - # PIC (with -KPIC) is the default. - ;; - - cygwin* | mingw* | os2*) - # We can build DLLs from non-PIC. - ;; - - osf3* | osf4*) - # All OSF/1 code is PIC. - wl='-Wl,' - link_static_flag='-non_shared' - ;; - - sco3.2v5*) - pic_flag='-Kpic' - link_static_flag='-dn' - special_shlib_compile_flags='-belf' - ;; - - solaris*) - pic_flag='-KPIC' - link_static_flag='-Bstatic' - wl='-Wl,' - ;; - - sunos4*) - pic_flag='-PIC' - link_static_flag='-Bstatic' - wl='-Qoption ld ' - ;; - - sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) - pic_flag='-KPIC' - link_static_flag='-Bstatic' - wl='-Wl,' - ;; - - uts4*) - pic_flag='-pic' - link_static_flag='-Bstatic' - ;; - sysv4*MP*) - if test -d /usr/nec ;then - pic_flag='-Kconform_pic' - link_static_flag='-Bstatic' - fi - ;; - *) - can_build_shared=no - ;; - esac -fi - -if test -n "$pic_flag"; then - echo "$ac_t$pic_flag" 1>&6 - - # Check to make sure the pic_flag actually works. - echo $ac_n "checking if $compiler PIC flag $pic_flag works... $ac_c" 1>&6 - $rm conftest* - echo "int some_variable = 0;" > conftest.c - save_CFLAGS="$CFLAGS" - CFLAGS="$CFLAGS $pic_flag -DPIC" - echo "$progname:776: checking if $compiler PIC flag $pic_flag works" >&5 - if { (eval echo $progname:777: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>conftest.err; } && test -s conftest.$objext; then - # Append any warnings to the config.log. - cat conftest.err 1>&5 - - case "$host_os" in - hpux9* | hpux10* | hpux11*) - # On HP-UX, both CC and GCC only warn that PIC is supported... then they - # create non-PIC objects. So, if there were any warnings, we assume that - # PIC is not supported. - if test -s conftest.err; then - echo "$ac_t"no 1>&6 - can_build_shared=no - pic_flag= - else - echo "$ac_t"yes 1>&6 - pic_flag=" $pic_flag" - fi - ;; - *) - echo "$ac_t"yes 1>&6 - pic_flag=" $pic_flag" - ;; - esac - else - # Append any errors to the config.log. - cat conftest.err 1>&5 - can_build_shared=no - pic_flag= - echo "$ac_t"no 1>&6 - fi - CFLAGS="$save_CFLAGS" - $rm conftest* -else - echo "$ac_t"none 1>&6 -fi - -# Check to see if options -o and -c are simultaneously supported by compiler -echo $ac_n "checking if $compiler supports -c -o file.o... $ac_c" 1>&6 -$rm -r conftest 2>/dev/null -mkdir conftest -cd conftest -$rm conftest* -echo "int some_variable = 0;" > conftest.c -mkdir out -# According to Tom Tromey, Ian Lance Taylor reported there are C compilers -# that will create temporary files in the current directory regardless of -# the output directory. Thus, making CWD read-only will cause this test -# to fail, enabling locking or at least warning the user not to do parallel -# builds. -chmod -w . -save_CFLAGS="$CFLAGS" -CFLAGS="$CFLAGS -o out/conftest2.o" -echo "$progname:829: checking if $compiler supports -c -o file.o" >&5 -if { (eval echo $progname:830: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>out/conftest.err; } && test -s out/conftest2.o; then - - # The compiler can only warn and ignore the option if not recognized - # So say no if there are warnings - if test -s out/conftest.err; then - echo "$ac_t"no 1>&6 - compiler_c_o=no - else - echo "$ac_t"yes 1>&6 - compiler_c_o=yes - fi -else - # Append any errors to the config.log. - cat out/conftest.err 1>&5 - compiler_c_o=no - echo "$ac_t"no 1>&6 -fi -CFLAGS="$save_CFLAGS" -chmod u+w . -$rm conftest* out/* -rmdir out -cd .. -rmdir conftest -$rm -r conftest 2>/dev/null - -if test x"$compiler_c_o" = x"yes"; then - # Check to see if we can write to a .lo - echo $ac_n "checking if $compiler supports -c -o file.lo... $ac_c" 1>&6 - $rm conftest* - echo "int some_variable = 0;" > conftest.c - save_CFLAGS="$CFLAGS" - CFLAGS="$CFLAGS -c -o conftest.lo" - echo "$progname:862: checking if $compiler supports -c -o file.lo" >&5 -if { (eval echo $progname:863: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>conftest.err; } && test -s conftest.lo; then - - # The compiler can only warn and ignore the option if not recognized - # So say no if there are warnings - if test -s conftest.err; then - echo "$ac_t"no 1>&6 - compiler_o_lo=no - else - echo "$ac_t"yes 1>&6 - compiler_o_lo=yes - fi - else - # Append any errors to the config.log. - cat conftest.err 1>&5 - compiler_o_lo=no - echo "$ac_t"no 1>&6 - fi - CFLAGS="$save_CFLAGS" - $rm conftest* -else - compiler_o_lo=no -fi - -# Check to see if we can do hard links to lock some files if needed -hard_links="nottested" -if test "$compiler_c_o" = no && test "$need_locks" != no; then - # do not overwrite the value of need_locks provided by the user - echo $ac_n "checking if we can lock with hard links... $ac_c" 1>&6 - hard_links=yes - $rm conftest* - ln conftest.a conftest.b 2>/dev/null && hard_links=no - touch conftest.a - ln conftest.a conftest.b 2>&5 || hard_links=no - ln conftest.a conftest.b 2>/dev/null && hard_links=no - echo "$ac_t$hard_links" 1>&6 - $rm conftest* - if test "$hard_links" = no; then - echo "*** WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2 - need_locks=warn - fi -else - need_locks=no -fi - -if test "$with_gcc" = yes; then - # Check to see if options -fno-rtti -fno-exceptions are supported by compiler - echo $ac_n "checking if $compiler supports -fno-rtti -fno-exceptions ... $ac_c" 1>&6 - $rm conftest* - echo "int some_variable = 0;" > conftest.c - save_CFLAGS="$CFLAGS" - CFLAGS="$CFLAGS -fno-rtti -fno-exceptions -c conftest.c" - echo "$progname:914: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 - if { (eval echo $progname:915: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>conftest.err; } && test -s conftest.o; then - - # The compiler can only warn and ignore the option if not recognized - # So say no if there are warnings - if test -s conftest.err; then - echo "$ac_t"no 1>&6 - compiler_rtti_exceptions=no - else - echo "$ac_t"yes 1>&6 - compiler_rtti_exceptions=yes - fi - else - # Append any errors to the config.log. - cat conftest.err 1>&5 - compiler_rtti_exceptions=no - echo "$ac_t"no 1>&6 - fi - CFLAGS="$save_CFLAGS" - $rm conftest* - - if test "$compiler_rtti_exceptions" = "yes"; then - no_builtin_flag=' -fno-builtin -fno-rtti -fno-exceptions' - else - no_builtin_flag=' -fno-builtin' - fi - -fi - -# Check for any special shared library compilation flags. -if test -n "$special_shlib_compile_flags"; then - echo "$progname: warning: \`$CC' requires \`$special_shlib_compile_flags' to build shared libraries" 1>&2 - if echo "$old_CC $old_CFLAGS " | egrep -e "[ ]$special_shlib_compile_flags[ ]" >/dev/null; then : - else - echo "$progname: add \`$special_shlib_compile_flags' to the CC or CFLAGS env variable and reconfigure" 1>&2 - can_build_shared=no - fi -fi - -echo $ac_n "checking if $compiler static flag $link_static_flag works... $ac_c" 1>&6 -$rm conftest* -echo 'main(){return(0);}' > conftest.c -save_LDFLAGS="$LDFLAGS" -LDFLAGS="$LDFLAGS $link_static_flag" -echo "$progname:958: checking if $compiler static flag $link_static_flag works" >&5 -if { (eval echo $progname:959: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then - echo "$ac_t$link_static_flag" 1>&6 -else - echo "$ac_t"none 1>&6 - link_static_flag= -fi -LDFLAGS="$save_LDFLAGS" -$rm conftest* - -if test -z "$LN_S"; then - # Check to see if we can use ln -s, or we need hard links. - echo $ac_n "checking whether ln -s works... $ac_c" 1>&6 - $rm conftest.dat - if ln -s X conftest.dat 2>/dev/null; then - $rm conftest.dat - LN_S="ln -s" - else - LN_S=ln - fi - if test "$LN_S" = "ln -s"; then - echo "$ac_t"yes 1>&6 - else - echo "$ac_t"no 1>&6 - fi -fi - -# Make sure LD is an absolute path. -if test -z "$LD"; then - ac_prog=ld - if test "$with_gcc" = yes; then - # Check if gcc -print-prog-name=ld gives a path. - echo $ac_n "checking for ld used by GCC... $ac_c" 1>&6 - echo "$progname:991: checking for ld used by GCC" >&5 - ac_prog=`($CC -print-prog-name=ld) 2>&5` - case "$ac_prog" in - # Accept absolute paths. - [\\/]* | [A-Za-z]:[\\/]*) - re_direlt='/[^/][^/]*/\.\./' - # Canonicalize the path of ld - ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'` - while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do - ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"` - done - test -z "$LD" && LD="$ac_prog" - ;; - "") - # If it fails, then pretend we are not using GCC. - ac_prog=ld - ;; - *) - # If it is relative, then search for the first ld in PATH. - with_gnu_ld=unknown - ;; - esac - elif test "$with_gnu_ld" = yes; then - echo $ac_n "checking for GNU ld... $ac_c" 1>&6 - echo "$progname:1015: checking for GNU ld" >&5 - else - echo $ac_n "checking for non-GNU ld""... $ac_c" 1>&6 - echo "$progname:1018: checking for non-GNU ld" >&5 - fi - - if test -z "$LD"; then - IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR}" - for ac_dir in $PATH; do - test -z "$ac_dir" && ac_dir=. - if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then - LD="$ac_dir/$ac_prog" - # Check to see if the program is GNU ld. I'd rather use --version, - # but apparently some GNU ld's only accept -v. - # Break only if it was the GNU/non-GNU ld that we prefer. - if "$LD" -v 2>&1 < /dev/null | egrep '(GNU|with BFD)' > /dev/null; then - test "$with_gnu_ld" != no && break - else - test "$with_gnu_ld" != yes && break - fi - fi - done - IFS="$ac_save_ifs" - fi - - if test -n "$LD"; then - echo "$ac_t$LD" 1>&6 - else - echo "$ac_t"no 1>&6 - fi - - if test -z "$LD"; then - echo "$progname: error: no acceptable ld found in \$PATH" 1>&2 - exit 1 - fi -fi - -# Check to see if it really is or is not GNU ld. -echo $ac_n "checking if the linker ($LD) is GNU ld... $ac_c" 1>&6 -# I'd rather use --version here, but apparently some GNU ld's only accept -v. -if $LD -v 2>&1 </dev/null | egrep '(GNU|with BFD)' 1>&5; then - with_gnu_ld=yes -else - with_gnu_ld=no -fi -echo "$ac_t$with_gnu_ld" 1>&6 - -# See if the linker supports building shared libraries. -echo $ac_n "checking whether the linker ($LD) supports shared libraries... $ac_c" 1>&6 - -allow_undefined_flag= -no_undefined_flag= -need_lib_prefix=unknown -need_version=unknown -# when you set need_version to no, make sure it does not cause -set_version -# flags to be left without arguments -archive_cmds= -archive_expsym_cmds= -old_archive_from_new_cmds= -export_dynamic_flag_spec= -whole_archive_flag_spec= -thread_safe_flag_spec= -hardcode_libdir_flag_spec= -hardcode_libdir_separator= -hardcode_direct=no -hardcode_minus_L=no -hardcode_shlibpath_var=unsupported -runpath_var= -always_export_symbols=no -export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | sed '\''s/.* //'\'' | sort | uniq > $export_symbols' -# include_expsyms should be a list of space-separated symbols to be *always* -# included in the symbol list -include_expsyms= -# exclude_expsyms can be an egrep regular expression of symbols to exclude -# it will be wrapped by ` (' and `)$', so one must not match beginning or -# end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', -# as well as any symbol that contains `d'. -exclude_expsyms="_GLOBAL_OFFSET_TABLE_" -# Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out -# platforms (ab)use it in PIC code, but their linkers get confused if -# the symbol is explicitly referenced. Since portable code cannot -# rely on this symbol name, it's probably fine to never include it in -# preloaded symbol tables. - -case "$host_os" in -cygwin* | mingw*) - # FIXME: the MSVC++ port hasn't been tested in a loooong time - # When not using gcc, we currently assume that we are using - # Microsoft Visual C++. - if test "$with_gcc" != yes; then - with_gnu_ld=no - fi - ;; - -esac - -ld_shlibs=yes -if test "$with_gnu_ld" = yes; then - # If archive_cmds runs LD, not CC, wlarc should be empty - wlarc='${wl}' - - # See if GNU ld supports shared libraries. - case "$host_os" in - aix3* | aix4*) - # On AIX, the GNU linker is very broken - ld_shlibs=no - cat <<EOF 1>&2 - -*** Warning: the GNU linker, at least up to release 2.9.1, is reported -*** to be unable to reliably create shared libraries on AIX. -*** Therefore, libtool is disabling shared libraries support. If you -*** really care for shared libraries, you may want to modify your PATH -*** so that a non-GNU linker is found, and then restart. - -EOF - ;; - - amigaos*) - archive_cmds='$rm $objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $objdir/a2ixlibrary.data~$AR cru $lib $libobjs~$RANLIB $lib~(cd $objdir && a2ixlibrary -32)' - hardcode_libdir_flag_spec='-L$libdir' - hardcode_minus_L=yes - - # Samuel A. Falvo II <kc5tja@dolphin.openprojects.net> reports - # that the semantics of dynamic libraries on AmigaOS, at least up - # to version 4, is to share data among multiple programs linked - # with the same dynamic library. Since this doesn't match the - # behavior of shared libraries on other platforms, we can use - # them. - ld_shlibs=no - ;; - - beos*) - if $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then - allow_undefined_flag=unsupported - # Joseph Beckenbach <jrb3@best.com> says some releases of gcc - # support --undefined. This deserves some investigation. FIXME - archive_cmds='$CC -nostart $libobjs $deplibs $linkopts ${wl}-soname $wl$soname -o $lib' - else - ld_shlibs=no - fi - ;; - - cygwin* | mingw*) - # hardcode_libdir_flag_spec is actually meaningless, as there is - # no search path for DLLs. - hardcode_libdir_flag_spec='-L$libdir' - allow_undefined_flag=unsupported - always_export_symbols=yes - - # Extract the symbol export list from an `--export-all' def file, - # then regenerate the def file from the symbol export list, so that - # the compiled dll only exports the symbol export list. - export_symbols_cmds='test -f $objdir/$soname-ltdll.c || sed -e "/^# \/\* ltdll\.c starts here \*\//,/^# \/\* ltdll.c ends here \*\// { s/^# //; p; }" -e d < $0 > $objdir/$soname-ltdll.c~ - test -f $objdir/$soname-ltdll.$objext || (cd $objdir && $CC -c $soname-ltdll.c)~ - $DLLTOOL --export-all --exclude-symbols DllMain@12,_cygwin_dll_entry@12,_cygwin_noncygwin_dll_entry@12 --output-def $objdir/$soname-def $objdir/$soname-ltdll.$objext $libobjs $convenience~ - sed -e "1,/EXPORTS/d" -e "s/ @ [0-9]* ; *//" < $objdir/$soname-def > $export_symbols' - - archive_expsym_cmds='echo EXPORTS > $objdir/$soname-def~ - _lt_hint=1; - for symbol in `cat $export_symbols`; do - echo " \$symbol @ \$_lt_hint ; " >> $objdir/$soname-def; - _lt_hint=`expr 1 + \$_lt_hint`; - done~ - test -f $objdir/$soname-ltdll.c || sed -e "/^# \/\* ltdll\.c starts here \*\//,/^# \/\* ltdll.c ends here \*\// { s/^# //; p; }" -e d < $0 > $objdir/$soname-ltdll.c~ - test -f $objdir/$soname-ltdll.$objext || (cd $objdir && $CC -c $soname-ltdll.c)~ - $CC -Wl,--base-file,$objdir/$soname-base -Wl,--dll -nostartfiles -Wl,-e,__cygwin_dll_entry@12 -o $lib $objdir/$soname-ltdll.$objext $libobjs $deplibs $linkopts~ - $DLLTOOL --as=$AS --dllname $soname --exclude-symbols DllMain@12,_cygwin_dll_entry@12,_cygwin_noncygwin_dll_entry@12 --def $objdir/$soname-def --base-file $objdir/$soname-base --output-exp $objdir/$soname-exp~ - $CC -Wl,--base-file,$objdir/$soname-base $objdir/$soname-exp -Wl,--dll -nostartfiles -Wl,-e,__cygwin_dll_entry@12 -o $lib $objdir/$soname-ltdll.$objext $libobjs $deplibs $linkopts~ - $DLLTOOL --as=$AS --dllname $soname --exclude-symbols DllMain@12,_cygwin_dll_entry@12,_cygwin_noncygwin_dll_entry@12 --def $objdir/$soname-def --base-file $objdir/$soname-base --output-exp $objdir/$soname-exp~ - $CC $objdir/$soname-exp -Wl,--dll -nostartfiles -Wl,-e,__cygwin_dll_entry@12 -o $lib $objdir/$soname-ltdll.$objext $libobjs $deplibs $linkopts' - - old_archive_from_new_cmds='$DLLTOOL --as=$AS --dllname $soname --def $objdir/$soname-def --output-lib $objdir/$libname.a' - ;; - - netbsd*) - if $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then - archive_cmds='$CC -shared $libobjs $deplibs $linkopts ${wl}-soname $wl$soname -o $lib' - archive_expsym_cmds='$CC -shared $libobjs $deplibs $linkopts ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' - else - archive_cmds='$LD -Bshareable $libobjs $deplibs $linkopts -o $lib' - # can we support soname and/or expsyms with a.out? -oliva - fi - ;; - - solaris*) - if $LD -v 2>&1 | egrep 'BFD 2\.8' > /dev/null; then - ld_shlibs=no - cat <<EOF 1>&2 - -*** Warning: The releases 2.8.* of the GNU linker cannot reliably -*** create shared libraries on Solaris systems. Therefore, libtool -*** is disabling shared libraries support. We urge you to upgrade GNU -*** binutils to release 2.9.1 or newer. Another option is to modify -*** your PATH or compiler configuration so that the native linker is -*** used, and then restart. - -EOF - elif $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then - archive_cmds='$CC -shared $libobjs $deplibs $linkopts ${wl}-soname $wl$soname -o $lib' - archive_expsym_cmds='$CC -shared $libobjs $deplibs $linkopts ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' - else - ld_shlibs=no - fi - ;; - - sunos4*) - archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linkopts' - wlarc= - hardcode_direct=yes - hardcode_shlibpath_var=no - ;; - - *) - if $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then - archive_cmds='$CC -shared $libobjs $deplibs $linkopts ${wl}-soname $wl$soname -o $lib' - archive_expsym_cmds='$CC -shared $libobjs $deplibs $linkopts ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' - else - ld_shlibs=no - fi - ;; - esac - - if test "$ld_shlibs" = yes; then - runpath_var=LD_RUN_PATH - hardcode_libdir_flag_spec='${wl}--rpath ${wl}$libdir' - export_dynamic_flag_spec='${wl}--export-dynamic' - case $host_os in - cygwin* | mingw*) - # dlltool doesn't understand --whole-archive et. al. - whole_archive_flag_spec= - ;; - *) - whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' - ;; - esac - fi -else - # PORTME fill in a description of your system's linker (not GNU ld) - case "$host_os" in - aix3*) - allow_undefined_flag=unsupported - always_export_symbols=yes - archive_expsym_cmds='$LD -o $objdir/$soname $libobjs $deplibs $linkopts -bE:$export_symbols -T512 -H512 -bM:SRE~$AR cru $lib $objdir/$soname' - # Note: this linker hardcodes the directories in LIBPATH if there - # are no directories specified by -L. - hardcode_minus_L=yes - if test "$with_gcc" = yes && test -z "$link_static_flag"; then - # Neither direct hardcoding nor static linking is supported with a - # broken collect2. - hardcode_direct=unsupported - fi - ;; - - aix4*) - hardcode_libdir_flag_spec='${wl}-b ${wl}nolibpath ${wl}-b ${wl}libpath:$libdir:/usr/lib:/lib' - hardcode_libdir_separator=':' - if test "$with_gcc" = yes; then - collect2name=`${CC} -print-prog-name=collect2` - if test -f "$collect2name" && \ - strings "$collect2name" | grep resolve_lib_name >/dev/null - then - # We have reworked collect2 - hardcode_direct=yes - else - # We have old collect2 - hardcode_direct=unsupported - # It fails to find uninstalled libraries when the uninstalled - # path is not listed in the libpath. Setting hardcode_minus_L - # to unsupported forces relinking - hardcode_minus_L=yes - hardcode_libdir_flag_spec='-L$libdir' - hardcode_libdir_separator= - fi - shared_flag='-shared' - else - shared_flag='${wl}-bM:SRE' - hardcode_direct=yes - fi - allow_undefined_flag=' ${wl}-berok' - archive_cmds="\$CC $shared_flag"' -o $objdir/$soname $libobjs $deplibs $linkopts ${wl}-bexpall ${wl}-bnoentry${allow_undefined_flag}' - archive_expsym_cmds="\$CC $shared_flag"' -o $objdir/$soname $libobjs $deplibs $linkopts ${wl}-bE:$export_symbols ${wl}-bnoentry${allow_undefined_flag}' - case "$host_os" in aix4.[01]|aix4.[01].*) - # According to Greg Wooledge, -bexpall is only supported from AIX 4.2 on - always_export_symbols=yes ;; - esac - ;; - - amigaos*) - archive_cmds='$rm $objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $objdir/a2ixlibrary.data~$AR cru $lib $libobjs~$RANLIB $lib~(cd $objdir && a2ixlibrary -32)' - hardcode_libdir_flag_spec='-L$libdir' - hardcode_minus_L=yes - # see comment about different semantics on the GNU ld section - ld_shlibs=no - ;; - - cygwin* | mingw*) - # When not using gcc, we currently assume that we are using - # Microsoft Visual C++. - # hardcode_libdir_flag_spec is actually meaningless, as there is - # no search path for DLLs. - hardcode_libdir_flag_spec=' ' - allow_undefined_flag=unsupported - # Tell ltmain to make .lib files, not .a files. - libext=lib - # FIXME: Setting linknames here is a bad hack. - archive_cmds='$CC -o $lib $libobjs $linkopts `echo "$deplibs" | sed -e '\''s/ -lc$//'\''` -link -dll~linknames=' - # The linker will automatically build a .lib file if we build a DLL. - old_archive_from_new_cmds='true' - # FIXME: Should let the user specify the lib program. - old_archive_cmds='lib /OUT:$oldlib$oldobjs' - fix_srcfile_path='`cygpath -w $srcfile`' - ;; - - freebsd1*) - ld_shlibs=no - ;; - - # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor - # support. Future versions do this automatically, but an explicit c++rt0.o - # does not break anything, and helps significantly (at the cost of a little - # extra space). - freebsd2.2*) - archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linkopts /usr/lib/c++rt0.o' - hardcode_libdir_flag_spec='-R$libdir' - hardcode_direct=yes - hardcode_shlibpath_var=no - ;; - - # Unfortunately, older versions of FreeBSD 2 do not have this feature. - freebsd2*) - archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linkopts' - hardcode_direct=yes - hardcode_minus_L=yes - hardcode_shlibpath_var=no - ;; - - # FreeBSD 3 and greater uses gcc -shared to do shared libraries. - freebsd*) - archive_cmds='$CC -shared -o $lib $libobjs $deplibs $linkopts' - hardcode_libdir_flag_spec='-R$libdir' - hardcode_direct=yes - hardcode_shlibpath_var=no - ;; - - hpux9* | hpux10* | hpux11*) - case "$host_os" in - hpux9*) archive_cmds='$rm $objdir/$soname~$LD -b +b $install_libdir -o $objdir/$soname $libobjs $deplibs $linkopts~test $objdir/$soname = $lib || mv $objdir/$soname $lib' ;; - *) archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linkopts' ;; - esac - hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' - hardcode_libdir_separator=: - hardcode_direct=yes - hardcode_minus_L=yes # Not in the search PATH, but as the default - # location of the library. - export_dynamic_flag_spec='${wl}-E' - ;; - - irix5* | irix6*) - if test "$with_gcc" = yes; then - archive_cmds='$CC -shared $libobjs $deplibs $linkopts ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib' - else - archive_cmds='$LD -shared $libobjs $deplibs $linkopts -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib' - fi - hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' - hardcode_libdir_separator=: - ;; - - netbsd*) - if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then - archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linkopts' # a.out - else - archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linkopts' # ELF - fi - hardcode_libdir_flag_spec='${wl}-R$libdir' - hardcode_direct=yes - hardcode_shlibpath_var=no - ;; - - openbsd*) - archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linkopts' - hardcode_libdir_flag_spec='-R$libdir' - hardcode_direct=yes - hardcode_shlibpath_var=no - ;; - - os2*) - hardcode_libdir_flag_spec='-L$libdir' - hardcode_minus_L=yes - allow_undefined_flag=unsupported - archive_cmds='$echo "LIBRARY $libname INITINSTANCE" > $objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $objdir/$libname.def~$echo DATA >> $objdir/$libname.def~$echo " SINGLE NONSHARED" >> $objdir/$libname.def~$echo EXPORTS >> $objdir/$libname.def~emxexp $libobjs >> $objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $linkopts $objdir/$libname.def' - old_archive_from_new_cmds='emximp -o $objdir/$libname.a $objdir/$libname.def' - ;; - - osf3* | osf4*) - if test "$with_gcc" = yes; then - allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' - archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $linkopts ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib' - else - allow_undefined_flag=' -expect_unresolved \*' - archive_cmds='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linkopts -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib' - fi - hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' - hardcode_libdir_separator=: - ;; - - sco3.2v5*) - archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linkopts' - hardcode_shlibpath_var=no - runpath_var=LD_RUN_PATH - hardcode_runpath_var=yes - ;; - - solaris*) - no_undefined_flag=' -z text' - # $CC -shared without GNU ld will not create a library from C++ - # object files and a static libstdc++, better avoid it by now - archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linkopts' - archive_expsym_cmds='$echo "{ global:" > $lib.exp~cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ - $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linkopts~$rm $lib.exp' - hardcode_libdir_flag_spec='-R$libdir' - hardcode_shlibpath_var=no - case "$host_os" in - solaris2.[0-5] | solaris2.[0-5].*) ;; - *) # Supported since Solaris 2.6 (maybe 2.5.1?) - whole_archive_flag_spec='-z allextract$convenience -z defaultextract' ;; - esac - ;; - - sunos4*) - archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linkopts' - hardcode_libdir_flag_spec='-L$libdir' - hardcode_direct=yes - hardcode_minus_L=yes - hardcode_shlibpath_var=no - ;; - - sysv4) - archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linkopts' - runpath_var='LD_RUN_PATH' - hardcode_shlibpath_var=no - hardcode_direct=no #Motorola manual says yes, but my tests say they lie - ;; - - sysv4.3*) - archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linkopts' - hardcode_shlibpath_var=no - export_dynamic_flag_spec='-Bexport' - ;; - - uts4*) - archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linkopts' - hardcode_libdir_flag_spec='-L$libdir' - hardcode_shlibpath_var=no - ;; - - dgux*) - archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linkopts' - hardcode_libdir_flag_spec='-L$libdir' - hardcode_shlibpath_var=no - ;; - - sysv4*MP*) - if test -d /usr/nec ;then - # archive_cmds='$LD -G -z text -h $soname -o $lib$libobjs$deplibs' - archive_cmds='$LD -G -h $soname -o $lib$libobjs$deplibs' - hardcode_shlibpath_var=no - runpath_var=LD_RUN_PATH - hardcode_runpath_var=yes - ld_shlibs=yes - fi - ;; - - *) - ld_shlibs=no - ;; - esac -fi -echo "$ac_t$ld_shlibs" 1>&6 -test "$ld_shlibs" = no && can_build_shared=no - -if test -z "$NM"; then - echo $ac_n "checking for BSD-compatible nm... $ac_c" 1>&6 - case "$NM" in - [\\/]* | [A-Za-z]:[\\/]*) ;; # Let the user override the test with a path. - *) - IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR}" - for ac_dir in $PATH /usr/ucb /usr/ccs/bin /bin; do - test -z "$ac_dir" && ac_dir=. - if test -f $ac_dir/nm || test -f $ac_dir/nm$ac_exeext; then - # Check to see if the nm accepts a BSD-compat flag. - # Adding the `sed 1q' prevents false positives on HP-UX, which says: - # nm: unknown option "B" ignored - if ($ac_dir/nm -B /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then - NM="$ac_dir/nm -B" - break - elif ($ac_dir/nm -p /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then - NM="$ac_dir/nm -p" - break - else - NM=${NM="$ac_dir/nm"} # keep the first match, but - continue # so that we can try to find one that supports BSD flags - fi - fi - done - IFS="$ac_save_ifs" - test -z "$NM" && NM=nm - ;; - esac - echo "$ac_t$NM" 1>&6 -fi - -# Check for command to grab the raw symbol name followed by C symbol from nm. -echo $ac_n "checking command to parse $NM output... $ac_c" 1>&6 - -# These are sane defaults that work on at least a few old systems. -# [They come from Ultrix. What could be older than Ultrix?!! ;)] - -# Character class describing NM global symbol codes. -symcode='[BCDEGRST]' - -# Regexp to match symbols that can be accessed directly from C. -sympat='\([_A-Za-z][_A-Za-z0-9]*\)' - -# Transform the above into a raw symbol and a C symbol. -symxfrm='\1 \2\3 \3' - -# Transform an extracted symbol line into a proper C declaration -global_symbol_to_cdecl="sed -n -e 's/^. .* \(.*\)$/extern char \1;/p'" - -# Define system-specific variables. -case "$host_os" in -aix*) - symcode='[BCDT]' - ;; -cygwin* | mingw*) - symcode='[ABCDGISTW]' - ;; -hpux*) # Its linker distinguishes data from code symbols - global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern char \1();/p' -e 's/^. .* \(.*\)$/extern char \1;/p'" - ;; -irix*) - symcode='[BCDEGRST]' - ;; -solaris*) - symcode='[BDT]' - ;; -sysv4) - symcode='[DFNSTU]' - ;; -esac - -# If we're using GNU nm, then use its standard symbol codes. -if $NM -V 2>&1 | egrep '(GNU|with BFD)' > /dev/null; then - symcode='[ABCDGISTW]' -fi - -# Try without a prefix undercore, then with it. -for ac_symprfx in "" "_"; do - - # Write the raw and C identifiers. - global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode\)[ ][ ]*\($ac_symprfx\)$sympat$/$symxfrm/p'" - - # Check to see that the pipe works correctly. - pipe_works=no - $rm conftest* - cat > conftest.c <<EOF -#ifdef __cplusplus -extern "C" { -#endif -char nm_test_var; -void nm_test_func(){} -#ifdef __cplusplus -} -#endif -main(){nm_test_var='a';nm_test_func();return(0);} -EOF - - echo "$progname:1592: checking if global_symbol_pipe works" >&5 - if { (eval echo $progname:1593: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; } && test -s conftest.$objext; then - # Now try to grab the symbols. - nlist=conftest.nm - if { echo "$progname:1596: eval \"$NM conftest.$objext | $global_symbol_pipe > $nlist\"" >&5; eval "$NM conftest.$objext | $global_symbol_pipe > $nlist 2>&5"; } && test -s "$nlist"; then - - # Try sorting and uniquifying the output. - if sort "$nlist" | uniq > "$nlist"T; then - mv -f "$nlist"T "$nlist" - else - rm -f "$nlist"T - fi - - # Make sure that we snagged all the symbols we need. - if egrep ' nm_test_var$' "$nlist" >/dev/null; then - if egrep ' nm_test_func$' "$nlist" >/dev/null; then - cat <<EOF > conftest.c -#ifdef __cplusplus -extern "C" { -#endif - -EOF - # Now generate the symbol file. - eval "$global_symbol_to_cdecl"' < "$nlist" >> conftest.c' - - cat <<EOF >> conftest.c -#if defined (__STDC__) && __STDC__ -# define lt_ptr_t void * -#else -# define lt_ptr_t char * -# define const -#endif - -/* The mapping between symbol names and symbols. */ -const struct { - const char *name; - lt_ptr_t address; -} -lt_preloaded_symbols[] = -{ -EOF - sed 's/^. \(.*\) \(.*\)$/ {"\2", (lt_ptr_t) \&\2},/' < "$nlist" >> conftest.c - cat <<\EOF >> conftest.c - {0, (lt_ptr_t) 0} -}; - -#ifdef __cplusplus -} -#endif -EOF - # Now try linking the two files. - mv conftest.$objext conftstm.$objext - save_LIBS="$LIBS" - save_CFLAGS="$CFLAGS" - LIBS="conftstm.$objext" - CFLAGS="$CFLAGS$no_builtin_flag" - if { (eval echo $progname:1648: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then - pipe_works=yes - else - echo "$progname: failed program was:" >&5 - cat conftest.c >&5 - fi - LIBS="$save_LIBS" - else - echo "cannot find nm_test_func in $nlist" >&5 - fi - else - echo "cannot find nm_test_var in $nlist" >&5 - fi - else - echo "cannot run $global_symbol_pipe" >&5 - fi - else - echo "$progname: failed program was:" >&5 - cat conftest.c >&5 - fi - $rm conftest* conftst* - - # Do not use the global_symbol_pipe unless it works. - if test "$pipe_works" = yes; then - break - else - global_symbol_pipe= - fi -done -if test "$pipe_works" = yes; then - echo "${ac_t}ok" 1>&6 -else - echo "${ac_t}failed" 1>&6 -fi - -if test -z "$global_symbol_pipe"; then - global_symbol_to_cdecl= -fi - -# Check hardcoding attributes. -echo $ac_n "checking how to hardcode library paths into programs... $ac_c" 1>&6 -hardcode_action= -if test -n "$hardcode_libdir_flag_spec" || \ - test -n "$runpath_var"; then - - # We can hardcode non-existant directories. - if test "$hardcode_direct" != no && - # If the only mechanism to avoid hardcoding is shlibpath_var, we - # have to relink, otherwise we might link with an installed library - # when we should be linking with a yet-to-be-installed one - ## test "$hardcode_shlibpath_var" != no && - test "$hardcode_minus_L" != no; then - # Linking always hardcodes the temporary library directory. - hardcode_action=relink - else - # We can link without hardcoding, and we can hardcode nonexisting dirs. - hardcode_action=immediate - fi -else - # We cannot hardcode anything, or else we can only hardcode existing - # directories. - hardcode_action=unsupported -fi -echo "$ac_t$hardcode_action" 1>&6 - - -reload_flag= -reload_cmds='$LD$reload_flag -o $output$reload_objs' -echo $ac_n "checking for $LD option to reload object files... $ac_c" 1>&6 -# PORTME Some linkers may need a different reload flag. -reload_flag='-r' -echo "$ac_t$reload_flag" 1>&6 -test -n "$reload_flag" && reload_flag=" $reload_flag" - -# PORTME Fill in your ld.so characteristics -library_names_spec= -libname_spec='lib$name' -soname_spec= -postinstall_cmds= -postuninstall_cmds= -finish_cmds= -finish_eval= -shlibpath_var= -shlibpath_overrides_runpath=unknown -version_type=none -dynamic_linker="$host_os ld.so" -sys_lib_dlsearch_path_spec="/lib /usr/lib" -sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" -file_magic_cmd= -file_magic_test_file= -deplibs_check_method='unknown' -# Need to set the preceding variable on all platforms that support -# interlibrary dependencies. -# 'none' -- dependencies not supported. -# `unknown' -- same as none, but documents that we really don't know. -# 'pass_all' -- all dependencies passed with no checks. -# 'test_compile' -- check by making test program. -# 'file_magic [regex]' -- check by looking for files in library path -# which responds to the $file_magic_cmd with a given egrep regex. -# If you have `file' or equivalent on your system and you're not sure -# whether `pass_all' will *always* work, you probably want this one. -echo $ac_n "checking dynamic linker characteristics... $ac_c" 1>&6 -case "$host_os" in -aix3*) - version_type=linux - library_names_spec='${libname}${release}.so$versuffix $libname.a' - shlibpath_var=LIBPATH - - # AIX has no versioning support, so we append a major version to the name. - soname_spec='${libname}${release}.so$major' - ;; - -aix4*) - version_type=linux - # AIX has no versioning support, so currently we can not hardcode correct - # soname into executable. Probably we can add versioning support to - # collect2, so additional links can be useful in future. - # We preserve .a as extension for shared libraries though AIX4.2 - # and later linker supports .so - library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.a' - shlibpath_var=LIBPATH - deplibs_check_method=pass_all - ;; - -amigaos*) - library_names_spec='$libname.ixlibrary $libname.a' - # Create ${libname}_ixlibrary.a entries in /sys/libs. - finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "(cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a)"; (cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a) || exit 1; done' - ;; - -beos*) - library_names_spec='${libname}.so' - dynamic_linker="$host_os ld.so" - shlibpath_var=LIBRARY_PATH - deplibs_check_method=pass_all - lt_cv_dlopen="load_add_on" - lt_cv_dlopen_libs= - lt_cv_dlopen_self=yes - ;; - -bsdi4*) - version_type=linux - library_names_spec='${libname}.so$major ${libname}.so' - soname_spec='${libname}.so' - finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' - shlibpath_var=LD_LIBRARY_PATH - deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)' - file_magic_cmd=/usr/bin/file - file_magic_test_file=/shlib/libc.so - sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" - sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" - # the default ld.so.conf also contains /usr/contrib/lib and - # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow - # libtool to hard-code these into programs - ;; - -cygwin* | mingw*) - version_type=windows - need_version=no - need_lib_prefix=no - if test "$with_gcc" = yes; then - library_names_spec='${libname}`echo ${release} | sed -e 's/[.]/-/g'`${versuffix}.dll $libname.a' - else - library_names_spec='${libname}`echo ${release} | sed -e 's/[.]/-/g'`${versuffix}.dll $libname.lib' - fi - dynamic_linker='Win32 ld.exe' - deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?' - file_magic_cmd='${OBJDUMP} -f' - # FIXME: first we should search . and the directory the executable is in - shlibpath_var=PATH - lt_cv_dlopen="LoadLibrary" - lt_cv_dlopen_libs= - ;; - -freebsd1*) - dynamic_linker=no - ;; - -freebsd*) - objformat=`test -x /usr/bin/objformat && /usr/bin/objformat || echo aout` - version_type=freebsd-$objformat - case "$version_type" in - freebsd-elf*) - deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB shared object' - file_magic_cmd=/usr/bin/file - file_magic_test_file=`echo /usr/lib/libc.so*` - library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so $libname.so' - need_version=no - need_lib_prefix=no - ;; - freebsd-*) - deplibs_check_method=unknown - library_names_spec='${libname}${release}.so$versuffix $libname.so$versuffix' - need_version=yes - ;; - esac - finish_cmds='PATH="\$PATH:/sbin" OBJFORMAT="'"$objformat"'" ldconfig -m $libdir' - shlibpath_var=LD_LIBRARY_PATH - case "$host_os" in - freebsd2* | freebsd3.[01]*) - shlibpath_overrides_runpath=yes - ;; - *) # from 3.2 on - shlibpath_overrides_runpath=no - ;; - esac - ;; - -gnu*) - version_type=linux - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so${major} ${libname}.so' - soname_spec='${libname}${release}.so$major' - shlibpath_var=LD_LIBRARY_PATH - ;; - -hpux9* | hpux10* | hpux11*) - # Give a soname corresponding to the major version so that dld.sl refuses to - # link against other versions. - dynamic_linker="$host_os dld.sl" - version_type=sunos - need_lib_prefix=no - need_version=no - shlibpath_var=SHLIB_PATH - shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH - library_names_spec='${libname}${release}.sl$versuffix ${libname}${release}.sl$major $libname.sl' - soname_spec='${libname}${release}.sl$major' - # HP-UX runs *really* slowly unless shared libraries are mode 555. - postinstall_cmds='chmod 555 $lib' - ;; - -irix5* | irix6*) - version_type=irix - need_lib_prefix=no - need_version=no - soname_spec='${libname}${release}.so.$major' - library_names_spec='${libname}${release}.so.$versuffix ${libname}${release}.so.$major ${libname}${release}.so $libname.so' - case "$host_os" in - irix5*) - libsuff= shlibsuff= - # this will be overridden with pass_all, but let us keep it just in case - deplibs_check_method="file_magic ELF 32-bit MSB dynamic lib MIPS - version 1" - ;; - *) - case "$LD" in # libtool.m4 will add one of these switches to LD - *-32|*"-32 ") libsuff= shlibsuff= libmagic=32-bit;; - *-n32|*"-n32 ") libsuff=32 shlibsuff=N32 libmagic=N32;; - *-64|*"-64 ") libsuff=64 shlibsuff=64 libmagic=64-bit;; - *) libsuff= shlibsuff= libmagic=never-match;; - esac - # this will be overridden with pass_all, but let us keep it just in case - deplibs_check_method="file_magic ELF ${libmagic} MSB mips-[1234] dynamic lib MIPS - version 1" - ;; - esac - shlibpath_var=LD_LIBRARY${shlibsuff}_PATH - shlibpath_overrides_runpath=no - sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" - sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" - file_magic_cmd=/usr/bin/file - file_magic_test_file=`echo /lib${libsuff}/libc.so*` - deplibs_check_method='pass_all' - ;; - -# No shared lib support for Linux oldld, aout, or coff. -linux-gnuoldld* | linux-gnuaout* | linux-gnucoff*) - dynamic_linker=no - ;; - -# This must be Linux ELF. -linux-gnu*) - version_type=linux - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' - soname_spec='${libname}${release}.so$major' - finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )' - file_magic_cmd=/usr/bin/file - file_magic_test_file=`echo /lib/libc.so* /lib/libc-*.so` - - if test -f /lib/ld.so.1; then - dynamic_linker='GNU ld.so' - else - # Only the GNU ld.so supports shared libraries on MkLinux. - case "$host_cpu" in - powerpc*) dynamic_linker=no ;; - *) dynamic_linker='Linux ld.so' ;; - esac - fi - ;; - -netbsd*) - version_type=sunos - if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then - library_names_spec='${libname}${release}.so$versuffix ${libname}.so$versuffix' - finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' - dynamic_linker='NetBSD (a.out) ld.so' - else - library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major ${libname}${release}.so ${libname}.so' - soname_spec='${libname}${release}.so$major' - dynamic_linker='NetBSD ld.elf_so' - fi - shlibpath_var=LD_LIBRARY_PATH - ;; - -openbsd*) - version_type=sunos - if test "$with_gnu_ld" = yes; then - need_lib_prefix=no - need_version=no - fi - library_names_spec='${libname}${release}.so$versuffix ${libname}.so$versuffix' - finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' - shlibpath_var=LD_LIBRARY_PATH - ;; - -os2*) - libname_spec='$name' - need_lib_prefix=no - library_names_spec='$libname.dll $libname.a' - dynamic_linker='OS/2 ld.exe' - shlibpath_var=LIBPATH - ;; - -osf3* | osf4*) - version_type=osf - need_version=no - soname_spec='${libname}${release}.so' - library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so $libname.so' - shlibpath_var=LD_LIBRARY_PATH - # this will be overridden with pass_all, but let us keep it just in case - deplibs_check_method='file_magic COFF format alpha shared library' - file_magic_cmd=/usr/bin/file - file_magic_test_file=/shlib/libc.so - deplibs_check_method='pass_all' - sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" - sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" - ;; - -sco3.2v5*) - version_type=osf - soname_spec='${libname}${release}.so$major' - library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' - shlibpath_var=LD_LIBRARY_PATH - ;; - -solaris*) - version_type=linux - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' - soname_spec='${libname}${release}.so$major' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - # ldd complains unless libraries are executable - postinstall_cmds='chmod +x $lib' - deplibs_check_method="file_magic ELF [0-9][0-9]-bit [LM]SB dynamic lib" - file_magic_cmd=/usr/bin/file - file_magic_test_file=/lib/libc.so - ;; - -sunos4*) - version_type=sunos - library_names_spec='${libname}${release}.so$versuffix ${libname}.so$versuffix' - finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - if test "$with_gnu_ld" = yes; then - need_lib_prefix=no - fi - need_version=yes - ;; - -sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) - version_type=linux - library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' - soname_spec='${libname}${release}.so$major' - shlibpath_var=LD_LIBRARY_PATH - case "$host_vendor" in - ncr) - deplibs_check_method='pass_all' - ;; - motorola) - need_lib_prefix=no - need_version=no - shlibpath_overrides_runpath=no - sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' - deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]' - file_magic_cmd=/usr/bin/file - file_magic_test_file=`echo /usr/lib/libc.so*` - ;; - esac - ;; - -uts4*) - version_type=linux - library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' - soname_spec='${libname}${release}.so$major' - shlibpath_var=LD_LIBRARY_PATH - ;; - -dgux*) - version_type=linux - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' - soname_spec='${libname}${release}.so$major' - shlibpath_var=LD_LIBRARY_PATH - ;; - -sysv4*MP*) - if test -d /usr/nec ;then - version_type=linux - library_names_spec='$libname.so.$versuffix $libname.so.$major $libname.so' - soname_spec='$libname.so.$major' - shlibpath_var=LD_LIBRARY_PATH - fi - ;; - -*) - dynamic_linker=no - ;; -esac -echo "$ac_t$dynamic_linker" 1>&6 -test "$dynamic_linker" = no && can_build_shared=no - -# Report the final consequences. -echo "checking if libtool supports shared libraries... $can_build_shared" 1>&6 - -# Only try to build win32 dlls if AC_LIBTOOL_WIN32_DLL was used in -# configure.in, otherwise build static only libraries. -case "$host_os" in -cygwin* | mingw* | os2*) - if test x$can_build_shared = xyes; then - test x$enable_win32_dll = xno && can_build_shared=no - echo "checking if package supports dlls... $can_build_shared" 1>&6 - fi -;; -esac - -if test -n "$file_magic_test_file" && test -n "$file_magic_cmd"; then - case "$deplibs_check_method" in - "file_magic "*) - file_magic_regex="`expr \"$deplibs_check_method\" : \"file_magic \(.*\)\"`" - if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | - egrep "$file_magic_regex" > /dev/null; then - : - else - cat <<EOF 1>&2 - -*** Warning: the command libtool uses to detect shared libraries, -*** $file_magic_cmd, produces output that libtool cannot recognize. -*** The result is that libtool may fail to recognize shared libraries -*** as such. This will affect the creation of libtool libraries that -*** depend on shared libraries, but programs linked with such libtool -*** libraries will work regardless of this problem. Nevertheless, you -*** may want to report the problem to your system manager and/or to -*** bug-libtool@gnu.org - -EOF - fi ;; - esac -fi - -echo $ac_n "checking whether to build shared libraries... $ac_c" 1>&6 -test "$can_build_shared" = "no" && enable_shared=no - -# On AIX, shared libraries and static libraries use the same namespace, and -# are all built from PIC. -case "$host_os" in -aix3*) - test "$enable_shared" = yes && enable_static=no - if test -n "$RANLIB"; then - archive_cmds="$archive_cmds~\$RANLIB \$lib" - postinstall_cmds='$RANLIB $lib' - fi - ;; - -aix4*) - test "$enable_shared" = yes && enable_static=no - ;; -esac - -echo "$ac_t$enable_shared" 1>&6 - -# Make sure either enable_shared or enable_static is yes. -test "$enable_shared" = yes || enable_static=yes - -echo "checking whether to build static libraries... $enable_static" 1>&6 - -if test "$hardcode_action" = relink; then - # Fast installation is not supported - enable_fast_install=no -elif test "$shlibpath_overrides_runpath" = yes || - test "$enable_shared" = no; then - # Fast installation is not necessary - enable_fast_install=needless -fi - -echo $ac_n "checking for objdir... $ac_c" 1>&6 -rm -f .libs 2>/dev/null -mkdir .libs 2>/dev/null -if test -d .libs; then - objdir=.libs -else - # MS-DOS does not allow filenames that begin with a dot. - objdir=_libs -fi -rmdir .libs 2>/dev/null -echo "$ac_t$objdir" 1>&6 - -if test "x$enable_dlopen" != xyes; then - enable_dlopen=unknown - enable_dlopen_self=unknown - enable_dlopen_self_static=unknown -else -if eval "test \"`echo '$''{'lt_cv_dlopen'+set}'`\" != set"; then - lt_cv_dlopen=no lt_cv_dlopen_libs= -echo $ac_n "checking for dlopen in -ldl""... $ac_c" 1>&6 -echo "$progname:2170: checking for dlopen in -ldl" >&5 -ac_lib_var=`echo dl'_'dlopen | sed 'y%./+-%__p_%'` -if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - ac_save_LIBS="$LIBS" -LIBS="-ldl $LIBS" -cat > conftest.$ac_ext <<EOF -#line 2178 "ltconfig" -/* Override any gcc2 internal prototype to avoid an error. */ -/* We use char because int might match the return type of a gcc2 - builtin and then its argument prototype would still apply. */ -char dlopen(); - -int main() { -dlopen() -; return 0; } -EOF -if { (eval echo $progname:2188: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then - rm -rf conftest* - eval "ac_cv_lib_$ac_lib_var=yes" -else - echo "$progname: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -rf conftest* - eval "ac_cv_lib_$ac_lib_var=no" -fi -rm -f conftest* -LIBS="$ac_save_LIBS" - -fi -if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then - echo "$ac_t""yes" 1>&6 - lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" -else - echo "$ac_t""no" 1>&6 -echo $ac_n "checking for dlopen""... $ac_c" 1>&6 -echo "$progname:2207: checking for dlopen" >&5 -if eval "test \"`echo '$''{'ac_cv_func_dlopen'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - cat > conftest.$ac_ext <<EOF -#line 2212 "ltconfig" -/* System header to define __stub macros and hopefully few prototypes, - which can conflict with char dlopen(); below. */ -#include <assert.h> -/* Override any gcc2 internal prototype to avoid an error. */ -/* We use char because int might match the return type of a gcc2 - builtin and then its argument prototype would still apply. */ -char dlopen(); - -int main() { - -/* The GNU C library defines this for functions which it implements - to always fail with ENOSYS. Some functions are actually named - something starting with __ and the normal name is an alias. */ -#if defined (__stub_dlopen) || defined (__stub___dlopen) -choke me -#else -dlopen(); -#endif - -; return 0; } -EOF -if { (eval echo $progname:2234: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then - rm -rf conftest* - eval "ac_cv_func_dlopen=yes" -else - echo "$progname: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -rf conftest* - eval "ac_cv_func_dlopen=no" -fi -rm -f conftest* -fi -if eval "test \"`echo '$ac_cv_func_'dlopen`\" = yes"; then - echo "$ac_t""yes" 1>&6 - lt_cv_dlopen="dlopen" -else - echo "$ac_t""no" 1>&6 -echo $ac_n "checking for dld_link in -ldld""... $ac_c" 1>&6 -echo "$progname:2251: checking for dld_link in -ldld" >&5 -ac_lib_var=`echo dld'_'dld_link | sed 'y%./+-%__p_%'` -if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - ac_save_LIBS="$LIBS" -LIBS="-ldld $LIBS" -cat > conftest.$ac_ext <<EOF -#line 2259 "ltconfig" -/* Override any gcc2 internal prototype to avoid an error. */ -/* We use char because int might match the return type of a gcc2 - builtin and then its argument prototype would still apply. */ -char dld_link(); - -int main() { -dld_link() -; return 0; } -EOF -if { (eval echo $progname:2269: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then - rm -rf conftest* - eval "ac_cv_lib_$ac_lib_var=yes" -else - echo "$progname: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -rf conftest* - eval "ac_cv_lib_$ac_lib_var=no" -fi -rm -f conftest* -LIBS="$ac_save_LIBS" - -fi -if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then - echo "$ac_t""yes" 1>&6 - lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld" -else - echo "$ac_t""no" 1>&6 -echo $ac_n "checking for shl_load""... $ac_c" 1>&6 -echo "$progname:2288: checking for shl_load" >&5 -if eval "test \"`echo '$''{'ac_cv_func_shl_load'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - cat > conftest.$ac_ext <<EOF -#line 2293 "ltconfig" -/* System header to define __stub macros and hopefully few prototypes, - which can conflict with char shl_load(); below. */ -#include <assert.h> -/* Override any gcc2 internal prototype to avoid an error. */ -/* We use char because int might match the return type of a gcc2 - builtin and then its argument prototype would still apply. */ -char shl_load(); - -int main() { - -/* The GNU C library defines this for functions which it implements - to always fail with ENOSYS. Some functions are actually named - something starting with __ and the normal name is an alias. */ -#if defined (__stub_shl_load) || defined (__stub___shl_load) -choke me -#else -shl_load(); -#endif - -; return 0; } -EOF -if { (eval echo $progname:2315: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then - rm -rf conftest* - eval "ac_cv_func_shl_load=yes" -else - echo "$progname: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -rf conftest* - eval "ac_cv_func_shl_load=no" -fi -rm -f conftest* -fi - -if eval "test \"`echo '$ac_cv_func_'shl_load`\" = yes"; then - echo "$ac_t""yes" 1>&6 - lt_cv_dlopen="shl_load" -else - echo "$ac_t""no" 1>&6 -echo $ac_n "checking for shl_load in -ldld""... $ac_c" 1>&6 -echo "$progname:2333: checking for shl_load in -ldld" >&5 -ac_lib_var=`echo dld'_'shl_load | sed 'y%./+-%__p_%'` -if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - ac_save_LIBS="$LIBS" -LIBS="-ldld $LIBS" -cat > conftest.$ac_ext <<EOF -#line 2341 "ltconfig" -#include "confdefs.h" -/* Override any gcc2 internal prototype to avoid an error. */ -/* We use char because int might match the return type of a gcc2 - builtin and then its argument prototype would still apply. */ -char shl_load(); - -int main() { -shl_load() -; return 0; } -EOF -if { (eval echo $progname:2352: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then - rm -rf conftest* - eval "ac_cv_lib_$ac_lib_var=yes" -else - echo "$progname: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -rf conftest* - eval "ac_cv_lib_$ac_lib_var=no" -fi -rm -f conftest* -LIBS="$ac_save_LIBS" - -fi -if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then - echo "$ac_t""yes" 1>&6 - lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld" -else - echo "$ac_t""no" 1>&6 -fi - - -fi - - -fi - - -fi - - -fi - -fi - - if test "x$lt_cv_dlopen" != xno; then - enable_dlopen=yes - fi - - case "$lt_cv_dlopen" in - dlopen) -for ac_hdr in dlfcn.h; do -ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` -echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "$progname:2395: checking for $ac_hdr" >&5 -if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - cat > conftest.$ac_ext <<EOF -#line 2400 "ltconfig" -#include <$ac_hdr> -int fnord = 0; -EOF -ac_try="$ac_compile conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo $progname:2405: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } -ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` -if test -z "$ac_err"; then - rm -rf conftest* - eval "ac_cv_header_$ac_safe=yes" -else - echo "$ac_err" >&5 - echo "$progname: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -rf conftest* - eval "ac_cv_header_$ac_safe=no" -fi -rm -f conftest* -fi -if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then - echo "$ac_t""yes" 1>&6 -else - echo "$ac_t""no" 1>&6 -fi -done - - if test "x$ac_cv_header_dlfcn_h" = xyes; then - CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" - fi - eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" - LIBS="$lt_cv_dlopen_libs $LIBS" - - echo $ac_n "checking whether a program can dlopen itself""... $ac_c" 1>&6 -echo "$progname:2433: checking whether a program can dlopen itself" >&5 -if test "${lt_cv_dlopen_self+set}" = set; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - if test "$cross_compiling" = yes; then - lt_cv_dlopen_self=cross - else - cat > conftest.c <<EOF -#line 2441 "ltconfig" - -#if HAVE_DLFCN_H -#include <dlfcn.h> -#endif - -#include <stdio.h> - -#ifdef RTLD_GLOBAL -# define LTDL_GLOBAL RTLD_GLOBAL -#else -# ifdef DL_GLOBAL -# define LTDL_GLOBAL DL_GLOBAL -# else -# define LTDL_GLOBAL 0 -# endif -#endif - -/* We may have to define LTDL_LAZY_OR_NOW in the command line if we - find out it does not work in some platform. */ -#ifndef LTDL_LAZY_OR_NOW -# ifdef RTLD_LAZY -# define LTDL_LAZY_OR_NOW RTLD_LAZY -# else -# ifdef DL_LAZY -# define LTDL_LAZY_OR_NOW DL_LAZY -# else -# ifdef RTLD_NOW -# define LTDL_LAZY_OR_NOW RTLD_NOW -# else -# ifdef DL_NOW -# define LTDL_LAZY_OR_NOW DL_NOW -# else -# define LTDL_LAZY_OR_NOW 0 -# endif -# endif -# endif -# endif -#endif - -fnord() { int i=42;} -main() { void *self, *ptr1, *ptr2; self=dlopen(0,LTDL_GLOBAL|LTDL_LAZY_OR_NOW); - if(self) { ptr1=dlsym(self,"fnord"); ptr2=dlsym(self,"_fnord"); - if(ptr1 || ptr2) { dlclose(self); exit(0); } } exit(1); } - -EOF -if { (eval echo $progname:2487: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null -then - lt_cv_dlopen_self=yes -else - echo "$progname: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -fr conftest* - lt_cv_dlopen_self=no -fi -rm -fr conftest* -fi - -fi - -echo "$ac_t""$lt_cv_dlopen_self" 1>&6 - - if test "$lt_cv_dlopen_self" = yes; then - LDFLAGS="$LDFLAGS $link_static_flag" - echo $ac_n "checking whether a statically linked program can dlopen itself""... $ac_c" 1>&6 -echo "$progname:2506: checking whether a statically linked program can dlopen itself" >&5 -if test "${lt_cv_dlopen_self_static+set}" = set; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - if test "$cross_compiling" = yes; then - lt_cv_dlopen_self_static=cross - else - cat > conftest.c <<EOF -#line 2514 "ltconfig" - -#if HAVE_DLFCN_H -#include <dlfcn.h> -#endif - -#include <stdio.h> - -#ifdef RTLD_GLOBAL -# define LTDL_GLOBAL RTLD_GLOBAL -#else -# ifdef DL_GLOBAL -# define LTDL_GLOBAL DL_GLOBAL -# else -# define LTDL_GLOBAL 0 -# endif -#endif - -/* We may have to define LTDL_LAZY_OR_NOW in the command line if we - find out it does not work in some platform. */ -#ifndef LTDL_LAZY_OR_NOW -# ifdef RTLD_LAZY -# define LTDL_LAZY_OR_NOW RTLD_LAZY -# else -# ifdef DL_LAZY -# define LTDL_LAZY_OR_NOW DL_LAZY -# else -# ifdef RTLD_NOW -# define LTDL_LAZY_OR_NOW RTLD_NOW -# else -# ifdef DL_NOW -# define LTDL_LAZY_OR_NOW DL_NOW -# else -# define LTDL_LAZY_OR_NOW 0 -# endif -# endif -# endif -# endif -#endif - -fnord() { int i=42;} -main() { void *self, *ptr1, *ptr2; self=dlopen(0,LTDL_GLOBAL|LTDL_LAZY_OR_NOW); - if(self) { ptr1=dlsym(self,"fnord"); ptr2=dlsym(self,"_fnord"); - if(ptr1 || ptr2) { dlclose(self); exit(0); } } exit(1); } - -EOF -if { (eval echo $progname:2560: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null -then - lt_cv_dlopen_self_static=yes -else - echo "$progname: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -fr conftest* - lt_cv_dlopen_self_static=no -fi -rm -fr conftest* -fi - -fi - -echo "$ac_t""$lt_cv_dlopen_self_static" 1>&6 -fi - ;; - esac - - case "$lt_cv_dlopen_self" in - yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; - *) enable_dlopen_self=unknown ;; - esac - - case "$lt_cv_dlopen_self_static" in - yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; - *) enable_dlopen_self_static=unknown ;; - esac -fi - -# Copy echo and quote the copy, instead of the original, because it is -# used later. -ltecho="$echo" -if test "X$ltecho" = "X$CONFIG_SHELL $0 --fallback-echo"; then - ltecho="$CONFIG_SHELL \$0 --fallback-echo" -fi -LTSHELL="$SHELL" - -LTCONFIG_VERSION="$VERSION" - -# Only quote variables if we're using ltmain.sh. -case "$ltmain" in -*.sh) - # Now quote all the things that may contain metacharacters. - for var in ltecho old_CC old_CFLAGS old_CPPFLAGS \ - old_LD old_LDFLAGS old_LIBS \ - old_NM old_RANLIB old_LN_S old_DLLTOOL old_OBJDUMP old_AS \ - AR CC LD LN_S NM LTSHELL LTCONFIG_VERSION \ - reload_flag reload_cmds wl \ - pic_flag link_static_flag no_builtin_flag export_dynamic_flag_spec \ - thread_safe_flag_spec whole_archive_flag_spec libname_spec \ - library_names_spec soname_spec \ - RANLIB old_archive_cmds old_archive_from_new_cmds old_postinstall_cmds \ - old_postuninstall_cmds archive_cmds archive_expsym_cmds postinstall_cmds postuninstall_cmds \ - file_magic_cmd export_symbols_cmds deplibs_check_method allow_undefined_flag no_undefined_flag \ - finish_cmds finish_eval global_symbol_pipe global_symbol_to_cdecl \ - hardcode_libdir_flag_spec hardcode_libdir_separator \ - sys_lib_search_path_spec sys_lib_dlsearch_path_spec \ - compiler_c_o compiler_o_lo need_locks exclude_expsyms include_expsyms; do - - case "$var" in - reload_cmds | old_archive_cmds | old_archive_from_new_cmds | \ - old_postinstall_cmds | old_postuninstall_cmds | \ - export_symbols_cmds | archive_cmds | archive_expsym_cmds | \ - postinstall_cmds | postuninstall_cmds | \ - finish_cmds | sys_lib_search_path_spec | sys_lib_dlsearch_path_spec) - # Double-quote double-evaled strings. - eval "$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\"" - ;; - *) - eval "$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\"" - ;; - esac - done - - case "$ltecho" in - *'\$0 --fallback-echo"') - ltecho=`$echo "X$ltecho" | $Xsed -e 's/\\\\\\\$0 --fallback-echo"$/$0 --fallback-echo"/'` - ;; - esac - - trap "$rm \"$ofile\"; exit 1" 1 2 15 - echo "creating $ofile" - $rm "$ofile" - cat <<EOF > "$ofile" -#! $SHELL - -# `$echo "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. -# Generated automatically by $PROGRAM (GNU $PACKAGE $VERSION$TIMESTAMP) -# NOTE: Changes made to this file will be lost: look at ltconfig or ltmain.sh. -# -# Copyright (C) 1996-1999 Free Software Foundation, Inc. -# Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996 -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# -# As a special exception to the GNU General Public License, if you -# distribute this file as part of a program that contains a -# configuration script generated by Autoconf, you may include it under -# the same distribution terms that you use for the rest of that program. - -# Sed that helps us avoid accidentally triggering echo(1) options like -n. -Xsed="sed -e s/^X//" - -# The HP-UX ksh and POSIX shell print the target directory to stdout -# if CDPATH is set. -if test "\${CDPATH+set}" = set; then CDPATH=; export CDPATH; fi - -### BEGIN LIBTOOL CONFIG -EOF - cfgfile="$ofile" - ;; - -*) - # Double-quote the variables that need it (for aesthetics). - for var in old_CC old_CFLAGS old_CPPFLAGS \ - old_LD old_LDFLAGS old_LIBS \ - old_NM old_RANLIB old_LN_S old_DLLTOOL old_OBJDUMP old_AS; do - eval "$var=\\\"\$var\\\"" - done - - # Just create a config file. - cfgfile="$ofile.cfg" - trap "$rm \"$cfgfile\"; exit 1" 1 2 15 - echo "creating $cfgfile" - $rm "$cfgfile" - cat <<EOF > "$cfgfile" -# `$echo "$cfgfile" | sed 's%^.*/%%'` - Libtool configuration file. -# Generated automatically by $PROGRAM (GNU $PACKAGE $VERSION$TIMESTAMP) -EOF - ;; -esac - -cat <<EOF >> "$cfgfile" -# Libtool was configured as follows, on host `(hostname || uname -n) 2>/dev/null | sed 1q`: -# -# CC=$old_CC CFLAGS=$old_CFLAGS CPPFLAGS=$old_CPPFLAGS \\ -# LD=$old_LD LDFLAGS=$old_LDFLAGS LIBS=$old_LIBS \\ -# NM=$old_NM RANLIB=$old_RANLIB LN_S=$old_LN_S \\ -# DLLTOOL=$old_DLLTOOL OBJDUMP=$old_OBJDUMP AS=$old_AS \\ -# $0$ltconfig_args -# -# Compiler and other test output produced by $progname, useful for -# debugging $progname, is in ./config.log if it exists. - -# The version of $progname that generated this script. -LTCONFIG_VERSION=$LTCONFIG_VERSION - -# Shell to use when invoking shell scripts. -SHELL=$LTSHELL - -# Whether or not to build shared libraries. -build_libtool_libs=$enable_shared - -# Whether or not to build static libraries. -build_old_libs=$enable_static - -# Whether or not to optimize for fast installation. -fast_install=$enable_fast_install - -# The host system. -host_alias=$host_alias -host=$host - -# An echo program that does not interpret backslashes. -echo=$ltecho - -# The archiver. -AR=$AR - -# The default C compiler. -CC=$CC - -# The linker used to build libraries. -LD=$LD - -# Whether we need hard or soft links. -LN_S=$LN_S - -# A BSD-compatible nm program. -NM=$NM - -# Used on cygwin: DLL creation program. -DLLTOOL="$DLLTOOL" - -# Used on cygwin: object dumper. -OBJDUMP="$OBJDUMP" - -# Used on cygwin: assembler. -AS="$AS" - -# The name of the directory that contains temporary libtool files. -objdir=$objdir - -# How to create reloadable object files. -reload_flag=$reload_flag -reload_cmds=$reload_cmds - -# How to pass a linker flag through the compiler. -wl=$wl - -# Object file suffix (normally "o"). -objext="$objext" - -# Old archive suffix (normally "a"). -libext="$libext" - -# Executable file suffix (normally ""). -exeext="$exeext" - -# Additional compiler flags for building library objects. -pic_flag=$pic_flag - -# Does compiler simultaneously support -c and -o options? -compiler_c_o=$compiler_c_o - -# Can we write directly to a .lo ? -compiler_o_lo=$compiler_o_lo - -# Must we lock files when doing compilation ? -need_locks=$need_locks - -# Do we need the lib prefix for modules? -need_lib_prefix=$need_lib_prefix - -# Do we need a version for libraries? -need_version=$need_version - -# Whether dlopen is supported. -dlopen=$enable_dlopen - -# Whether dlopen of programs is supported. -dlopen_self=$enable_dlopen_self - -# Whether dlopen of statically linked programs is supported. -dlopen_self_static=$enable_dlopen_self_static - -# Compiler flag to prevent dynamic linking. -link_static_flag=$link_static_flag - -# Compiler flag to turn off builtin functions. -no_builtin_flag=$no_builtin_flag - -# Compiler flag to allow reflexive dlopens. -export_dynamic_flag_spec=$export_dynamic_flag_spec - -# Compiler flag to generate shared objects directly from archives. -whole_archive_flag_spec=$whole_archive_flag_spec - -# Compiler flag to generate thread-safe objects. -thread_safe_flag_spec=$thread_safe_flag_spec - -# Library versioning type. -version_type=$version_type - -# Format of library name prefix. -libname_spec=$libname_spec - -# List of archive names. First name is the real one, the rest are links. -# The last name is the one that the linker finds with -lNAME. -library_names_spec=$library_names_spec - -# The coded name of the library, if different from the real name. -soname_spec=$soname_spec - -# Commands used to build and install an old-style archive. -RANLIB=$RANLIB -old_archive_cmds=$old_archive_cmds -old_postinstall_cmds=$old_postinstall_cmds -old_postuninstall_cmds=$old_postuninstall_cmds - -# Create an old-style archive from a shared archive. -old_archive_from_new_cmds=$old_archive_from_new_cmds - -# Commands used to build and install a shared archive. -archive_cmds=$archive_cmds -archive_expsym_cmds=$archive_expsym_cmds -postinstall_cmds=$postinstall_cmds -postuninstall_cmds=$postuninstall_cmds - -# Method to check whether dependent libraries are shared objects. -deplibs_check_method=$deplibs_check_method - -# Command to use when deplibs_check_method == file_magic. -file_magic_cmd=$file_magic_cmd - -# Flag that allows shared libraries with undefined symbols to be built. -allow_undefined_flag=$allow_undefined_flag - -# Flag that forces no undefined symbols. -no_undefined_flag=$no_undefined_flag - -# Commands used to finish a libtool library installation in a directory. -finish_cmds=$finish_cmds - -# Same as above, but a single script fragment to be evaled but not shown. -finish_eval=$finish_eval - -# Take the output of nm and produce a listing of raw symbols and C names. -global_symbol_pipe=$global_symbol_pipe - -# Transform the output of nm in a proper C declaration -global_symbol_to_cdecl=$global_symbol_to_cdecl - -# This is the shared library runtime path variable. -runpath_var=$runpath_var - -# This is the shared library path variable. -shlibpath_var=$shlibpath_var - -# Is shlibpath searched before the hard-coded library search path? -shlibpath_overrides_runpath=$shlibpath_overrides_runpath - -# How to hardcode a shared library path into an executable. -hardcode_action=$hardcode_action - -# Flag to hardcode \$libdir into a binary during linking. -# This must work even if \$libdir does not exist. -hardcode_libdir_flag_spec=$hardcode_libdir_flag_spec - -# Whether we need a single -rpath flag with a separated argument. -hardcode_libdir_separator=$hardcode_libdir_separator - -# Set to yes if using DIR/libNAME.so during linking hardcodes DIR into the -# resulting binary. -hardcode_direct=$hardcode_direct - -# Set to yes if using the -LDIR flag during linking hardcodes DIR into the -# resulting binary. -hardcode_minus_L=$hardcode_minus_L - -# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into -# the resulting binary. -hardcode_shlibpath_var=$hardcode_shlibpath_var - -# Compile-time system search path for libraries -sys_lib_search_path_spec=$sys_lib_search_path_spec - -# Run-time system search path for libraries -sys_lib_dlsearch_path_spec=$sys_lib_dlsearch_path_spec - -# Fix the shell variable \$srcfile for the compiler. -fix_srcfile_path="$fix_srcfile_path" - -# Set to yes if exported symbols are required. -always_export_symbols=$always_export_symbols - -# The commands to list exported symbols. -export_symbols_cmds=$export_symbols_cmds - -# Symbols that should not be listed in the preloaded symbols. -exclude_expsyms=$exclude_expsyms - -# Symbols that must always be exported. -include_expsyms=$include_expsyms - -EOF - -case "$ltmain" in -*.sh) - echo '### END LIBTOOL CONFIG' >> "$ofile" - echo >> "$ofile" - case "$host_os" in - aix3*) - cat <<\EOF >> "$ofile" - -# AIX sometimes has problems with the GCC collect2 program. For some -# reason, if we set the COLLECT_NAMES environment variable, the problems -# vanish in a puff of smoke. -if test "${COLLECT_NAMES+set}" != set; then - COLLECT_NAMES= - export COLLECT_NAMES -fi -EOF - ;; - esac - - # Append the ltmain.sh script. - sed '$q' "$ltmain" >> "$ofile" || (rm -f "$ofile"; exit 1) - - chmod +x "$ofile" - ;; - -*) - # Compile the libtool program. - echo "FIXME: would compile $ltmain" - ;; -esac - -test -n "$cache_file" || exit 0 - -# AC_CACHE_SAVE -trap '' 1 2 15 -cat > confcache <<\EOF -# This file is a shell script that caches the results of configure -# tests run on this system so they can be shared between configure -# scripts and configure runs. It is not useful on other systems. -# If it contains results you don't want to keep, you may remove or edit it. -# -# By default, configure uses ./config.cache as the cache file, -# creating it if it does not exist already. You can give configure -# the --cache-file=FILE option to use a different cache file; that is -# what configure does when it calls configure scripts in -# subdirectories, so they share the cache. -# Giving --cache-file=/dev/null disables caching, for debugging configure. -# config.status only pays attention to the cache file if you give it the -# --recheck option to rerun configure. -# -EOF -# The following way of writing the cache mishandles newlines in values, -# but we know of no workaround that is simple, portable, and efficient. -# So, don't put newlines in cache variables' values. -# Ultrix sh set writes to stderr and can't be redirected directly, -# and sets the high bit in the cache file unless we assign to the vars. -(set) 2>&1 | - case `(ac_space=' '; set | grep ac_space) 2>&1` in - *ac_space=\ *) - # `set' does not quote correctly, so add quotes (double-quote substitution - # turns \\\\ into \\, and sed turns \\ into \). - sed -n \ - -e "s/'/'\\\\''/g" \ - -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p" - ;; - *) - # `set' quotes correctly as required by POSIX, so do not add quotes. - sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p' - ;; - esac >> confcache -if cmp -s $cache_file confcache; then - : -else - if test -w $cache_file; then - echo "updating cache $cache_file" - cat confcache > $cache_file - else - echo "not updating unwritable cache $cache_file" - fi -fi -rm -f confcache - -exit 0 - -# Local Variables: -# mode:shell-script -# sh-indentation:2 -# End: diff --git a/shmem/unix/mm/ltmain.sh b/shmem/unix/mm/ltmain.sh deleted file mode 100644 index f479d1ef57f..00000000000 --- a/shmem/unix/mm/ltmain.sh +++ /dev/null @@ -1,3975 +0,0 @@ -# ltmain.sh - Provide generalized library-building support services. -# NOTE: Changing this file will not affect anything until you rerun ltconfig. -# -# Copyright (C) 1996-1999 Free Software Foundation, Inc. -# Originally by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996 -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# -# As a special exception to the GNU General Public License, if you -# distribute this file as part of a program that contains a -# configuration script generated by Autoconf, you may include it under -# the same distribution terms that you use for the rest of that program. - -# Check that we have a working $echo. -if test "X$1" = X--no-reexec; then - # Discard the --no-reexec flag, and continue. - shift -elif test "X$1" = X--fallback-echo; then - # Avoid inline document here, it may be left over - : -elif test "X`($echo '\t') 2>/dev/null`" = 'X\t'; then - # Yippee, $echo works! - : -else - # Restart under the correct shell, and then maybe $echo will work. - exec $SHELL "$0" --no-reexec ${1+"$@"} -fi - -if test "X$1" = X--fallback-echo; then - # used as fallback echo - shift - cat <<EOF -$* -EOF - exit 0 -fi - -# The name of this program. -progname=`$echo "$0" | sed 's%^.*/%%'` -modename="$progname" - -# Constants. -PROGRAM=ltmain.sh -PACKAGE=libtool -VERSION=1.3.3 -TIMESTAMP=" (1.385.2.181 1999/07/02 15:49:11)" - -default_mode= -help="Try \`$progname --help' for more information." -magic="%%%MAGIC variable%%%" -mkdir="mkdir" -mv="mv -f" -rm="rm -f" - -# Sed substitution that helps us do robust quoting. It backslashifies -# metacharacters that are still active within double-quoted strings. -Xsed='sed -e 1s/^X//' -sed_quote_subst='s/\([\\`\\"$\\\\]\)/\\\1/g' -SP2NL='tr \040 \012' -NL2SP='tr \015\012 \040\040' - -# NLS nuisances. -# Only set LANG and LC_ALL to C if already set. -# These must not be set unconditionally because not all systems understand -# e.g. LANG=C (notably SCO). -# We save the old values to restore during execute mode. -if test "${LC_ALL+set}" = set; then - save_LC_ALL="$LC_ALL"; LC_ALL=C; export LC_ALL -fi -if test "${LANG+set}" = set; then - save_LANG="$LANG"; LANG=C; export LANG -fi - -if test "$LTCONFIG_VERSION" != "$VERSION"; then - echo "$modename: ltconfig version \`$LTCONFIG_VERSION' does not match $PROGRAM version \`$VERSION'" 1>&2 - echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2 - exit 1 -fi - -if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then - echo "$modename: not configured to build any kind of library" 1>&2 - echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2 - exit 1 -fi - -# Global variables. -mode=$default_mode -nonopt= -prev= -prevopt= -run= -show="$echo" -show_help= -execute_dlfiles= -lo2o="s/\\.lo\$/.${objext}/" -o2lo="s/\\.${objext}\$/.lo/" - -# Parse our command line options once, thoroughly. -while test $# -gt 0 -do - arg="$1" - shift - - case "$arg" in - -*=*) optarg=`$echo "X$arg" | $Xsed -e 's/[-_a-zA-Z0-9]*=//'` ;; - *) optarg= ;; - esac - - # If the previous option needs an argument, assign it. - if test -n "$prev"; then - case "$prev" in - execute_dlfiles) - eval "$prev=\"\$$prev \$arg\"" - ;; - *) - eval "$prev=\$arg" - ;; - esac - - prev= - prevopt= - continue - fi - - # Have we seen a non-optional argument yet? - case "$arg" in - --help) - show_help=yes - ;; - - --version) - echo "$PROGRAM (GNU $PACKAGE) $VERSION$TIMESTAMP" - exit 0 - ;; - - --config) - sed -e '1,/^### BEGIN LIBTOOL CONFIG/d' -e '/^### END LIBTOOL CONFIG/,$d' $0 - exit 0 - ;; - - --debug) - echo "$progname: enabling shell trace mode" - set -x - ;; - - --dry-run | -n) - run=: - ;; - - --features) - echo "host: $host" - if test "$build_libtool_libs" = yes; then - echo "enable shared libraries" - else - echo "disable shared libraries" - fi - if test "$build_old_libs" = yes; then - echo "enable static libraries" - else - echo "disable static libraries" - fi - exit 0 - ;; - - --finish) mode="finish" ;; - - --mode) prevopt="--mode" prev=mode ;; - --mode=*) mode="$optarg" ;; - - --quiet | --silent) - show=: - ;; - - -dlopen) - prevopt="-dlopen" - prev=execute_dlfiles - ;; - - -*) - $echo "$modename: unrecognized option \`$arg'" 1>&2 - $echo "$help" 1>&2 - exit 1 - ;; - - *) - nonopt="$arg" - break - ;; - esac -done - -if test -n "$prevopt"; then - $echo "$modename: option \`$prevopt' requires an argument" 1>&2 - $echo "$help" 1>&2 - exit 1 -fi - -if test -z "$show_help"; then - - # Infer the operation mode. - if test -z "$mode"; then - case "$nonopt" in - *cc | *++ | gcc* | *-gcc*) - mode=link - for arg - do - case "$arg" in - -c) - mode=compile - break - ;; - esac - done - ;; - *db | *dbx | *strace | *truss) - mode=execute - ;; - *install*|cp|mv) - mode=install - ;; - *rm) - mode=uninstall - ;; - *) - # If we have no mode, but dlfiles were specified, then do execute mode. - test -n "$execute_dlfiles" && mode=execute - - # Just use the default operation mode. - if test -z "$mode"; then - if test -n "$nonopt"; then - $echo "$modename: warning: cannot infer operation mode from \`$nonopt'" 1>&2 - else - $echo "$modename: warning: cannot infer operation mode without MODE-ARGS" 1>&2 - fi - fi - ;; - esac - fi - - # Only execute mode is allowed to have -dlopen flags. - if test -n "$execute_dlfiles" && test "$mode" != execute; then - $echo "$modename: unrecognized option \`-dlopen'" 1>&2 - $echo "$help" 1>&2 - exit 1 - fi - - # Change the help message to a mode-specific one. - generic_help="$help" - help="Try \`$modename --help --mode=$mode' for more information." - - # These modes are in order of execution frequency so that they run quickly. - case "$mode" in - # libtool compile mode - compile) - modename="$modename: compile" - # Get the compilation command and the source file. - base_compile= - lastarg= - srcfile="$nonopt" - suppress_output= - - user_target=no - for arg - do - # Accept any command-line options. - case "$arg" in - -o) - if test "$user_target" != "no"; then - $echo "$modename: you cannot specify \`-o' more than once" 1>&2 - exit 1 - fi - user_target=next - ;; - - -static) - build_old_libs=yes - continue - ;; - esac - - case "$user_target" in - next) - # The next one is the -o target name - user_target=yes - continue - ;; - yes) - # We got the output file - user_target=set - libobj="$arg" - continue - ;; - esac - - # Accept the current argument as the source file. - lastarg="$srcfile" - srcfile="$arg" - - # Aesthetically quote the previous argument. - - # Backslashify any backslashes, double quotes, and dollar signs. - # These are the only characters that are still specially - # interpreted inside of double-quoted scrings. - lastarg=`$echo "X$lastarg" | $Xsed -e "$sed_quote_subst"` - - # Double-quote args containing other shell metacharacters. - # Many Bourne shells cannot handle close brackets correctly in scan - # sets, so we specify it separately. - case "$lastarg" in - *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) - lastarg="\"$lastarg\"" - ;; - esac - - # Add the previous argument to base_compile. - if test -z "$base_compile"; then - base_compile="$lastarg" - else - base_compile="$base_compile $lastarg" - fi - done - - case "$user_target" in - set) - ;; - no) - # Get the name of the library object. - libobj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%'` - ;; - *) - $echo "$modename: you must specify a target with \`-o'" 1>&2 - exit 1 - ;; - esac - - # Recognize several different file suffixes. - # If the user specifies -o file.o, it is replaced with file.lo - xform='[cCFSfmso]' - case "$libobj" in - *.ada) xform=ada ;; - *.adb) xform=adb ;; - *.ads) xform=ads ;; - *.asm) xform=asm ;; - *.c++) xform=c++ ;; - *.cc) xform=cc ;; - *.cpp) xform=cpp ;; - *.cxx) xform=cxx ;; - *.f90) xform=f90 ;; - *.for) xform=for ;; - esac - - libobj=`$echo "X$libobj" | $Xsed -e "s/\.$xform$/.lo/"` - - case "$libobj" in - *.lo) obj=`$echo "X$libobj" | $Xsed -e "$lo2o"` ;; - *) - $echo "$modename: cannot determine name of library object from \`$libobj'" 1>&2 - exit 1 - ;; - esac - - if test -z "$base_compile"; then - $echo "$modename: you must specify a compilation command" 1>&2 - $echo "$help" 1>&2 - exit 1 - fi - - # Delete any leftover library objects. - if test "$build_old_libs" = yes; then - removelist="$obj $libobj" - else - removelist="$libobj" - fi - - $run $rm $removelist - trap "$run $rm $removelist; exit 1" 1 2 15 - - # Calculate the filename of the output object if compiler does - # not support -o with -c - if test "$compiler_c_o" = no; then - output_obj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%' -e 's%\..*$%%'`.${objext} - lockfile="$output_obj.lock" - removelist="$removelist $output_obj $lockfile" - trap "$run $rm $removelist; exit 1" 1 2 15 - else - need_locks=no - lockfile= - fi - - # Lock this critical section if it is needed - # We use this script file to make the link, it avoids creating a new file - if test "$need_locks" = yes; then - until ln "$0" "$lockfile" 2>/dev/null; do - $show "Waiting for $lockfile to be removed" - sleep 2 - done - elif test "$need_locks" = warn; then - if test -f "$lockfile"; then - echo "\ -*** ERROR, $lockfile exists and contains: -`cat $lockfile 2>/dev/null` - -This indicates that another process is trying to use the same -temporary object file, and libtool could not work around it because -your compiler does not support \`-c' and \`-o' together. If you -repeat this compilation, it may succeed, by chance, but you had better -avoid parallel builds (make -j) in this platform, or get a better -compiler." - - $run $rm $removelist - exit 1 - fi - echo $srcfile > "$lockfile" - fi - - if test -n "$fix_srcfile_path"; then - eval srcfile=\"$fix_srcfile_path\" - fi - - # Only build a PIC object if we are building libtool libraries. - if test "$build_libtool_libs" = yes; then - # Without this assignment, base_compile gets emptied. - fbsd_hideous_sh_bug=$base_compile - - # All platforms use -DPIC, to notify preprocessed assembler code. - command="$base_compile $pic_flag -DPIC $srcfile" - if test "$build_old_libs" = yes; then - lo_libobj="$libobj" - dir=`$echo "X$libobj" | $Xsed -e 's%/[^/]*$%%'` - if test "X$dir" = "X$libobj"; then - dir="$objdir" - else - dir="$dir/$objdir" - fi - libobj="$dir/"`$echo "X$libobj" | $Xsed -e 's%^.*/%%'` - - if test -d "$dir"; then - $show "$rm $libobj" - $run $rm $libobj - else - $show "$mkdir $dir" - $run $mkdir $dir - status=$? - if test $status -ne 0 && test ! -d $dir; then - exit $status - fi - fi - fi - if test "$compiler_o_lo" = yes; then - output_obj="$libobj" - command="$command -o $output_obj" - elif test "$compiler_c_o" = yes; then - output_obj="$obj" - command="$command -o $output_obj" - fi - - $run $rm "$output_obj" - $show "$command" - if $run eval "$command"; then : - else - test -n "$output_obj" && $run $rm $removelist - exit 1 - fi - - if test "$need_locks" = warn && - test x"`cat $lockfile 2>/dev/null`" != x"$srcfile"; then - echo "\ -*** ERROR, $lockfile contains: -`cat $lockfile 2>/dev/null` - -but it should contain: -$srcfile - -This indicates that another process is trying to use the same -temporary object file, and libtool could not work around it because -your compiler does not support \`-c' and \`-o' together. If you -repeat this compilation, it may succeed, by chance, but you had better -avoid parallel builds (make -j) in this platform, or get a better -compiler." - - $run $rm $removelist - exit 1 - fi - - # Just move the object if needed, then go on to compile the next one - if test x"$output_obj" != x"$libobj"; then - $show "$mv $output_obj $libobj" - if $run $mv $output_obj $libobj; then : - else - error=$? - $run $rm $removelist - exit $error - fi - fi - - # If we have no pic_flag, then copy the object into place and finish. - if test -z "$pic_flag" && test "$build_old_libs" = yes; then - # Rename the .lo from within objdir to obj - if test -f $obj; then - $show $rm $obj - $run $rm $obj - fi - - $show "$mv $libobj $obj" - if $run $mv $libobj $obj; then : - else - error=$? - $run $rm $removelist - exit $error - fi - - # Now arrange that obj and lo_libobj become the same file - $show "$LN_S $obj $lo_libobj" - if $run $LN_S $obj $lo_libobj; then - exit 0 - else - error=$? - $run $rm $removelist - exit $error - fi - fi - - # Allow error messages only from the first compilation. - suppress_output=' >/dev/null 2>&1' - fi - - # Only build a position-dependent object if we build old libraries. - if test "$build_old_libs" = yes; then - command="$base_compile $srcfile" - if test "$compiler_c_o" = yes; then - command="$command -o $obj" - output_obj="$obj" - fi - - # Suppress compiler output if we already did a PIC compilation. - command="$command$suppress_output" - $run $rm "$output_obj" - $show "$command" - if $run eval "$command"; then : - else - $run $rm $removelist - exit 1 - fi - - if test "$need_locks" = warn && - test x"`cat $lockfile 2>/dev/null`" != x"$srcfile"; then - echo "\ -*** ERROR, $lockfile contains: -`cat $lockfile 2>/dev/null` - -but it should contain: -$srcfile - -This indicates that another process is trying to use the same -temporary object file, and libtool could not work around it because -your compiler does not support \`-c' and \`-o' together. If you -repeat this compilation, it may succeed, by chance, but you had better -avoid parallel builds (make -j) in this platform, or get a better -compiler." - - $run $rm $removelist - exit 1 - fi - - # Just move the object if needed - if test x"$output_obj" != x"$obj"; then - $show "$mv $output_obj $obj" - if $run $mv $output_obj $obj; then : - else - error=$? - $run $rm $removelist - exit $error - fi - fi - - # Create an invalid libtool object if no PIC, so that we do not - # accidentally link it into a program. - if test "$build_libtool_libs" != yes; then - $show "echo timestamp > $libobj" - $run eval "echo timestamp > \$libobj" || exit $? - else - # Move the .lo from within objdir - $show "$mv $libobj $lo_libobj" - if $run $mv $libobj $lo_libobj; then : - else - error=$? - $run $rm $removelist - exit $error - fi - fi - fi - - # Unlock the critical section if it was locked - if test "$need_locks" != no; then - $rm "$lockfile" - fi - - exit 0 - ;; - - # libtool link mode - link) - modename="$modename: link" - C_compiler="$CC" # save it, to compile generated C sources - CC="$nonopt" - case "$host" in - *-*-cygwin* | *-*-mingw* | *-*-os2*) - # It is impossible to link a dll without this setting, and - # we shouldn't force the makefile maintainer to figure out - # which system we are compiling for in order to pass an extra - # flag for every libtool invokation. - # allow_undefined=no - - # FIXME: Unfortunately, there are problems with the above when trying - # to make a dll which has undefined symbols, in which case not - # even a static library is built. For now, we need to specify - # -no-undefined on the libtool link line when we can be certain - # that all symbols are satisfied, otherwise we get a static library. - allow_undefined=yes - - # This is a source program that is used to create dlls on Windows - # Don't remove nor modify the starting and closing comments -# /* ltdll.c starts here */ -# #define WIN32_LEAN_AND_MEAN -# #include <windows.h> -# #undef WIN32_LEAN_AND_MEAN -# #include <stdio.h> -# -# #ifndef __CYGWIN__ -# # ifdef __CYGWIN32__ -# # define __CYGWIN__ __CYGWIN32__ -# # endif -# #endif -# -# #ifdef __cplusplus -# extern "C" { -# #endif -# BOOL APIENTRY DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved); -# #ifdef __cplusplus -# } -# #endif -# -# #ifdef __CYGWIN__ -# #include <cygwin/cygwin_dll.h> -# DECLARE_CYGWIN_DLL( DllMain ); -# #endif -# HINSTANCE __hDllInstance_base; -# -# BOOL APIENTRY -# DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved) -# { -# __hDllInstance_base = hInst; -# return TRUE; -# } -# /* ltdll.c ends here */ - # This is a source program that is used to create import libraries - # on Windows for dlls which lack them. Don't remove nor modify the - # starting and closing comments -# /* impgen.c starts here */ -# /* Copyright (C) 1999 Free Software Foundation, Inc. -# -# This file is part of GNU libtool. -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# */ -# -# #include <stdio.h> /* for printf() */ -# #include <unistd.h> /* for open(), lseek(), read() */ -# #include <fcntl.h> /* for O_RDONLY, O_BINARY */ -# #include <string.h> /* for strdup() */ -# -# static unsigned int -# pe_get16 (fd, offset) -# int fd; -# int offset; -# { -# unsigned char b[2]; -# lseek (fd, offset, SEEK_SET); -# read (fd, b, 2); -# return b[0] + (b[1]<<8); -# } -# -# static unsigned int -# pe_get32 (fd, offset) -# int fd; -# int offset; -# { -# unsigned char b[4]; -# lseek (fd, offset, SEEK_SET); -# read (fd, b, 4); -# return b[0] + (b[1]<<8) + (b[2]<<16) + (b[3]<<24); -# } -# -# static unsigned int -# pe_as32 (ptr) -# void *ptr; -# { -# unsigned char *b = ptr; -# return b[0] + (b[1]<<8) + (b[2]<<16) + (b[3]<<24); -# } -# -# int -# main (argc, argv) -# int argc; -# char *argv[]; -# { -# int dll; -# unsigned long pe_header_offset, opthdr_ofs, num_entries, i; -# unsigned long export_rva, export_size, nsections, secptr, expptr; -# unsigned long name_rvas, nexp; -# unsigned char *expdata, *erva; -# char *filename, *dll_name; -# -# filename = argv[1]; -# -# dll = open(filename, O_RDONLY|O_BINARY); -# if (!dll) -# return 1; -# -# dll_name = filename; -# -# for (i=0; filename[i]; i++) -# if (filename[i] == '/' || filename[i] == '\\' || filename[i] == ':') -# dll_name = filename + i +1; -# -# pe_header_offset = pe_get32 (dll, 0x3c); -# opthdr_ofs = pe_header_offset + 4 + 20; -# num_entries = pe_get32 (dll, opthdr_ofs + 92); -# -# if (num_entries < 1) /* no exports */ -# return 1; -# -# export_rva = pe_get32 (dll, opthdr_ofs + 96); -# export_size = pe_get32 (dll, opthdr_ofs + 100); -# nsections = pe_get16 (dll, pe_header_offset + 4 +2); -# secptr = (pe_header_offset + 4 + 20 + -# pe_get16 (dll, pe_header_offset + 4 + 16)); -# -# expptr = 0; -# for (i = 0; i < nsections; i++) -# { -# char sname[8]; -# unsigned long secptr1 = secptr + 40 * i; -# unsigned long vaddr = pe_get32 (dll, secptr1 + 12); -# unsigned long vsize = pe_get32 (dll, secptr1 + 16); -# unsigned long fptr = pe_get32 (dll, secptr1 + 20); -# lseek(dll, secptr1, SEEK_SET); -# read(dll, sname, 8); -# if (vaddr <= export_rva && vaddr+vsize > export_rva) -# { -# expptr = fptr + (export_rva - vaddr); -# if (export_rva + export_size > vaddr + vsize) -# export_size = vsize - (export_rva - vaddr); -# break; -# } -# } -# -# expdata = (unsigned char*)malloc(export_size); -# lseek (dll, expptr, SEEK_SET); -# read (dll, expdata, export_size); -# erva = expdata - export_rva; -# -# nexp = pe_as32 (expdata+24); -# name_rvas = pe_as32 (expdata+32); -# -# printf ("EXPORTS\n"); -# for (i = 0; i<nexp; i++) -# { -# unsigned long name_rva = pe_as32 (erva+name_rvas+i*4); -# printf ("\t%s @ %ld ;\n", erva+name_rva, 1+ i); -# } -# -# return 0; -# } -# /* impgen.c ends here */ - ;; - *) - allow_undefined=yes - ;; - esac - compile_command="$CC" - finalize_command="$CC" - - compile_rpath= - finalize_rpath= - compile_shlibpath= - finalize_shlibpath= - convenience= - old_convenience= - deplibs= - linkopts= - - if test -n "$shlibpath_var"; then - # get the directories listed in $shlibpath_var - eval lib_search_path=\`\$echo \"X \${$shlibpath_var}\" \| \$Xsed -e \'s/:/ /g\'\` - else - lib_search_path= - fi - # now prepend the system-specific ones - eval lib_search_path=\"$sys_lib_search_path_spec\$lib_search_path\" - eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\" - - avoid_version=no - dlfiles= - dlprefiles= - dlself=no - export_dynamic=no - export_symbols= - export_symbols_regex= - generated= - libobjs= - link_against_libtool_libs= - ltlibs= - module=no - objs= - prefer_static_libs=no - preload=no - prev= - prevarg= - release= - rpath= - xrpath= - perm_rpath= - temp_rpath= - thread_safe=no - vinfo= - - # We need to know -static, to get the right output filenames. - for arg - do - case "$arg" in - -all-static | -static) - if test "X$arg" = "X-all-static"; then - if test "$build_libtool_libs" = yes && test -z "$link_static_flag"; then - $echo "$modename: warning: complete static linking is impossible in this configuration" 1>&2 - fi - if test -n "$link_static_flag"; then - dlopen_self=$dlopen_self_static - fi - else - if test -z "$pic_flag" && test -n "$link_static_flag"; then - dlopen_self=$dlopen_self_static - fi - fi - build_libtool_libs=no - build_old_libs=yes - prefer_static_libs=yes - break - ;; - esac - done - - # See if our shared archives depend on static archives. - test -n "$old_archive_from_new_cmds" && build_old_libs=yes - - # Go through the arguments, transforming them on the way. - while test $# -gt 0; do - arg="$1" - shift - - # If the previous option needs an argument, assign it. - if test -n "$prev"; then - case "$prev" in - output) - compile_command="$compile_command @OUTPUT@" - finalize_command="$finalize_command @OUTPUT@" - ;; - esac - - case "$prev" in - dlfiles|dlprefiles) - if test "$preload" = no; then - # Add the symbol object into the linking commands. - compile_command="$compile_command @SYMFILE@" - finalize_command="$finalize_command @SYMFILE@" - preload=yes - fi - case "$arg" in - *.la | *.lo) ;; # We handle these cases below. - force) - if test "$dlself" = no; then - dlself=needless - export_dynamic=yes - fi - prev= - continue - ;; - self) - if test "$prev" = dlprefiles; then - dlself=yes - elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then - dlself=yes - else - dlself=needless - export_dynamic=yes - fi - prev= - continue - ;; - *) - if test "$prev" = dlfiles; then - dlfiles="$dlfiles $arg" - else - dlprefiles="$dlprefiles $arg" - fi - prev= - ;; - esac - ;; - expsyms) - export_symbols="$arg" - if test ! -f "$arg"; then - $echo "$modename: symbol file \`$arg' does not exist" - exit 1 - fi - prev= - continue - ;; - expsyms_regex) - export_symbols_regex="$arg" - prev= - continue - ;; - release) - release="-$arg" - prev= - continue - ;; - rpath | xrpath) - # We need an absolute path. - case "$arg" in - [\\/]* | [A-Za-z]:[\\/]*) ;; - *) - $echo "$modename: only absolute run-paths are allowed" 1>&2 - exit 1 - ;; - esac - if test "$prev" = rpath; then - case "$rpath " in - *" $arg "*) ;; - *) rpath="$rpath $arg" ;; - esac - else - case "$xrpath " in - *" $arg "*) ;; - *) xrpath="$xrpath $arg" ;; - esac - fi - prev= - continue - ;; - *) - eval "$prev=\"\$arg\"" - prev= - continue - ;; - esac - fi - - prevarg="$arg" - - case "$arg" in - -all-static) - if test -n "$link_static_flag"; then - compile_command="$compile_command $link_static_flag" - finalize_command="$finalize_command $link_static_flag" - fi - continue - ;; - - -allow-undefined) - # FIXME: remove this flag sometime in the future. - $echo "$modename: \`-allow-undefined' is deprecated because it is the default" 1>&2 - continue - ;; - - -avoid-version) - avoid_version=yes - continue - ;; - - -dlopen) - prev=dlfiles - continue - ;; - - -dlpreopen) - prev=dlprefiles - continue - ;; - - -export-dynamic) - export_dynamic=yes - continue - ;; - - -export-symbols | -export-symbols-regex) - if test -n "$export_symbols" || test -n "$export_symbols_regex"; then - $echo "$modename: not more than one -exported-symbols argument allowed" - exit 1 - fi - if test "X$arg" = "X-export-symbols"; then - prev=expsyms - else - prev=expsyms_regex - fi - continue - ;; - - -L*) - dir=`$echo "X$arg" | $Xsed -e 's/^-L//'` - # We need an absolute path. - case "$dir" in - [\\/]* | [A-Za-z]:[\\/]*) ;; - *) - absdir=`cd "$dir" && pwd` - if test -z "$absdir"; then - $echo "$modename: warning: cannot determine absolute directory name of \`$dir'" 1>&2 - $echo "$modename: passing it literally to the linker, although it might fail" 1>&2 - absdir="$dir" - fi - dir="$absdir" - ;; - esac - case " $deplibs " in - *" $arg "*) ;; - *) deplibs="$deplibs $arg";; - esac - case " $lib_search_path " in - *" $dir "*) ;; - *) lib_search_path="$lib_search_path $dir";; - esac - case "$host" in - *-*-cygwin* | *-*-mingw* | *-*-os2*) - dllsearchdir=`cd "$dir" && pwd || echo "$dir"` - case ":$dllsearchpath:" in - ::) dllsearchpath="$dllsearchdir";; - *":$dllsearchdir:"*) ;; - *) dllsearchpath="$dllsearchpath:$dllsearchdir";; - esac - ;; - esac - ;; - - -l*) - if test "$arg" = "-lc"; then - case "$host" in - *-*-cygwin* | *-*-mingw* | *-*-os2* | *-*-beos*) - # These systems don't actually have c library (as such) - continue - ;; - esac - elif test "$arg" = "-lm"; then - case "$host" in - *-*-cygwin* | *-*-beos*) - # These systems don't actually have math library (as such) - continue - ;; - esac - fi - deplibs="$deplibs $arg" - ;; - - -module) - module=yes - continue - ;; - - -no-undefined) - allow_undefined=no - continue - ;; - - -o) prev=output ;; - - -release) - prev=release - continue - ;; - - -rpath) - prev=rpath - continue - ;; - - -R) - prev=xrpath - continue - ;; - - -R*) - dir=`$echo "X$arg" | $Xsed -e 's/^-R//'` - # We need an absolute path. - case "$dir" in - [\\/]* | [A-Za-z]:[\\/]*) ;; - *) - $echo "$modename: only absolute run-paths are allowed" 1>&2 - exit 1 - ;; - esac - case "$xrpath " in - *" $dir "*) ;; - *) xrpath="$xrpath $dir" ;; - esac - continue - ;; - - -static) - # If we have no pic_flag, then this is the same as -all-static. - if test -z "$pic_flag" && test -n "$link_static_flag"; then - compile_command="$compile_command $link_static_flag" - finalize_command="$finalize_command $link_static_flag" - fi - continue - ;; - - -thread-safe) - thread_safe=yes - continue - ;; - - -version-info) - prev=vinfo - continue - ;; - - # Some other compiler flag. - -* | +*) - # Unknown arguments in both finalize_command and compile_command need - # to be aesthetically quoted because they are evaled later. - arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` - case "$arg" in - *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) - arg="\"$arg\"" - ;; - esac - ;; - - *.o | *.obj | *.a | *.lib) - # A standard object. - objs="$objs $arg" - ;; - - *.lo) - # A library object. - if test "$prev" = dlfiles; then - dlfiles="$dlfiles $arg" - if test "$build_libtool_libs" = yes && test "$dlopen" = yes; then - prev= - continue - else - # If libtool objects are unsupported, then we need to preload. - prev=dlprefiles - fi - fi - - if test "$prev" = dlprefiles; then - # Preload the old-style object. - dlprefiles="$dlprefiles "`$echo "X$arg" | $Xsed -e "$lo2o"` - prev= - fi - libobjs="$libobjs $arg" - ;; - - *.la) - # A libtool-controlled library. - - dlname= - libdir= - library_names= - old_library= - - # Check to see that this really is a libtool archive. - if (sed -e '2q' $arg | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then : - else - $echo "$modename: \`$arg' is not a valid libtool archive" 1>&2 - exit 1 - fi - - # If the library was installed with an old release of libtool, - # it will not redefine variable installed. - installed=yes - - # Read the .la file - # If there is no directory component, then add one. - case "$arg" in - */* | *\\*) . $arg ;; - *) . ./$arg ;; - esac - - # Get the name of the library we link against. - linklib= - for l in $old_library $library_names; do - linklib="$l" - done - - if test -z "$linklib"; then - $echo "$modename: cannot find name of link library for \`$arg'" 1>&2 - exit 1 - fi - - # Find the relevant object directory and library name. - name=`$echo "X$arg" | $Xsed -e 's%^.*/%%' -e 's/\.la$//' -e 's/^lib//'` - - if test "X$installed" = Xyes; then - dir="$libdir" - else - dir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'` - if test "X$dir" = "X$arg"; then - dir="$objdir" - else - dir="$dir/$objdir" - fi - fi - - if test -n "$dependency_libs"; then - # Extract -R and -L from dependency_libs - temp_deplibs= - for deplib in $dependency_libs; do - case "$deplib" in - -R*) temp_xrpath=`$echo "X$deplib" | $Xsed -e 's/^-R//'` - case " $rpath $xrpath " in - *" $temp_xrpath "*) ;; - *) xrpath="$xrpath $temp_xrpath";; - esac;; - -L*) case "$compile_command $temp_deplibs " in - *" $deplib "*) ;; - *) temp_deplibs="$temp_deplibs $deplib";; - esac - temp_dir=`$echo "X$deplib" | $Xsed -e 's/^-L//'` - case " $lib_search_path " in - *" $temp_dir "*) ;; - *) lib_search_path="$lib_search_path $temp_dir";; - esac - ;; - *) temp_deplibs="$temp_deplibs $deplib";; - esac - done - dependency_libs="$temp_deplibs" - fi - - if test -z "$libdir"; then - # It is a libtool convenience library, so add in its objects. - convenience="$convenience $dir/$old_library" - old_convenience="$old_convenience $dir/$old_library" - deplibs="$deplibs$dependency_libs" - compile_command="$compile_command $dir/$old_library$dependency_libs" - finalize_command="$finalize_command $dir/$old_library$dependency_libs" - continue - fi - - # This library was specified with -dlopen. - if test "$prev" = dlfiles; then - dlfiles="$dlfiles $arg" - if test -z "$dlname" || test "$dlopen" != yes || test "$build_libtool_libs" = no; then - # If there is no dlname, no dlopen support or we're linking statically, - # we need to preload. - prev=dlprefiles - else - # We should not create a dependency on this library, but we - # may need any libraries it requires. - compile_command="$compile_command$dependency_libs" - finalize_command="$finalize_command$dependency_libs" - prev= - continue - fi - fi - - # The library was specified with -dlpreopen. - if test "$prev" = dlprefiles; then - # Prefer using a static library (so that no silly _DYNAMIC symbols - # are required to link). - if test -n "$old_library"; then - dlprefiles="$dlprefiles $dir/$old_library" - else - dlprefiles="$dlprefiles $dir/$linklib" - fi - prev= - fi - - if test -n "$library_names" && - { test "$prefer_static_libs" = no || test -z "$old_library"; }; then - link_against_libtool_libs="$link_against_libtool_libs $arg" - if test -n "$shlibpath_var"; then - # Make sure the rpath contains only unique directories. - case "$temp_rpath " in - *" $dir "*) ;; - *) temp_rpath="$temp_rpath $dir" ;; - esac - fi - - # We need an absolute path. - case "$dir" in - [\\/] | [A-Za-z]:[\\/]*) absdir="$dir" ;; - *) - absdir=`cd "$dir" && pwd` - if test -z "$absdir"; then - $echo "$modename: warning: cannot determine absolute directory name of \`$dir'" 1>&2 - $echo "$modename: passing it literally to the linker, although it might fail" 1>&2 - absdir="$dir" - fi - ;; - esac - - # This is the magic to use -rpath. - # Skip directories that are in the system default run-time - # search path, unless they have been requested with -R. - case " $sys_lib_dlsearch_path " in - *" $absdir "*) ;; - *) - case "$compile_rpath " in - *" $absdir "*) ;; - *) compile_rpath="$compile_rpath $absdir" - esac - ;; - esac - - case " $sys_lib_dlsearch_path " in - *" $libdir "*) ;; - *) - case "$finalize_rpath " in - *" $libdir "*) ;; - *) finalize_rpath="$finalize_rpath $libdir" - esac - ;; - esac - - lib_linked=yes - case "$hardcode_action" in - immediate | unsupported) - if test "$hardcode_direct" = no; then - compile_command="$compile_command $dir/$linklib" - deplibs="$deplibs $dir/$linklib" - case "$host" in - *-*-cygwin* | *-*-mingw* | *-*-os2*) - dllsearchdir=`cd "$dir" && pwd || echo "$dir"` - if test -n "$dllsearchpath"; then - dllsearchpath="$dllsearchpath:$dllsearchdir" - else - dllsearchpath="$dllsearchdir" - fi - ;; - esac - elif test "$hardcode_minus_L" = no; then - case "$host" in - *-*-sunos*) - compile_shlibpath="$compile_shlibpath$dir:" - ;; - esac - case "$compile_command " in - *" -L$dir "*) ;; - *) compile_command="$compile_command -L$dir";; - esac - compile_command="$compile_command -l$name" - deplibs="$deplibs -L$dir -l$name" - elif test "$hardcode_shlibpath_var" = no; then - case ":$compile_shlibpath:" in - *":$dir:"*) ;; - *) compile_shlibpath="$compile_shlibpath$dir:";; - esac - compile_command="$compile_command -l$name" - deplibs="$deplibs -l$name" - else - lib_linked=no - fi - ;; - - relink) - if test "$hardcode_direct" = yes; then - compile_command="$compile_command $absdir/$linklib" - deplibs="$deplibs $absdir/$linklib" - elif test "$hardcode_minus_L" = yes; then - case "$compile_command " in - *" -L$absdir "*) ;; - *) compile_command="$compile_command -L$absdir";; - esac - compile_command="$compile_command -l$name" - deplibs="$deplibs -L$absdir -l$name" - elif test "$hardcode_shlibpath_var" = yes; then - case ":$compile_shlibpath:" in - *":$absdir:"*) ;; - *) compile_shlibpath="$compile_shlibpath$absdir:";; - esac - compile_command="$compile_command -l$name" - deplibs="$deplibs -l$name" - else - lib_linked=no - fi - ;; - - *) - lib_linked=no - ;; - esac - - if test "$lib_linked" != yes; then - $echo "$modename: configuration error: unsupported hardcode properties" - exit 1 - fi - - # Finalize command for both is simple: just hardcode it. - if test "$hardcode_direct" = yes; then - finalize_command="$finalize_command $libdir/$linklib" - elif test "$hardcode_minus_L" = yes; then - case "$finalize_command " in - *" -L$libdir "*) ;; - *) finalize_command="$finalize_command -L$libdir";; - esac - finalize_command="$finalize_command -l$name" - elif test "$hardcode_shlibpath_var" = yes; then - case ":$finalize_shlibpath:" in - *":$libdir:"*) ;; - *) finalize_shlibpath="$finalize_shlibpath$libdir:";; - esac - finalize_command="$finalize_command -l$name" - else - # We cannot seem to hardcode it, guess we'll fake it. - case "$finalize_command " in - *" -L$dir "*) ;; - *) finalize_command="$finalize_command -L$libdir";; - esac - finalize_command="$finalize_command -l$name" - fi - else - # Transform directly to old archives if we don't build new libraries. - if test -n "$pic_flag" && test -z "$old_library"; then - $echo "$modename: cannot find static library for \`$arg'" 1>&2 - exit 1 - fi - - # Here we assume that one of hardcode_direct or hardcode_minus_L - # is not unsupported. This is valid on all known static and - # shared platforms. - if test "$hardcode_direct" != unsupported; then - test -n "$old_library" && linklib="$old_library" - compile_command="$compile_command $dir/$linklib" - finalize_command="$finalize_command $dir/$linklib" - else - case "$compile_command " in - *" -L$dir "*) ;; - *) compile_command="$compile_command -L$dir";; - esac - compile_command="$compile_command -l$name" - case "$finalize_command " in - *" -L$dir "*) ;; - *) finalize_command="$finalize_command -L$dir";; - esac - finalize_command="$finalize_command -l$name" - fi - fi - - # Add in any libraries that this one depends upon. - compile_command="$compile_command$dependency_libs" - finalize_command="$finalize_command$dependency_libs" - continue - ;; - - # Some other compiler argument. - *) - # Unknown arguments in both finalize_command and compile_command need - # to be aesthetically quoted because they are evaled later. - arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` - case "$arg" in - *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) - arg="\"$arg\"" - ;; - esac - ;; - esac - - # Now actually substitute the argument into the commands. - if test -n "$arg"; then - compile_command="$compile_command $arg" - finalize_command="$finalize_command $arg" - fi - done - - if test -n "$prev"; then - $echo "$modename: the \`$prevarg' option requires an argument" 1>&2 - $echo "$help" 1>&2 - exit 1 - fi - - if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then - eval arg=\"$export_dynamic_flag_spec\" - compile_command="$compile_command $arg" - finalize_command="$finalize_command $arg" - fi - - oldlibs= - # calculate the name of the file, without its directory - outputname=`$echo "X$output" | $Xsed -e 's%^.*/%%'` - libobjs_save="$libobjs" - - case "$output" in - "") - $echo "$modename: you must specify an output file" 1>&2 - $echo "$help" 1>&2 - exit 1 - ;; - - *.a | *.lib) - if test -n "$link_against_libtool_libs"; then - $echo "$modename: error: cannot link libtool libraries into archives" 1>&2 - exit 1 - fi - - if test -n "$deplibs"; then - $echo "$modename: warning: \`-l' and \`-L' are ignored for archives" 1>&2 - fi - - if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then - $echo "$modename: warning: \`-dlopen' is ignored for archives" 1>&2 - fi - - if test -n "$rpath"; then - $echo "$modename: warning: \`-rpath' is ignored for archives" 1>&2 - fi - - if test -n "$xrpath"; then - $echo "$modename: warning: \`-R' is ignored for archives" 1>&2 - fi - - if test -n "$vinfo"; then - $echo "$modename: warning: \`-version-info' is ignored for archives" 1>&2 - fi - - if test -n "$release"; then - $echo "$modename: warning: \`-release' is ignored for archives" 1>&2 - fi - - if test -n "$export_symbols" || test -n "$export_symbols_regex"; then - $echo "$modename: warning: \`-export-symbols' is ignored for archives" 1>&2 - fi - - # Now set the variables for building old libraries. - build_libtool_libs=no - oldlibs="$output" - ;; - - *.la) - # Make sure we only generate libraries of the form `libNAME.la'. - case "$outputname" in - lib*) - name=`$echo "X$outputname" | $Xsed -e 's/\.la$//' -e 's/^lib//'` - eval libname=\"$libname_spec\" - ;; - *) - if test "$module" = no; then - $echo "$modename: libtool library \`$output' must begin with \`lib'" 1>&2 - $echo "$help" 1>&2 - exit 1 - fi - if test "$need_lib_prefix" != no; then - # Add the "lib" prefix for modules if required - name=`$echo "X$outputname" | $Xsed -e 's/\.la$//'` - eval libname=\"$libname_spec\" - else - libname=`$echo "X$outputname" | $Xsed -e 's/\.la$//'` - fi - ;; - esac - - output_objdir=`$echo "X$output" | $Xsed -e 's%/[^/]*$%%'` - if test "X$output_objdir" = "X$output"; then - output_objdir="$objdir" - else - output_objdir="$output_objdir/$objdir" - fi - - if test -n "$objs"; then - $echo "$modename: cannot build libtool library \`$output' from non-libtool objects:$objs" 2>&1 - exit 1 - fi - - # How the heck are we supposed to write a wrapper for a shared library? - if test -n "$link_against_libtool_libs"; then - $echo "$modename: error: cannot link shared libraries into libtool libraries" 1>&2 - exit 1 - fi - - if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then - $echo "$modename: warning: \`-dlopen' is ignored for libtool libraries" 1>&2 - fi - - set dummy $rpath - if test $# -gt 2; then - $echo "$modename: warning: ignoring multiple \`-rpath's for a libtool library" 1>&2 - fi - install_libdir="$2" - - oldlibs= - if test -z "$rpath"; then - if test "$build_libtool_libs" = yes; then - # Building a libtool convenience library. - libext=al - oldlibs="$output_objdir/$libname.$libext $oldlibs" - build_libtool_libs=convenience - build_old_libs=yes - fi - dependency_libs="$deplibs" - - if test -n "$vinfo"; then - $echo "$modename: warning: \`-version-info' is ignored for convenience libraries" 1>&2 - fi - - if test -n "$release"; then - $echo "$modename: warning: \`-release' is ignored for convenience libraries" 1>&2 - fi - else - - # Parse the version information argument. - IFS="${IFS= }"; save_ifs="$IFS"; IFS=':' - set dummy $vinfo 0 0 0 - IFS="$save_ifs" - - if test -n "$8"; then - $echo "$modename: too many parameters to \`-version-info'" 1>&2 - $echo "$help" 1>&2 - exit 1 - fi - - current="$2" - revision="$3" - age="$4" - - # Check that each of the things are valid numbers. - case "$current" in - 0 | [1-9] | [1-9][0-9]*) ;; - *) - $echo "$modename: CURRENT \`$current' is not a nonnegative integer" 1>&2 - $echo "$modename: \`$vinfo' is not valid version information" 1>&2 - exit 1 - ;; - esac - - case "$revision" in - 0 | [1-9] | [1-9][0-9]*) ;; - *) - $echo "$modename: REVISION \`$revision' is not a nonnegative integer" 1>&2 - $echo "$modename: \`$vinfo' is not valid version information" 1>&2 - exit 1 - ;; - esac - - case "$age" in - 0 | [1-9] | [1-9][0-9]*) ;; - *) - $echo "$modename: AGE \`$age' is not a nonnegative integer" 1>&2 - $echo "$modename: \`$vinfo' is not valid version information" 1>&2 - exit 1 - ;; - esac - - if test $age -gt $current; then - $echo "$modename: AGE \`$age' is greater than the current interface number \`$current'" 1>&2 - $echo "$modename: \`$vinfo' is not valid version information" 1>&2 - exit 1 - fi - - # Calculate the version variables. - major= - versuffix= - verstring= - case "$version_type" in - none) ;; - - irix) - major=`expr $current - $age + 1` - versuffix="$major.$revision" - verstring="sgi$major.$revision" - - # Add in all the interfaces that we are compatible with. - loop=$revision - while test $loop != 0; do - iface=`expr $revision - $loop` - loop=`expr $loop - 1` - verstring="sgi$major.$iface:$verstring" - done - ;; - - linux) - major=.`expr $current - $age` - versuffix="$major.$age.$revision" - ;; - - osf) - major=`expr $current - $age` - versuffix=".$current.$age.$revision" - verstring="$current.$age.$revision" - - # Add in all the interfaces that we are compatible with. - loop=$age - while test $loop != 0; do - iface=`expr $current - $loop` - loop=`expr $loop - 1` - verstring="$verstring:${iface}.0" - done - - # Make executables depend on our current version. - verstring="$verstring:${current}.0" - ;; - - sunos) - major=".$current" - versuffix=".$current.$revision" - ;; - - freebsd-aout) - major=".$current" - versuffix=".$current.$revision"; - ;; - - freebsd-elf) - major=".$current" - versuffix=".$current"; - ;; - - windows) - # Like Linux, but with '-' rather than '.', since we only - # want one extension on Windows 95. - major=`expr $current - $age` - versuffix="-$major-$age-$revision" - ;; - - *) - $echo "$modename: unknown library version type \`$version_type'" 1>&2 - echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2 - exit 1 - ;; - esac - - # Clear the version info if we defaulted, and they specified a release. - if test -z "$vinfo" && test -n "$release"; then - major= - verstring="0.0" - if test "$need_version" = no; then - versuffix= - else - versuffix=".0.0" - fi - fi - - # Remove version info from name if versioning should be avoided - if test "$avoid_version" = yes && test "$need_version" = no; then - major= - versuffix= - verstring="" - fi - - # Check to see if the archive will have undefined symbols. - if test "$allow_undefined" = yes; then - if test "$allow_undefined_flag" = unsupported; then - $echo "$modename: warning: undefined symbols not allowed in $host shared libraries" 1>&2 - build_libtool_libs=no - build_old_libs=yes - fi - else - # Don't allow undefined symbols. - allow_undefined_flag="$no_undefined_flag" - fi - - dependency_libs="$deplibs" - case "$host" in - *-*-cygwin* | *-*-mingw* | *-*-os2* | *-*-beos*) - # these systems don't actually have a c library (as such)! - ;; - *) - # Add libc to deplibs on all other systems. - deplibs="$deplibs -lc" - ;; - esac - fi - - # Create the output directory, or remove our outputs if we need to. - if test -d $output_objdir; then - $show "${rm}r $output_objdir/$outputname $output_objdir/$libname.* $output_objdir/${libname}${release}.*" - $run ${rm}r $output_objdir/$outputname $output_objdir/$libname.* $output_objdir/${libname}${release}.* - else - $show "$mkdir $output_objdir" - $run $mkdir $output_objdir - status=$? - if test $status -ne 0 && test ! -d $output_objdir; then - exit $status - fi - fi - - # Now set the variables for building old libraries. - if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then - oldlibs="$oldlibs $output_objdir/$libname.$libext" - - # Transform .lo files to .o files. - oldobjs="$objs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}'$/d' -e "$lo2o" | $NL2SP` - fi - - if test "$build_libtool_libs" = yes; then - # Transform deplibs into only deplibs that can be linked in shared. - name_save=$name - libname_save=$libname - release_save=$release - versuffix_save=$versuffix - major_save=$major - # I'm not sure if I'm treating the release correctly. I think - # release should show up in the -l (ie -lgmp5) so we don't want to - # add it in twice. Is that correct? - release="" - versuffix="" - major="" - newdeplibs= - droppeddeps=no - case "$deplibs_check_method" in - pass_all) - # Don't check for shared/static. Everything works. - # This might be a little naive. We might want to check - # whether the library exists or not. But this is on - # osf3 & osf4 and I'm not really sure... Just - # implementing what was already the behaviour. - newdeplibs=$deplibs - ;; - test_compile) - # This code stresses the "libraries are programs" paradigm to its - # limits. Maybe even breaks it. We compile a program, linking it - # against the deplibs as a proxy for the library. Then we can check - # whether they linked in statically or dynamically with ldd. - $rm conftest.c - cat > conftest.c <<EOF - int main() { return 0; } -EOF - $rm conftest - $C_compiler -o conftest conftest.c $deplibs - if test $? -eq 0 ; then - ldd_output=`ldd conftest` - for i in $deplibs; do - name="`expr $i : '-l\(.*\)'`" - # If $name is empty we are operating on a -L argument. - if test "$name" != "" ; then - libname=`eval \\$echo \"$libname_spec\"` - deplib_matches=`eval \\$echo \"$library_names_spec\"` - set dummy $deplib_matches - deplib_match=$2 - if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0 ; then - newdeplibs="$newdeplibs $i" - else - droppeddeps=yes - echo - echo "*** Warning: This library needs some functionality provided by $i." - echo "*** I have the capability to make that library automatically link in when" - echo "*** you link to this library. But I can only do this if you have a" - echo "*** shared version of the library, which you do not appear to have." - fi - else - newdeplibs="$newdeplibs $i" - fi - done - else - # Error occured in the first compile. Let's try to salvage the situation: - # Compile a seperate program for each library. - for i in $deplibs; do - name="`expr $i : '-l\(.*\)'`" - # If $name is empty we are operating on a -L argument. - if test "$name" != "" ; then - $rm conftest - $C_compiler -o conftest conftest.c $i - # Did it work? - if test $? -eq 0 ; then - ldd_output=`ldd conftest` - libname=`eval \\$echo \"$libname_spec\"` - deplib_matches=`eval \\$echo \"$library_names_spec\"` - set dummy $deplib_matches - deplib_match=$2 - if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0 ; then - newdeplibs="$newdeplibs $i" - else - droppeddeps=yes - echo - echo "*** Warning: This library needs some functionality provided by $i." - echo "*** I have the capability to make that library automatically link in when" - echo "*** you link to this library. But I can only do this if you have a" - echo "*** shared version of the library, which you do not appear to have." - fi - else - droppeddeps=yes - echo - echo "*** Warning! Library $i is needed by this library but I was not able to" - echo "*** make it link in! You will probably need to install it or some" - echo "*** library that it depends on before this library will be fully" - echo "*** functional. Installing it before continuing would be even better." - fi - else - newdeplibs="$newdeplibs $i" - fi - done - fi - ;; - file_magic*) - set dummy $deplibs_check_method - file_magic_regex="`expr \"$deplibs_check_method\" : \"$2 \(.*\)\"`" - for a_deplib in $deplibs; do - name="`expr $a_deplib : '-l\(.*\)'`" - # If $name is empty we are operating on a -L argument. - if test "$name" != "" ; then - libname=`eval \\$echo \"$libname_spec\"` - for i in $lib_search_path; do - potential_libs=`ls $i/$libname[.-]* 2>/dev/null` - for potent_lib in $potential_libs; do - # Follow soft links. - if ls -lLd "$potent_lib" 2>/dev/null \ - | grep " -> " >/dev/null; then - continue - fi - # The statement above tries to avoid entering an - # endless loop below, in case of cyclic links. - # We might still enter an endless loop, since a link - # loop can be closed while we follow links, - # but so what? - potlib="$potent_lib" - while test -h "$potlib" 2>/dev/null; do - potliblink=`ls -ld $potlib | sed 's/.* -> //'` - case "$potliblink" in - [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";; - *) potlib=`$echo "X$potlib" | $Xsed -e 's,[^/]*$,,'`"$potliblink";; - esac - done - if eval $file_magic_cmd \"\$potlib\" 2>/dev/null \ - | sed 10q \ - | egrep "$file_magic_regex" > /dev/null; then - newdeplibs="$newdeplibs $a_deplib" - a_deplib="" - break 2 - fi - done - done - if test -n "$a_deplib" ; then - droppeddeps=yes - echo - echo "*** Warning: This library needs some functionality provided by $a_deplib." - echo "*** I have the capability to make that library automatically link in when" - echo "*** you link to this library. But I can only do this if you have a" - echo "*** shared version of the library, which you do not appear to have." - fi - else - # Add a -L argument. - newdeplibs="$newdeplibs $a_deplib" - fi - done # Gone through all deplibs. - ;; - none | unknown | *) - newdeplibs="" - if $echo "X $deplibs" | $Xsed -e 's/ -lc$//' \ - -e 's/ -[LR][^ ]*//g' -e 's/[ ]//g' | - grep . >/dev/null; then - echo - if test "X$deplibs_check_method" = "Xnone"; then - echo "*** Warning: inter-library dependencies are not supported in this platform." - else - echo "*** Warning: inter-library dependencies are not known to be supported." - fi - echo "*** All declared inter-library dependencies are being dropped." - droppeddeps=yes - fi - ;; - esac - versuffix=$versuffix_save - major=$major_save - release=$release_save - libname=$libname_save - name=$name_save - - if test "$droppeddeps" = yes; then - if test "$module" = yes; then - echo - echo "*** Warning: libtool could not satisfy all declared inter-library" - echo "*** dependencies of module $libname. Therefore, libtool will create" - echo "*** a static module, that should work as long as the dlopening" - echo "*** application is linked with the -dlopen flag." - if test -z "$global_symbol_pipe"; then - echo - echo "*** However, this would only work if libtool was able to extract symbol" - echo "*** lists from a program, using \`nm' or equivalent, but libtool could" - echo "*** not find such a program. So, this module is probably useless." - echo "*** \`nm' from GNU binutils and a full rebuild may help." - fi - if test "$build_old_libs" = no; then - oldlibs="$output_objdir/$libname.$libext" - build_libtool_libs=module - build_old_libs=yes - else - build_libtool_libs=no - fi - else - echo "*** The inter-library dependencies that have been dropped here will be" - echo "*** automatically added whenever a program is linked with this library" - echo "*** or is declared to -dlopen it." - fi - fi - # Done checking deplibs! - deplibs=$newdeplibs - fi - - # All the library-specific variables (install_libdir is set above). - library_names= - old_library= - dlname= - - # Test again, we may have decided not to build it any more - if test "$build_libtool_libs" = yes; then - # Get the real and link names of the library. - eval library_names=\"$library_names_spec\" - set dummy $library_names - realname="$2" - shift; shift - - if test -n "$soname_spec"; then - eval soname=\"$soname_spec\" - else - soname="$realname" - fi - - lib="$output_objdir/$realname" - for link - do - linknames="$linknames $link" - done - - # Ensure that we have .o objects for linkers which dislike .lo - # (e.g. aix) incase we are running --disable-static - for obj in $libobjs; do - oldobj=`$echo "X$obj" | $Xsed -e "$lo2o"` - if test ! -f $oldobj; then - $show "${LN_S} $obj $oldobj" - $run ${LN_S} $obj $oldobj || exit $? - fi - done - - # Use standard objects if they are pic - test -z "$pic_flag" && libobjs=`$echo "X$libobjs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` - - # Prepare the list of exported symbols - if test -z "$export_symbols"; then - if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then - $show "generating symbol list for \`$libname.la'" - export_symbols="$output_objdir/$libname.exp" - $run $rm $export_symbols - eval cmds=\"$export_symbols_cmds\" - IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' - for cmd in $cmds; do - IFS="$save_ifs" - $show "$cmd" - $run eval "$cmd" || exit $? - done - IFS="$save_ifs" - if test -n "$export_symbols_regex"; then - $show "egrep -e \"$export_symbols_regex\" \"$export_symbols\" > \"${export_symbols}T\"" - $run eval 'egrep -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' - $show "$mv \"${export_symbols}T\" \"$export_symbols\"" - $run eval '$mv "${export_symbols}T" "$export_symbols"' - fi - fi - fi - - if test -n "$export_symbols" && test -n "$include_expsyms"; then - $run eval '$echo "X$include_expsyms" | $SP2NL >> "$export_symbols"' - fi - - if test -n "$convenience"; then - if test -n "$whole_archive_flag_spec"; then - eval libobjs=\"\$libobjs $whole_archive_flag_spec\" - else - gentop="$output_objdir/${outputname}x" - $show "${rm}r $gentop" - $run ${rm}r "$gentop" - $show "mkdir $gentop" - $run mkdir "$gentop" - status=$? - if test $status -ne 0 && test ! -d "$gentop"; then - exit $status - fi - generated="$generated $gentop" - - for xlib in $convenience; do - # Extract the objects. - case "$xlib" in - [\\/]* | [A-Za-z]:[\\/]*) xabs="$xlib" ;; - *) xabs=`pwd`"/$xlib" ;; - esac - xlib=`$echo "X$xlib" | $Xsed -e 's%^.*/%%'` - xdir="$gentop/$xlib" - - $show "${rm}r $xdir" - $run ${rm}r "$xdir" - $show "mkdir $xdir" - $run mkdir "$xdir" - status=$? - if test $status -ne 0 && test ! -d "$xdir"; then - exit $status - fi - $show "(cd $xdir && $AR x $xabs)" - $run eval "(cd \$xdir && $AR x \$xabs)" || exit $? - - libobjs="$libobjs "`find $xdir -name \*.o -print -o -name \*.lo -print | $NL2SP` - done - fi - fi - - if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then - eval flag=\"$thread_safe_flag_spec\" - linkopts="$linkopts $flag" - fi - - # Do each of the archive commands. - if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then - eval cmds=\"$archive_expsym_cmds\" - else - eval cmds=\"$archive_cmds\" - fi - IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' - for cmd in $cmds; do - IFS="$save_ifs" - $show "$cmd" - $run eval "$cmd" || exit $? - done - IFS="$save_ifs" - - # Create links to the real library. - for linkname in $linknames; do - if test "$realname" != "$linkname"; then - $show "(cd $output_objdir && $rm $linkname && $LN_S $realname $linkname)" - $run eval '(cd $output_objdir && $rm $linkname && $LN_S $realname $linkname)' || exit $? - fi - done - - # If -module or -export-dynamic was specified, set the dlname. - if test "$module" = yes || test "$export_dynamic" = yes; then - # On all known operating systems, these are identical. - dlname="$soname" - fi - fi - ;; - - *.lo | *.o | *.obj) - if test -n "$link_against_libtool_libs"; then - $echo "$modename: error: cannot link libtool libraries into objects" 1>&2 - exit 1 - fi - - if test -n "$deplibs"; then - $echo "$modename: warning: \`-l' and \`-L' are ignored for objects" 1>&2 - fi - - if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then - $echo "$modename: warning: \`-dlopen' is ignored for objects" 1>&2 - fi - - if test -n "$rpath"; then - $echo "$modename: warning: \`-rpath' is ignored for objects" 1>&2 - fi - - if test -n "$xrpath"; then - $echo "$modename: warning: \`-R' is ignored for objects" 1>&2 - fi - - if test -n "$vinfo"; then - $echo "$modename: warning: \`-version-info' is ignored for objects" 1>&2 - fi - - if test -n "$release"; then - $echo "$modename: warning: \`-release' is ignored for objects" 1>&2 - fi - - case "$output" in - *.lo) - if test -n "$objs"; then - $echo "$modename: cannot build library object \`$output' from non-libtool objects" 1>&2 - exit 1 - fi - libobj="$output" - obj=`$echo "X$output" | $Xsed -e "$lo2o"` - ;; - *) - libobj= - obj="$output" - ;; - esac - - # Delete the old objects. - $run $rm $obj $libobj - - # Objects from convenience libraries. This assumes - # single-version convenience libraries. Whenever we create - # different ones for PIC/non-PIC, this we'll have to duplicate - # the extraction. - reload_conv_objs= - gentop= - # reload_cmds runs $LD directly, so let us get rid of - # -Wl from whole_archive_flag_spec - wl= - - if test -n "$convenience"; then - if test -n "$whole_archive_flag_spec"; then - eval reload_conv_objs=\"\$reload_objs $whole_archive_flag_spec\" - else - gentop="$output_objdir/${obj}x" - $show "${rm}r $gentop" - $run ${rm}r "$gentop" - $show "mkdir $gentop" - $run mkdir "$gentop" - status=$? - if test $status -ne 0 && test ! -d "$gentop"; then - exit $status - fi - generated="$generated $gentop" - - for xlib in $convenience; do - # Extract the objects. - case "$xlib" in - [\\/]* | [A-Za-z]:[\\/]*) xabs="$xlib" ;; - *) xabs=`pwd`"/$xlib" ;; - esac - xlib=`$echo "X$xlib" | $Xsed -e 's%^.*/%%'` - xdir="$gentop/$xlib" - - $show "${rm}r $xdir" - $run ${rm}r "$xdir" - $show "mkdir $xdir" - $run mkdir "$xdir" - status=$? - if test $status -ne 0 && test ! -d "$xdir"; then - exit $status - fi - $show "(cd $xdir && $AR x $xabs)" - $run eval "(cd \$xdir && $AR x \$xabs)" || exit $? - - reload_conv_objs="$reload_objs "`find $xdir -name \*.o -print -o -name \*.lo -print | $NL2SP` - done - fi - fi - - # Create the old-style object. - reload_objs="$objs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}$'/d' -e '/\.lib$/d' -e "$lo2o" | $NL2SP`" $reload_conv_objs" - - output="$obj" - eval cmds=\"$reload_cmds\" - IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' - for cmd in $cmds; do - IFS="$save_ifs" - $show "$cmd" - $run eval "$cmd" || exit $? - done - IFS="$save_ifs" - - # Exit if we aren't doing a library object file. - if test -z "$libobj"; then - if test -n "$gentop"; then - $show "${rm}r $gentop" - $run ${rm}r $gentop - fi - - exit 0 - fi - - if test "$build_libtool_libs" != yes; then - if test -n "$gentop"; then - $show "${rm}r $gentop" - $run ${rm}r $gentop - fi - - # Create an invalid libtool object if no PIC, so that we don't - # accidentally link it into a program. - $show "echo timestamp > $libobj" - $run eval "echo timestamp > $libobj" || exit $? - exit 0 - fi - - if test -n "$pic_flag"; then - # Only do commands if we really have different PIC objects. - reload_objs="$libobjs $reload_conv_objs" - output="$libobj" - eval cmds=\"$reload_cmds\" - IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' - for cmd in $cmds; do - IFS="$save_ifs" - $show "$cmd" - $run eval "$cmd" || exit $? - done - IFS="$save_ifs" - else - # Just create a symlink. - $show $rm $libobj - $run $rm $libobj - $show "$LN_S $obj $libobj" - $run $LN_S $obj $libobj || exit $? - fi - - if test -n "$gentop"; then - $show "${rm}r $gentop" - $run ${rm}r $gentop - fi - - exit 0 - ;; - - # Anything else should be a program. - *) - if test -n "$vinfo"; then - $echo "$modename: warning: \`-version-info' is ignored for programs" 1>&2 - fi - - if test -n "$release"; then - $echo "$modename: warning: \`-release' is ignored for programs" 1>&2 - fi - - if test "$preload" = yes; then - if test "$dlopen" = unknown && test "$dlopen_self" = unknown && - test "$dlopen_self_static" = unknown; then - $echo "$modename: warning: \`AC_LIBTOOL_DLOPEN' not used. Assuming no dlopen support." - fi - fi - - if test -n "$rpath$xrpath"; then - # If the user specified any rpath flags, then add them. - for libdir in $rpath $xrpath; do - # This is the magic to use -rpath. - case "$compile_rpath " in - *" $libdir "*) ;; - *) compile_rpath="$compile_rpath $libdir" ;; - esac - case "$finalize_rpath " in - *" $libdir "*) ;; - *) finalize_rpath="$finalize_rpath $libdir" ;; - esac - done - fi - - # Now hardcode the library paths - rpath= - hardcode_libdirs= - for libdir in $compile_rpath $finalize_rpath; do - if test -n "$hardcode_libdir_flag_spec"; then - if test -n "$hardcode_libdir_separator"; then - if test -z "$hardcode_libdirs"; then - hardcode_libdirs="$libdir" - else - # Just accumulate the unique libdirs. - case "$hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator" in - *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) - ;; - *) - hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" - ;; - esac - fi - else - eval flag=\"$hardcode_libdir_flag_spec\" - rpath="$rpath $flag" - fi - elif test -n "$runpath_var"; then - case "$perm_rpath " in - *" $libdir "*) ;; - *) perm_rpath="$perm_rpath $libdir" ;; - esac - fi - done - # Substitute the hardcoded libdirs into the rpath. - if test -n "$hardcode_libdir_separator" && - test -n "$hardcode_libdirs"; then - libdir="$hardcode_libdirs" - eval rpath=\" $hardcode_libdir_flag_spec\" - fi - compile_rpath="$rpath" - - rpath= - hardcode_libdirs= - for libdir in $finalize_rpath; do - if test -n "$hardcode_libdir_flag_spec"; then - if test -n "$hardcode_libdir_separator"; then - if test -z "$hardcode_libdirs"; then - hardcode_libdirs="$libdir" - else - # Just accumulate the unique libdirs. - case "$hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator" in - *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) - ;; - *) - hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" - ;; - esac - fi - else - eval flag=\"$hardcode_libdir_flag_spec\" - rpath="$rpath $flag" - fi - elif test -n "$runpath_var"; then - case "$finalize_perm_rpath " in - *" $libdir "*) ;; - *) finalize_perm_rpath="$finalize_perm_rpath $libdir" ;; - esac - fi - done - # Substitute the hardcoded libdirs into the rpath. - if test -n "$hardcode_libdir_separator" && - test -n "$hardcode_libdirs"; then - libdir="$hardcode_libdirs" - eval rpath=\" $hardcode_libdir_flag_spec\" - fi - finalize_rpath="$rpath" - - output_objdir=`$echo "X$output" | $Xsed -e 's%/[^/]*$%%'` - if test "X$output_objdir" = "X$output"; then - output_objdir="$objdir" - else - output_objdir="$output_objdir/$objdir" - fi - - # Create the binary in the object directory, then wrap it. - if test ! -d $output_objdir; then - $show "$mkdir $output_objdir" - $run $mkdir $output_objdir - status=$? - if test $status -ne 0 && test ! -d $output_objdir; then - exit $status - fi - fi - - if test -n "$libobjs" && test "$build_old_libs" = yes; then - # Transform all the library objects into standard objects. - compile_command=`$echo "X$compile_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` - finalize_command=`$echo "X$finalize_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` - fi - - dlsyms= - if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then - if test -n "$NM" && test -n "$global_symbol_pipe"; then - dlsyms="${outputname}S.c" - else - $echo "$modename: not configured to extract global symbols from dlpreopened files" 1>&2 - fi - fi - - if test -n "$dlsyms"; then - case "$dlsyms" in - "") ;; - *.c) - # Discover the nlist of each of the dlfiles. - nlist="$output_objdir/${outputname}.nm" - - $show "$rm $nlist ${nlist}S ${nlist}T" - $run $rm "$nlist" "${nlist}S" "${nlist}T" - - # Parse the name list into a source file. - $show "creating $output_objdir/$dlsyms" - - test -z "$run" && $echo > "$output_objdir/$dlsyms" "\ -/* $dlsyms - symbol resolution table for \`$outputname' dlsym emulation. */ -/* Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP */ - -#ifdef __cplusplus -extern \"C\" { -#endif - -/* Prevent the only kind of declaration conflicts we can make. */ -#define lt_preloaded_symbols some_other_symbol - -/* External symbol declarations for the compiler. */\ -" - - if test "$dlself" = yes; then - $show "generating symbol list for \`$output'" - - test -z "$run" && $echo ': @PROGRAM@ ' > "$nlist" - - # Add our own program objects to the symbol list. - progfiles=`$echo "X$objs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` - for arg in $progfiles; do - $show "extracting global C symbols from \`$arg'" - $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'" - done - - if test -n "$exclude_expsyms"; then - $run eval 'egrep -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T' - $run eval '$mv "$nlist"T "$nlist"' - fi - - if test -n "$export_symbols_regex"; then - $run eval 'egrep -e "$export_symbols_regex" "$nlist" > "$nlist"T' - $run eval '$mv "$nlist"T "$nlist"' - fi - - # Prepare the list of exported symbols - if test -z "$export_symbols"; then - export_symbols="$output_objdir/$output.exp" - $run $rm $export_symbols - $run eval "sed -n -e '/^: @PROGRAM@$/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"' - else - $run eval "sed -e 's/\([][.*^$]\)/\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$output.exp"' - $run eval 'grep -f "$output_objdir/$output.exp" < "$nlist" > "$nlist"T' - $run eval 'mv "$nlist"T "$nlist"' - fi - fi - - for arg in $dlprefiles; do - $show "extracting global C symbols from \`$arg'" - name=`echo "$arg" | sed -e 's%^.*/%%'` - $run eval 'echo ": $name " >> "$nlist"' - $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'" - done - - if test -z "$run"; then - # Make sure we have at least an empty file. - test -f "$nlist" || : > "$nlist" - - if test -n "$exclude_expsyms"; then - egrep -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T - $mv "$nlist"T "$nlist" - fi - - # Try sorting and uniquifying the output. - if grep -v "^: " < "$nlist" | sort +2 | uniq > "$nlist"S; then - : - else - grep -v "^: " < "$nlist" > "$nlist"S - fi - - if test -f "$nlist"S; then - eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$dlsyms"' - else - echo '/* NONE */' >> "$output_objdir/$dlsyms" - fi - - $echo >> "$output_objdir/$dlsyms" "\ - -#undef lt_preloaded_symbols - -#if defined (__STDC__) && __STDC__ -# define lt_ptr_t void * -#else -# define lt_ptr_t char * -# define const -#endif - -/* The mapping between symbol names and symbols. */ -const struct { - const char *name; - lt_ptr_t address; -} -lt_preloaded_symbols[] = -{\ -" - - sed -n -e 's/^: \([^ ]*\) $/ {\"\1\", (lt_ptr_t) 0},/p' \ - -e 's/^. \([^ ]*\) \([^ ]*\)$/ {"\2", (lt_ptr_t) \&\2},/p' \ - < "$nlist" >> "$output_objdir/$dlsyms" - - $echo >> "$output_objdir/$dlsyms" "\ - {0, (lt_ptr_t) 0} -}; - -/* This works around a problem in FreeBSD linker */ -#ifdef FREEBSD_WORKAROUND -static const void *lt_preloaded_setup() { - return lt_preloaded_symbols; -} -#endif - -#ifdef __cplusplus -} -#endif\ -" - fi - - pic_flag_for_symtable= - case "$host" in - # compiling the symbol table file with pic_flag works around - # a FreeBSD bug that causes programs to crash when -lm is - # linked before any other PIC object. But we must not use - # pic_flag when linking with -static. The problem exists in - # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1. - *-*-freebsd2*|*-*-freebsd3.0*) - case "$compile_command " in - *" -static "*) ;; - *) pic_flag_for_symtable=" $pic_flag -DPIC -DFREEBSD_WORKAROUND";; - esac - esac - - # Now compile the dynamic symbol file. - $show "(cd $output_objdir && $C_compiler -c$no_builtin_flag$pic_flag_for_symtable \"$dlsyms\")" - $run eval '(cd $output_objdir && $C_compiler -c$no_builtin_flag$pic_flag_for_symtable "$dlsyms")' || exit $? - - # Clean up the generated files. - $show "$rm $output_objdir/$dlsyms $nlist ${nlist}S ${nlist}T" - $run $rm "$output_objdir/$dlsyms" "$nlist" "${nlist}S" "${nlist}T" - - # Transform the symbol file into the correct name. - compile_command=`$echo "X$compile_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"` - finalize_command=`$echo "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"` - ;; - *) - $echo "$modename: unknown suffix for \`$dlsyms'" 1>&2 - exit 1 - ;; - esac - else - # We keep going just in case the user didn't refer to - # lt_preloaded_symbols. The linker will fail if global_symbol_pipe - # really was required. - - # Nullify the symbol file. - compile_command=`$echo "X$compile_command" | $Xsed -e "s% @SYMFILE@%%"` - finalize_command=`$echo "X$finalize_command" | $Xsed -e "s% @SYMFILE@%%"` - fi - - if test -z "$link_against_libtool_libs" || test "$build_libtool_libs" != yes; then - # Replace the output file specification. - compile_command=`$echo "X$compile_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'` - link_command="$compile_command$compile_rpath" - - # We have no uninstalled library dependencies, so finalize right now. - $show "$link_command" - $run eval "$link_command" - status=$? - - # Delete the generated files. - if test -n "$dlsyms"; then - $show "$rm $output_objdir/${outputname}S.${objext}" - $run $rm "$output_objdir/${outputname}S.${objext}" - fi - - exit $status - fi - - if test -n "$shlibpath_var"; then - # We should set the shlibpath_var - rpath= - for dir in $temp_rpath; do - case "$dir" in - [\\/]* | [A-Za-z]:[\\/]*) - # Absolute path. - rpath="$rpath$dir:" - ;; - *) - # Relative path: add a thisdir entry. - rpath="$rpath\$thisdir/$dir:" - ;; - esac - done - temp_rpath="$rpath" - fi - - if test -n "$compile_shlibpath$finalize_shlibpath"; then - compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command" - fi - if test -n "$finalize_shlibpath"; then - finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command" - fi - - compile_var= - finalize_var= - if test -n "$runpath_var"; then - if test -n "$perm_rpath"; then - # We should set the runpath_var. - rpath= - for dir in $perm_rpath; do - rpath="$rpath$dir:" - done - compile_var="$runpath_var=\"$rpath\$$runpath_var\" " - fi - if test -n "$finalize_perm_rpath"; then - # We should set the runpath_var. - rpath= - for dir in $finalize_perm_rpath; do - rpath="$rpath$dir:" - done - finalize_var="$runpath_var=\"$rpath\$$runpath_var\" " - fi - fi - - if test "$hardcode_action" = relink; then - # Fast installation is not supported - link_command="$compile_var$compile_command$compile_rpath" - relink_command="$finalize_var$finalize_command$finalize_rpath" - - $echo "$modename: warning: this platform does not like uninstalled shared libraries" 1>&2 - $echo "$modename: \`$output' will be relinked during installation" 1>&2 - else - if test "$fast_install" != no; then - link_command="$finalize_var$compile_command$finalize_rpath" - if test "$fast_install" = yes; then - relink_command=`$echo "X$compile_var$compile_command$compile_rpath" | $Xsed -e 's%@OUTPUT@%\$progdir/\$file%g'` - else - # fast_install is set to needless - relink_command= - fi - else - link_command="$compile_var$compile_command$compile_rpath" - relink_command="$finalize_var$finalize_command$finalize_rpath" - fi - fi - - # Replace the output file specification. - link_command=`$echo "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'` - - # Delete the old output files. - $run $rm $output $output_objdir/$outputname $output_objdir/lt-$outputname - - $show "$link_command" - $run eval "$link_command" || exit $? - - # Now create the wrapper script. - $show "creating $output" - - # Quote the relink command for shipping. - if test -n "$relink_command"; then - relink_command=`$echo "X$relink_command" | $Xsed -e "$sed_quote_subst"` - fi - - # Quote $echo for shipping. - if test "X$echo" = "X$SHELL $0 --fallback-echo"; then - case "$0" in - [\\/]* | [A-Za-z]:[\\/]*) qecho="$SHELL $0 --fallback-echo";; - *) qecho="$SHELL `pwd`/$0 --fallback-echo";; - esac - qecho=`$echo "X$qecho" | $Xsed -e "$sed_quote_subst"` - else - qecho=`$echo "X$echo" | $Xsed -e "$sed_quote_subst"` - fi - - # Only actually do things if our run command is non-null. - if test -z "$run"; then - # win32 will think the script is a binary if it has - # a .exe suffix, so we strip it off here. - case $output in - *.exe) output=`echo $output|sed 's,.exe$,,'` ;; - esac - $rm $output - trap "$rm $output; exit 1" 1 2 15 - - $echo > $output "\ -#! $SHELL - -# $output - temporary wrapper script for $objdir/$outputname -# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP -# -# The $output program cannot be directly executed until all the libtool -# libraries that it depends on are installed. -# -# This wrapper script should never be moved out of the build directory. -# If it is, it will not operate correctly. - -# Sed substitution that helps us do robust quoting. It backslashifies -# metacharacters that are still active within double-quoted strings. -Xsed='sed -e 1s/^X//' -sed_quote_subst='$sed_quote_subst' - -# The HP-UX ksh and POSIX shell print the target directory to stdout -# if CDPATH is set. -if test \"\${CDPATH+set}\" = set; then CDPATH=; export CDPATH; fi - -relink_command=\"$relink_command\" - -# This environment variable determines our operation mode. -if test \"\$libtool_install_magic\" = \"$magic\"; then - # install mode needs the following variable: - link_against_libtool_libs='$link_against_libtool_libs' -else - # When we are sourced in execute mode, \$file and \$echo are already set. - if test \"\$libtool_execute_magic\" != \"$magic\"; then - echo=\"$qecho\" - file=\"\$0\" - # Make sure echo works. - if test \"X\$1\" = X--no-reexec; then - # Discard the --no-reexec flag, and continue. - shift - elif test \"X\`(\$echo '\t') 2>/dev/null\`\" = 'X\t'; then - # Yippee, \$echo works! - : - else - # Restart under the correct shell, and then maybe \$echo will work. - exec $SHELL \"\$0\" --no-reexec \${1+\"\$@\"} - fi - fi\ -" - $echo >> $output "\ - - # Find the directory that this script lives in. - thisdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*$%%'\` - test \"x\$thisdir\" = \"x\$file\" && thisdir=. - - # Follow symbolic links until we get to the real thisdir. - file=\`ls -ld \"\$file\" | sed -n 's/.*-> //p'\` - while test -n \"\$file\"; do - destdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*\$%%'\` - - # If there was a directory component, then change thisdir. - if test \"x\$destdir\" != \"x\$file\"; then - case \"\$destdir\" in - [\\/]* | [A-Za-z]:[\\/]*) thisdir=\"\$destdir\" ;; - *) thisdir=\"\$thisdir/\$destdir\" ;; - esac - fi - - file=\`\$echo \"X\$file\" | \$Xsed -e 's%^.*/%%'\` - file=\`ls -ld \"\$thisdir/\$file\" | sed -n 's/.*-> //p'\` - done - - # Try to get the absolute directory name. - absdir=\`cd \"\$thisdir\" && pwd\` - test -n \"\$absdir\" && thisdir=\"\$absdir\" -" - - if test "$fast_install" = yes; then - echo >> $output "\ - program=lt-'$outputname' - progdir=\"\$thisdir/$objdir\" - - if test ! -f \"\$progdir/\$program\" || \\ - { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | sed 1q\`; \\ - test \"X\$file\" != \"X\$progdir/\$program\"; }; then - - file=\"\$\$-\$program\" - - if test ! -d \"\$progdir\"; then - $mkdir \"\$progdir\" - else - $rm \"\$progdir/\$file\" - fi" - - echo >> $output "\ - - # relink executable if necessary - if test -n \"\$relink_command\"; then - if (cd \"\$thisdir\" && eval \$relink_command); then : - else - $rm \"\$progdir/\$file\" - exit 1 - fi - fi - - $mv \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null || - { $rm \"\$progdir/\$program\"; - $mv \"\$progdir/\$file\" \"\$progdir/\$program\"; } - $rm \"\$progdir/\$file\" - fi" - else - echo >> $output "\ - program='$outputname$exeext' - progdir=\"\$thisdir/$objdir\" -" - fi - - echo >> $output "\ - - if test -f \"\$progdir/\$program\"; then" - - # Export our shlibpath_var if we have one. - if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then - $echo >> $output "\ - # Add our own library path to $shlibpath_var - $shlibpath_var=\"$temp_rpath\$$shlibpath_var\" - - # Some systems cannot cope with colon-terminated $shlibpath_var - # The second colon is a workaround for a bug in BeOS R4 sed - $shlibpath_var=\`\$echo \"X\$$shlibpath_var\" | \$Xsed -e 's/::*\$//'\` - - export $shlibpath_var -" - fi - - # fixup the dll searchpath if we need to. - if test -n "$dllsearchpath"; then - $echo >> $output "\ - # Add the dll search path components to the executable PATH - PATH=$dllsearchpath:\$PATH -" - fi - - $echo >> $output "\ - if test \"\$libtool_execute_magic\" != \"$magic\"; then - # Run the actual program with our arguments. -" - case $host in - *-*-cygwin* | *-*-mingw | *-*-os2*) - # win32 systems need to use the prog path for dll - # lookup to work - $echo >> $output "\ - exec \$progdir\\\\\$program \${1+\"\$@\"} -" - ;; - *) - $echo >> $output "\ - # Export the path to the program. - PATH=\"\$progdir:\$PATH\" - export PATH - - exec \$program \${1+\"\$@\"} -" - ;; - esac - $echo >> $output "\ - \$echo \"\$0: cannot exec \$program \${1+\"\$@\"}\" - exit 1 - fi - else - # The program doesn't exist. - \$echo \"\$0: error: \$progdir/\$program does not exist\" 1>&2 - \$echo \"This script is just a wrapper for \$program.\" 1>&2 - echo \"See the $PACKAGE documentation for more information.\" 1>&2 - exit 1 - fi -fi\ -" - chmod +x $output - fi - exit 0 - ;; - esac - - # See if we need to build an old-fashioned archive. - for oldlib in $oldlibs; do - - if test "$build_libtool_libs" = convenience; then - oldobjs="$libobjs_save" - addlibs="$convenience" - build_libtool_libs=no - else - if test "$build_libtool_libs" = module; then - oldobjs="$libobjs_save" - build_libtool_libs=no - else - oldobjs="$objs "`$echo "X$libobjs_save" | $SP2NL | $Xsed -e '/\.'${libext}'$/d' -e '/\.lib$/d' -e "$lo2o" | $NL2SP` - fi - addlibs="$old_convenience" - fi - - if test -n "$addlibs"; then - gentop="$output_objdir/${outputname}x" - $show "${rm}r $gentop" - $run ${rm}r "$gentop" - $show "mkdir $gentop" - $run mkdir "$gentop" - status=$? - if test $status -ne 0 && test ! -d "$gentop"; then - exit $status - fi - generated="$generated $gentop" - - # Add in members from convenience archives. - for xlib in $addlibs; do - # Extract the objects. - case "$xlib" in - [\\/]* | [A-Za-z]:[\\/]*) xabs="$xlib" ;; - *) xabs=`pwd`"/$xlib" ;; - esac - xlib=`$echo "X$xlib" | $Xsed -e 's%^.*/%%'` - xdir="$gentop/$xlib" - - $show "${rm}r $xdir" - $run ${rm}r "$xdir" - $show "mkdir $xdir" - $run mkdir "$xdir" - status=$? - if test $status -ne 0 && test ! -d "$xdir"; then - exit $status - fi - $show "(cd $xdir && $AR x $xabs)" - $run eval "(cd \$xdir && $AR x \$xabs)" || exit $? - - oldobjs="$oldobjs "`find $xdir -name \*.${objext} -print -o -name \*.lo -print | $NL2SP` - done - fi - - # Do each command in the archive commands. - if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then - eval cmds=\"$old_archive_from_new_cmds\" - else - # Ensure that we have .o objects in place incase we decided - # not to build a shared library, and have fallen back to building - # static libs even though --disable-static was passed! - for oldobj in $oldobjs; do - if test ! -f $oldobj; then - obj=`$echo "X$oldobj" | $Xsed -e "$o2lo"` - $show "${LN_S} $obj $oldobj" - $run ${LN_S} $obj $oldobj || exit $? - fi - done - - eval cmds=\"$old_archive_cmds\" - fi - IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' - for cmd in $cmds; do - IFS="$save_ifs" - $show "$cmd" - $run eval "$cmd" || exit $? - done - IFS="$save_ifs" - done - - if test -n "$generated"; then - $show "${rm}r$generated" - $run ${rm}r$generated - fi - - # Now create the libtool archive. - case "$output" in - *.la) - old_library= - test "$build_old_libs" = yes && old_library="$libname.$libext" - $show "creating $output" - - if test -n "$xrpath"; then - temp_xrpath= - for libdir in $xrpath; do - temp_xrpath="$temp_xrpath -R$libdir" - done - dependency_libs="$temp_xrpath $dependency_libs" - fi - - # Only create the output if not a dry run. - if test -z "$run"; then - for installed in no yes; do - if test "$installed" = yes; then - if test -z "$install_libdir"; then - break - fi - output="$output_objdir/$outputname"i - fi - $rm $output - $echo > $output "\ -# $outputname - a libtool library file -# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP -# -# Please DO NOT delete this file! -# It is necessary for linking the library. - -# The name that we can dlopen(3). -dlname='$dlname' - -# Names of this library. -library_names='$library_names' - -# The name of the static archive. -old_library='$old_library' - -# Libraries that this one depends upon. -dependency_libs='$dependency_libs' - -# Version information for $libname. -current=$current -age=$age -revision=$revision - -# Is this an already installed library? -installed=$installed - -# Directory that this library needs to be installed in: -libdir='$install_libdir'\ -" - done - fi - - # Do a symbolic link so that the libtool archive can be found in - # LD_LIBRARY_PATH before the program is installed. - $show "(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)" - $run eval "(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)" || exit $? - ;; - esac - exit 0 - ;; - - # libtool install mode - install) - modename="$modename: install" - - # There may be an optional sh(1) argument at the beginning of - # install_prog (especially on Windows NT). - if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh || test "$nonopt" = ./shtool;then - # Aesthetically quote it. - arg=`$echo "X$nonopt" | $Xsed -e "$sed_quote_subst"` - case "$arg" in - *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) - arg="\"$arg\"" - ;; - esac - install_prog="$arg " - arg="$1" - shift - else - install_prog= - arg="$nonopt" - fi - - # The real first argument should be the name of the installation program. - # Aesthetically quote it. - arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` - case "$arg" in - *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) - arg="\"$arg\"" - ;; - esac - install_prog="$install_prog$arg" - - # We need to accept at least all the BSD install flags. - dest= - files= - opts= - prev= - install_type= - isdir=no - stripme= - for arg - do - if test -n "$dest"; then - files="$files $dest" - dest="$arg" - continue - fi - - case "$arg" in - -d) isdir=yes ;; - -f) prev="-f" ;; - -g) prev="-g" ;; - -m) prev="-m" ;; - -o) prev="-o" ;; - -s) - stripme=" -s" - continue - ;; - -*) ;; - - *) - # If the previous option needed an argument, then skip it. - if test -n "$prev"; then - prev= - else - dest="$arg" - continue - fi - ;; - esac - - # Aesthetically quote the argument. - arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` - case "$arg" in - *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) - arg="\"$arg\"" - ;; - esac - install_prog="$install_prog $arg" - done - - if test -z "$install_prog"; then - $echo "$modename: you must specify an install program" 1>&2 - $echo "$help" 1>&2 - exit 1 - fi - - if test -n "$prev"; then - $echo "$modename: the \`$prev' option requires an argument" 1>&2 - $echo "$help" 1>&2 - exit 1 - fi - - if test -z "$files"; then - if test -z "$dest"; then - $echo "$modename: no file or destination specified" 1>&2 - else - $echo "$modename: you must specify a destination" 1>&2 - fi - $echo "$help" 1>&2 - exit 1 - fi - - # Strip any trailing slash from the destination. - dest=`$echo "X$dest" | $Xsed -e 's%/$%%'` - - # Check to see that the destination is a directory. - test -d "$dest" && isdir=yes - if test "$isdir" = yes; then - destdir="$dest" - destname= - else - destdir=`$echo "X$dest" | $Xsed -e 's%/[^/]*$%%'` - test "X$destdir" = "X$dest" && destdir=. - destname=`$echo "X$dest" | $Xsed -e 's%^.*/%%'` - - # Not a directory, so check to see that there is only one file specified. - set dummy $files - if test $# -gt 2; then - $echo "$modename: \`$dest' is not a directory" 1>&2 - $echo "$help" 1>&2 - exit 1 - fi - fi - case "$destdir" in - [\\/]* | [A-Za-z]:[\\/]*) ;; - *) - for file in $files; do - case "$file" in - *.lo) ;; - *) - $echo "$modename: \`$destdir' must be an absolute directory name" 1>&2 - $echo "$help" 1>&2 - exit 1 - ;; - esac - done - ;; - esac - - # This variable tells wrapper scripts just to set variables rather - # than running their programs. - libtool_install_magic="$magic" - - staticlibs= - future_libdirs= - current_libdirs= - for file in $files; do - - # Do each installation. - case "$file" in - *.a | *.lib) - # Do the static libraries later. - staticlibs="$staticlibs $file" - ;; - - *.la) - # Check to see that this really is a libtool archive. - if (sed -e '2q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then : - else - $echo "$modename: \`$file' is not a valid libtool archive" 1>&2 - $echo "$help" 1>&2 - exit 1 - fi - - library_names= - old_library= - # If there is no directory component, then add one. - case "$file" in - */* | *\\*) . $file ;; - *) . ./$file ;; - esac - - # Add the libdir to current_libdirs if it is the destination. - if test "X$destdir" = "X$libdir"; then - case "$current_libdirs " in - *" $libdir "*) ;; - *) current_libdirs="$current_libdirs $libdir" ;; - esac - else - # Note the libdir as a future libdir. - case "$future_libdirs " in - *" $libdir "*) ;; - *) future_libdirs="$future_libdirs $libdir" ;; - esac - fi - - dir="`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`/" - test "X$dir" = "X$file/" && dir= - dir="$dir$objdir" - - # See the names of the shared library. - set dummy $library_names - if test -n "$2"; then - realname="$2" - shift - shift - - # Install the shared library and build the symlinks. - $show "$install_prog $dir/$realname $destdir/$realname" - $run eval "$install_prog $dir/$realname $destdir/$realname" || exit $? - - if test $# -gt 0; then - # Delete the old symlinks, and create new ones. - for linkname - do - if test "$linkname" != "$realname"; then - $show "(cd $destdir && $rm $linkname && $LN_S $realname $linkname)" - $run eval "(cd $destdir && $rm $linkname && $LN_S $realname $linkname)" - fi - done - fi - - # Do each command in the postinstall commands. - lib="$destdir/$realname" - eval cmds=\"$postinstall_cmds\" - IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' - for cmd in $cmds; do - IFS="$save_ifs" - $show "$cmd" - $run eval "$cmd" || exit $? - done - IFS="$save_ifs" - fi - - # Install the pseudo-library for information purposes. - name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` - instname="$dir/$name"i - $show "$install_prog $instname $destdir/$name" - $run eval "$install_prog $instname $destdir/$name" || exit $? - - # Maybe install the static library, too. - test -n "$old_library" && staticlibs="$staticlibs $dir/$old_library" - ;; - - *.lo) - # Install (i.e. copy) a libtool object. - - # Figure out destination file name, if it wasn't already specified. - if test -n "$destname"; then - destfile="$destdir/$destname" - else - destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'` - destfile="$destdir/$destfile" - fi - - # Deduce the name of the destination old-style object file. - case "$destfile" in - *.lo) - staticdest=`$echo "X$destfile" | $Xsed -e "$lo2o"` - ;; - *.o | *.obj) - staticdest="$destfile" - destfile= - ;; - *) - $echo "$modename: cannot copy a libtool object to \`$destfile'" 1>&2 - $echo "$help" 1>&2 - exit 1 - ;; - esac - - # Install the libtool object if requested. - if test -n "$destfile"; then - $show "$install_prog $file $destfile" - $run eval "$install_prog $file $destfile" || exit $? - fi - - # Install the old object if enabled. - if test "$build_old_libs" = yes; then - # Deduce the name of the old-style object file. - staticobj=`$echo "X$file" | $Xsed -e "$lo2o"` - - $show "$install_prog $staticobj $staticdest" - $run eval "$install_prog \$staticobj \$staticdest" || exit $? - fi - exit 0 - ;; - - *) - # Figure out destination file name, if it wasn't already specified. - if test -n "$destname"; then - destfile="$destdir/$destname" - else - destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'` - destfile="$destdir/$destfile" - fi - - # Do a test to see if this is really a libtool program. - if (sed -e '4q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then - link_against_libtool_libs= - relink_command= - - # If there is no directory component, then add one. - case "$file" in - */* | *\\*) . $file ;; - *) . ./$file ;; - esac - - # Check the variables that should have been set. - if test -z "$link_against_libtool_libs"; then - $echo "$modename: invalid libtool wrapper script \`$file'" 1>&2 - exit 1 - fi - - finalize=yes - for lib in $link_against_libtool_libs; do - # Check to see that each library is installed. - libdir= - if test -f "$lib"; then - # If there is no directory component, then add one. - case "$lib" in - */* | *\\*) . $lib ;; - *) . ./$lib ;; - esac - fi - libfile="$libdir/`$echo "X$lib" | $Xsed -e 's%^.*/%%g'`" - if test -n "$libdir" && test ! -f "$libfile"; then - $echo "$modename: warning: \`$lib' has not been installed in \`$libdir'" 1>&2 - finalize=no - fi - done - - outputname= - if test "$fast_install" = no && test -n "$relink_command"; then - if test "$finalize" = yes && test -z "$run"; then - tmpdir="/tmp" - test -n "$TMPDIR" && tmpdir="$TMPDIR" - tmpdir="$tmpdir/libtool-$$" - if $mkdir -p "$tmpdir" && chmod 700 "$tmpdir"; then : - else - $echo "$modename: error: cannot create temporary directory \`$tmpdir'" 1>&2 - continue - fi - outputname="$tmpdir/$file" - # Replace the output file specification. - relink_command=`$echo "X$relink_command" | $Xsed -e 's%@OUTPUT@%'"$outputname"'%g'` - - $show "$relink_command" - if $run eval "$relink_command"; then : - else - $echo "$modename: error: relink \`$file' with the above command before installing it" 1>&2 - ${rm}r "$tmpdir" - continue - fi - file="$outputname" - else - $echo "$modename: warning: cannot relink \`$file'" 1>&2 - fi - else - # Install the binary that we compiled earlier. - file=`$echo "X$file" | $Xsed -e "s%\([^/]*\)$%$objdir/\1%"` - fi - fi - - $show "$install_prog$stripme $file $destfile" - $run eval "$install_prog\$stripme \$file \$destfile" || exit $? - test -n "$outputname" && ${rm}r "$tmpdir" - ;; - esac - done - - for file in $staticlibs; do - name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` - - # Set up the ranlib parameters. - oldlib="$destdir/$name" - - $show "$install_prog $file $oldlib" - $run eval "$install_prog \$file \$oldlib" || exit $? - - # Do each command in the postinstall commands. - eval cmds=\"$old_postinstall_cmds\" - IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' - for cmd in $cmds; do - IFS="$save_ifs" - $show "$cmd" - $run eval "$cmd" || exit $? - done - IFS="$save_ifs" - done - - if test -n "$future_libdirs"; then - $echo "$modename: warning: remember to run \`$progname --finish$future_libdirs'" 1>&2 - fi - - if test -n "$current_libdirs"; then - # Maybe just do a dry run. - test -n "$run" && current_libdirs=" -n$current_libdirs" - exit 0 #$current_libdirs - exit 1 - fi - - exit 0 - ;; - - # libtool finish mode - finish) - modename="$modename: finish" - libdirs="$nonopt" - admincmds= - - if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then - for dir - do - libdirs="$libdirs $dir" - done - - for libdir in $libdirs; do - if test -n "$finish_cmds"; then - # Do each command in the finish commands. - eval cmds=\"$finish_cmds\" - IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' - for cmd in $cmds; do - IFS="$save_ifs" - $show "$cmd" - $run eval "$cmd" || admincmds="$admincmds - $cmd" - done - IFS="$save_ifs" - fi - if test -n "$finish_eval"; then - # Do the single finish_eval. - eval cmds=\"$finish_eval\" - $run eval "$cmds" || admincmds="$admincmds - $cmds" - fi - done - fi - - # Exit here if they wanted silent mode. - test "$show" = : && exit 0 - - echo "----------------------------------------------------------------------" - echo "Libraries have been installed in:" - for libdir in $libdirs; do - echo " $libdir" - done - echo - echo "If you ever happen to want to link against installed libraries" - echo "in a given directory, LIBDIR, you must either use libtool, and" - echo "specify the full pathname of the library, or use \`-LLIBDIR'" - echo "flag during linking and do at least one of the following:" - if test -n "$shlibpath_var"; then - echo " - add LIBDIR to the \`$shlibpath_var' environment variable" - echo " during execution" - fi - if test -n "$runpath_var"; then - echo " - add LIBDIR to the \`$runpath_var' environment variable" - echo " during linking" - fi - if test -n "$hardcode_libdir_flag_spec"; then - libdir=LIBDIR - eval flag=\"$hardcode_libdir_flag_spec\" - - echo " - use the \`$flag' linker flag" - fi - if test -n "$admincmds"; then - echo " - have your system administrator run these commands:$admincmds" - fi - if test -f /etc/ld.so.conf; then - echo " - have your system administrator add LIBDIR to \`/etc/ld.so.conf'" - fi - echo - echo "See any operating system documentation about shared libraries for" - echo "more information, such as the ld(1) and ld.so(8) manual pages." - echo "----------------------------------------------------------------------" - exit 0 - ;; - - # libtool execute mode - execute) - modename="$modename: execute" - - # The first argument is the command name. - cmd="$nonopt" - if test -z "$cmd"; then - $echo "$modename: you must specify a COMMAND" 1>&2 - $echo "$help" - exit 1 - fi - - # Handle -dlopen flags immediately. - for file in $execute_dlfiles; do - if test ! -f "$file"; then - $echo "$modename: \`$file' is not a file" 1>&2 - $echo "$help" 1>&2 - exit 1 - fi - - dir= - case "$file" in - *.la) - # Check to see that this really is a libtool archive. - if (sed -e '2q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then : - else - $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 - $echo "$help" 1>&2 - exit 1 - fi - - # Read the libtool library. - dlname= - library_names= - - # If there is no directory component, then add one. - case "$file" in - */* | *\\*) . $file ;; - *) . ./$file ;; - esac - - # Skip this library if it cannot be dlopened. - if test -z "$dlname"; then - # Warn if it was a shared library. - test -n "$library_names" && $echo "$modename: warning: \`$file' was not linked with \`-export-dynamic'" - continue - fi - - dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'` - test "X$dir" = "X$file" && dir=. - - if test -f "$dir/$objdir/$dlname"; then - dir="$dir/$objdir" - else - $echo "$modename: cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" 1>&2 - exit 1 - fi - ;; - - *.lo) - # Just add the directory containing the .lo file. - dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'` - test "X$dir" = "X$file" && dir=. - ;; - - *) - $echo "$modename: warning \`-dlopen' is ignored for non-libtool libraries and objects" 1>&2 - continue - ;; - esac - - # Get the absolute pathname. - absdir=`cd "$dir" && pwd` - test -n "$absdir" && dir="$absdir" - - # Now add the directory to shlibpath_var. - if eval "test -z \"\$$shlibpath_var\""; then - eval "$shlibpath_var=\"\$dir\"" - else - eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\"" - fi - done - - # This variable tells wrapper scripts just to set shlibpath_var - # rather than running their programs. - libtool_execute_magic="$magic" - - # Check if any of the arguments is a wrapper script. - args= - for file - do - case "$file" in - -*) ;; - *) - # Do a test to see if this is really a libtool program. - if (sed -e '4q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then - # If there is no directory component, then add one. - case "$file" in - */* | *\\*) . $file ;; - *) . ./$file ;; - esac - - # Transform arg to wrapped name. - file="$progdir/$program" - fi - ;; - esac - # Quote arguments (to preserve shell metacharacters). - file=`$echo "X$file" | $Xsed -e "$sed_quote_subst"` - args="$args \"$file\"" - done - - if test -z "$run"; then - # Export the shlibpath_var. - eval "export $shlibpath_var" - - # Restore saved enviroment variables - if test "${save_LC_ALL+set}" = set; then - LC_ALL="$save_LC_ALL"; export LC_ALL - fi - if test "${save_LANG+set}" = set; then - LANG="$save_LANG"; export LANG - fi - - # Now actually exec the command. - eval "exec \$cmd$args" - - $echo "$modename: cannot exec \$cmd$args" - exit 1 - else - # Display what would be done. - eval "\$echo \"\$shlibpath_var=\$$shlibpath_var\"" - $echo "export $shlibpath_var" - $echo "$cmd$args" - exit 0 - fi - ;; - - # libtool uninstall mode - uninstall) - modename="$modename: uninstall" - rm="$nonopt" - files= - - for arg - do - case "$arg" in - -*) rm="$rm $arg" ;; - *) files="$files $arg" ;; - esac - done - - if test -z "$rm"; then - $echo "$modename: you must specify an RM program" 1>&2 - $echo "$help" 1>&2 - exit 1 - fi - - for file in $files; do - dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'` - test "X$dir" = "X$file" && dir=. - name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` - - rmfiles="$file" - - case "$name" in - *.la) - # Possibly a libtool archive, so verify it. - if (sed -e '2q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then - . $dir/$name - - # Delete the libtool libraries and symlinks. - for n in $library_names; do - rmfiles="$rmfiles $dir/$n" - done - test -n "$old_library" && rmfiles="$rmfiles $dir/$old_library" - - $show "$rm $rmfiles" - $run $rm $rmfiles - - if test -n "$library_names"; then - # Do each command in the postuninstall commands. - eval cmds=\"$postuninstall_cmds\" - IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' - for cmd in $cmds; do - IFS="$save_ifs" - $show "$cmd" - $run eval "$cmd" - done - IFS="$save_ifs" - fi - - if test -n "$old_library"; then - # Do each command in the old_postuninstall commands. - eval cmds=\"$old_postuninstall_cmds\" - IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' - for cmd in $cmds; do - IFS="$save_ifs" - $show "$cmd" - $run eval "$cmd" - done - IFS="$save_ifs" - fi - - # FIXME: should reinstall the best remaining shared library. - fi - ;; - - *.lo) - if test "$build_old_libs" = yes; then - oldobj=`$echo "X$name" | $Xsed -e "$lo2o"` - rmfiles="$rmfiles $dir/$oldobj" - fi - $show "$rm $rmfiles" - $run $rm $rmfiles - ;; - - *) - $show "$rm $rmfiles" - $run $rm $rmfiles - ;; - esac - done - exit 0 - ;; - - "") - $echo "$modename: you must specify a MODE" 1>&2 - $echo "$generic_help" 1>&2 - exit 1 - ;; - esac - - $echo "$modename: invalid operation mode \`$mode'" 1>&2 - $echo "$generic_help" 1>&2 - exit 1 -fi # test -z "$show_help" - -# We need to display help for each of the modes. -case "$mode" in -"") $echo \ -"Usage: $modename [OPTION]... [MODE-ARG]... - -Provide generalized library-building support services. - - --config show all configuration variables - --debug enable verbose shell tracing --n, --dry-run display commands without modifying any files - --features display basic configuration information and exit - --finish same as \`--mode=finish' - --help display this help message and exit - --mode=MODE use operation mode MODE [default=inferred from MODE-ARGS] - --quiet same as \`--silent' - --silent don't print informational messages - --version print version information - -MODE must be one of the following: - - compile compile a source file into a libtool object - execute automatically set library path, then run a program - finish complete the installation of libtool libraries - install install libraries or executables - link create a library or an executable - uninstall remove libraries from an installed directory - -MODE-ARGS vary depending on the MODE. Try \`$modename --help --mode=MODE' for -a more detailed description of MODE." - exit 0 - ;; - -compile) - $echo \ -"Usage: $modename [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE - -Compile a source file into a libtool library object. - -This mode accepts the following additional options: - - -o OUTPUT-FILE set the output file name to OUTPUT-FILE - -static always build a \`.o' file suitable for static linking - -COMPILE-COMMAND is a command to be used in creating a \`standard' object file -from the given SOURCEFILE. - -The output file name is determined by removing the directory component from -SOURCEFILE, then substituting the C source code suffix \`.c' with the -library object suffix, \`.lo'." - ;; - -execute) - $echo \ -"Usage: $modename [OPTION]... --mode=execute COMMAND [ARGS]... - -Automatically set library path, then run a program. - -This mode accepts the following additional options: - - -dlopen FILE add the directory containing FILE to the library path - -This mode sets the library path environment variable according to \`-dlopen' -flags. - -If any of the ARGS are libtool executable wrappers, then they are translated -into their corresponding uninstalled binary, and any of their required library -directories are added to the library path. - -Then, COMMAND is executed, with ARGS as arguments." - ;; - -finish) - $echo \ -"Usage: $modename [OPTION]... --mode=finish [LIBDIR]... - -Complete the installation of libtool libraries. - -Each LIBDIR is a directory that contains libtool libraries. - -The commands that this mode executes may require superuser privileges. Use -the \`--dry-run' option if you just want to see what would be executed." - ;; - -install) - $echo \ -"Usage: $modename [OPTION]... --mode=install INSTALL-COMMAND... - -Install executables or libraries. - -INSTALL-COMMAND is the installation command. The first component should be -either the \`install' or \`cp' program. - -The rest of the components are interpreted as arguments to that command (only -BSD-compatible install options are recognized)." - ;; - -link) - $echo \ -"Usage: $modename [OPTION]... --mode=link LINK-COMMAND... - -Link object files or libraries together to form another library, or to -create an executable program. - -LINK-COMMAND is a command using the C compiler that you would use to create -a program from several object files. - -The following components of LINK-COMMAND are treated specially: - - -all-static do not do any dynamic linking at all - -avoid-version do not add a version suffix if possible - -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime - -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols - -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3) - -export-symbols SYMFILE - try to export only the symbols listed in SYMFILE - -export-symbols-regex REGEX - try to export only the symbols matching REGEX - -LLIBDIR search LIBDIR for required installed libraries - -lNAME OUTPUT-FILE requires the installed library libNAME - -module build a library that can dlopened - -no-undefined declare that a library does not refer to external symbols - -o OUTPUT-FILE create OUTPUT-FILE from the specified objects - -release RELEASE specify package release information - -rpath LIBDIR the created library will eventually be installed in LIBDIR - -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries - -static do not do any dynamic linking of libtool libraries - -version-info CURRENT[:REVISION[:AGE]] - specify library version info [each variable defaults to 0] - -All other options (arguments beginning with \`-') are ignored. - -Every other argument is treated as a filename. Files ending in \`.la' are -treated as uninstalled libtool libraries, other files are standard or library -object files. - -If the OUTPUT-FILE ends in \`.la', then a libtool library is created, -only library objects (\`.lo' files) may be specified, and \`-rpath' is -required, except when creating a convenience library. - -If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created -using \`ar' and \`ranlib', or on Windows using \`lib'. - -If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file -is created, otherwise an executable program is created." - ;; - -uninstall) - $echo \ -"Usage: $modename [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE... - -Remove libraries from an installation directory. - -RM is the name of the program to use to delete files associated with each FILE -(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed -to RM. - -If FILE is a libtool library, all the files associated with it are deleted. -Otherwise, only FILE itself is deleted using RM." - ;; - -*) - $echo "$modename: invalid operation mode \`$mode'" 1>&2 - $echo "$help" 1>&2 - exit 1 - ;; -esac - -echo -$echo "Try \`$modename --help' for more information about other modes." - -exit 0 - -# Local Variables: -# mode:shell-script -# sh-indentation:2 -# End: diff --git a/shmem/unix/mm/mm-config.1 b/shmem/unix/mm/mm-config.1 deleted file mode 100644 index 512f0d4e830..00000000000 --- a/shmem/unix/mm/mm-config.1 +++ /dev/null @@ -1,283 +0,0 @@ -.rn '' }` -''' $RCSfile: mm-config.1,v $$Revision: 1.2 $$Date: 1999/09/27 07:42:06 $ -''' -''' $Log: mm-config.1,v $ -''' Revision 1.2 1999/09/27 07:42:06 rse -''' Update the MM version APR contains to a more recent one. -''' -''' Revision 1.7 1999/09/06 11:32:17 rse -''' *** empty log message *** -''' -''' -.de Sh -.br -.if t .Sp -.ne 5 -.PP -\fB\\$1\fR -.PP -.. -.de Sp -.if t .sp .5v -.if n .sp -.. -.de Ip -.br -.ie \\n(.$>=3 .ne \\$3 -.el .ne 3 -.IP "\\$1" \\$2 -.. -.de Vb -.ft CW -.nf -.ne \\$1 -.. -.de Ve -.ft R - -.fi -.. -''' -''' -''' Set up \*(-- to give an unbreakable dash; -''' string Tr holds user defined translation string. -''' Bell System Logo is used as a dummy character. -''' -.tr \(*W-|\(bv\*(Tr -.ie n \{\ -.ds -- \(*W- -.ds PI pi -.if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch -.if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch -.ds L" "" -.ds R" "" -''' \*(M", \*(S", \*(N" and \*(T" are the equivalent of -''' \*(L" and \*(R", except that they are used on ".xx" lines, -''' such as .IP and .SH, which do another additional levels of -''' double-quote interpretation -.ds M" """ -.ds S" """ -.ds N" """"" -.ds T" """"" -.ds L' ' -.ds R' ' -.ds M' ' -.ds S' ' -.ds N' ' -.ds T' ' -'br\} -.el\{\ -.ds -- \(em\| -.tr \*(Tr -.ds L" `` -.ds R" '' -.ds M" `` -.ds S" '' -.ds N" `` -.ds T" '' -.ds L' ` -.ds R' ' -.ds M' ` -.ds S' ' -.ds N' ` -.ds T' ' -.ds PI \(*p -'br\} -.\" If the F register is turned on, we'll generate -.\" index entries out stderr for the following things: -.\" TH Title -.\" SH Header -.\" Sh Subsection -.\" Ip Item -.\" X<> Xref (embedded -.\" Of course, you have to process the output yourself -.\" in some meaninful fashion. -.if \nF \{ -.de IX -.tm Index:\\$1\t\\n%\t"\\$2" -.. -.nr % 0 -.rr F -.\} -.TH MM-CONFIG 1 "06-Sep-1999" "MM 1.0.11" "Shared Memory Library" -.UC -.if n .hy 0 -.if n .na -.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' -.de CQ \" put $1 in typewriter font -.ft CW -'if n "\c -'if t \\&\\$1\c -'if n \\&\\$1\c -'if n \&" -\\&\\$2 \\$3 \\$4 \\$5 \\$6 \\$7 -'.ft R -.. -.\" @(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2 -. \" AM - accent mark definitions -.bd B 3 -. \" fudge factors for nroff and troff -.if n \{\ -. ds #H 0 -. ds #V .8m -. ds #F .3m -. ds #[ \f1 -. ds #] \fP -.\} -.if t \{\ -. ds #H ((1u-(\\\\n(.fu%2u))*.13m) -. ds #V .6m -. ds #F 0 -. ds #[ \& -. ds #] \& -.\} -. \" simple accents for nroff and troff -.if n \{\ -. ds ' \& -. ds ` \& -. ds ^ \& -. ds , \& -. ds ~ ~ -. ds ? ? -. ds ! ! -. ds / -. ds q -.\} -.if t \{\ -. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" -. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' -. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' -. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' -. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' -. ds ? \s-2c\h'-\w'c'u*7/10'\u\h'\*(#H'\zi\d\s+2\h'\w'c'u*8/10' -. ds ! \s-2\(or\s+2\h'-\w'\(or'u'\v'-.8m'.\v'.8m' -. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' -. ds q o\h'-\w'o'u*8/10'\s-4\v'.4m'\z\(*i\v'-.4m'\s+4\h'\w'o'u*8/10' -.\} -. \" troff and (daisy-wheel) nroff accents -.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' -.ds 8 \h'\*(#H'\(*b\h'-\*(#H' -.ds v \\k:\h'-(\\n(.wu*9/10-\*(#H)'\v'-\*(#V'\*(#[\s-4v\s0\v'\*(#V'\h'|\\n:u'\*(#] -.ds _ \\k:\h'-(\\n(.wu*9/10-\*(#H+(\*(#F*2/3))'\v'-.4m'\z\(hy\v'.4m'\h'|\\n:u' -.ds . \\k:\h'-(\\n(.wu*8/10)'\v'\*(#V*4/10'\z.\v'-\*(#V*4/10'\h'|\\n:u' -.ds 3 \*(#[\v'.2m'\s-2\&3\s0\v'-.2m'\*(#] -.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] -.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' -.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' -.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] -.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] -.ds ae a\h'-(\w'a'u*4/10)'e -.ds Ae A\h'-(\w'A'u*4/10)'E -.ds oe o\h'-(\w'o'u*4/10)'e -.ds Oe O\h'-(\w'O'u*4/10)'E -. \" corrections for vroff -.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' -.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' -. \" for low resolution devices (crt and lpr) -.if \n(.H>23 .if \n(.V>19 \ -\{\ -. ds : e -. ds 8 ss -. ds v \h'-1'\o'\(aa\(ga' -. ds _ \h'-1'^ -. ds . \h'-1'. -. ds 3 3 -. ds o a -. ds d- d\h'-1'\(ga -. ds D- D\h'-1'\(hy -. ds th \o'bp' -. ds Th \o'LP' -. ds ae ae -. ds Ae AE -. ds oe oe -. ds Oe OE -.\} -.rm #[ #] #H #V #F C -.SH "NAME" -\fBmm-config\fR \- MM library configuration/build utility -.SH "VERSION" -MM 1.0.11 (06-Sep-1999) -.SH "SYNOPSIS" -\fBmm-config\fR -[\fB--help\fR] -[\fB--version\fR] -[\fB--cflags\fR] -[\fB--ldflags\fR] -[\fB--libs\fR] -.SH "DESCRIPTION" -The \fBmm-config\fR program is a little helper utility for easy configuring and -building applications based on the \fImm\fR\|(3) library. It can be used to query the -C compiler and linker flags which are required to correctly compile and link -the application against the \fImm\fR\|(3) library. -.SH "OPTIONS" -\fBmm-config\fR accepts the following options: -.Ip "\fB--help\fR" 4 -Prints the short usage information. -.Ip "\fB--version\fR" 4 -Prints the version number and date of the installed \fImm\fR\|(3) library. -.Ip "\fB--cflags\fR" 4 -Prints the C compiler flags which are needed to compile the \fImm\fR\|(3)\-based -application. The output is usually added to the \f(CWCFLAGS\fR variable of the -applications \f(CWMakefile\fR. -.Ip "\fB--ldflags\fR" 4 -Prints the linker flags (\f(CW-L\fR) which are needed to link the application with -the \fImm\fR\|(3) library. The output is usually added to the \f(CWLDFLAGS\fR variable of -the applications \f(CWMakefile\fR. -.Ip "\fB--libs\fR" 4 -Prints the library flags (\f(CW-l\fR) which are needed to link the application with -the \fImm\fR\|(3) library. The output is usually added to the \f(CWLIBS\fR variable of the -applications \f(CWMakefile\fR. -.SH "EXAMPLE" -.PP -.Vb 10 -\& CC=cc -\& CFLAGS=-O `mm-config --cflags` -\& LDFLAGS=`mm-config --ldflags` -\& LIBS=-lm `mm-config --libs` -\& -\& all: foo -\& foo: foo.o -\& $(CC) $(LDFLAGS) -o foo foo.o $(LIBS) -\& foo.o: foo.c -\& $(CC) $(CFLAGS) -c foo.c -.Ve -.SH "SEE ALSO" -\fImm\fR\|(3). -.SH "AUTHOR" -.PP -.Vb 3 -\& Ralf S. Engelschall -\& rse@engelschall.com -\& www.engelschall.com -.Ve - -.rn }` '' -.IX Title "MM-CONFIG 1" -.IX Name "B<mm-config> - MM library configuration/build utility" - -.IX Header "NAME" - -.IX Header "VERSION" - -.IX Header "SYNOPSIS" - -.IX Header "DESCRIPTION" - -.IX Header "OPTIONS" - -.IX Item "\fB--help\fR" - -.IX Item "\fB--version\fR" - -.IX Item "\fB--cflags\fR" - -.IX Item "\fB--ldflags\fR" - -.IX Item "\fB--libs\fR" - -.IX Header "EXAMPLE" - -.IX Header "SEE ALSO" - -.IX Header "AUTHOR" - diff --git a/shmem/unix/mm/mm-config.in b/shmem/unix/mm/mm-config.in deleted file mode 100644 index 7e4e774cfbd..00000000000 --- a/shmem/unix/mm/mm-config.in +++ /dev/null @@ -1,127 +0,0 @@ -#!/bin/sh -## -## mm-config -- MM library build configuration utility -## -## ==================================================================== -## Copyright (c) 1999 Ralf S. Engelschall. 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 acknowledgment: -## "This product includes software developed by -## Ralf S. Engelschall <rse@engelschall.com>." -## -## 4. Redistributions of any form whatsoever must retain the following -## acknowledgment: -## "This product includes software developed by -## Ralf S. Engelschall <rse@engelschall.com>." -## -## THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``AS IS'' AND ANY -## EXPRESSED 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 RALF S. ENGELSCHALL OR -## ITS 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. -## ==================================================================== - -DIFS=' -' - -prefix="@prefix@" -exec_prefix="@exec_prefix@" - -mm_prefix="$prefix" -mm_libdir="@libdir@" -mm_includedir="@includedir@" -mm_mandir="@mandir@" -mm_cflags="@CFLAGS@" -mm_ldflags="@LDFLAGS@" -mm_libs="@LIBS@" -mm_version="@MM_VERSION_STR@" - -help=no -version=no - -usage="mm-config [--help] [--version] [--all] [--cflags] [--ldflags] [--libs]" -if [ $# -eq 0 ]; then - echo "mm-config:Error: Invalid option" 1>&2 - echo "mm-config:Usage: $usage" 1>&2 - exit 1 -fi -output="" -output_extra="" -all=no -prev='' -OIFS="$IFS" IFS="$DIFS" -for option -do - if [ ".$prev" != . ]; then - eval "$prev=\$option" - prev="" - continue - fi - case "$option" in - -*=*) optarg=`echo "$option" | sed 's/[-_a-zA-Z0-9]*=//'` ;; - *) optarg='' ;; - esac - case "$option" in - --help|-h) - echo "Usage: $usage" - echo "Report bugs to rse@engelschall.com" - exit 0 - ;; - --version|-v) - echo "MM $mm_version" - exit 0 - ;; - --all) - all=yes - ;; - --cflags) - output="$output -I$mm_includedir" - output_extra="$output_extra $mm_cflags" - ;; - --ldflags) - output="$output -L$mm_libdir" - output_extra="$output_extra $mm_ldflags" - ;; - --libs) - output="$output -lmm" - output_extra="$output_extra $mm_libs" - ;; - * ) - echo "mm-config:Error: Invalid option" 1>&2 - echo "mm-config:Usage: $usage" 1>&2 - exit 1; - ;; - esac -done -IFS="$OIFS" -if [ ".$prev" != . ]; then - echo "mm-config:Error: missing argument to --`echo $prev | sed 's/_/-/g'`" 1>&2 - exit 1 -fi -if [ ".$output" != . ]; then - if [ ".$all" = .yes ]; then - output="$output $output_extra" - fi - echo $output -fi - diff --git a/shmem/unix/mm/mm-config.pod b/shmem/unix/mm/mm-config.pod deleted file mode 100644 index 1891a62e802..00000000000 --- a/shmem/unix/mm/mm-config.pod +++ /dev/null @@ -1,128 +0,0 @@ -## ==================================================================== -## Copyright (c) 1999 Ralf S. Engelschall. 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 acknowledgment: -## "This product includes software developed by -## Ralf S. Engelschall <rse@engelschall.com>." -## -## 4. Redistributions of any form whatsoever must retain the following -## acknowledgment: -## "This product includes software developed by -## Ralf S. Engelschall <rse@engelschall.com>." -## -## THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``AS IS'' AND ANY -## EXPRESSED 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 RALF S. ENGELSCHALL OR -## ITS 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. -## ==================================================================== - -## -## mm-config.pod -- Manpage -## - -=pod - -=head1 NAME - -B<mm-config> - MM library configuration/build utility - -=head1 VERSION - -MM MM_VERSION_STR - -=head1 SYNOPSIS - -B<mm-config> -[B<--help>] -[B<--version>] -[B<--cflags>] -[B<--ldflags>] -[B<--libs>] - -=head1 DESCRIPTION - -The B<mm-config> program is a little helper utility for easy configuring and -building applications based on the mm(3) library. It can be used to query the -C compiler and linker flags which are required to correctly compile and link -the application against the mm(3) library. - -=head1 OPTIONS - -B<mm-config> accepts the following options: - -=over 4 - -=item B<--help> - -Prints the short usage information. - -=item B<--version> - -Prints the version number and date of the installed mm(3) library. - -=item B<--cflags> - -Prints the C compiler flags which are needed to compile the mm(3)-based -application. The output is usually added to the C<CFLAGS> variable of the -applications C<Makefile>. - -=item B<--ldflags> - -Prints the linker flags (C<-L>) which are needed to link the application with -the mm(3) library. The output is usually added to the C<LDFLAGS> variable of -the applications C<Makefile>. - -=item B<--libs> - -Prints the library flags (C<-l>) which are needed to link the application with -the mm(3) library. The output is usually added to the C<LIBS> variable of the -applications C<Makefile>. - -=back - -=head1 EXAMPLE - - CC=cc - CFLAGS=-O `mm-config --cflags` - LDFLAGS=`mm-config --ldflags` - LIBS=-lm `mm-config --libs` - - all: foo - foo: foo.o - $(CC) $(LDFLAGS) -o foo foo.o $(LIBS) - foo.o: foo.c - $(CC) $(CFLAGS) -c foo.c - -=head1 SEE ALSO - -mm(3). - -=head1 AUTHOR - - Ralf S. Engelschall - rse@engelschall.com - www.engelschall.com - -=cut - diff --git a/shmem/unix/mm/mm.3 b/shmem/unix/mm/mm.3 deleted file mode 100644 index 94ef391a31b..00000000000 --- a/shmem/unix/mm/mm.3 +++ /dev/null @@ -1,762 +0,0 @@ -.rn '' }` -''' $RCSfile: mm.3,v $$Revision: 1.3 $$Date: 2000/03/10 00:06:32 $ -''' -''' $Log: mm.3,v $ -''' Revision 1.3 2000/03/10 00:06:32 rbb -''' Fix all the License issues. Including: -''' s/Apache Group/Apache Software Foundation/ -''' s/1999/2000/ -''' s/Sascha's license/ASF license -''' -''' -.de Sh -.br -.if t .Sp -.ne 5 -.PP -\fB\\$1\fR -.PP -.. -.de Sp -.if t .sp .5v -.if n .sp -.. -.de Ip -.br -.ie \\n(.$>=3 .ne \\$3 -.el .ne 3 -.IP "\\$1" \\$2 -.. -.de Vb -.ft CW -.nf -.ne \\$1 -.. -.de Ve -.ft R - -.fi -.. -''' -''' -''' Set up \*(-- to give an unbreakable dash; -''' string Tr holds user defined translation string. -''' Bell System Logo is used as a dummy character. -''' -.tr \(*W-|\(bv\*(Tr -.ie n \{\ -.ds -- \(*W- -.ds PI pi -.if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch -.if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch -.ds L" "" -.ds R" "" -''' \*(M", \*(S", \*(N" and \*(T" are the equivalent of -''' \*(L" and \*(R", except that they are used on ".xx" lines, -''' such as .IP and .SH, which do another additional levels of -''' double-quote interpretation -.ds M" """ -.ds S" """ -.ds N" """"" -.ds T" """"" -.ds L' ' -.ds R' ' -.ds M' ' -.ds S' ' -.ds N' ' -.ds T' ' -'br\} -.el\{\ -.ds -- \(em\| -.tr \*(Tr -.ds L" `` -.ds R" '' -.ds M" `` -.ds S" '' -.ds N" `` -.ds T" '' -.ds L' ` -.ds R' ' -.ds M' ` -.ds S' ' -.ds N' ` -.ds T' ' -.ds PI \(*p -'br\} -.\" If the F register is turned on, we'll generate -.\" index entries out stderr for the following things: -.\" TH Title -.\" SH Header -.\" Sh Subsection -.\" Ip Item -.\" X<> Xref (embedded -.\" Of course, you have to process the output yourself -.\" in some meaninful fashion. -.if \nF \{ -.de IX -.tm Index:\\$1\t\\n%\t"\\$2" -.. -.nr % 0 -.rr F -.\} -.TH mm 3 "06-Sep-1999" "MM 1.0.11" "Shared Memory Library" -.UC -.if n .hy 0 -.if n .na -.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' -.de CQ \" put $1 in typewriter font -.ft CW -'if n "\c -'if t \\&\\$1\c -'if n \\&\\$1\c -'if n \&" -\\&\\$2 \\$3 \\$4 \\$5 \\$6 \\$7 -'.ft R -.. -.\" @(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2 -. \" AM - accent mark definitions -.bd B 3 -. \" fudge factors for nroff and troff -.if n \{\ -. ds #H 0 -. ds #V .8m -. ds #F .3m -. ds #[ \f1 -. ds #] \fP -.\} -.if t \{\ -. ds #H ((1u-(\\\\n(.fu%2u))*.13m) -. ds #V .6m -. ds #F 0 -. ds #[ \& -. ds #] \& -.\} -. \" simple accents for nroff and troff -.if n \{\ -. ds ' \& -. ds ` \& -. ds ^ \& -. ds , \& -. ds ~ ~ -. ds ? ? -. ds ! ! -. ds / -. ds q -.\} -.if t \{\ -. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" -. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' -. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' -. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' -. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' -. ds ? \s-2c\h'-\w'c'u*7/10'\u\h'\*(#H'\zi\d\s+2\h'\w'c'u*8/10' -. ds ! \s-2\(or\s+2\h'-\w'\(or'u'\v'-.8m'.\v'.8m' -. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' -. ds q o\h'-\w'o'u*8/10'\s-4\v'.4m'\z\(*i\v'-.4m'\s+4\h'\w'o'u*8/10' -.\} -. \" troff and (daisy-wheel) nroff accents -.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' -.ds 8 \h'\*(#H'\(*b\h'-\*(#H' -.ds v \\k:\h'-(\\n(.wu*9/10-\*(#H)'\v'-\*(#V'\*(#[\s-4v\s0\v'\*(#V'\h'|\\n:u'\*(#] -.ds _ \\k:\h'-(\\n(.wu*9/10-\*(#H+(\*(#F*2/3))'\v'-.4m'\z\(hy\v'.4m'\h'|\\n:u' -.ds . \\k:\h'-(\\n(.wu*8/10)'\v'\*(#V*4/10'\z.\v'-\*(#V*4/10'\h'|\\n:u' -.ds 3 \*(#[\v'.2m'\s-2\&3\s0\v'-.2m'\*(#] -.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] -.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' -.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' -.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] -.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] -.ds ae a\h'-(\w'a'u*4/10)'e -.ds Ae A\h'-(\w'A'u*4/10)'E -.ds oe o\h'-(\w'o'u*4/10)'e -.ds Oe O\h'-(\w'O'u*4/10)'E -. \" corrections for vroff -.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' -.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' -. \" for low resolution devices (crt and lpr) -.if \n(.H>23 .if \n(.V>19 \ -\{\ -. ds : e -. ds 8 ss -. ds v \h'-1'\o'\(aa\(ga' -. ds _ \h'-1'^ -. ds . \h'-1'. -. ds 3 3 -. ds o a -. ds d- d\h'-1'\(ga -. ds D- D\h'-1'\(hy -. ds th \o'bp' -. ds Th \o'LP' -. ds ae ae -. ds Ae AE -. ds oe oe -. ds Oe OE -.\} -.rm #[ #] #H #V #F C -.SH "NAME" -\fBMM \- Shared Memory Library\fR -.SH "VERSION" -MM 1.0.11 (06-Sep-1999) -.SH "SYNOPSIS" -.PP -.Vb 1 -\& #include "mm.h" -.Ve -\fB Global Malloc-Replacement API\fR -.PP -.Vb 14 -\& int \fBMM_create\fR(size_t size, const char *file); -\& int \fBMM_permission\fR(mode_t mode, uid_t owner, gid_t group); -\& void \fBMM_destroy\fR(void); -\& int \fBMM_lock\fR(mm_lock_mode mode); -\& int \fBMM_unlock\fR(void); -\& void *\fBMM_malloc\fR(size_t size); -\& void *\fBMM_realloc\fR(void *ptr, size_t size); -\& void \fBMM_free\fR(void *ptr); -\& void *\fBMM_calloc\fR(size_t number, size_t size); -\& char *\fBMM_strdup\fR(const char *str); -\& size_t \fBMM_sizeof\fR(void *ptr); -\& size_t \fBMM_maxsize\fR(void); -\& size_t \fBMM_available\fR(void); -\& char *\fBMM_error\fR(void); -.Ve -\fB Standard Malloc-Style API\fR -.PP -.Vb 15 -\& MM *\fBmm_create\fR(size_t size, char *file); -\& int \fBmm_permission\fR(MM *mm, mode_t mode, uid_t owner, gid_t group); -\& void \fBmm_destroy\fR(MM *mm); -\& int \fBmm_lock\fR(MM *mm, mm_lock_mode mode); -\& int \fBmm_unlock\fR(MM *mm); -\& void *\fBmm_malloc\fR(MM *mm, size_t size); -\& void *\fBmm_realloc\fR(MM *mm, void *ptr, size_t size); -\& void \fBmm_free\fR(MM *mm, void *ptr); -\& void *\fBmm_calloc\fR(MM *mm, size_t number, size_t size); -\& char *\fBmm_strdup\fR(MM *mm, const char *str); -\& size_t \fBmm_sizeof\fR(void *ptr); -\& size_t \fBmm_maxsize\fR(void); -\& size_t \fBmm_available\fR(MM *mm); -\& char *\fBmm_error\fR(void); -\& void \fBmm_display_info\fR(MM *mm); -.Ve -\fB Low-level Shared Memory API\fR -.PP -.Vb 9 -\& void *\fBmm_core_create\fR(size_t size, char *file); -\& int \fBmm_core_permission\fR(void *core, mode_t mode, uid_t owner, gid_t group); -\& void \fBmm_core_delete\fR(void *core); -\& int \fBmm_core_lock\fR(void *core, mm_lock_mode mode); -\& int \fBmm_core_unlock\fR(void *core); -\& size_t \fBmm_core_size\fR(void *core); -\& size_t \fBmm_core_maxsegsize\fR(void); -\& size_t \fBmm_core_align2page\fR(size_t size); -\& size_t \fBmm_core_align2click\fR(size_t size); -.Ve -\fB Internal Library API\fR -.PP -.Vb 3 -\& void \fBmm_lib_error_set\fR(unsigned int, const char *str); -\& char *\fBmm_lib_error_get\fR(void); -\& int \fBmm_lib_version\fR(void); -.Ve -.SH "DESCRIPTION" -The \fBMM\fR library is a 2-layer abstraction library which simplifies the usage -of shared memory between forked (and this way strongly related) processes -under Unix platforms. On the first (lower) layer it hides all platform -dependent implementation details (allocation and locking) when dealing with -shared memory segments and on the second (higher) layer it provides a -high-level \fImalloc\fR\|(3)\-style API for a convenient and well known way to work -with data-structures inside those shared memory segments. -.PP -The abbreviation \fBMM\fR is historically and originally comes from the phrase -``\fImemory mapped\fR'\*(R' as used by the POSIX.1 \fImmap\fR\|(2) function. Because this -facility is internally used by this library on most platforms to create the -shared memory segments. -.Sh "\s-1LIBRARY\s0 \s-1STRUCTURE\s0" -This library is structured into three main APIs which are internally based on -each other: -.Ip "\fBGlobal Malloc-Replacement \s-1API\s0\fR" 4 -This is the most high-level \s-1API\s0 which directly can be used as replacement \s-1API\s0 -for the \s-1POSIX\s0.1 memory allocation \s-1API\s0 (\fImalloc\fR\|(2) and friends). This is -useful when converting \fIheap\fR based data structures to \fIshared memory\fR -based data structures without the need to change the code dramatically. All -which is needed is to prefix the \s-1POSIX\s0.1 memory allocation functions with -`\f(CWMM_\fR\*(R', i.e. `\f(CWmalloc\fR\*(R' becomes `\f(CWMM_malloc\fR\*(R', `\f(CWstrdup\fR\*(R' becomes -`\f(CWMM_strdup\fR\*(R', etc. This \s-1API\s0 internally uses just a global `\f(CWMM *\fR\*(R' pool for -calling the corresponding functions (with prefix `\f(CWmm_\fR') of the \fIStandard -Malloc-Style \s-1API\s0\fR. -.Ip "\fBStandard Malloc-Style \s-1API\s0\fR" 4 -This is the standard high-level memory allocation \s-1API\s0. Its interface is -similar to the \fIGlobal Malloc-Replacement \s-1API\s0\fR but it uses an explicit `\f(CWMM *\fR\*(R' -pool to operate on. That's why every function of this \s-1API\s0 has an argument of -type `\f(CWMM *\fR\*(R' as the first argument. This \s-1API\s0 provides a comfortable way to -work with small dynamically allocated shared memory chunks inside large -statically allocated shared memory segments. It's internally based on the -\fILow-Level Shared Memory \s-1API\s0\fR for creating the underlaying shared memory -segment. -.Ip "\fBLow-Level Shared Memory \s-1API\s0\fR" 4 -This is the basis of the whole \fB\s-1MM\s0\fR library. It provides low-level functions -for creating shared memory segments with mutual exclusion (in short: \fImutex\fR) -capabilities in a portable way. Internally the shared memory and mutex -facility is implemented in various platform-dependent ways. A list of -implementation variants follows under the next topic. -.Sh "\s-1SHARED\s0 \s-1MEMORY\s0 \s-1IMPLEMENTATION\s0" -Internally the shared memory facility is implemented in various -platform-dependent variants. Each has it's own advantages and disadvantages -(in addition to the fact that some variants aren't available at all on some -platforms). The \s-1MM\s0 libraries configuration procedure tried hard to make a good -decision. The implemented variants are now given for overview and background -reasons with their advantages and disadvantages and in an ascending order, -i.e. the \s-1MM\s0 configuration mechanism chooses the last available one in the list -as the preferred variant. -.Ip "Classical mmap(2) on temporary file (\s-1MMFILE\s0)" 4 -\fIAdvantage:\fR maximum portable. -\fIDisadvantage:\fR needs a temporary file on the filesystem -.Ip "mmap(2) via \s-1POSIX\s0.1 shm_open(3) on temporary file (\s-1MMPOSX\s0)" 4 -\fIAdvantage:\fR standardized by \s-1POSIX\s0.1 and theoretically portable. -\fIDisadvantage:\fR needs a temporary file on the filesystem and is -is usually not available on existing Unix platform. -.Ip "\s-1SVR4-\s0style mmap(2) on \f(CW/dev/zero\fR device (\s-1MMZERO\s0)" 4 -\fIAdvantage:\fR widely available on mostly portable on \s-1SVR4\s0 platforms. -\fIDisadvantage:\fR needs the \f(CW/dev/zero/\fR device and an \fImmap\fR\|(2) -which supports memory mapping through it. -.Ip "4.4BSD\-style mmap(2) via \f(CWMAP_ANON\fR facility (\s-1MMANON\s0)" 4 -\fIAdvantage:\fR doesn't need a temporary file or external device -\fIDisadvantage:\fR usually only available on \s-1BSD\s0 platforms and derivatives. -.Ip "SysV \s-1IPC\s0 shmget(2) (\s-1IPCSHM\s0)" 4 -\fIAdvantage:\fR doesn't need a temporary file or external device -\fIDisadvantage:\fR although available on mostly all modern Unix platforms it has -hard restrictions like the maximum size of a single shared memory segment (can -be as small as 100KB, but depends on the platform). -.Sh "\s-1LOCKING\s0 \s-1IMPLEMENTATION\s0" -As for the shared memory facility, internally the locking facility is -implemented in various platform-dependent variants. A short overview of -implemented variants is given: -.Ip "4.2BSD\-style flock(2) on temporary file (\s-1FLOCK\s0)" 4 -\fIAdvantage:\fR exists on a lot of platforms, especially on older Unix -derivates. \fIDisadvantage:\fR needs a temporary file on the filesystem and has -to reopen filedescriptors to it in \fIeach\fR\|(!) \fIfork\fR\|(2)ed child process. -.Ip "SysV \s-1IPC\s0 semget(2) (\s-1IPCSEM\s0)" 4 -\fIAdvantage:\fR exists on a lot of platforms and doesn't need a temporary file. -\fIDisadvantage:\fR an unmeant termination of the application leads to a -semaphore leak because the facility doesn't allow an \*(L"remove in advance\*(R" trick -(as the \s-1IPC\s0 shared memory facility does!) for safe cleanups. -.Ip "\s-1SVR4-\s0style fcntl(2) on temporary file (\s-1FCNTL\s0)" 4 -\fIAdvantage:\fR exists on a lot of platforms and is also the most powerful -variant (although not always the fastest one). \fIDisadvantage:\fR needs a -temporary file. -.Sh "\s-1MEMORY\s0 \s-1ALLOCATION\s0 \s-1STRATEGY\s0" -The memory allocation strategy the \fIStandard Malloc-Style \s-1API\s0\fR functions use -internally is the following: -.Ip "\fBAllocation\fR" 4 -When a chunk of memory has to be allocated, the internal list of free chunks -is searched for a minimal-sized chunk which is larger or equal than the size -of the to be allocated chunk (some sort of a \fIbest fit algorithm\fR). -.Sp -When a chunk is found which matches this best-fit criteria, but is still a lot -larger than the requested size, it is split into two chunks: One with exactly -the requested size (which is the resulting chunk) and one with the remaining -size (which is immediately re-inserted into the list of free chunks). -.Sp -When no fitting chunk is found at all in the list of free chunks, a new one is -created from the spare area of the shared memory segment until the segment is -full (in which case an \fIout of memory\fR error occurs). -.Ip "\fBDeallocation\fR" 4 -When a chunk of memory has to be deallocated, it is inserted in sorted manner -into the internal list of free chunks. The insertion operation automatically -merges the chunk with a previous and/or next free chunk when possible, i.e. -the free chunks stay physically seamless (one after another) in memory, to -automatically form larger free chunks out of smaller ones. -.Sp -This way the shared memory segment is automatically defragmented when memory -is deallocated. -.PP -This strategy reduces memory waste and fragmentation caused by small and -frequent allocations and deallocations to a minimum. -.PP -The internal implementation of the list of free chunks is not specially -optimized (for instance by using binary search trees or even splay trees, -etc.), because it's assumed that the total amount of entries in the list of -free chunks is always small (caused both by the fact that shared memory -segments are usually a lot smaller than heaps and the fact that we always -defragment by merging the free chunks when possible). -.SH "API FUNCTIONS" -In the following all API functions are described in detail. -The order directly follows the one in the SYNOPSIS. -.Sh "Global Malloc-Replacement \s-1API\s0" -.Ip "int \fBMM_create\fR(size_t \fIsize\fR, const char *\fIfile\fR);" 4 -This initialized the global shared memory pool with \fIsize\fR and \fIfile\fR and -has be called \fIbefore\fR any \fIfork\fR\|(2) operations are performed by the -application. -.Ip "int \fBMM_permission\fR(mode_t \fImode\fR, uid_t \fIowner\fR, gid_t \fIgroup\fR);" 4 -This sets the filesystem \fImode\fR, \fIowner\fR and \fIgroup\fR for the global shared -memory pool (has effects only when the underlaying shared memory segment -implementation is actually based on external auxiliary files). The arguments -are directly passed through to \fIchmod\fR\|(2) and \fIchown\fR\|(2). -.Ip "void \fBMM_destroy\fR(void);" 4 -This destroys the global shared memory pool and should be called \fIafter\fR all -child processes were killed. -.Ip "int \fBMM_lock\fR(mm_lock_mode \fImode\fR);" 4 -This locks the global shared memory pool for the current process in order to -perform either shared/read-only (\fImode\fR is \f(CWMM_LOCK_RD\fR) or -exclusive/read-write (\fImode\fR is \f(CWMM_LOCK_RW\fR) operations inside the global -shared memory pool. -.Ip "int \fBMM_unlock\fR(void);" 4 -This unlocks the global shared memory pool for the current process after -mutual exclusion operations were performed inside the global shared memory -pool. -.Ip "void *\fBMM_malloc\fR(size_t \fIsize\fR);" 4 -Identical to the \s-1POSIX\s0.1 \fImalloc\fR\|(3) function but instead of allocating -memory from the \fIheap\fR it allocates it from the global shared memory pool. -.Ip "void \fBMM_free\fR(void *\fIptr\fR);" 4 -Identical to the \s-1POSIX\s0.1 \fIfree\fR\|(3) function but instead of deallocating -memory in the \fIheap\fR it deallocates it in the global shared memory pool. -.Ip "void *\fBMM_realloc\fR(void *\fIptr\fR, size_t \fIsize\fR);" 4 -Identical to the \s-1POSIX\s0.1 \fIrealloc\fR\|(3) function but instead of reallocating -memory in the \fIheap\fR it reallocates it inside the global shared memory pool. -.Ip "void *\fBMM_calloc\fR(size_t \fInumber\fR, size_t \fIsize\fR);" 4 -Identical to the \s-1POSIX\s0.1 \fIcalloc\fR\|(3) function but instead of allocating and -initializing memory from the \fIheap\fR it allocates and initializes it from the -global shared memory pool. -.Ip "char *\fBMM_strdup\fR(const char *\fIstr\fR);" 4 -Identical to the \s-1POSIX\s0.1 \fIstrdup\fR\|(3) function but instead of creating the -string copy in the \fIheap\fR it creates it in the global shared memory pool. -.Ip "size_t \fBMM_sizeof\fR(const void *\fIptr\fR);" 4 -This function returns the size in bytes of the chunk starting at \fIptr\fR when -\fIptr\fR was previously allocated with \fIMM_malloc\fR\|(3). The result is undefined -when \fIptr\fR was not previously allocated with \fIMM_malloc\fR\|(3). -.Ip "size_t \fBMM_maxsize\fR(void);" 4 -This function returns the maximum size which is allowed -as the first argument to the \fIMM_create\fR\|(3) function. -.Ip "size_t \fBMM_available\fR(void);" 4 -Returns the amount in bytes of still available (free) memory in the global -shared memory pool. -.Ip "char *\fBMM_error\fR(void);" 4 -Returns the last error message which occurred inside the \fB\s-1MM\s0\fR library. -.Sh "Standard Malloc-Style \s-1API\s0" -.Ip "\s-1MM\s0 *\fBmm_create\fR(size_t \fIsize\fR, const char *\fIfile\fR);" 4 -This creates a shared memory pool which has space for approximately a total of -\fIsize\fR bytes with the help of \fIfile\fR. Here \fIfile\fR is a filesystem path to a -file which need not to exist (and perhaps is never created because this -depends on the platform and chosen shared memory and mutex implementation). -The return value is a pointer to an \f(CWMM\fR structure which should be treated as -opaque by the application. It describes the internals of the created shared -memory pool. In case of an error \f(CWNULL\fR is returned. A \fIsize\fR of 0 means to -allocate the maximum allowed size which is platform dependent and between a -few \s-1KB\s0 and the soft limit of 64MB. -.Ip "int \fBmm_permission\fR(\s-1MM\s0 *\fImm\fR, mode_t \fImode\fR, uid_t \fIowner\fR, gid_t \fIgroup\fR);" 4 -This sets the filesystem \fImode\fR, \fIowner\fR and \fIgroup\fR for the shared memory -pool \fImm\fR (has effects only when the underlaying shared memory segment -implementation is actually based on external auxiliary files). The arguments -are directly passed through to \fIchmod\fR\|(2) and \fIchown\fR\|(2). -.Ip "void \fBmm_destroy\fR(\s-1MM\s0 *\fImm\fR);" 4 -This destroys the complete shared memory pool \fImm\fR and with it all chunks -which were allocated in this pool. Additionally any created files on the -filesystem corresponding the to shared memory pool are unlinked. -.Ip "int \fBmm_lock\fR(\s-1MM\s0 *\fImm\fR, mm_lock_mode \fImode\fR);" 4 -This locks the shared memory pool \fImm\fR for the current process in order to -perform either shared/read-only (\fImode\fR is \f(CWMM_LOCK_RD\fR) or -exclusive/read-write (\fImode\fR is \f(CWMM_LOCK_RW\fR) operations inside the global -shared memory pool. -.Ip "int \fBmm_unlock\fR(\s-1MM\s0 *\fImm\fR);" 4 -This unlocks the shared memory pool \fImm\fR for the current process after mutual -exclusion operations were performed inside the global shared memory pool. -.Ip "void *\fBmm_malloc\fR(\s-1MM\s0 *\fImm\fR, size_t \fIsize\fR);" 4 -This function allocates \fIsize\fR bytes from the shared memory pool \fImm\fR and -returns either a (virtual memory word aligned) pointer to it or \f(CWNULL\fR in -case of an error (out of memory). It behaves like the \s-1POSIX\s0.1 \fImalloc\fR\|(3) -function but instead of allocating memory from the \fIheap\fR it allocates it -from the shared memory segment underlaying \fImm\fR. -.Ip "void \fBmm_free\fR(\s-1MM\s0 *\fImm\fR, void *\fIptr\fR);" 4 -This deallocates the chunk starting at \fIptr\fR in the shared memory pool \fImm\fR. -It behaves like the \s-1POSIX\s0.1 \fIfree\fR\|(3) function but instead of deallocating -memory from the \fIheap\fR it deallocates it from the shared memory segment -underlaying \fImm\fR. -.Ip "void *\fBmm_realloc\fR(\s-1MM\s0 *\fImm\fR, void *\fIptr\fR, size_t \fIsize\fR);" 4 -This function reallocates the chunk starting at \fIptr\fR inside the shared -memory pool \fImm\fR with the new size of \fIsize\fR bytes. It behaves like the -\s-1POSIX\s0.1 \fIrealloc\fR\|(3) function but instead of reallocating memory in the -\fIheap\fR it reallocates it in the shared memory segment underlaying \fImm\fR. -.Ip "void *\fBmm_calloc\fR(\s-1MM\s0 *\fImm\fR, size_t \fInumber\fR, size_t \fIsize\fR);" 4 -This is similar to \fImm_malloc\fR\|(3), but additionally clears the chunk. It behaves -like the \s-1POSIX\s0.1 \fIcalloc\fR\|(3) function. It allocates space for \fInumber\fR -objects, each \fIsize\fR bytes in length from the shared memory pool \fImm\fR. The -result is identical to calling \fImm_malloc\fR\|(3) with an argument of ``\fInumber\fR * -\fIsize\fR'\*(R', with the exception that the allocated memory is initialized to nul -bytes. -.Ip "char *\fBmm_strdup\fR(\s-1MM\s0 *\fImm\fR, const char *\fIstr\fR);" 4 -This function behaves like the \s-1POSIX\s0.1 \fIstrdup\fR\|(3) function. It allocates -sufficient memory inside the shared memory pool \fImm\fR for a copy of the string -\fIstr\fR, does the copy, and returns a pointer to it. The pointer may -subsequently be used as an argument to the function \fImm_free\fR\|(3). If -insufficient shared memory is available, \f(CWNULL\fR is returned. -.Ip "size_t \fBmm_sizeof\fR(const void *\fIptr\fR);" 4 -This function returns the size in bytes of the chunk starting at \fIptr\fR when -\fIptr\fR was previously allocated with \fImm_malloc\fR\|(3). The result is undefined -when \fIptr\fR was not previously allocated with \fImm_malloc\fR\|(3). -.Ip "size_t \fBmm_maxsize\fR(void);" 4 -This function returns the maximum size which is allowed as the first argument -to the \fImm_create\fR\|(3) function. -.Ip "size_t \fBmm_available\fR(\s-1MM\s0 *\fImm\fR);" 4 -Returns the amount in bytes of still available (free) memory in the -shared memory pool \fImm\fR. -.Ip "char *\fBmm_error\fR(void);" 4 -Returns the last error message which occurred inside the \fB\s-1MM\s0\fR library. -.Ip "void \fBmm_display_info\fR(\s-1MM\s0 *\fImm\fR);" 4 -This is debugging function which displays a summary page for the shared memory -pool \fImm\fR describing various internal sizes and counters. -.Sh "Low-Level Shared Memory \s-1API\s0" -.Ip "void *\fBmm_core_create\fR(size_t \fIsize\fR, const char *\fIfile\fR);" 4 -This creates a shared memory area which is at least \fIsize\fR bytes in size with -the help of \fIfile\fR. The value \fIsize\fR has to be greater than 0 and less or -equal the value returned by \fImm_core_maxsegsize\fR\|(3). Here \fIfile\fR is a -filesystem path to a file which need not to exist (and perhaps is never -created because this depends on the platform and chosen shared memory and -mutex implementation). The return value is either a (virtual memory word -aligned) pointer to the shared memory segment or \f(CWNULL\fR in case of an error. -The application is guaranteed to be able to access the shared memory segment -from byte 0 to byte \fIsize\fR\-1 starting at the returned address. -.Ip "int \fBmm_core_permission\fR(void *\fIcore\fR, mode_t \fImode\fR, uid_t \fIowner\fR, gid_t \fIgroup\fR);" 4 -This sets the filesystem \fImode\fR, \fIowner\fR and \fIgroup\fR for the shared memory -segment \fIcode\fR (has effects only when the underlaying shared memory segment -implementation is actually based on external auxiliary files). The arguments -are directly passed through to \fIchmod\fR\|(2) and \fIchown\fR\|(2). -.Ip "void \fBmm_core_delete\fR(void *\fIcore\fR);" 4 -This deletes a shared memory segment \fIcore\fR (as previously returned by a -\fImm_core_create\fR\|(3) call). After this operation, accessing the segment starting -at \fIcore\fR is no longer allowed and will usually lead to a segmentation fault. -.Ip "int \fBmm_core_lock\fR(const void *\fIcore\fR, mm_lock_mode \fImode\fR);" 4 -This function acquires an advisory lock for the current process on the shared -memory segment \fIcore\fR for either shared/read-only (\fImode\fR is \f(CWMM_LOCK_RD\fR) -or exclusive/read-write (\fImode\fR is \f(CWMM_LOCK_RW\fR) operations between -\fIfork\fR\|(2)'ed child processes. -.Ip "int \fBmm_core_unlock\fR(const void *\fIcore\fR);" 4 -This function releases a previously acquired advisory lock for the current -process on the shared memory segment \fIcore\fR. -.Ip "size_t \fBmm_core_size\fR(const void *\fIcore\fR);" 4 -This returns the size in bytes of \fIcore\fR. This size is exactly the size which -was used for creating the shared memory area via \fImm_core_create\fR\|(3). The -function is provided just for convenience reasons to not require the -application to remember the memory size behind \fIcore\fR itself. -.Ip "size_t \fBmm_core_maxsegsize\fR(void);" 4 -This returns the number of bytes of a maximum-size shared memory segment which -is allowed to allocate via the \s-1MM\s0 library. It is between a few \s-1KB\s0 and the soft -limit of 64MB. -.Ip "size_t \fBmm_core_align2page\fR(size_t \fIsize\fR);" 4 -This is just a utility function which can be used to align the number \fIsize\fR -to the next virtual memory \fIpage\fR boundary used by the underlaying platform. -The memory page boundary under Unix platforms is usually somewhere between -2048 and 16384 bytes. You don't have to align the \fIsize\fR arguments of other -\fB\s-1MM\s0\fR library functions yourself, because this is already done internally. -This function is exported by the \fB\s-1MM\s0\fR library just for convenience reasons in -case an application wants to perform simular calculations for other purposes. -.Ip "size_t \fBmm_core_align2word\fR(size_t \fIsize\fR);" 4 -This is another utility function which can be used to align the number \fIsize\fR -to the next virtual memory \fIword\fR boundary used by the underlaying platform. -The memory word boundary under Unix platforms is usually somewhere between 4 -and 16 bytes. You don't have to align the \fIsize\fR arguments of other \fB\s-1MM\s0\fR -library functions yourself, because this is already done internally. This -function is exported by the \fB\s-1MM\s0\fR library just for convenience reasons in case -an application wants to perform simular calculations for other purposes. -.Sh "Low-Level Shared Memory \s-1API\s0" -.Ip "void \fBmm_lib_error_set\fR(unsigned int, const char *str);" 4 -This is a function which is used internally by the various \s-1MM\s0 function to set -an error string. It's usually not called directly from applications. -.Ip "char *\fBmm_lib_error_get\fR(void);" 4 -This is a function which is used internally by \fIMM_error\fR\|(3) and \fImm_error\fR\|(3) -functions to get the current error string. It's usually not called directly -from applications. -.Ip "int \fBmm_lib_version\fR(void);" 4 -This function returns a hex-value ``0x\fIV\fR\fI\s-1RR\s0\fR\fIT\fR\fI\s-1LL\s0\fR'\*(R' which describes the -current \s-1MM\s0 library version. \fIV\fR is the version, \fI\s-1RR\s0\fR the revisions, \fI\s-1LL\s0\fR -the level and \fIT\fR the type of the level (alphalevel=0, betalevel=1, -patchlevel=2, etc). For instance \s-1MM\s0 version 1.0.4 is encoded as 0x100204. The -reason for this unusual mapping is that this way the version number is -steadily \fIincreasing\fR. -.SH "RESTRICTIONS" -The maximum size of a continuous shared memory segment one can allocate -depends on the underlaying platform. This cannot be changed, of course. But -currently the high-level \fImalloc\fR\|(3)\-style API just uses a single shared memory -segment as the underlaying data structure for an \f(CWMM\fR object which means that -the maximum amount of memory a \f(CWMM\fR object represents also depends on the -platform. -.PP -This should be changed in later versions by allowing the high-level -\fImalloc\fR\|(3)\-style API to internally use multiple shared memory segments to form -the \f(CWMM\fR object. This way \f(CWMM\fR objects could have arbitrary sizes, although -the maximum size of an allocatable chunk still is bounded by the maximum size -of a shared memory segment. -.SH "SEE ALSO" -mm-\fIconfig\fR\|(1). -.PP -\fImalloc\fR\|(3), \fIcalloc\fR\|(3), \fIrealloc\fR\|(3), \fIstrdup\fR\|(3), \fIfree\fR\|(3), \fImmap\fR\|(2), \fIshmget\fR\|(2), -\fIshmctl\fR\|(2), \fIflock\fR\|(2), \fIfcntl\fR\|(2), \fIsemget\fR\|(2), \fIsemctl\fR\|(2), \fIsemop\fR\|(2). -.SH "HOME" -http://www.engelschall.com/sw/mm/ - -.SH "HISTORY" -This library was originally written in January 1999 by \fIRalf S. Engelschall\fR -<rse@engelschall.com> for use in the \fBExtended API\fR (EAPI) of the \fBApache\fR -HTTP server project (see www.apache.org), which was originally invented for -\fBmod_ssl\fR (see http://www.modssl.org/). -.PP -Its base idea (a malloc-style API for handling shared memory) was originally -derived from the non-publically available \fImm_malloc\fR library written in -October 1997 by \fICharles Randall\fR <crandall@matchlogic.com> for MatchLogic, -Inc. -.SH "AUTHOR" -.PP -.Vb 3 -\& Ralf S. Engelschall -\& rse@engelschall.com -\& www.engelschall.com -.Ve - -.rn }` '' -.IX Title "mm 3" -.IX Name "B<MM - Shared Memory Library>" - -.IX Header "NAME" - -.IX Header "VERSION" - -.IX Header "SYNOPSIS" - -.IX Header "DESCRIPTION" - -.IX Subsection "\s-1LIBRARY\s0 \s-1STRUCTURE\s0" - -.IX Item "\fBGlobal Malloc-Replacement \s-1API\s0\fR" - -.IX Item "\fBStandard Malloc-Style \s-1API\s0\fR" - -.IX Item "\fBLow-Level Shared Memory \s-1API\s0\fR" - -.IX Subsection "\s-1SHARED\s0 \s-1MEMORY\s0 \s-1IMPLEMENTATION\s0" - -.IX Item "Classical mmap(2) on temporary file (\s-1MMFILE\s0)" - -.IX Item "mmap(2) via \s-1POSIX\s0.1 shm_open(3) on temporary file (\s-1MMPOSX\s0)" - -.IX Item "\s-1SVR4-\s0style mmap(2) on \f(CW/dev/zero\fR device (\s-1MMZERO\s0)" - -.IX Item "4.4BSD\-style mmap(2) via \f(CWMAP_ANON\fR facility (\s-1MMANON\s0)" - -.IX Item "SysV \s-1IPC\s0 shmget(2) (\s-1IPCSHM\s0)" - -.IX Subsection "\s-1LOCKING\s0 \s-1IMPLEMENTATION\s0" - -.IX Item "4.2BSD\-style flock(2) on temporary file (\s-1FLOCK\s0)" - -.IX Item "SysV \s-1IPC\s0 semget(2) (\s-1IPCSEM\s0)" - -.IX Item "\s-1SVR4-\s0style fcntl(2) on temporary file (\s-1FCNTL\s0)" - -.IX Subsection "\s-1MEMORY\s0 \s-1ALLOCATION\s0 \s-1STRATEGY\s0" - -.IX Item "\fBAllocation\fR" - -.IX Item "\fBDeallocation\fR" - -.IX Header "API FUNCTIONS" - -.IX Subsection "Global Malloc-Replacement \s-1API\s0" - -.IX Item "int \fBMM_create\fR(size_t \fIsize\fR, const char *\fIfile\fR);" - -.IX Item "int \fBMM_permission\fR(mode_t \fImode\fR, uid_t \fIowner\fR, gid_t \fIgroup\fR);" - -.IX Item "void \fBMM_destroy\fR(void);" - -.IX Item "int \fBMM_lock\fR(mm_lock_mode \fImode\fR);" - -.IX Item "int \fBMM_unlock\fR(void);" - -.IX Item "void *\fBMM_malloc\fR(size_t \fIsize\fR);" - -.IX Item "void \fBMM_free\fR(void *\fIptr\fR);" - -.IX Item "void *\fBMM_realloc\fR(void *\fIptr\fR, size_t \fIsize\fR);" - -.IX Item "void *\fBMM_calloc\fR(size_t \fInumber\fR, size_t \fIsize\fR);" - -.IX Item "char *\fBMM_strdup\fR(const char *\fIstr\fR);" - -.IX Item "size_t \fBMM_sizeof\fR(const void *\fIptr\fR);" - -.IX Item "size_t \fBMM_maxsize\fR(void);" - -.IX Item "size_t \fBMM_available\fR(void);" - -.IX Item "char *\fBMM_error\fR(void);" - -.IX Subsection "Standard Malloc-Style \s-1API\s0" - -.IX Item "\s-1MM\s0 *\fBmm_create\fR(size_t \fIsize\fR, const char *\fIfile\fR);" - -.IX Item "int \fBmm_permission\fR(\s-1MM\s0 *\fImm\fR, mode_t \fImode\fR, uid_t \fIowner\fR, gid_t \fIgroup\fR);" - -.IX Item "void \fBmm_destroy\fR(\s-1MM\s0 *\fImm\fR);" - -.IX Item "int \fBmm_lock\fR(\s-1MM\s0 *\fImm\fR, mm_lock_mode \fImode\fR);" - -.IX Item "int \fBmm_unlock\fR(\s-1MM\s0 *\fImm\fR);" - -.IX Item "void *\fBmm_malloc\fR(\s-1MM\s0 *\fImm\fR, size_t \fIsize\fR);" - -.IX Item "void \fBmm_free\fR(\s-1MM\s0 *\fImm\fR, void *\fIptr\fR);" - -.IX Item "void *\fBmm_realloc\fR(\s-1MM\s0 *\fImm\fR, void *\fIptr\fR, size_t \fIsize\fR);" - -.IX Item "void *\fBmm_calloc\fR(\s-1MM\s0 *\fImm\fR, size_t \fInumber\fR, size_t \fIsize\fR);" - -.IX Item "char *\fBmm_strdup\fR(\s-1MM\s0 *\fImm\fR, const char *\fIstr\fR);" - -.IX Item "size_t \fBmm_sizeof\fR(const void *\fIptr\fR);" - -.IX Item "size_t \fBmm_maxsize\fR(void);" - -.IX Item "size_t \fBmm_available\fR(\s-1MM\s0 *\fImm\fR);" - -.IX Item "char *\fBmm_error\fR(void);" - -.IX Item "void \fBmm_display_info\fR(\s-1MM\s0 *\fImm\fR);" - -.IX Subsection "Low-Level Shared Memory \s-1API\s0" - -.IX Item "void *\fBmm_core_create\fR(size_t \fIsize\fR, const char *\fIfile\fR);" - -.IX Item "int \fBmm_core_permission\fR(void *\fIcore\fR, mode_t \fImode\fR, uid_t \fIowner\fR, gid_t \fIgroup\fR);" - -.IX Item "void \fBmm_core_delete\fR(void *\fIcore\fR);" - -.IX Item "int \fBmm_core_lock\fR(const void *\fIcore\fR, mm_lock_mode \fImode\fR);" - -.IX Item "int \fBmm_core_unlock\fR(const void *\fIcore\fR);" - -.IX Item "size_t \fBmm_core_size\fR(const void *\fIcore\fR);" - -.IX Item "size_t \fBmm_core_maxsegsize\fR(void);" - -.IX Item "size_t \fBmm_core_align2page\fR(size_t \fIsize\fR);" - -.IX Item "size_t \fBmm_core_align2word\fR(size_t \fIsize\fR);" - -.IX Subsection "Low-Level Shared Memory \s-1API\s0" - -.IX Item "void \fBmm_lib_error_set\fR(unsigned int, const char *str);" - -.IX Item "char *\fBmm_lib_error_get\fR(void);" - -.IX Item "int \fBmm_lib_version\fR(void);" - -.IX Header "RESTRICTIONS" - -.IX Header "SEE ALSO" - -.IX Header "HOME" - -.IX Header "HISTORY" - -.IX Header "AUTHOR" - diff --git a/shmem/unix/mm/mm.h b/shmem/unix/mm/mm.h deleted file mode 100644 index 3c029e63061..00000000000 --- a/shmem/unix/mm/mm.h +++ /dev/null @@ -1,361 +0,0 @@ -/* ==================================================================== - * Copyright (c) 1999 Ralf S. Engelschall. 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 acknowledgment: - * "This product includes software developed by - * Ralf S. Engelschall <rse@engelschall.com>." - * - * 4. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by - * Ralf S. Engelschall <rse@engelschall.com>." - * - * THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``AS IS'' AND ANY - * EXPRESSED 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 RALF S. ENGELSCHALL OR - * ITS 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. - * ==================================================================== - */ - -/* -** -** mm.h -- Shared Memory library API header -** -*/ - -#ifndef MM_H -#define MM_H 1 - -#ifdef __cplusplus -extern "C" { -#endif - -/* -** ____ Public Part (I) of the API ________________________ -*/ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <sys/types.h> -#include <sys/stat.h> - -typedef enum { - MM_LOCK_RD, MM_LOCK_RW -} mm_lock_mode; - -/* -** ____ Private Part of the API ___________________________ -*/ - -#if defined(MM_PRIVATE) - -#include "mm_conf.h" - -#include <errno.h> -#include <limits.h> -#include <unistd.h> -#include <fcntl.h> -#include <sys/stat.h> -#include <sys/types.h> - -#ifdef MM_OS_SUNOS -#define KERNEL 1 -#include <memory.h> -/* SunOS lacks prototypes */ -extern int getpagesize(void); -extern int munmap(caddr_t, int); -extern int ftruncate(int, off_t); -extern int flock(int, int); -extern char *strerror(int); -#endif - -#if !defined(FALSE) -#define FALSE 0 -#endif -#if !defined(TRUE) -#define TRUE !FALSE -#endif -#if !defined(NULL) -#define NULL (void *)0 -#endif -#if !defined(NUL) -#define NUL '\0' -#endif -#if !defined(min_of) -#define min_of(a,b) ((a) < (b) ? (a) : (b)) -#endif -#if !defined(max_of) -#define max_of(a,b) ((a) > (b) ? (a) : (b)) -#endif -#if !defined(absof) -#define abs_of(a) ((a) < 0 ? -(a) : (a)) -#endif -#if !defined(offset_of) -#define offset_of(type,member) ((size_t)(&((type *)0)->member)) -#endif - -#if !defined(HAVE_MEMCPY) -#if defined(HAVE_BCOPY) -#define memcpy(to,from,len) bcopy(from,to,len) -#else -#define memcpy(to,from,len) \ - { int i; for (i = 0; i < (len); i++) *((to)+i) = *((from)+i); } -#endif -#endif -#if !defined(HAVE_MEMSET) -#define memset(to,ch,len) \ - { int i; for (i = 0; i < (len); i++) *((to)+i) = (ch); } -#endif - -#define ERR(type,str) mm_lib_error_set(type,str) -#define FAIL(type,str) { ERR(type,str); goto cus; } -#define BEGIN_FAILURE cus: -#define END_FAILURE - -#if defined(HAVE_PATH_MAX) -#define MM_MAXPATH PATH_MAX -#elif defined(HAVE__POSIX_PATH_MAX) -#define MM_MAXPATH _POSIX_PATH_MAX -#elif defined(HAVE_MAXPATHLEN) -#define MM_MAXPATH MAXPATHLEN -#else -#define MM_MAXPATH 2048 -#endif - -#if defined(HAVE_CHILD_MAX) -#define MM_MAXCHILD CHILD_MAX -#elif defined(HAVE__POSIX_CHILD_MAX) -#define MM_MAXCHILD _POSIX_CHILD_MAX -#else -#define MM_MAXCHILD 512 -#endif - -#if defined(MM_SHMT_MMANON) || defined(MM_SHMT_MMPOSX) ||\ - defined(MM_SHMT_MMZERO) || defined(MM_SHMT_MMFILE) -#include <sys/mman.h> -#if !defined(MAP_ANON) && defined(MAP_ANONYMOUS) -#define MAP_ANON MAP_ANONYMOUS -#endif -#if !defined(MAP_FAILED) -#define MAP_FAILED ((void *)-1) -#endif -#endif - -#if defined(MM_SHMT_IPCSHM) || defined(MM_SEMT_IPCSEM) -#include <sys/ipc.h> -#endif - -#if defined(MM_SHMT_IPCSHM) -#include <sys/shm.h> -#endif - -#if defined(MM_SEMT_IPCSEM) -#include <sys/sem.h> -#ifndef HAVE_UNION_SEMUN -union semun { - int val; - struct semid_ds *buf; - u_short *array; -}; -#endif -#endif - -#ifdef MM_SEMT_FLOCK -#include <sys/file.h> -#endif - -#ifdef MM_SHMT_BEOS -#include <kernel/OS.h> -#endif - -#define MM_ALLOC_MINSIZE (1024*8) -#define MM_CORE_FILEMODE (S_IRUSR|S_IWUSR) -#define MM_CORE_DEFAULT_PAGESIZE (1024*8) -#define MM_CORE_DEFAULT_FILE "/tmp/mm.core.%d" /* %d is PID */ - -#define MM_ERR_ALLOC 1 -#define MM_ERR_CORE 2 -#define MM_ERR_SYSTEM 4 - -/* - * Define a union with types which are likely to have the longest - * *relevant* CPU-specific memory word alignment restrictions... - */ -union mem_word { - void *mw_vp; - void (*mw_fp)(void); - char *mw_cp; - long mw_l; - double mw_d; -}; -typedef union mem_word mem_word; -#define SIZEOF_mem_word (sizeof(mem_word)) - -/* - * Define the structure used for memory chunks - */ -union mem_chunk_mc_u { - struct mem_chunk *mc_next; /* really used when it's free */ - mem_word mc_base; /* virtually used when it's allocated */ -}; -struct mem_chunk { - size_t mc_size; /* physical size */ - size_t mc_usize; /* user known size */ - union mem_chunk_mc_u mc_u; -}; -typedef struct mem_chunk mem_chunk; -#define SIZEOF_mem_chunk (sizeof(mem_chunk)-sizeof(union mem_chunk_mc_u)) - -/* - * Define the structure describing a memory pool - */ -struct mem_pool { - size_t mp_size; - size_t mp_offset; - mem_chunk mp_freechunks; - mem_word mp_base; -}; -typedef struct mem_pool mem_pool; -#define SIZEOF_mem_pool (sizeof(mem_pool)-SIZEOF_mem_word) - -/* - * Define the structure holding per-process filedescriptors - */ -#if defined(MM_SEMT_FLOCK) -struct mem_core_fd { - pid_t pid; - int fd; -}; -typedef struct mem_core_fd mem_core_fd; -#define SIZEOF_mem_core_fd (sizeof(mem_core_fd) -#endif - -/* - * Define the structure describing a shared memory core area - * (the actual contents depends on the shared memory and - * semaphore/mutex type and is stripped down to a minimum - * required) - */ -struct mem_core { - size_t mc_size; - size_t mc_usize; - pid_t mc_pid; - int mc_fdmem; -#if defined(MM_SHMT_MMFILE) - char mc_fnmem[MM_MAXPATH]; -#endif -#if defined(MM_SHMT_BEOS) - area_id mc_areaid; -#endif -#if defined(MM_SEMT_BEOS) - sem_id mc_semid; - int32 mc_ben; -#endif -#if !defined(MM_SEMT_FLOCK) - int mc_fdsem; -#endif -#if defined(MM_SEMT_FLOCK) - mem_core_fd mc_fdsem[MM_MAXCHILD]; -#endif -#if defined(MM_SEMT_IPCSEM) - int mc_fdsem_rd; - int mc_readers; - mm_lock_mode mc_lockmode; -#endif -#if defined(MM_SEMT_FLOCK) || defined(MM_SEMT_FCNTL) - char mc_fnsem[MM_MAXPATH]; -#endif - mem_word mc_base; -}; -typedef struct mem_core mem_core; -#define SIZEOF_mem_core (sizeof(mem_core)-SIZEOF_mem_word) - -#endif /* MM_PRIVATE */ - -/* -** ____ Public Part (II) of the API _______________________ -*/ - -#if defined(MM_PRIVATE) -typedef mem_pool MM; -#else -typedef void MM; -#endif - -/* Global Malloc-Replacement API */ -int MM_create(size_t size, const char *file); -int MM_permission(mode_t mode, uid_t owner, gid_t group); -void MM_destroy(void); -int MM_lock(mm_lock_mode mode); -int MM_unlock(void); -void *MM_malloc(size_t size); -void *MM_realloc(void *ptr, size_t size); -void MM_free(void *ptr); -void *MM_calloc(size_t number, size_t size); -char *MM_strdup(const char *str); -size_t MM_sizeof(const void *ptr); -size_t MM_maxsize(void); -size_t MM_available(void); -char *MM_error(void); - -/* Standard Malloc-Style API */ -MM *mm_create(size_t size, const char *file); -int mm_permission(MM *mm, mode_t mode, uid_t owner, gid_t group); -void mm_destroy(MM *mm); -int mm_lock(MM *mm, mm_lock_mode mode); -int mm_unlock(MM *mm); -void *mm_malloc(MM *mm, size_t size); -void *mm_realloc(MM *mm, void *ptr, size_t size); -void mm_free(MM *mm, void *ptr); -void *mm_calloc(MM *mm, size_t number, size_t size); -char *mm_strdup(MM *mm, const char *str); -size_t mm_sizeof(MM *mm, const void *ptr); -size_t mm_maxsize(void); -size_t mm_available(MM *mm); -char *mm_error(void); -void mm_display_info(MM *mm); - -/* Low-Level Shared Memory API */ -void *mm_core_create(size_t size, const char *file); -int mm_core_permission(void *core, mode_t mode, uid_t owner, gid_t group); -void mm_core_delete(void *core); -size_t mm_core_size(const void *core); -int mm_core_lock(const void *core, mm_lock_mode mode); -int mm_core_unlock(const void *core); -size_t mm_core_maxsegsize(void); -size_t mm_core_align2page(size_t size); -size_t mm_core_align2word(size_t size); - -/* Internal Library API */ -void mm_lib_error_set(unsigned int, const char *str); -char *mm_lib_error_get(void); -int mm_lib_version(void); - -#ifdef __cplusplus -} -#endif - -#endif /* MM_H */ diff --git a/shmem/unix/mm/mm.pod b/shmem/unix/mm/mm.pod deleted file mode 100644 index 7746612b5d6..00000000000 --- a/shmem/unix/mm/mm.pod +++ /dev/null @@ -1,633 +0,0 @@ -## ==================================================================== -## Copyright (c) 1999 Ralf S. Engelschall. 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 acknowledgment: -## "This product includes software developed by -## Ralf S. Engelschall <rse@engelschall.com>." -## -## 4. Redistributions of any form whatsoever must retain the following -## acknowledgment: -## "This product includes software developed by -## Ralf S. Engelschall <rse@engelschall.com>." -## -## THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``AS IS'' AND ANY -## EXPRESSED 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 RALF S. ENGELSCHALL OR -## ITS 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. -## ==================================================================== - -## -## mm.pod -- Manpage -## - -=pod - -=head1 NAME - -B<MM - Shared Memory Library> - -=head1 VERSION - -MM MM_VERSION_STR - -=head1 SYNOPSIS - - #include "mm.h" - -B< Global Malloc-Replacement API> - - int MM_create(size_t size, const char *file); - int MM_permission(mode_t mode, uid_t owner, gid_t group); - void MM_destroy(void); - int MM_lock(mm_lock_mode mode); - int MM_unlock(void); - void *MM_malloc(size_t size); - void *MM_realloc(void *ptr, size_t size); - void MM_free(void *ptr); - void *MM_calloc(size_t number, size_t size); - char *MM_strdup(const char *str); - size_t MM_sizeof(void *ptr); - size_t MM_maxsize(void); - size_t MM_available(void); - char *MM_error(void); - -B< Standard Malloc-Style API> - - MM *mm_create(size_t size, char *file); - int mm_permission(MM *mm, mode_t mode, uid_t owner, gid_t group); - void mm_destroy(MM *mm); - int mm_lock(MM *mm, mm_lock_mode mode); - int mm_unlock(MM *mm); - void *mm_malloc(MM *mm, size_t size); - void *mm_realloc(MM *mm, void *ptr, size_t size); - void mm_free(MM *mm, void *ptr); - void *mm_calloc(MM *mm, size_t number, size_t size); - char *mm_strdup(MM *mm, const char *str); - size_t mm_sizeof(void *ptr); - size_t mm_maxsize(void); - size_t mm_available(MM *mm); - char *mm_error(void); - void mm_display_info(MM *mm); - -B< Low-level Shared Memory API> - - void *mm_core_create(size_t size, char *file); - int mm_core_permission(void *core, mode_t mode, uid_t owner, gid_t group); - void mm_core_delete(void *core); - int mm_core_lock(void *core, mm_lock_mode mode); - int mm_core_unlock(void *core); - size_t mm_core_size(void *core); - size_t mm_core_maxsegsize(void); - size_t mm_core_align2page(size_t size); - size_t mm_core_align2click(size_t size); - -B< Internal Library API> - - void mm_lib_error_set(unsigned int, const char *str); - char *mm_lib_error_get(void); - int mm_lib_version(void); - -=head1 DESCRIPTION - -The B<MM> library is a 2-layer abstraction library which simplifies the usage -of shared memory between forked (and this way strongly related) processes -under Unix platforms. On the first (lower) layer it hides all platform -dependent implementation details (allocation and locking) when dealing with -shared memory segments and on the second (higher) layer it provides a -high-level malloc(3)-style API for a convenient and well known way to work -with data-structures inside those shared memory segments. - -The abbreviation B<MM> is historically and originally comes from the phrase -``I<memory mapped>'' as used by the POSIX.1 mmap(2) function. Because this -facility is internally used by this library on most platforms to create the -shared memory segments. - -=head2 LIBRARY STRUCTURE - -This library is structured into three main APIs which are internally based on -each other: - -=over 4 - -=item B<Global Malloc-Replacement API> - -This is the most high-level API which directly can be used as replacement API -for the POSIX.1 memory allocation API (malloc(2) and friends). This is -useful when converting I<heap> based data structures to I<shared memory> -based data structures without the need to change the code dramatically. All -which is needed is to prefix the POSIX.1 memory allocation functions with -`C<MM_>', i.e. `C<malloc>' becomes `C<MM_malloc>', `C<strdup>' becomes -`C<MM_strdup>', etc. This API internally uses just a global `C<MM *>' pool for -calling the corresponding functions (with prefix `C<mm_>') of the I<Standard -Malloc-Style API>. - -=item B<Standard Malloc-Style API> - -This is the standard high-level memory allocation API. Its interface is -similar to the I<Global Malloc-Replacement API> but it uses an explicit `C<MM *>' -pool to operate on. That's why every function of this API has an argument of -type `C<MM *>' as the first argument. This API provides a comfortable way to -work with small dynamically allocated shared memory chunks inside large -statically allocated shared memory segments. It's internally based on the -I<Low-Level Shared Memory API> for creating the underlaying shared memory -segment. - -=item B<Low-Level Shared Memory API> - -This is the basis of the whole B<MM> library. It provides low-level functions -for creating shared memory segments with mutual exclusion (in short: I<mutex>) -capabilities in a portable way. Internally the shared memory and mutex -facility is implemented in various platform-dependent ways. A list of -implementation variants follows under the next topic. - -=back - -=head2 SHARED MEMORY IMPLEMENTATION - -Internally the shared memory facility is implemented in various -platform-dependent variants. Each has it's own advantages and disadvantages -(in addition to the fact that some variants aren't available at all on some -platforms). The MM libraries configuration procedure tried hard to make a good -decision. The implemented variants are now given for overview and background -reasons with their advantages and disadvantages and in an ascending order, -i.e. the MM configuration mechanism chooses the last available one in the list -as the preferred variant. - -=over 4 - -=item Classical mmap(2) on temporary file (MMFILE) - -I<Advantage:> maximum portable. -I<Disadvantage:> needs a temporary file on the filesystem - -=item mmap(2) via POSIX.1 shm_open(3) on temporary file (MMPOSX) - -I<Advantage:> standardized by POSIX.1 and theoretically portable. -I<Disadvantage:> needs a temporary file on the filesystem and is -is usually not available on existing Unix platform. - -=item SVR4-style mmap(2) on C</dev/zero> device (MMZERO) - -I<Advantage:> widely available on mostly portable on SVR4 platforms. -I<Disadvantage:> needs the C</dev/zero/> device and an mmap(2) -which supports memory mapping through it. - -=item 4.4BSD-style mmap(2) via C<MAP_ANON> facility (MMANON) - -I<Advantage:> doesn't need a temporary file or external device -I<Disadvantage:> usually only available on BSD platforms and derivatives. - -=item SysV IPC shmget(2) (IPCSHM) - -I<Advantage:> doesn't need a temporary file or external device -I<Disadvantage:> although available on mostly all modern Unix platforms it has -hard restrictions like the maximum size of a single shared memory segment (can -be as small as 100KB, but depends on the platform). - -=back - -=head2 LOCKING IMPLEMENTATION - -As for the shared memory facility, internally the locking facility is -implemented in various platform-dependent variants. A short overview of -implemented variants is given: - -=over 4 - -=item 4.2BSD-style flock(2) on temporary file (FLOCK) - -I<Advantage:> exists on a lot of platforms, especially on older Unix -derivates. I<Disadvantage:> needs a temporary file on the filesystem and has -to reopen filedescriptors to it in each(!) fork(2)ed child process. - -=item SysV IPC semget(2) (IPCSEM) - -I<Advantage:> exists on a lot of platforms and doesn't need a temporary file. -I<Disadvantage:> an unmeant termination of the application leads to a -semaphore leak because the facility doesn't allow an "remove in advance" trick -(as the IPC shared memory facility does!) for safe cleanups. - -=item SVR4-style fcntl(2) on temporary file (FCNTL) - -I<Advantage:> exists on a lot of platforms and is also the most powerful -variant (although not always the fastest one). I<Disadvantage:> needs a -temporary file. - -=back - -=head2 MEMORY ALLOCATION STRATEGY - -The memory allocation strategy the I<Standard Malloc-Style API> functions use -internally is the following: - -=over 4 - -=item B<Allocation> - -When a chunk of memory has to be allocated, the internal list of free chunks -is searched for a minimal-sized chunk which is larger or equal than the size -of the to be allocated chunk (some sort of a I<best fit algorithm>). - -When a chunk is found which matches this best-fit criteria, but is still a lot -larger than the requested size, it is split into two chunks: One with exactly -the requested size (which is the resulting chunk) and one with the remaining -size (which is immediately re-inserted into the list of free chunks). - -When no fitting chunk is found at all in the list of free chunks, a new one is -created from the spare area of the shared memory segment until the segment is -full (in which case an I<out of memory> error occurs). - -=item B<Deallocation> - -When a chunk of memory has to be deallocated, it is inserted in sorted manner -into the internal list of free chunks. The insertion operation automatically -merges the chunk with a previous and/or next free chunk when possible, i.e. -the free chunks stay physically seamless (one after another) in memory, to -automatically form larger free chunks out of smaller ones. - -This way the shared memory segment is automatically defragmented when memory -is deallocated. - -=back - -This strategy reduces memory waste and fragmentation caused by small and -frequent allocations and deallocations to a minimum. - -The internal implementation of the list of free chunks is not specially -optimized (for instance by using binary search trees or even splay trees, -etc.), because it's assumed that the total amount of entries in the list of -free chunks is always small (caused both by the fact that shared memory -segments are usually a lot smaller than heaps and the fact that we always -defragment by merging the free chunks when possible). - -=head1 API FUNCTIONS - -In the following all API functions are described in detail. -The order directly follows the one in the SYNOPSIS. - -=head2 Global Malloc-Replacement API - -=over 4 - -=item int B<MM_create>(size_t I<size>, const char *I<file>); - -This initialized the global shared memory pool with I<size> and I<file> and -has be called I<before> any fork(2) operations are performed by the -application. - -=item int B<MM_permission>(mode_t I<mode>, uid_t I<owner>, gid_t I<group>); - -This sets the filesystem I<mode>, I<owner> and I<group> for the global shared -memory pool (has effects only when the underlaying shared memory segment -implementation is actually based on external auxiliary files). The arguments -are directly passed through to chmod(2) and chown(2). - -=item void B<MM_destroy>(void); - -This destroys the global shared memory pool and should be called I<after> all -child processes were killed. - -=item int B<MM_lock>(mm_lock_mode I<mode>); - -This locks the global shared memory pool for the current process in order to -perform either shared/read-only (I<mode> is C<MM_LOCK_RD>) or -exclusive/read-write (I<mode> is C<MM_LOCK_RW>) operations inside the global -shared memory pool. - -=item int B<MM_unlock>(void); - -This unlocks the global shared memory pool for the current process after -mutual exclusion operations were performed inside the global shared memory -pool. - -=item void *B<MM_malloc>(size_t I<size>); - -Identical to the POSIX.1 malloc(3) function but instead of allocating -memory from the I<heap> it allocates it from the global shared memory pool. - -=item void B<MM_free>(void *I<ptr>); - -Identical to the POSIX.1 free(3) function but instead of deallocating -memory in the I<heap> it deallocates it in the global shared memory pool. - -=item void *B<MM_realloc>(void *I<ptr>, size_t I<size>); - -Identical to the POSIX.1 realloc(3) function but instead of reallocating -memory in the I<heap> it reallocates it inside the global shared memory pool. - -=item void *B<MM_calloc>(size_t I<number>, size_t I<size>); - -Identical to the POSIX.1 calloc(3) function but instead of allocating and -initializing memory from the I<heap> it allocates and initializes it from the -global shared memory pool. - -=item char *B<MM_strdup>(const char *I<str>); - -Identical to the POSIX.1 strdup(3) function but instead of creating the -string copy in the I<heap> it creates it in the global shared memory pool. - -=item size_t B<MM_sizeof>(const void *I<ptr>); - -This function returns the size in bytes of the chunk starting at I<ptr> when -I<ptr> was previously allocated with MM_malloc(3). The result is undefined -when I<ptr> was not previously allocated with MM_malloc(3). - -=item size_t B<MM_maxsize>(void); - -This function returns the maximum size which is allowed -as the first argument to the MM_create(3) function. - -=item size_t B<MM_available>(void); - -Returns the amount in bytes of still available (free) memory in the global -shared memory pool. - -=item char *B<MM_error>(void); - -Returns the last error message which occurred inside the B<MM> library. - -=back - -=head2 Standard Malloc-Style API - -=over 4 - -=item MM *B<mm_create>(size_t I<size>, const char *I<file>); - -This creates a shared memory pool which has space for approximately a total of -I<size> bytes with the help of I<file>. Here I<file> is a filesystem path to a -file which need not to exist (and perhaps is never created because this -depends on the platform and chosen shared memory and mutex implementation). -The return value is a pointer to an C<MM> structure which should be treated as -opaque by the application. It describes the internals of the created shared -memory pool. In case of an error C<NULL> is returned. A I<size> of 0 means to -allocate the maximum allowed size which is platform dependent and between a -few KB and the soft limit of 64MB. - -=item int B<mm_permission>(MM *I<mm>, mode_t I<mode>, uid_t I<owner>, gid_t I<group>); - -This sets the filesystem I<mode>, I<owner> and I<group> for the shared memory -pool I<mm> (has effects only when the underlaying shared memory segment -implementation is actually based on external auxiliary files). The arguments -are directly passed through to chmod(2) and chown(2). - -=item void B<mm_destroy>(MM *I<mm>); - -This destroys the complete shared memory pool I<mm> and with it all chunks -which were allocated in this pool. Additionally any created files on the -filesystem corresponding the to shared memory pool are unlinked. - -=item int B<mm_lock>(MM *I<mm>, mm_lock_mode I<mode>); - -This locks the shared memory pool I<mm> for the current process in order to -perform either shared/read-only (I<mode> is C<MM_LOCK_RD>) or -exclusive/read-write (I<mode> is C<MM_LOCK_RW>) operations inside the global -shared memory pool. - -=item int B<mm_unlock>(MM *I<mm>); - -This unlocks the shared memory pool I<mm> for the current process after mutual -exclusion operations were performed inside the global shared memory pool. - -=item void *B<mm_malloc>(MM *I<mm>, size_t I<size>); - -This function allocates I<size> bytes from the shared memory pool I<mm> and -returns either a (virtual memory word aligned) pointer to it or C<NULL> in -case of an error (out of memory). It behaves like the POSIX.1 malloc(3) -function but instead of allocating memory from the I<heap> it allocates it -from the shared memory segment underlaying I<mm>. - -=item void B<mm_free>(MM *I<mm>, void *I<ptr>); - -This deallocates the chunk starting at I<ptr> in the shared memory pool I<mm>. -It behaves like the POSIX.1 free(3) function but instead of deallocating -memory from the I<heap> it deallocates it from the shared memory segment -underlaying I<mm>. - -=item void *B<mm_realloc>(MM *I<mm>, void *I<ptr>, size_t I<size>); - -This function reallocates the chunk starting at I<ptr> inside the shared -memory pool I<mm> with the new size of I<size> bytes. It behaves like the -POSIX.1 realloc(3) function but instead of reallocating memory in the -I<heap> it reallocates it in the shared memory segment underlaying I<mm>. - -=item void *B<mm_calloc>(MM *I<mm>, size_t I<number>, size_t I<size>); - -This is similar to mm_malloc(3), but additionally clears the chunk. It behaves -like the POSIX.1 calloc(3) function. It allocates space for I<number> -objects, each I<size> bytes in length from the shared memory pool I<mm>. The -result is identical to calling mm_malloc(3) with an argument of ``I<number> * -I<size>'', with the exception that the allocated memory is initialized to nul -bytes. - -=item char *B<mm_strdup>(MM *I<mm>, const char *I<str>); - -This function behaves like the POSIX.1 strdup(3) function. It allocates -sufficient memory inside the shared memory pool I<mm> for a copy of the string -I<str>, does the copy, and returns a pointer to it. The pointer may -subsequently be used as an argument to the function mm_free(3). If -insufficient shared memory is available, C<NULL> is returned. - -=item size_t B<mm_sizeof>(const void *I<ptr>); - -This function returns the size in bytes of the chunk starting at I<ptr> when -I<ptr> was previously allocated with mm_malloc(3). The result is undefined -when I<ptr> was not previously allocated with mm_malloc(3). - -=item size_t B<mm_maxsize>(void); - -This function returns the maximum size which is allowed as the first argument -to the mm_create(3) function. - -=item size_t B<mm_available>(MM *I<mm>); - -Returns the amount in bytes of still available (free) memory in the -shared memory pool I<mm>. - -=item char *B<mm_error>(void); - -Returns the last error message which occurred inside the B<MM> library. - -=item void B<mm_display_info>(MM *I<mm>); - -This is debugging function which displays a summary page for the shared memory -pool I<mm> describing various internal sizes and counters. - -=back - -=head2 Low-Level Shared Memory API - -=over 4 - -=item void *B<mm_core_create>(size_t I<size>, const char *I<file>); - -This creates a shared memory area which is at least I<size> bytes in size with -the help of I<file>. The value I<size> has to be greater than 0 and less or -equal the value returned by mm_core_maxsegsize(3). Here I<file> is a -filesystem path to a file which need not to exist (and perhaps is never -created because this depends on the platform and chosen shared memory and -mutex implementation). The return value is either a (virtual memory word -aligned) pointer to the shared memory segment or C<NULL> in case of an error. -The application is guaranteed to be able to access the shared memory segment -from byte 0 to byte I<size>-1 starting at the returned address. - -=item int B<mm_core_permission>(void *I<core>, mode_t I<mode>, uid_t I<owner>, gid_t I<group>); - -This sets the filesystem I<mode>, I<owner> and I<group> for the shared memory -segment I<code> (has effects only when the underlaying shared memory segment -implementation is actually based on external auxiliary files). The arguments -are directly passed through to chmod(2) and chown(2). - -=item void B<mm_core_delete>(void *I<core>); - -This deletes a shared memory segment I<core> (as previously returned by a -mm_core_create(3) call). After this operation, accessing the segment starting -at I<core> is no longer allowed and will usually lead to a segmentation fault. - -=item int B<mm_core_lock>(const void *I<core>, mm_lock_mode I<mode>); - -This function acquires an advisory lock for the current process on the shared -memory segment I<core> for either shared/read-only (I<mode> is C<MM_LOCK_RD>) -or exclusive/read-write (I<mode> is C<MM_LOCK_RW>) operations between -fork(2)'ed child processes. - -=item int B<mm_core_unlock>(const void *I<core>); - -This function releases a previously acquired advisory lock for the current -process on the shared memory segment I<core>. - -=item size_t B<mm_core_size>(const void *I<core>); - -This returns the size in bytes of I<core>. This size is exactly the size which -was used for creating the shared memory area via mm_core_create(3). The -function is provided just for convenience reasons to not require the -application to remember the memory size behind I<core> itself. - -=item size_t B<mm_core_maxsegsize>(void); - -This returns the number of bytes of a maximum-size shared memory segment which -is allowed to allocate via the MM library. It is between a few KB and the soft -limit of 64MB. - -=item size_t B<mm_core_align2page>(size_t I<size>); - -This is just a utility function which can be used to align the number I<size> -to the next virtual memory I<page> boundary used by the underlaying platform. -The memory page boundary under Unix platforms is usually somewhere between -2048 and 16384 bytes. You don't have to align the I<size> arguments of other -B<MM> library functions yourself, because this is already done internally. -This function is exported by the B<MM> library just for convenience reasons in -case an application wants to perform simular calculations for other purposes. - -=item size_t B<mm_core_align2word>(size_t I<size>); - -This is another utility function which can be used to align the number I<size> -to the next virtual memory I<word> boundary used by the underlaying platform. -The memory word boundary under Unix platforms is usually somewhere between 4 -and 16 bytes. You don't have to align the I<size> arguments of other B<MM> -library functions yourself, because this is already done internally. This -function is exported by the B<MM> library just for convenience reasons in case -an application wants to perform simular calculations for other purposes. - -=back - -=head2 Low-Level Shared Memory API - -=over 4 - -=item void B<mm_lib_error_set>(unsigned int, const char *str); - -This is a function which is used internally by the various MM function to set -an error string. It's usually not called directly from applications. - -=item char *B<mm_lib_error_get>(void); - -This is a function which is used internally by MM_error(3) and mm_error(3) -functions to get the current error string. It's usually not called directly -from applications. - -=item int B<mm_lib_version>(void); - -This function returns a hex-value ``0xI<V>I<RR>I<T>I<LL>'' which describes the -current MM library version. I<V> is the version, I<RR> the revisions, I<LL> -the level and I<T> the type of the level (alphalevel=0, betalevel=1, -patchlevel=2, etc). For instance MM version 1.0.4 is encoded as 0x100204. The -reason for this unusual mapping is that this way the version number is -steadily I<increasing>. - -=back - -=head1 RESTRICTIONS - -The maximum size of a continuous shared memory segment one can allocate -depends on the underlaying platform. This cannot be changed, of course. But -currently the high-level malloc(3)-style API just uses a single shared memory -segment as the underlaying data structure for an C<MM> object which means that -the maximum amount of memory a C<MM> object represents also depends on the -platform. - -This should be changed in later versions by allowing the high-level -malloc(3)-style API to internally use multiple shared memory segments to form -the C<MM> object. This way C<MM> objects could have arbitrary sizes, although -the maximum size of an allocatable chunk still is bounded by the maximum size -of a shared memory segment. - -=head1 SEE ALSO - -mm-config(1). - -malloc(3), calloc(3), realloc(3), strdup(3), free(3), mmap(2), shmget(2), -shmctl(2), flock(2), fcntl(2), semget(2), semctl(2), semop(2). - -=head1 HOME - -=for html -<a href="http://www.engelschall.com/sw/mm/">http://www.engelschall.com/sw/mm/</a> - -=for text -http://www.engelschall.com/sw/mm/ - -=for man -http://www.engelschall.com/sw/mm/ - -=head1 HISTORY - -This library was originally written in January 1999 by I<Ralf S. Engelschall> -<rse@engelschall.com> for use in the B<Extended API> (EAPI) of the B<Apache> -HTTP server project (see www.apache.org), which was originally invented for -B<mod_ssl> (see http://www.modssl.org/). - -Its base idea (a malloc-style API for handling shared memory) was originally -derived from the non-publically available I<mm_malloc> library written in -October 1997 by I<Charles Randall> <crandall@matchlogic.com> for MatchLogic, -Inc. - -=head1 AUTHOR - - Ralf S. Engelschall - rse@engelschall.com - www.engelschall.com - -=cut - diff --git a/shmem/unix/mm/mm_alloc.c b/shmem/unix/mm/mm_alloc.c deleted file mode 100644 index 049a4ab20f2..00000000000 --- a/shmem/unix/mm/mm_alloc.c +++ /dev/null @@ -1,446 +0,0 @@ -/* ==================================================================== - * Copyright (c) 1999 Ralf S. Engelschall. 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 acknowledgment: - * "This product includes software developed by - * Ralf S. Engelschall <rse@engelschall.com>." - * - * 4. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by - * Ralf S. Engelschall <rse@engelschall.com>." - * - * THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``AS IS'' AND ANY - * EXPRESSED 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 RALF S. ENGELSCHALL OR - * ITS 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. - * ==================================================================== - */ - -/* -** -** mm_alloc.c -- Standard Malloc-Style API -** -*/ - -#define MM_PRIVATE -#include "mm.h" - -/* - * Create a memory pool - */ -MM *mm_create(size_t usize, const char *file) -{ - MM *mm = NULL; - void *core; - size_t size; - size_t maxsize; - - /* defaults */ - maxsize = mm_maxsize(); - if (usize < 0) { - errno = EINVAL; - return NULL; - } - if (usize == 0) - usize = maxsize; - if (usize > maxsize) - usize = maxsize; - if (usize < MM_ALLOC_MINSIZE) - usize = MM_ALLOC_MINSIZE; - - /* determine size */ - size = usize+SIZEOF_mem_pool; - - /* get a shared memory area */ - if ((core = mm_core_create(size, file)) == NULL) - return NULL; - - /* fill in the memory pool structure */ - mm = (MM *)core; - mm->mp_size = size; - mm->mp_offset = SIZEOF_mem_pool; - - /* first element of list of free chunks counts existing chunks */ - mm->mp_freechunks.mc_size = 0; - mm->mp_freechunks.mc_usize = 0; - mm->mp_freechunks.mc_u.mc_next = NULL; - - return mm; -} - -/* - * Set permissions on memory pools underlaying disk files - */ -int mm_permission(MM *mm, mode_t mode, uid_t owner, gid_t group) -{ - if (mm == NULL) - return -1; - return mm_core_permission((void *)mm, mode, owner, group); -} - -/* - * Destroy a memory pool - */ -void mm_destroy(MM *mm) -{ - if (mm == NULL) - return; - /* wipe out the whole area to be safe */ - memset(mm, 0, mm->mp_size); - /* and delete the core area */ - (void)mm_core_delete((void *)mm); - return; -} - -/* - * Lock a memory pool - */ -int mm_lock(MM *mm, mm_lock_mode mode) -{ - if (mm == NULL) - return FALSE; - return mm_core_lock((void *)mm, mode); -} - -/* - * Unlock a memory pool - */ -int mm_unlock(MM *mm) -{ - if (mm == NULL) - return FALSE; - return mm_core_unlock((void *)mm); -} - -/* - * Display debugging information - */ -void mm_display_info(MM *mm) -{ - mem_chunk *mc; - int nFree; - int nAlloc; - int i; - - if (!mm_core_lock((void *)mm, MM_LOCK_RD)) - return; - mc = &(mm->mp_freechunks); - nFree = 0; - while (mc->mc_u.mc_next != NULL) { - mc = mc->mc_u.mc_next; - nFree += mc->mc_size; - } - nAlloc = mm->mp_offset-SIZEOF_mem_pool-nFree; - - fprintf(stderr, "Information for MM\n"); - fprintf(stderr, " memory area = 0x%lx - 0x%lx\n", (unsigned long)mm, (unsigned long)(mm+mm->mp_size)); - fprintf(stderr, " memory size = %d\n", mm->mp_size); - fprintf(stderr, " memory offset = %d\n", mm->mp_offset); - fprintf(stderr, " bytes spare = %d\n", mm->mp_size-mm->mp_offset); - fprintf(stderr, " bytes free = %d (%d chunk%s)\n", - nFree, mm->mp_freechunks.mc_usize, - mm->mp_freechunks.mc_usize == 1 ? "" : "s"); - fprintf(stderr, " bytes allocated = %d\n", nAlloc); - - fprintf(stderr, " List of free chunks:\n"); - if (mm->mp_freechunks.mc_usize > 0) { - mc = &(mm->mp_freechunks); - i = 1; - while (mc->mc_u.mc_next != NULL) { - mc = mc->mc_u.mc_next; - fprintf(stderr, " chunk #%03d: 0x%lx-0x%lx (%d bytes)\n", - i++, (unsigned long)mc, (unsigned long)(mc+mc->mc_size), mc->mc_size); - } - } - else { - fprintf(stderr, " <empty-list>\n"); - } - mm_core_unlock((void *)mm); - return; -} - -/* - * Insert a chunk to the list of free chunks. Algorithm used is: - * Insert in sorted manner to the list and merge with previous - * and/or next chunk when possible to form larger chunks out of - * smaller ones. - */ -static void mm_insert_chunk(MM *mm, mem_chunk *mcInsert) -{ - mem_chunk *mc; - mem_chunk *mcPrev; - mem_chunk *mcNext; - - if (!mm_core_lock((void *)mm, MM_LOCK_RW)) - return; - mc = &(mm->mp_freechunks); - while (mc->mc_u.mc_next != NULL && (char *)(mc->mc_u.mc_next) < (char *)mcInsert) - mc = mc->mc_u.mc_next; - mcPrev = mc; - mcNext = mc->mc_u.mc_next; - if ((char *)mcPrev+mcPrev->mc_size == (char *)mcInsert && - (mcNext != NULL && (char *)mcInsert+mcInsert->mc_size == (char *)mcNext)) { - /* merge with previous and next chunk */ - mcPrev->mc_size += mcInsert->mc_size + mcNext->mc_size; - mcPrev->mc_u.mc_next = mcNext->mc_u.mc_next; - mm->mp_freechunks.mc_usize -= 1; - } - else if ((char *)mcPrev+mcPrev->mc_size == (char *)mcInsert) { - /* merge with previous chunk */ - mcPrev->mc_size += mcInsert->mc_size; - } - else if (mcNext != NULL && (char *)mcInsert+mcInsert->mc_size == (char *)mcNext) { - /* merge with next chunk */ - mcInsert->mc_size += mcNext->mc_size; - mcInsert->mc_u.mc_next = mcNext->mc_u.mc_next; - mcPrev->mc_u.mc_next = mcInsert; - } - else { - /* no merging possible, so insert as new chunk */ - mcInsert->mc_u.mc_next = mcNext; - mcPrev->mc_u.mc_next = mcInsert; - mm->mp_freechunks.mc_usize += 1; - } - mm_core_unlock((void *)mm); - return; -} - -/* - * Retrieve a chunk from the list of free chunks. Algorithm used - * is: Search for minimal-sized chunk which is larger or equal - * than the request size. But when the retrieved chunk is still a - * lot larger than the requested size, split out the requested - * size to not waste memory. - */ -static mem_chunk *mm_retrieve_chunk(MM *mm, size_t size) -{ - mem_chunk *mc; - mem_chunk **pmcMin; - mem_chunk *mcRes; - size_t sMin; - size_t s; - - if (mm->mp_freechunks.mc_usize == 0) - return NULL; - if (!mm_core_lock((void *)mm, MM_LOCK_RW)) - return NULL; - /* find best-fitting chunk */ - pmcMin = NULL; - sMin = mm->mp_size; /* maximum possible */ - mc = &(mm->mp_freechunks); - while (mc->mc_u.mc_next != NULL) { - s = mc->mc_u.mc_next->mc_size; - if (s >= size && s < sMin) { - pmcMin = &(mc->mc_u.mc_next); - sMin = s; - if (s == size) - break; - } - mc = mc->mc_u.mc_next; - } - /* create result chunk */ - if (pmcMin == NULL) - mcRes = NULL; - else { - mcRes = *pmcMin; - if (mcRes->mc_size >= (size + min_of(2*size,128))) { - /* split out in part */ - s = mcRes->mc_size - size; - mcRes->mc_size = size; - /* add back remaining chunk part as new chunk */ - mc = (mem_chunk *)((char *)mcRes + size); - mc->mc_size = s; - mc->mc_u.mc_next = mcRes->mc_u.mc_next; - *pmcMin = mc; - } - else { - /* split out as a whole */ - *pmcMin = mcRes->mc_u.mc_next; - mm->mp_freechunks.mc_usize--; - } - } - mm_core_unlock((void *)mm); - return mcRes; -} - -/* - * Allocate a chunk of memory - */ -void *mm_malloc(MM *mm, size_t usize) -{ - mem_chunk *mc; - size_t size; - void *vp; - - if (mm == NULL || usize == 0) - return NULL; - size = mm_core_align2word(SIZEOF_mem_chunk+usize); - if ((mc = mm_retrieve_chunk(mm, size)) != NULL) { - mc->mc_usize = usize; - return &(mc->mc_u.mc_base.mw_cp); - } - if (!mm_core_lock((void *)mm, MM_LOCK_RW)) - return NULL; - if ((mm->mp_size - mm->mp_offset) < size) { - mm_core_unlock((void *)mm); - ERR(MM_ERR_ALLOC, "Out of memory"); - errno = ENOMEM; - return NULL; - } - mc = (mem_chunk *)((char *)mm + mm->mp_offset); - mc->mc_size = size; - mc->mc_usize = usize; - vp = (void *)&(mc->mc_u.mc_base.mw_cp); - mm->mp_offset += size; - mm_core_unlock((void *)mm); - return vp; -} - -/* - * Reallocate a chunk of memory - */ -void *mm_realloc(MM *mm, void *ptr, size_t usize) -{ - size_t size; - mem_chunk *mc; - void *vp; - - if (mm == NULL || usize == 0) - return NULL; - if (ptr == NULL) - return mm_malloc(mm, usize); /* POSIX.1 semantics */ - mc = (mem_chunk *)((char *)ptr - SIZEOF_mem_chunk); - if (usize <= mc->mc_usize) { - mc->mc_usize = usize; - return ptr; - } - size = mm_core_align2word(SIZEOF_mem_chunk+usize); - if (size <= mc->mc_size) { - mc->mc_usize = usize; - return ptr; - } - if ((vp = mm_malloc(mm, usize)) == NULL) - return NULL; - memcpy(vp, ptr, usize); - mm_free(mm, ptr); - return vp; -} - -/* - * Free a chunk of memory - */ -void mm_free(MM *mm, void *ptr) -{ - mem_chunk *mc; - - if (mm == NULL || ptr == NULL) - return; - mc = (mem_chunk *)((char *)ptr - SIZEOF_mem_chunk); - mm_insert_chunk(mm, mc); - return; -} - -/* - * Allocate and initialize a chunk of memory - */ -void *mm_calloc(MM *mm, size_t number, size_t usize) -{ - void *vp; - - if (mm == NULL || number*usize == 0) - return NULL; - if ((vp = mm_malloc(mm, number*usize)) == NULL) - return NULL; - memset(vp, 0, number*usize); - return vp; -} - -/* - * Duplicate a string - */ -char *mm_strdup(MM *mm, const char *str) -{ - int n; - void *vp; - - if (mm == NULL || str == NULL) - return NULL; - n = strlen(str); - if ((vp = mm_malloc(mm, n+1)) == NULL) - return NULL; - memcpy(vp, str, n+1); - return vp; -} - -/* - * Determine user size of a memory chunk - */ -size_t mm_sizeof(MM *mm, const void *ptr) -{ - mem_chunk *mc; - - if (mm == NULL || ptr == NULL) - return -1; - mc = (mem_chunk *)((char *)ptr - SIZEOF_mem_chunk); - return mc->mc_usize; -} - -/* - * Determine maximum size of an allocateable memory pool - */ -size_t mm_maxsize(void) -{ - return (mm_core_maxsegsize()-SIZEOF_mem_pool); -} - -/* - * Determine available memory - */ -size_t mm_available(MM *mm) -{ - mem_chunk *mc; - int nFree; - - if (!mm_core_lock((void *)mm, MM_LOCK_RD)) - return 0; - nFree = mm->mp_size-mm->mp_offset; - mc = &(mm->mp_freechunks); - while (mc->mc_u.mc_next != NULL) { - mc = mc->mc_u.mc_next; - nFree += mc->mc_size; - } - mm_core_unlock((void *)mm); - return nFree; -} - -/* - * Return last error string - */ -char *mm_error(void) -{ - return mm_lib_error_get(); -} - -/*EOF*/ diff --git a/shmem/unix/mm/mm_conf.h.in b/shmem/unix/mm/mm_conf.h.in deleted file mode 100644 index 5d6be09f06e..00000000000 --- a/shmem/unix/mm/mm_conf.h.in +++ /dev/null @@ -1,44 +0,0 @@ -/* -** mm_conf.h -*/ - -#ifndef MM_CONF_HH -#define MM_CONF_HH - -/* VM Page Size Determination */ -#undef MM_VMPS_GETPAGESIZE -#undef MM_VMPS_SYSCONF -#undef MM_VMPS_BEOS - -/* Shared Memory Type */ -#undef MM_SHMT_MMANON -#undef MM_SHMT_MMPOSX -#undef MM_SHMT_MMZERO -#undef MM_SHMT_MMFILE -#undef MM_SHMT_IPCSHM -#undef MM_SHMT_BEOS - -/* Shared Memory Maximum Segment Size */ -#define MM_SHM_MAXSEGSIZE @MM_SHM_MAXSEGSIZE@ - -/* Semaphore Type */ -#undef MM_SEMT_FLOCK -#undef MM_SEMT_FCNTL -#undef MM_SEMT_IPCSEM -#undef MM_SEMT_BEOS - -/* Debugging */ -#undef MM_DEBUG - -/* Standard Autoconf stuff */ -#undef HAVE_MEMCPY -#undef HAVE_MEMSET -#undef HAVE_BCOPY -#undef HAVE_MEMORY_H -#undef MM_OS_SUNOS -#undef HAVE_PATH_MAX -#undef HAVE__POSIX_PATH_MAX -#undef HAVE_MAXPATHLEN -#undef HAVE_UNION_SEMUN - -#endif /* MM_CONF_HH */ diff --git a/shmem/unix/mm/mm_core.c b/shmem/unix/mm/mm_core.c deleted file mode 100644 index 37d938ea0b1..00000000000 --- a/shmem/unix/mm/mm_core.c +++ /dev/null @@ -1,626 +0,0 @@ -/* ==================================================================== - * Copyright (c) 1999 Ralf S. Engelschall. 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 acknowledgment: - * "This product includes software developed by - * Ralf S. Engelschall <rse@engelschall.com>." - * - * 4. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by - * Ralf S. Engelschall <rse@engelschall.com>." - * - * THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``AS IS'' AND ANY - * EXPRESSED 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 RALF S. ENGELSCHALL OR - * ITS 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. - * ==================================================================== - */ - -/* -** -** mm_core.c -- Low-level Shared Memory API -** -*/ - -#define MM_PRIVATE -#include "mm.h" - -/* - * Some global variables - */ - -#if defined(MM_SEMT_FCNTL) -/* lock/unlock structures for fcntl() */ -static struct flock mm_core_dolock_rd; -static struct flock mm_core_dolock_rw; -static struct flock mm_core_dounlock; -#endif - -#if defined(MM_SEMT_IPCSEM) -/* lock/unlock structures for semop() */ -static union semun mm_core_semctlarg; -static struct sembuf mm_core_dolock[2]; -static struct sembuf mm_core_dounlock[1]; -#endif - -#if defined(MM_SHMT_MMFILE) || defined(MM_SHMT_MMPOSX) -static size_t mm_core_mapoffset = 0; /* we use own file */ -#elif defined(MM_SHMT_MMZERO) -static size_t mm_core_mapoffset = 1024*1024*1; /* we share with other apps */ -#endif - -static void mm_core_init(void) -{ - static int initialized = FALSE; - if (!initialized) { -#if defined(MM_SEMT_FCNTL) - mm_core_dolock_rd.l_whence = SEEK_SET; /* from current point */ - mm_core_dolock_rd.l_start = 0; /* -"- */ - mm_core_dolock_rd.l_len = 0; /* until end of file */ - mm_core_dolock_rd.l_type = F_RDLCK; /* set shard/read lock */ - mm_core_dolock_rd.l_pid = 0; /* pid not actually interesting */ - mm_core_dolock_rw.l_whence = SEEK_SET; /* from current point */ - mm_core_dolock_rw.l_start = 0; /* -"- */ - mm_core_dolock_rw.l_len = 0; /* until end of file */ - mm_core_dolock_rw.l_type = F_WRLCK; /* set exclusive/read-write lock */ - mm_core_dolock_rw.l_pid = 0; /* pid not actually interesting */ - mm_core_dounlock.l_whence = SEEK_SET; /* from current point */ - mm_core_dounlock.l_start = 0; /* -"- */ - mm_core_dounlock.l_len = 0; /* until end of file */ - mm_core_dounlock.l_type = F_UNLCK; /* unlock */ - mm_core_dounlock.l_pid = 0; /* pid not actually interesting */ -#endif -#if defined(MM_SEMT_IPCSEM) - mm_core_dolock[0].sem_num = 0; - mm_core_dolock[0].sem_op = 0; - mm_core_dolock[0].sem_flg = 0; - mm_core_dolock[1].sem_num = 0; - mm_core_dolock[1].sem_op = 1; - mm_core_dolock[1].sem_flg = SEM_UNDO; - mm_core_dounlock[0].sem_num = 0; - mm_core_dounlock[0].sem_op = -1; - mm_core_dounlock[0].sem_flg = SEM_UNDO; -#endif - initialized = TRUE; - } - return; -} - -#if defined(MM_SEMT_FLOCK) -/* - * Determine per-process fd for semaphore - * (needed only for flock() based semaphore) - */ -static int mm_core_getfdsem(mem_core *mc) -{ - int fd = -1; - pid_t pid; - int i; - - pid = getpid(); - for (i = 0; i < MM_MAXCHILD && - mc->mc_fdsem[i].pid != 0 && - mc->mc_fdsem[i].fd != -1; i++) { - if (mc->mc_fdsem[i].pid == pid) { - fd = mc->mc_fdsem[i].fd; - break; - } - } - if (fd == -1 && i < MM_MAXCHILD) { - fd = open(mc->mc_fnsem, O_WRONLY, MM_CORE_FILEMODE); - mc->mc_fdsem[i].pid = getpid(); - mc->mc_fdsem[i].fd = fd; - } - return fd; -} -#endif /* MM_SEMT_FLOCK */ - -/* - * Determine memory page size of OS - */ - -static size_t mm_core_pagesize(void) -{ - static int pagesize = 0; - if (pagesize == 0) -#if defined(MM_VMPS_GETPAGESIZE) - pagesize = getpagesize(); -#elif defined(MM_VMPS_SYSCONF) - pagesize = sysconf(_SC_PAGESIZE); -#elif defined(MM_VMPS_BEOS) - pagesize = B_PAGE_SIZE; -#else - pagesize = MM_CORE_DEFAULT_PAGESIZE; -#endif - return pagesize; -} - -/* - * Align a size to the next page or word boundary - */ - -size_t mm_core_align2page(size_t size) -{ - int psize = mm_core_pagesize(); - return ((size)%(psize) > 0 ? ((size)/(psize)+1)*(psize) : (size)); -} - -size_t mm_core_align2word(size_t size) -{ - return ((1+((size-1) / SIZEOF_mem_word)) * SIZEOF_mem_word); -} - -size_t mm_core_maxsegsize(void) -{ - return mm_core_align2page((MM_SHM_MAXSEGSIZE-SIZEOF_mem_core)-mm_core_pagesize()); -} - -/* - * Create a shared memory area - */ - -void *mm_core_create(size_t usersize, const char *file) -{ - mem_core *mc; - void *area = ((void *)-1); - int fdmem = 0; - int fdsem = 0; -#if defined(MM_SEMT_IPCSEM) - int fdsem_rd = 0; -#endif -#if defined(MM_SHMT_MMPOSX) || defined(MM_SHMT_MMFILE) - char *fnmem; -#endif -#if defined(MM_SEMT_FLOCK) || defined(MM_SEMT_FCNTL) - char *fnsem; -#endif - size_t size; -#if defined(MM_SHMT_MMZERO) || defined(MM_SHMT_MMPOSX) || defined(MM_SHMT_MMFILE) - int zero = 0; -#endif -#if defined(MM_SHMT_IPCSHM) - struct shmid_ds shmbuf; -#endif -#if defined(MM_SHMT_MMPOSX) || defined(MM_SHMT_MMFILE) - char shmfilename[MM_MAXPATH]; -#endif -#if defined(MM_SEMT_FLOCK) || defined(MM_SEMT_FCNTL) - char semfilename[MM_MAXPATH]; -#endif -#if defined(MM_SHMT_BEOS) - area_id temparea; -#endif - char filename[MM_MAXPATH]; - - if (usersize <= 0 || usersize > mm_core_maxsegsize()) { - errno = EINVAL; - return NULL; - } - if (file == NULL) { - sprintf(filename, MM_CORE_DEFAULT_FILE, (int)getpid()); - file = filename; - } - - mm_core_init(); - size = mm_core_align2page(usersize+SIZEOF_mem_core); - -#if defined(MM_SHMT_MMPOSX) || defined(MM_SHMT_MMFILE) - sprintf(shmfilename, "%s.mem", file); - fnmem = shmfilename; -#endif -#if defined(MM_SEMT_FLOCK) || defined(MM_SEMT_FCNTL) - sprintf(semfilename, "%s.sem", file); - fnsem = semfilename; -#endif - -#if defined(MM_SHMT_MMANON) - if ((area = (void *)mmap(NULL, size, PROT_READ|PROT_WRITE, - MAP_ANON|MAP_SHARED, -1, 0)) == (void *)MAP_FAILED) - FAIL(MM_ERR_CORE|MM_ERR_SYSTEM, "failed to memory map anonymous area"); -#endif /* MM_SHMT_MMANON */ - -#if defined(MM_SHMT_BEOS) - if ((temparea = create_area("mm",(void*)&area, B_ANY_ADDRESS, - size, B_LAZY_LOCK, B_READ_AREA | B_WRITE_AREA)) < 0) - FAIL(MM_ERR_CORE|MM_ERR_SYSTEM, "failed to create the memory area"); -#endif /* MM_SHMT_BEOS */ -#if defined(MM_SHMT_MMPOSX) - shm_unlink(fnmem); /* Ok when it fails */ - if ((fdmem = shm_open(fnmem, O_RDWR|O_CREAT, MM_CORE_FILEMODE)) == -1) - FAIL(MM_ERR_CORE|MM_ERR_SYSTEM, "failed to open tempfile"); - if (ftruncate(fdmem, mm_core_mapoffset+size) == -1) - FAIL(MM_ERR_CORE|MM_ERR_SYSTEM, "failed to truncate tempfile"); - write(fdmem, &zero, sizeof(zero)); - if ((area = (void *)mmap(NULL, size, PROT_READ|PROT_WRITE, - MAP_SHARED, fdmem, mm_core_mapoffset)) == (void *)MAP_FAILED) - FAIL(MM_ERR_CORE|MM_ERR_SYSTEM, "failed to memory map tempfile"); - shm_unlink(fnmem); - mm_core_mapoffset += size; -#endif /* MM_SHMT_MMPOSX */ - -#if defined(MM_SHMT_MMZERO) - if ((fdmem = open("/dev/zero", O_RDWR, MM_CORE_FILEMODE)) == -1) - FAIL(MM_ERR_CORE|MM_ERR_SYSTEM, "failed to open /dev/zero"); - if (lseek(fdmem, mm_core_mapoffset+size, SEEK_SET) == -1) - FAIL(MM_ERR_CORE|MM_ERR_SYSTEM, "failed to seek in /dev/zero"); - write(fdmem, &zero, sizeof(zero)); - if ((area = (void *)mmap(NULL, size, PROT_READ|PROT_WRITE, - MAP_SHARED, fdmem, mm_core_mapoffset)) == (void *)MAP_FAILED) - FAIL(MM_ERR_CORE|MM_ERR_SYSTEM, "failed to memory map /dev/zero"); - mm_core_mapoffset += size; -#endif /* MM_SHMT_MMZERO */ - -#if defined(MM_SHMT_MMFILE) - unlink(fnmem); - if ((fdmem = open(fnmem, O_RDWR|O_CREAT, MM_CORE_FILEMODE)) == -1) - FAIL(MM_ERR_CORE|MM_ERR_SYSTEM, "failed to open memory file"); - if (ftruncate(fdmem, mm_core_mapoffset+size) == -1) - FAIL(MM_ERR_CORE|MM_ERR_SYSTEM, "failed to truncate memory file"); - write(fdmem, &zero, sizeof(zero)); - if ((area = (void *)mmap(NULL, size, PROT_READ|PROT_WRITE, - MAP_SHARED, fdmem, mm_core_mapoffset)) == (void *)MAP_FAILED) - FAIL(MM_ERR_CORE|MM_ERR_SYSTEM, "failed to memory map memory file"); - mm_core_mapoffset += size; -#endif /* MM_SHMT_MMFILE */ - -#if defined(MM_SHMT_IPCSHM) - if ((fdmem = shmget(IPC_PRIVATE, size, (SHM_R|SHM_W|IPC_CREAT))) == -1) - FAIL(MM_ERR_CORE|MM_ERR_SYSTEM, "failed to acquire shared memory segment"); - if ((area = (void *)shmat(fdmem, NULL, 0)) == ((void *)-1)) - FAIL(MM_ERR_CORE|MM_ERR_SYSTEM, "failed to attach shared memory"); - if (shmctl(fdmem, IPC_STAT, &shmbuf) == -1) - FAIL(MM_ERR_CORE|MM_ERR_SYSTEM, "failed to get status of shared memory"); - shmbuf.shm_perm.uid = getuid(); - shmbuf.shm_perm.gid = getgid(); - if (shmctl(fdmem, IPC_SET, &shmbuf) == -1) - FAIL(MM_ERR_CORE|MM_ERR_SYSTEM, "failed to set status of shared memory"); - if (shmctl(fdmem, IPC_RMID, NULL) == -1) - FAIL(MM_ERR_CORE|MM_ERR_SYSTEM, "failed to remove shared memory in advance"); -#endif /* MM_SHMT_IPCSHM */ - -#if defined(MM_SEMT_FLOCK) - unlink(fnsem); - if ((fdsem = open(fnsem, O_RDWR|O_CREAT, MM_CORE_FILEMODE)) == -1) - FAIL(MM_ERR_CORE|MM_ERR_SYSTEM, "failed to open semaphore file"); -#endif /* MM_SEMT_FLOCK */ - -#if defined(MM_SEMT_FCNTL) - unlink(fnsem); - if ((fdsem = open(fnsem, O_RDWR|O_CREAT, MM_CORE_FILEMODE)) == -1) - FAIL(MM_ERR_CORE|MM_ERR_SYSTEM, "failed to open semaphore file"); -#endif /* MM_SEMT_FCNTL */ - -#if defined(MM_SEMT_IPCSEM) - fdsem = semget(IPC_PRIVATE, 1, IPC_CREAT|IPC_EXCL|S_IRUSR|S_IWUSR); - if (fdsem == -1 && errno == EEXIST) - fdsem = semget(IPC_PRIVATE, 1, IPC_EXCL|S_IRUSR|S_IWUSR); - if (fdsem == -1) - FAIL(MM_ERR_CORE|MM_ERR_SYSTEM, "failed to acquire semaphore"); - mm_core_semctlarg.val = 0; - semctl(fdsem, 0, SETVAL, mm_core_semctlarg); - fdsem_rd = semget(IPC_PRIVATE, 1, IPC_CREAT|IPC_EXCL|S_IRUSR|S_IWUSR); - if (fdsem_rd == -1 && errno == EEXIST) - fdsem_rd = semget(IPC_PRIVATE, 1, IPC_EXCL|S_IRUSR|S_IWUSR); - if (fdsem_rd == -1) - FAIL(MM_ERR_CORE|MM_ERR_SYSTEM, "failed to acquire semaphore"); - mm_core_semctlarg.val = 0; - semctl(fdsem_rd, 0, SETVAL, mm_core_semctlarg); -#endif /* MM_SEMT_IPCSEM */ - - /* - * Configure the memory core parameters - */ - mc = (mem_core *)area; - mc->mc_size = size; - mc->mc_usize = usersize; - mc->mc_pid = getpid(); - mc->mc_fdmem = fdmem; -#if defined(MM_SEMT_FLOCK) - mc->mc_fdsem[0].pid = getpid(); - mc->mc_fdsem[0].fd = fdsem; - mc->mc_fdsem[1].pid = 0; - mc->mc_fdsem[1].fd = -1; -#else - mc->mc_fdsem = fdsem; -#endif -#if defined(MM_SEMT_BEOS) - mc->mc_semid = create_sem(0, "mm_semid"); - mc->mc_ben=0; -#endif -#if defined(MM_SHMT_BEOS) - mc->mc_areaid = temparea; -#endif -#if defined(MM_SEMT_IPCSEM) - mc->mc_fdsem_rd = fdsem_rd; - mc->mc_readers = 0; -#endif -#if defined(MM_SHMT_MMFILE) - memcpy(mc->mc_fnmem, fnmem, MM_MAXPATH); -#endif -#if defined(MM_SEMT_FLOCK) || defined(MM_SEMT_FCNTL) - memcpy(mc->mc_fnsem, fnsem, MM_MAXPATH); -#endif - - /* - * Return successfully established core - */ - return ((void *)&(mc->mc_base.mw_cp)); - - /* - * clean-up sequence (CUS) for error situation - */ - BEGIN_FAILURE -#if defined(MM_SHMT_MMANON) || defined(MM_SHMT_MMZERO) || defined(MM_SHMT_MMPOSX) || defined(MM_SHMT_MMFILE) - if (area != ((void *)-1)) - munmap((caddr_t)area, size); -#endif -#if defined(MM_SHMT_IPCSHM) - if (area != ((void *)-1)) - shmdt(area); -#endif -#if defined(MM_SHMT_MMPOSX) || defined(MM_SHMT_MMFILE) - if (fdmem != -1) - close(fdmem); -#endif -#if defined(MM_SHMT_IPCSHM) - if (fdmem != -1) - shmctl(fdmem, IPC_RMID, NULL); -#endif -#if defined(MM_SHMT_BEOS) - delete_area(mc->mc_areaid); -#endif -#if defined(MM_SEMT_BEOS) - delete_sem(mc->mc_semid); -#endif - -#if defined(MM_SEMT_FLOCK) || defined(MM_SEMT_FCNTL) - if (fdsem != -1) - close(fdsem); -#endif -#if defined(MM_SEMT_IPCSEM) - if (fdsem != -1) - semctl(fdsem, 0, IPC_RMID, 0); - if (fdsem_rd != -1) - semctl(fdsem_rd, 0, IPC_RMID, 0); -#endif -#if defined(MM_SHMT_MMFILE) - unlink(fnmem); -#endif -#if defined(MM_SEMT_FLOCK) || defined(MM_SEMT_FCNTL) - unlink(fnsem); -#endif - return NULL; - END_FAILURE -} - -int mm_core_permission(void *core, mode_t mode, uid_t owner, gid_t group) -{ - int rc; - mem_core *mc; - - if (core == NULL) - return -1; - mc = (mem_core *)((char *)core-SIZEOF_mem_core); - rc = 0; -#if defined(MM_SHMT_MMFILE) - if (rc == 0 && chmod(mc->mc_fnmem, mode) < 0) - rc = -1; - if (rc == 0 && chown(mc->mc_fnmem, owner, group) < 0) - rc = -1; -#endif -#if defined(MM_SEMT_FLOCK) || defined(MM_SEMT_FCNTL) - if (rc == 0 && chmod(mc->mc_fnsem, mode) < 0) - rc = -1; - if (rc == 0 && chown(mc->mc_fnsem, owner, group) < 0) - rc = -1; -#endif - return rc; -} - -void mm_core_delete(void *core) -{ - mem_core *mc; - int fdmem; - int fdsem; -#if defined(MM_SEMT_IPCSEM) - int fdsem_rd; -#endif - size_t size; -#if defined(MM_SHMT_MMFILE) - char fnmem[MM_MAXPATH]; -#endif -#if defined(MM_SEMT_FLOCK) || defined(MM_SEMT_FCNTL) - char fnsem[MM_MAXPATH]; -#endif - - if (core == NULL) - return; - mc = (mem_core *)((char *)core-SIZEOF_mem_core); - size = mc->mc_size; - fdmem = mc->mc_fdmem; -#if !defined(MM_SEMT_FLOCK) - fdsem = mc->mc_fdsem; -#endif -#if defined(MM_SEMT_IPCSEM) - fdsem_rd = mc->mc_fdsem_rd; -#endif -#if defined(MM_SEMT_FLOCK) - fdsem = mm_core_getfdsem(mc); -#endif -#if defined(MM_SHMT_MMFILE) - memcpy(fnmem, mc->mc_fnmem, MM_MAXPATH); -#endif -#if defined(MM_SEMT_FLOCK) || defined(MM_SEMT_FCNTL) - memcpy(fnsem, mc->mc_fnsem, MM_MAXPATH); -#endif - -#if defined(MM_SHMT_MMANON) || defined(MM_SHMT_MMPOSX) || defined(MM_SHMT_MMZERO) || defined(MM_SHMT_MMFILE) - munmap((caddr_t)mc, size); -#endif -#if defined(MM_SHMT_IPCSHM) - shmdt((void *)mc); - shmctl(fdmem, IPC_RMID, NULL); -#endif -#if defined(MM_SHMT_MMPOSX) || defined(MM_SHMT_MMZERO) || defined(MM_SHMT_MMFILE) - close(fdmem); -#endif -#if defined(MM_SHMT_MMFILE) - unlink(fnmem); -#endif -#if defined(MM_SEMT_FLOCK) || defined(MM_SEMT_FCNTL) - close(fdsem); -#endif -#if defined(MM_SEMT_FLOCK) || defined(MM_SEMT_FCNTL) - unlink(fnsem); -#endif -#if defined(MM_SEMT_IPCSEM) - semctl(fdsem, 0, IPC_RMID, 0); - semctl(fdsem_rd, 0, IPC_RMID, 0); -#endif - return; -} - -size_t mm_core_size(const void *core) -{ - mem_core *mc; - - if (core == NULL) - return 0; - mc = (mem_core *)((char *)core-SIZEOF_mem_core); - return (mc->mc_usize); -} - -int mm_core_lock(const void *core, mm_lock_mode mode) -{ - mem_core *mc; - int rc; - int fdsem; - - if (core == NULL) - return FALSE; - mc = (mem_core *)((char *)core-SIZEOF_mem_core); -#if !defined(MM_SEMT_FLOCK) - fdsem = mc->mc_fdsem; -#endif -#if defined(MM_SEMT_FLOCK) - fdsem = mm_core_getfdsem(mc); -#endif - -#if defined(MM_SEMT_FCNTL) - if (mode == MM_LOCK_RD) - while (((rc = fcntl(fdsem, F_SETLKW, &mm_core_dolock_rd)) < 0) && (errno == EINTR)) ; - else - while (((rc = fcntl(fdsem, F_SETLKW, &mm_core_dolock_rw)) < 0) && (errno == EINTR)) ; -#endif -#if defined(MM_SEMT_FLOCK) - if (mode == MM_LOCK_RD) - while (((rc = flock(fdsem, LOCK_SH)) < 0) && (errno == EINTR)) ; - else - while (((rc = flock(fdsem, LOCK_EX)) < 0) && (errno == EINTR)) ; -#endif -#if defined(MM_SEMT_IPCSEM) - if (mode == MM_LOCK_RD) { - while (((rc = semop(mc->mc_fdsem_rd, mm_core_dolock, 2)) < 0) && (errno == EINTR)) ; - mc->mc_readers++; - if (mc->mc_readers == 1) - while (((rc = semop(fdsem, mm_core_dolock, 2)) < 0) && (errno == EINTR)) ; - while (((rc = semop(mc->mc_fdsem_rd, mm_core_dounlock, 1)) < 0) && (errno == EINTR)) ; - } - else { - while (((rc = semop(fdsem, mm_core_dolock, 2)) < 0) && (errno == EINTR)) ; - } - mc->mc_lockmode = mode; -#endif -#if defined(MM_SEMT_BEOS) - rc=0; - if (atomic_add (&mc->mc_ben, 1) > 0){ - /* someone already in lock..acquire sem and wait */ - if (acquire_sem(mc->mc_semid) != B_NO_ERROR){ - atomic_add(&mc->mc_ben,-1); - rc = -1; - } - } -#endif - - if (rc < 0) { - ERR(MM_ERR_CORE|MM_ERR_SYSTEM, "Failed to lock"); - rc = FALSE; - } - else - rc = TRUE; - return rc; -} - -int mm_core_unlock(const void *core) -{ - mem_core *mc; - int rc; - int fdsem; - - if (core == NULL) - return FALSE; - mc = (mem_core *)((char *)core-SIZEOF_mem_core); -#if !defined(MM_SEMT_FLOCK) - fdsem = mc->mc_fdsem; -#endif -#if defined(MM_SEMT_FLOCK) - fdsem = mm_core_getfdsem(mc); -#endif - -#if defined(MM_SEMT_FCNTL) - while (((rc = fcntl(fdsem, F_SETLKW, &mm_core_dounlock)) < 0) && (errno == EINTR)) ; -#endif -#if defined(MM_SEMT_FLOCK) - while (((rc = flock(fdsem, LOCK_UN)) < 0) && (errno == EINTR)) ; -#endif -#if defined(MM_SEMT_IPCSEM) - if (mc->mc_lockmode == MM_LOCK_RD) { - while (((rc = semop(mc->mc_fdsem_rd, mm_core_dolock, 2)) < 0) && (errno == EINTR)) ; - mc->mc_readers--; - if (mc->mc_readers == 0) - while (((rc = semop(fdsem, mm_core_dounlock, 1)) < 0) && (errno == EINTR)) ; - while (((rc = semop(mc->mc_fdsem_rd, mm_core_dounlock, 1)) < 0) && (errno == EINTR)) ; - } - else { - while (((rc = semop(fdsem, mm_core_dounlock, 1)) < 0) && (errno == EINTR)) ; - } -#endif -#if defined(MM_SEMT_BEOS) - rc=0; - if (atomic_add(&mc->mc_ben, -1) > 1){ - release_sem(mc->mc_semid); - } -#endif - - if (rc < 0) { - ERR(MM_ERR_CORE|MM_ERR_SYSTEM, "Failed to unlock"); - rc = FALSE; - } - else - rc = TRUE; - return rc; -} - -/*EOF*/ diff --git a/shmem/unix/mm/mm_global.c b/shmem/unix/mm/mm_global.c deleted file mode 100644 index 53efcca58c7..00000000000 --- a/shmem/unix/mm/mm_global.c +++ /dev/null @@ -1,151 +0,0 @@ -/* ==================================================================== - * Copyright (c) 1999 Ralf S. Engelschall. 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 acknowledgment: - * "This product includes software developed by - * Ralf S. Engelschall <rse@engelschall.com>." - * - * 4. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by - * Ralf S. Engelschall <rse@engelschall.com>." - * - * THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``AS IS'' AND ANY - * EXPRESSED 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 RALF S. ENGELSCHALL OR - * ITS 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. - * ==================================================================== - */ - -/* -** -** mm_global.c -- Global Malloc-Replacement API -** -*/ - -#define MM_PRIVATE -#include "mm.h" - -static MM *mm_global = NULL; - -int MM_create(size_t size, const char *file) -{ - if (mm_global != NULL) - return FALSE; - if ((mm_global = mm_create(size, file)) == NULL) - return FALSE; - return TRUE; -} - -int MM_permission(mode_t mode, uid_t owner, gid_t group) -{ - if (mm_global != NULL) - return -1; - return mm_permission(mm_global, mode, owner, group); -} - -void MM_destroy(void) -{ - if (mm_global == NULL) - return; - mm_destroy(mm_global); - mm_global = NULL; - return; -} - -int MM_lock(mm_lock_mode mode) -{ - if (mm_global == NULL) - return FALSE; - return mm_lock(mm_global, mode); -} - -int MM_unlock(void) -{ - if (mm_global == NULL) - return FALSE; - return mm_unlock(mm_global); -} - -void *MM_malloc(size_t size) -{ - if (mm_global == NULL) - return NULL; - return mm_malloc(mm_global, size); -} - -void *MM_realloc(void *ptr, size_t size) -{ - if (mm_global == NULL) - return NULL; - return mm_realloc(mm_global, ptr, size); -} - -void MM_free(void *ptr) -{ - if (mm_global == NULL) - return; - mm_free(mm_global, ptr); - return; -} - -void *MM_calloc(size_t number, size_t size) -{ - if (mm_global == NULL) - return NULL; - return mm_calloc(mm_global, number, size); -} - -char *MM_strdup(const char *str) -{ - if (mm_global == NULL) - return NULL; - return mm_strdup(mm_global, str); -} - -size_t MM_sizeof(const void *ptr) -{ - if (mm_global == NULL) - return -1; - return mm_sizeof(mm_global, ptr); -} - -size_t MM_maxsize(void) -{ - return mm_maxsize(); -} - -size_t MM_available(void) -{ - if (mm_global == NULL) - return -1; - return mm_available(mm_global); -} - -char *MM_error(void) -{ - return mm_lib_error_get(); -} - -/*EOF*/ diff --git a/shmem/unix/mm/mm_lib.c b/shmem/unix/mm/mm_lib.c deleted file mode 100644 index 0e7c34e86c9..00000000000 --- a/shmem/unix/mm/mm_lib.c +++ /dev/null @@ -1,114 +0,0 @@ -/* ==================================================================== - * Copyright (c) 1999 Ralf S. Engelschall. 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 acknowledgment: - * "This product includes software developed by - * Ralf S. Engelschall <rse@engelschall.com>." - * - * 4. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by - * Ralf S. Engelschall <rse@engelschall.com>." - * - * THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``AS IS'' AND ANY - * EXPRESSED 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 RALF S. ENGELSCHALL OR - * ITS 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. - * ==================================================================== - */ - -/* -** -** mm_lib.c -- Internal Library API -** -*/ - -#define MM_PRIVATE -#include "mm.h" - -/* - * Error Handling - */ - -#define MM_LIB_ERROR_MAXLEN 1024 -static char mm_lib_error[MM_LIB_ERROR_MAXLEN+1] = { NUL }; - -void mm_lib_error_set(unsigned int type, const char *str) -{ - int l, n; - char *cp; - - if (str == NULL) { - mm_lib_error[0] = NUL; - return; - } - if (type & MM_ERR_ALLOC) - strcpy(mm_lib_error, "mm:alloc: "); - else if (type & MM_ERR_CORE) - strcpy(mm_lib_error, "mm:core: "); - l = strlen(mm_lib_error); - n = strlen(str); - if (n > MM_LIB_ERROR_MAXLEN-l) - n = MM_LIB_ERROR_MAXLEN-l; - memcpy(mm_lib_error+l, str, n+1); - l += n; - if (type & MM_ERR_SYSTEM && errno != 0) { - if (MM_LIB_ERROR_MAXLEN-l > 2) { - strcpy(mm_lib_error+l, " ("); - l += 2; - } - cp = strerror(errno); - n = strlen(cp); - if (n > MM_LIB_ERROR_MAXLEN-l) - n = MM_LIB_ERROR_MAXLEN-l; - memcpy(mm_lib_error+l, cp, n+1); - l += n; - if (MM_LIB_ERROR_MAXLEN-l > 1) { - strcpy(mm_lib_error+l, ")"); - l += 1; - } - } - *(mm_lib_error+l) = NUL; - return; -} - -char *mm_lib_error_get(void) -{ - if (mm_lib_error[0] == NUL) - return NULL; - return mm_lib_error; -} - -/* - * Version Information - */ - -#define _AS_HEADER -#include "mm_vers.c" - -int mm_lib_version(void) -{ - return MM_Version; -} - diff --git a/shmem/unix/mm/mm_test.c b/shmem/unix/mm/mm_test.c deleted file mode 100644 index 38e5570ec16..00000000000 --- a/shmem/unix/mm/mm_test.c +++ /dev/null @@ -1,223 +0,0 @@ -/* -** mm_test.c -- Test Suite for MM Library -*/ - -#include <stdio.h> -#include <string.h> -#include <sys/types.h> -#include <sys/wait.h> -#include <signal.h> - -#define MM_PRIVATE -#include "mm.h" - -#define FAILED_IF(expr) \ - if (expr) { \ - char *e; \ - e = mm_error(); \ - fprintf(stderr, "%s\n", e != NULL ? e : "Unknown Error"); \ - exit(1); \ - } - -int main(int argc, char *argv[]) -{ - char *core; - int i; - size_t s, s2; - pid_t pid; - int size; - MM *mm; - int n; - char *cp[1025]; - int version; - struct count_test { int count; int prev; } *ct; - - setbuf(stderr, NULL); - - /* - ** - ** Test Global Library API - ** - */ - - fprintf(stderr, "\n*** TESTING GLOBAL LIBRARY API ***\n\n"); - - fprintf(stderr, "Fetching library version\n"); - version = mm_lib_version(); - FAILED_IF(version == 0x0); - fprintf(stderr, "version = 0x%X\n", version); - - /* - ** - ** Test Low-Level Shared Memory API - ** - */ - - fprintf(stderr, "\n*** TESTING LOW-LEVEL SHARED MEMORY API ***\n"); - - fprintf(stderr, "\n=== Testing Memory Segment Access ===\n"); - - fprintf(stderr, "Creating 16KB shared memory core area\n"); - core = mm_core_create(1024*16, NULL); - FAILED_IF(core == NULL); - s = mm_core_size(core); - FAILED_IF(s == 0); - fprintf(stderr, "actually allocated core size = %d\n", s); - - fprintf(stderr, "Writing 0xF5 bytes to shared memory core area\n"); - for (i = 0; i < s; i++) { - fprintf(stderr, "write to core[%06d]\r", i); - core[i] = 0xF5; - } - fprintf(stderr, "\n"); - - fprintf(stderr, "Reading back 0xF5 bytes from shared memory core area\n"); - for (i = 0; i < s; i++) { - fprintf(stderr, "read from core[%06d]\r", i); - if (core[i] != (char)0xF5) { - fprintf(stderr, "Offset %d: 0xF5 not found (found 0x%X\n", i, core[i]); - exit(0); - } - } - fprintf(stderr, "\n"); - - fprintf(stderr, "Destroying shared memory core area\n"); - mm_core_delete(core); - - fprintf(stderr, "\n=== Testing Memory Locking ===\n"); - - fprintf(stderr, "Creating small shared memory core area\n"); - ct = mm_core_create(sizeof(struct count_test), NULL); - FAILED_IF(ct == NULL); - s = mm_core_size(ct); - FAILED_IF(s == 0); - fprintf(stderr, "actually allocated core size = %d\n", s); - - ct->prev = 0; - ct->count = 1; - if ((pid = fork()) == 0) { - /* child */ - while (ct->count < 32768) { - if (!mm_core_lock(ct, MM_LOCK_RW)) { - fprintf(stderr, "locking failed (child)\n"); - FAILED_IF(1); - } - if (ct->prev != (ct->count-1)) { - fprintf(stderr, "Failed, prev=%d != count=%d\n", ct->prev, ct->count); - exit(1); - } - ct->count += 1; - fprintf(stderr, "count=%06d (child )\r", ct->count); - ct->prev += 1; - if (!mm_core_unlock(ct)) { - fprintf(stderr, "locking failed (child)\n"); - FAILED_IF(1); - } - } - exit(0); - } - /* parent ... */ - while (ct->count < 32768) { - if (!mm_core_lock(ct, MM_LOCK_RW)) { - fprintf(stderr, "locking failed (parent)\n"); - FAILED_IF(1); - } - if (ct->prev != (ct->count-1)) { - fprintf(stderr, "Failed, prev=%d != count=%d\n", ct->prev, ct->count); - exit(1); - } - ct->count += 1; - fprintf(stderr, "count=%06d (parent)\r", ct->count); - ct->prev += 1; - if (!mm_core_unlock(ct)) { - fprintf(stderr, "locking failed (parent)\n"); - kill(pid, SIGTERM); - FAILED_IF(1); - } - } - waitpid(pid, NULL, 0); - fprintf(stderr, "\n"); - - fprintf(stderr, "Destroying shared memory core area\n"); - mm_core_delete(ct); - - /* - ** - ** Test Standard Malloc-style API - ** - */ - - fprintf(stderr, "\n*** TESTING STANDARD MALLOC-STYLE API ***\n"); - - fprintf(stderr, "\n=== Testing Allocation ===\n"); - - fprintf(stderr, "Creating MM object\n"); - size = mm_maxsize(); - if (size > 1024*1024*1) - size = 1024*1024*1; - mm = mm_create(size, NULL); - FAILED_IF(mm == NULL) - mm_display_info(mm); - s = mm_available(mm); - FAILED_IF(s == 0); - fprintf(stderr, "actually available bytes = %d\n", s); - - fprintf(stderr, "Allocating areas inside MM\n"); - n = 0; - for (i = 0; i < 1024; i++) - cp[i] = NULL; - for (i = 0; i < 1024; i++) { - fprintf(stderr, "total=%09d allocated=%09d add=%06d\r", s, n, (i+1)*(i+1)); - s2 = mm_available(mm); - if ((i+1)*(i+1) > s2) { - cp[i] = mm_malloc(mm, (i+1)*(i+1)); - if (cp[i] != NULL) { - fprintf(stderr, "\nExpected an out of memory situation. Hmmmmm\n"); - FAILED_IF(1); - } - break; - } - cp[i] = mm_malloc(mm, (i+1)*(i+1)); - n += (i+1)*(i+1); - FAILED_IF(cp[i] == NULL) - memset(cp[i], 0xF5, (i+1)*(i+1)); - } - mm_display_info(mm); - - fprintf(stderr, "\n=== Testing Defragmentation ===\n"); - - fprintf(stderr, "Fragmenting memory area by freeing some selected areas\n"); - for (i = 0; i < 1024; i++) { - if (i % 2 == 0) - continue; - if (cp[i] != NULL) - mm_free(mm, cp[i]); - cp[i] = NULL; - } - mm_display_info(mm); - - fprintf(stderr, "Freeing all areas\n"); - for (i = 0; i < 1024; i++) { - mm_free(mm, cp[i]); - } - mm_display_info(mm); - - fprintf(stderr, "Checking for memory leaks\n"); - s2 = mm_available(mm); - if (s != s2) { - fprintf(stderr, "Something is leaking, we've lost %d bytes\n", s - s2); - FAILED_IF(1); - } - else { - fprintf(stderr, "Fine, we have again %d bytes available\n", s2); - } - - fprintf(stderr, "Destroying MM object\n"); - mm_destroy(mm); - - /******/ - - fprintf(stderr, "\nOK - ALL TESTS SUCCESSFULLY PASSED.\n\n"); - exit(0); -} - diff --git a/shmem/unix/mm/mm_vers.c b/shmem/unix/mm/mm_vers.c deleted file mode 100644 index ab61a88b199..00000000000 --- a/shmem/unix/mm/mm_vers.c +++ /dev/null @@ -1,32 +0,0 @@ -/* -** mm_vers.c -- Version Information -** [automatically generated and maintained by shtool] -*/ - -#ifdef _AS_HEADER - -#ifndef _MM_VERS_C -#define _MM_VERS_C -#define MM_VERSION 0x100211 -extern const int MM_Version; -extern const char MM_VersionStr[]; -extern const char MM_Hello[]; -extern const char MM_GNUVersion[]; -extern const char MM_WhatID[]; -extern const char MM_RCSIdentID[]; -extern const char MM_WebID[]; -extern const char MM_PlainID[]; -#endif /* _MM_VERS_C */ - -#else - -const int MM_Version = 0x100211; -const char MM_VersionStr[] = "1.0.11 (06-Sep-1999)"; -const char MM_Hello[] = "This is MM, Version 1.0.11 (06-Sep-1999)"; -const char MM_GNUVersion[] = "MM Version 1.0.11"; -const char MM_WhatID[] = "@(#)MM Version 1.0.11 (06-Sep-1999)"; -const char MM_RCSIdentID[] = "$Id: mm_vers.c,v 1.2 1999/09/27 07:42:10 rse Exp $"; -const char MM_WebID[] = "MM/1.0.11"; -const char MM_PlainID[] = "1.0.11"; - -#endif diff --git a/shmem/unix/mm/shtool b/shmem/unix/mm/shtool deleted file mode 100755 index cacca7eb67f..00000000000 --- a/shmem/unix/mm/shtool +++ /dev/null @@ -1,2721 +0,0 @@ -#!/bin/sh -## -## GNU shtool -- The GNU Portable Shell Tool -## Copyright (c) 1994-1999 Ralf S. Engelschall <rse@engelschall.com> -## -## See http://www.gnu.org/software/shtool/ for more information. -## See ftp://ftp.gnu.org/gnu/shtool/ for latest version. -## -## Version 1.4.6 (05-Sep-1999) -## Ingredients: all available modules -## - -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -## General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, -## USA, or contact Ralf S. Engelschall <rse@engelschall.com>. -## -## Notice: Given that you include this file verbatim into your own -## source tree, you are justified in saying that it remains separate -## from your package, and that this way you are simply just using GNU -## shtool. So, in this situation, there is no requirement that your -## package itself is licensed under the GNU General Public License in -## order to take advantage of GNU shtool. -## - -## -## Usage: shtool [<options>] [<cmd-name> [<cmd-options>] [<cmd-args>]] -## -## Available commands: -## echo Print string with optional construct expansion -## mdate Pretty-print modification time of a file or dir -## table Pretty print a field-separated list as a table -## prop Display progress with a running propeller -## move Move files with simultan substitution -## install Install a program, script or datafile -## mkdir Make one or more directories -## mkln Make link with calculation of relative paths -## mkshadow Make a shadow tree -## fixperm Fix file permissions inside a source tree -## tarball Roll distribution tarballs -## guessos Simple OS/platform guesser -## arx Extended archive command -## slo Separate linker options by library class -## scpp Sharing C Pre-Processor -## version Generate and maintain a version information file -## path Deal with program paths -## - -if [ $# -eq 0 ]; then - echo "$0:Error: invalid command line" 1>&2 - echo "$0:Hint: run \`$0 -h' for usage" 1>&2 - exit 1 -fi -if [ ".$1" = ".-h" -o ".$1" = ".--help" ]; then - echo "This is GNU shtool, version 1.4.6 (05-Sep-1999)" - echo "Copyright (c) 1994-1999 Ralf S. Engelschall <rse@engelschall.com>" - echo "Report bugs to <bug-shtool@gnu.org>" - echo '' - echo "Usage: shtool [<options>] [<cmd-name> [<cmd-options>] [<cmd-args>]]" - echo '' - echo 'Available global <options>:' - echo ' -v, --version display shtool version information' - echo ' -h, --help display shtool usage help page (this one)' - echo ' -d, --debug display shell trace information' - echo '' - echo 'Available <cmd-name> [<cmd-options>] [<cmd-args>]:' - echo ' echo [-n] [-e] [<str> ...]' - echo ' mdate [-n] [-z] [-s] [-d] [-f<str>] [-o<spec>] <path>' - echo ' table [-F<sep>] [-w<width>] [-c<cols>] [-s<strip>] <str><sep><str>...' - echo ' prop [-p<str>]' - echo ' move [-v] [-t] [-e] [-p] <src-file> <dst-file>' - echo ' install [-v] [-t] [-c] [-C] [-s] [-m<mode>] [-o<owner>] [-g<group>]' - echo ' [-e<ext>] <file> <path>' - echo ' mkdir [-t] [-f] [-p] [-m<mode>] <dir> [<dir> ...]' - echo ' mkln [-t] [-f] [-s] <src-path> [<src-path> ...] <dst-path>' - echo ' mkshadow [-v] [-t] [-a] <src-dir> <dst-dir>' - echo ' fixperm [-v] [-t] <path> [<path> ...]' - echo ' tarball [-t] [-v] [-o <tarball>] [-c <prog>] [-d <dir>] [-u' - echo ' <user>] [-g <group>] [-e <pattern>] <path> [<path> ...]' - echo ' guessos ' - echo ' arx [-t] [-C<cmd>] <op> <archive> [<file> ...]' - echo ' slo -- -L<dir> -l<lib> [ -L<dir> -l<lib> ... ]' - echo ' scpp [-v] [-p] [-o<ofile>] [-t<tfile>] [-M<mark>] [-D<dname>]' - echo ' [-C<cname>] <file> [<file> ...]' - echo ' version [-l<lang>] [-n<name>] [-p<prefix>] [-s<version>] [-i<knob>]' - echo ' [-d<type>] <file>' - echo ' path [-s] [-r] [-d] [-b] [-m] [-p<path>] <str> [<str> ...]' - echo '' - exit 0 -fi -if [ ".$1" = ".-v" -o ".$1" = ."--version" ]; then - echo "GNU shtool 1.4.6 (05-Sep-1999)" - exit 0 -fi -if [ ".$1" = ".-d" -o ".$1" = ."--debug" ]; then - shift - set -x -fi -name=`echo "$0" | sed -e 's;.*/\([^/]*\)$;\1;' -e 's;-sh$;;' -e 's;\.sh$;;'` -case "$name" in - echo|mdate|table|prop|move|install|mkdir|mkln|mkshadow|fixperm|tarball|guessos|arx|slo|scpp|version|path ) - # implicit tool command selection - tool="$name" - ;; - * ) - # explicit tool command selection - tool="$1" - shift - ;; -esac -arg_spec="" -opt_spec="" -gen_tmpfile=no - -## -## DISPATCH INTO SCRIPT PROLOG -## - -case $tool in - echo ) - str_tool="echo" - str_usage="[-n] [-e] [<str> ...]" - arg_spec="0+" - opt_spec="ne" - ;; - mdate ) - str_tool="mdate" - str_usage="[-n] [-z] [-s] [-d] [-f<str>] [-o<spec>] <path>" - arg_spec="1" - opt_spec="nzsdf:!o:!" - opt_f=" " - opt_o="dmy" - ;; - table ) - str_tool="table" - str_usage="[-F<sep>] [-w<width>] [-c<cols>] [-s<strip>] <str><sep><str>..." - arg_spec="1+" - opt_spec="F:!w:!c:!s:!" - opt_F=":" - opt_w=15 - opt_c=3 - opt_s=79 - ;; - prop ) - str_tool="prop" - str_usage="[-p<str>]" - arg_spec="0" - opt_spec="p:" - ;; - move ) - str_tool="move" - str_usage="[-v] [-t] [-e] [-p] <src-file> <dst-file>" - arg_spec="2" - opt_spec="vtep" - ;; - install ) - str_tool="install" - str_usage="[-v] [-t] [-c] [-C] [-s] [-m<mode>] [-o<owner>] [-g<group>] [-e<ext>] <file> <path>" - arg_spec="2" - opt_spec="vtcCsm:o:g:e:" - ;; - mkdir ) - str_tool="mkdir" - str_usage="[-t] [-f] [-p] [-m<mode>] <dir> [<dir> ...]" - arg_spec="1+" - opt_spec="tfpm:" - ;; - mkln ) - str_tool="mkln" - str_usage="[-t] [-f] [-s] <src-path> [<src-path> ...] <dst-path>" - arg_spec="2+" - opt_spec="tfs" - ;; - mkshadow ) - str_tool="mkshadow" - str_usage="[-v] [-t] [-a] <src-dir> <dst-dir>" - arg_spec="2" - opt_spec="vta" - ;; - fixperm ) - str_tool="fixperm" - str_usage="[-v] [-t] <path> [<path> ...]" - gen_tmpfile=yes - arg_spec="1+" - opt_spec="vt" - ;; - tarball ) - str_tool="tarball" - str_usage="[-t] [-v] [-o <tarball>] [-c <prog>] [-d <dir>] [-u <user>] [-g <group>] [-e <pattern>] <path> [<path> ...]" - gen_tmpfile=yes - arg_spec="1+" - opt_spec="tvo:c:d:u:g:e:!" - opt_e="CVS,\\.cvsignore,\\.[oa]\$" - ;; - guessos ) - str_tool="guessos" - str_usage="" - arg_spec="0" - opt_spec="" - ;; - arx ) - str_tool="arx" - str_usage="[-t] [-C<cmd>] <op> <archive> [<file> ...]" - arg_spec="2+" - opt_spec="tC:!" - opt_C="ar" - ;; - slo ) - str_tool="slo" - str_usage="-- -L<dir> -l<lib> [ -L<dir> -l<lib> ... ]" - arg_spec="1+" - opt_spec="" - ;; - scpp ) - str_tool="scpp" - str_usage="[-v] [-p] [-o<ofile>] [-t<tfile>] [-M<mark>] [-D<dname>] [-C<cname>] <file> [<file> ...]" - gen_tmpfile=yes - arg_spec="1+" - opt_spec="vpo:!t:!M:!D:!C:!" - opt_o="lib.h" - opt_t="lib.h.in" - opt_M="%%MARK%%" - opt_D="cpp" - opt_C="intern" - ;; - version ) - str_tool="version" - str_usage="[-l<lang>] [-n<name>] [-p<prefix>] [-s<version>] [-i<knob>] [-d<type>] <file>" - arg_spec="1+" - opt_spec="l:!n:!p:!s:!i:!d:!" - opt_l="txt" - opt_n="unknown" - opt_p="unknown" - opt_s="unknown" - opt_i="P" - opt_d="NO" - gen_tmpfile=yes - ;; - path ) - str_tool="path" - str_usage="[-s] [-r] [-d] [-b] [-m] [-p<path>] <str> [<str> ...]" - gen_tmpfile=yes - arg_spec="1+" - opt_spec="srdbmp:!" - opt_p="$PATH" - ;; - * ) - echo "$0:Error: unknown command \`$tool'" 2>&1 - echo "$0:Hint: run \`$0 -h' for usage" 2>&1 - exit 1 - ;; -esac - -## -## COMMON UTILITY CODE -## - -# determine name of tool -if [ ".$tool" != . ]; then - # inside shtool - toolcmd="$0 $tool" - toolcmdhelp="shtool $tool" - msgprefix="shtool:$tool" -else - # standalone - toolcmd="$0" - toolcmdhelp="sh.$tool" - msgprefix="$str_tool" -fi - -# parse argument specification string -eval `echo $arg_spec | sed -e 's/^\([0-9]*\)\(.*\)/arg_NUMS="\1"; arg_MODE="\2"/'` -test ".$arg_MODE" = . && arg_MODE="=" - -# parse option specification string -for opt in `echo "h$opt_spec" | sed -e 's/\([a-zA-Z0-9][!:+]*\)/\1 /g'`; do - opt_MODE="."; opt_INIT="." - eval `echo $opt |\ - sed -e 's/^\([a-zA-Z0-9]\)/opt_THIS="\1";/' \ - -e 's/";\([:+]\)/"; opt_MODE="\1";/' \ - -e 's/";\(!\)/"; opt_INIT="\1"/'` - eval "opt_MODE_${opt_THIS}=${opt_MODE}" - if [ ".$opt_INIT" != ".!" ]; then - case "$opt_MODE" in - "." ) eval "opt_${opt_THIS}=no" ;; - ":"|"+" ) eval "opt_${opt_THIS}=\"\"" ;; - esac - fi -done - -# interate over argument line -opt_PREV='' -while [ $# -gt 0 ]; do - # special option stops processing - if [ ".$1" = ".--" ]; then - shift - break - fi - - # determine option and argument - opt_ARG_OK=no - if [ ".$opt_PREV" != . ]; then - # merge previous seen option with argument - opt_OPT="$opt_PREV" - opt_ARG="$1" - opt_ARG_OK=yes - opt_PREV="" - else - # split argument into option and argument - case "$1" in - -[a-zA-Z0-9]*) - eval `echo "x$1" |\ - sed -e 's/^x-\([a-zA-Z0-9]\)/opt_OPT="\1";/' \ - -e 's/";\(.*\)$/"; opt_ARG="\1"/'` - ;; - -[a-zA-Z0-9]) - opt_OPT=`awk 'BEGIN { printf("%s", substr(OPT, 2)); }' \ - "OPT=$1" </dev/null"` - opt_ARG='' - ;; - *) - break - ;; - esac - fi - - # eat up option - shift - - # determine whether option needs an argument - eval "opt_MODE=\$opt_MODE_${opt_OPT}" - if [ ".$opt_ARG" = . -a ".$opt_ARG_OK" != .yes ]; then - if [ ".$opt_MODE" = ".:" -o ".$opt_MODE" = ".+" ]; then - opt_PREV="$opt_OPT" - continue - fi - fi - - # process option - case $opt_MODE in - "." ) - # boolean option - eval "opt_${opt_OPT}=yes" - ;; - ":" ) - # option with argument (multiple occurances override) - eval "opt_${opt_OPT}=\"\$opt_ARG\"" - ;; - "+" ) - # option with argument (multiple occurances append) - eval "opt_${opt_OPT}=\"\$opt_${opt_OPT} \$opt_ARG\"" - ;; - * ) - echo "$msgprefix:Error: unknown option: \`-$opt_OPT'" 1>&2 - echo "$msgprefix:Hint: run \`$toolcmdhelp -h' or \`man shtool' for details" 1>&2 - exit 1 - ;; - esac -done -if [ ".$opt_PREV" != . ]; then - echo "$msgprefix:Error: missing argument to option \`-$opt_PREV'" 1>&2 - echo "$msgprefix:Hint: run \`$toolcmdhelp -h' or \`man shtool' for details" 1>&2 - exit 1 -fi - -# process help option -if [ ".$opt_h" = .yes ]; then - echo "Usage: $toolcmdhelp $str_usage" - exit 0 -fi - -# complain about incorrect number of arguments -case $arg_MODE in - "=" ) - if [ $# -ne $arg_NUMS ]; then - echo "$msgprefix:Error: invalid number of arguments (exactly $arg_NUMS expected)" 1>&2 - echo "$msgprefix:Hint: run \`$toolcmd -h' or \`man shtool' for details" 1>&2 - exit 1 - fi - ;; - "+" ) - if [ $# -lt $arg_NUMS ]; then - echo "$msgprefix:Error: invalid number of arguments (at least $arg_NUMS expected)" 1>&2 - echo "$msgprefix:Hint: run \`$toolcmd -h' or \`man shtool' for details" 1>&2 - exit 1 - fi - ;; -esac - -# establish a temporary file on request -if [ ".$gen_tmpfile" = .yes ]; then - tmpdir="/tmp" - if [ ".$TMPDIR" != . ]; then - tmpdir="$TMPDIR" - else - if [ ".$TEMPDIR" != . ]; then - tmpdir="$TEMPDIR" - fi - fi - tmpfile="$tmpdir/.shtool.$$" - rm -f $tmpfile >/dev/null 2>&1 - touch $tmpfile -fi - -## -## DISPATCH INTO SCRIPT BODY -## - -case $tool in - -echo ) - ## - ## echo -- Print string with optional construct expansion - ## Copyright (c) 1998-1999 Ralf S. Engelschall <rse@engelschall.com> - ## Originally written for WML as buildinfo - ## - - text="$*" - - # check for broken escape sequence expansion - seo='' - bytes=`echo '\1' | wc -c | awk '{ printf("%s", $1); }'` - if [ ".$bytes" != .3 ]; then - bytes=`echo -E '\1' | wc -c | awk '{ printf("%s", $1); }'` - if [ ".$bytes" = .3 ]; then - seo='-E' - fi - fi - - # check for existing -n option (to suppress newline) - minusn='' - bytes=`echo -n 123 2>/dev/null | wc -c | awk '{ printf("%s", $1); }'` - if [ ".$bytes" = .3 ]; then - minusn='-n' - fi - - # determine terminal bold sequence - term_bold='' - term_norm='' - if [ ".$opt_e" = .yes -a ".`echo $text | egrep '%[Bb]'`" != . ]; then - # the most important terminals we directly know - case $TERM in - xterm|xterm*|vt220|vt220*) - term_bold=`awk 'BEGIN { printf("%c%c%c%c", 27, 91, 49, 109); }' </dev/null 2>/dev/null` - term_norm=`awk 'BEGIN { printf("%c%c%c", 27, 91, 109); }' </dev/null 2>/dev/null` - ;; - vt100|vt100*) - term_bold=`awk 'BEGIN { printf("%c%c%c%c%c%c", 27, 91, 49, 109, 0, 0); }' </dev/null 2>/dev/null` - term_norm=`awk 'BEGIN { printf("%c%c%c%c%c", 27, 91, 109, 0, 0); }' </dev/null 2>/dev/null` - ;; - esac - # then try a possibly existing "tput" or "tcout" utility - paths=`echo $PATH | sed -e 's/:/ /g'` - for tool in tput tcout; do - for dir in $paths; do - if [ -r "$dir/$tool" ]; then - for seq in bold md smso; do # smso is last - bold="`$dir/$tool $seq 2>/dev/null`" - if [ ".$bold" != . ]; then - term_bold="$bold" - break - fi - done - if [ ".$term_bold" != . ]; then - for seq in sgr0 me rmso reset; do # 'reset' is last - norm="`$dir/$tool $seq 2>/dev/null`" - if [ ".$norm" != . ]; then - term_norm="$norm" - break - fi - done - fi - break - fi - done - if [ ".$term_bold" != . -a ".$term_norm" != . ]; then - break; - fi - done - if [ ".$term_bold" = . -o ".$term_norm" = . ]; then - echo "$msgprefix:Warning: unable to determine terminal sequence for bold mode" 1>&2 - fi - fi - - # determine user name - username='' - if [ ".$opt_e" = .yes -a ".`echo $text | egrep '%[uU]'`" != . ]; then - username="$LOGNAME" - if [ ".$username" = . ]; then - username="$USER" - if [ ".$username" = . ]; then - username="`(whoami) 2>/dev/null |\ - awk '{ printf("%s", $1); }'`" - if [ ".$username" = . ]; then - username="`(who am i) 2>/dev/null |\ - awk '{ printf("%s", $1); }'`" - if [ ".$username" = . ]; then - username='unknown' - fi - fi - fi - fi - fi - - # determine user id - userid='' - if [ ".$opt_e" = .yes -a ".`echo $text | egrep '%U'`" != . ]; then - userid="`(id -u) 2>/dev/null`" - if [ ".$userid" = . ]; then - str="`(id) 2>/dev/null`" - if [ ".`echo $str | grep '^uid[ ]*=[ ]*[0-9]*('`" != . ]; then - userid=`echo $str | sed -e 's/^uid[ ]*=[ ]*//' -e 's/(.*//'` - fi - if [ ".$userid" = . ]; then - userid=`egrep "^${username}:" /etc/passwd 2>/dev/null | \ - sed -e 's/[^:]*:[^:]*://' -e 's/:.*$//'` - if [ ".$userid" = . ]; then - userid=`(ypcat passwd) 2>/dev/null | - egrep "^${username}:" | \ - sed -e 's/[^:]*:[^:]*://' -e 's/:.*$//'` - if [ ".$userid" = . ]; then - userid='?' - fi - fi - fi - fi - fi - - # determine host name - hostname='' - if [ ".$opt_e" = .yes -a ".`echo $text | egrep '%h'`" != . ]; then - hostname="`(uname -n) 2>/dev/null |\ - awk '{ printf("%s", $1); }'`" - if [ ".$hostname" = . ]; then - hostname="`(hostname) 2>/dev/null |\ - awk '{ printf("%s", $1); }'`" - if [ ".$hostname" = . ]; then - hostname='unknown' - fi - fi - case $hostname in - *.* ) - domainname=".`echo $hostname | cut -d. -f2-`" - hostname="`echo $hostname | cut -d. -f1`" - ;; - esac - fi - - # determine domain name - domainname='' - if [ ".$opt_e" = .yes -a ".`echo $text | egrep '%d'`" != . ]; then - if [ ".$domainname" = . ]; then - if [ -f /etc/resolv.conf ]; then - domainname="`egrep '^[ ]*domain' /etc/resolv.conf | head -1 |\ - sed -e 's/.*domain//' \ - -e 's/^[ ]*//' -e 's/^ *//' -e 's/^ *//' \ - -e 's/^\.//' -e 's/^/./' |\ - awk '{ printf("%s", $1); }'`" - if [ ".$domainname" = . ]; then - domainname="`egrep '^[ ]*search' /etc/resolv.conf | head -1 |\ - sed -e 's/.*search//' \ - -e 's/^[ ]*//' -e 's/^ *//' -e 's/^ *//' \ - -e 's/ .*//' -e 's/ .*//' \ - -e 's/^\.//' -e 's/^/./' |\ - awk '{ printf("%s", $1); }'`" - fi - fi - fi - fi - - # determine current time - time_day='' - time_month='' - time_year='' - time_monthname='' - if [ ".$opt_e" = .yes -a ".`echo $text | egrep '%[DMYm]'`" != . ]; then - time_day=`date '+%d'` - time_month=`date '+%m'` - time_year=`date '+%Y' 2>/dev/null` - if [ ".$time_year" = . ]; then - time_year=`date '+%y'` - case $time_year in - [5-9][0-9]) time_year="19$time_year" ;; - [0-4][0-9]) time_year="20$time_year" ;; - esac - fi - case $time_month in - 1|01) time_monthname='Jan' ;; - 2|02) time_monthname='Feb' ;; - 3|03) time_monthname='Mar' ;; - 4|04) time_monthname='Apr' ;; - 5|05) time_monthname='May' ;; - 6|06) time_monthname='Jun' ;; - 7|07) time_monthname='Jul' ;; - 8|08) time_monthname='Aug' ;; - 9|09) time_monthname='Sep' ;; - 10) time_monthname='Oct' ;; - 11) time_monthname='Nov' ;; - 12) time_monthname='Dec' ;; - esac - fi - - # expand special ``%x'' constructs - if [ ".$opt_e" = .yes ]; then - text=`echo $seo "$text" |\ - sed -e "s/%B/${term_bold}/g" \ - -e "s/%b/${term_norm}/g" \ - -e "s/%u/${username}/g" \ - -e "s/%U/${userid}/g" \ - -e "s/%h/${hostname}/g" \ - -e "s/%d/${domainname}/g" \ - -e "s/%D/${time_day}/g" \ - -e "s/%M/${time_month}/g" \ - -e "s/%Y/${time_year}/g" \ - -e "s/%m/${time_monthname}/g" 2>/dev/null` - fi - - # create output - if [ .$opt_n = .no ]; then - echo $seo $text - else - # the harder part: echo -n is best, because - # awk complains about some \xx sequences. - if [ ".$minusn" != . ]; then - echo $seo $minusn $text - else - echo dummy | awk '{ printf("%s", TEXT); }' TEXT="$text" - fi - fi - ;; - -mdate ) - ## - ## mdate -- Pretty-print modification time of a file or dir - ## Copyright (c) 1995-1997 Free Software Foundation, Inc. - ## Originally idea and basis code by Ulrich Drepper - ## Enhanced by Ralf S. Engelschall for shtool - ## - - fod="$1" - case "$opt_o" in - [dmy][dmy][dmy] ) - ;; - * ) echo "$msgprefix:Error: invalid argument to option \`-o': $opt_o" 1>&2 - exit 1 - ;; - esac - if [ ! -r "$fod" ]; then - echo "$msgprefix:Error: file or directory not found: $fod" 1>&2 - exit 1 - fi - - # prevent "date" giving response in another language - LANG=C; export LANG - LC_ALL=C; export LC_ALL - LC_TIME=C; export LC_TIME - - # get the extended ls output of the file or directory. - if ls -L /dev/null >/dev/null 2>&1; then - set - x`ls -L -l -d $fod` - else - set - x`ls -l -d $fod` - fi - - # The month is at least the fourth argument - # (3 shifts here, the next inside the loop). - shift; shift; shift - - # Find the month. Next argument is day, followed by the year or time. - month="" - while [ ".$month" = . ]; do - shift - case $1 in - Jan) month=January; nummonth=1 ;; - Feb) month=February; nummonth=2 ;; - Mar) month=March; nummonth=3 ;; - Apr) month=April; nummonth=4 ;; - May) month=May; nummonth=5 ;; - Jun) month=June; nummonth=6 ;; - Jul) month=July; nummonth=7 ;; - Aug) month=August; nummonth=8 ;; - Sep) month=September; nummonth=9 ;; - Oct) month=October; nummonth=10 ;; - Nov) month=November; nummonth=11 ;; - Dec) month=December; nummonth=12 ;; - esac - done - day="$2" - year="$3" - - # We finally have to deal with the problem that the "ls" output - # gives either the time of the day or the year. - case $year in - *:*) - this_year=`date '+%Y' 2>/dev/null` - if [ ".$this_year" = . ]; then - this_year=`date '+%y'` - case $this_year in - [5-9][0-9]) this_year="19$this_year" ;; - [0-4][0-9]) this_year="20$this_year" ;; - esac - fi - # for the following months of the last year the time notation - # is usually also used for files modified in the last year. - this_month=`date '+%m'` - if (expr $nummonth \> $this_month) >/dev/null; then - this_year=`expr $this_year - 1` - fi - year="$this_year" - ;; - esac - - # Optionally fill day and month with leeding zeros - if [ ".$opt_z" = .yes ]; then - case $day in - [0-9][0-9] ) ;; - [0-9] ) day="0$day" ;; - esac - case $nummonth in - [0-9][0-9] ) ;; - [0-9] ) nummonth="0$nummonth" ;; - esac - fi - - # Optionally use digits for month - if [ ".$opt_d" = .yes ]; then - month="$nummonth" - fi - - # Optionally shorten the month name to three characters - if [ ".$opt_s" = .yes ]; then - month=`echo $month | cut -c1-3` - fi - - # Output the resulting date string - echo dummy | awk '{ - for (i = 0; i < 3; i++) { - now = substr(order, 1, 1); - order = substr(order, 2); - if (now == "d") - out = day; - else if (now == "m") - out = month; - else if (now == "y") - out = year; - if (i < 2) - printf("%s%s", out, field); - else - printf("%s", out); - } - if (newline != "yes") - printf("\n"); - }' "day=$day" "month=$month" "year=$year" \ - "field=$opt_f" "order=$opt_o" "newline=$opt_n" - ;; - -table ) - ## - ## table -- Pretty print a field-separated list as a table - ## Copyright (c) 1998-1999 Ralf S. Engelschall <rse@engelschall.com> - ## Originally written for Apache - ## - - if [ $opt_c -gt 4 ]; then - echo "$msgprefix:Error: Invalid number of colums (1..4 allowed only)" 1>&2 - exit 1 - fi - case "x$opt_F" in - x? ) ;; - * ) echo "$msgprefix:Error: Invalid separator (one char allowed only)" 1>&2; exit 1 ;; - esac - - # split the list into a table - list=` - IFS="$opt_F" - for entry in $*; do - if [ ".$entry" != . ]; then - echo "$entry" - fi - done |\ - awk " - BEGIN { list = \"\"; n = 0; } - { - list = list \\$1; - n = n + 1; - if (n < $opt_c) { - list = list \":\"; - } - if (n == $opt_c) { - list = list \"\\n\"; - n = 0; - } - } - END { print list; } - " - ` - - # format table cells and make sure table - # doesn't exceed maximum width - OIFS="$IFS" - IFS=' -' - for entry in $list; do - case $opt_c in - 1 ) eval "echo \"\${entry}\" | awk -F: '{ printf(\"%-${opt_w}s\\n\", \$1); }'" ;; - 2 ) eval "echo \"\${entry}\" | awk -F: '{ printf(\"%-${opt_w}s %-${opt_w}s\\n\", \$1, \$2); }'" ;; - 3 ) eval "echo \"\${entry}\" | awk -F: '{ printf(\"%-${opt_w}s %-${opt_w}s %-${opt_w}s\\n\", \$1, \$2, \$3); }'" ;; - 4 ) eval "echo \"\${entry}\" | awk -F: '{ printf(\"%-${opt_w}s %-${opt_w}s %-${opt_w}s %-${opt_w}s\\n\", \$1, \$2, \$3, \$4); }'" ;; - esac - done |\ - awk "{ - if (length(\$0) > $opt_s) { - printf(\"%s\\n\", substr(\$0, 0, $opt_s-1)); - } else { - print \$0; - } - }" - IFS="$OIFS" - ;; - -prop ) - ## - ## prop -- Display progress with a running propeller - ## Copyright (c) 1998-1999 Ralf S. Engelschall <rse@engelschall.com> - ## Originally written for mod_ssl - ## - - perl='' - for dir in `echo $PATH | sed -e 's/:/ /g'` .; do - if [ -f "$dir/perl" ]; then - perl="$dir/perl" - break - fi - done - if [ ".$perl" != . ]; then - # Perl is preferred because writing to STDERR in - # Perl really writes immediately as one would expect - $perl -e ' - @p = ("|","/","-","\\"); - $i = 0; - while (<STDIN>) { - printf(STDERR "\r%s...%s\b", $ARGV[0], $p[$i++]); - $i = 0 if ($i > 3); - } - printf(STDERR "\r%s \n", $ARGV[0]); - ' "$opt_p" - else - # But when Perl doesn't exists we use Awk even - # some Awk's buffer even the /dev/stderr writing :-( - awk ' - BEGIN { - split("|#/#-#\\", p, "#"); - i = 1; - } - { - printf("\r%s%c\b", prefix, p[i++]) > "/dev/stderr"; - if (i > 4) { i = 1; } - } - END { - printf("\r%s \n", prefix) > "/dev/stderr"; - } - ' "prefix=$opt_p" - fi - ;; - -move ) - ## - ## move -- Move files with simultan substitution - ## Copyright (c) 1999 Ralf S. Engelschall <rse@engelschall.com> - ## Originally written for shtool - ## - - src="$1" - dst="$2" - - # consistency checks - if [ ".$src" = . -o ".$dst" = . ]; then - echo "$msgprefix:Error: Invalid arguments" 1>&2 - exit 1 - fi - if [ ".$src" = ".$dst" ]; then - echo "$msgprefix:Error: Source and destination files are the same" 1>&2 - exit 1 - fi - expsrc="$src" - if [ ".$opt_e" = .yes ]; then - expsrc="`echo $expsrc`" - fi - if [ ".$opt_e" = .yes ]; then - if [ ".`echo "$src" | sed -e 's;^.*\\*.*$;;'`" = ".$src" ]; then - echo "$msgprefix:Error: Source doesn't contain wildcard ('*'): $dst" 1>&2 - exit 1 - fi - if [ ".`echo "$dst" | sed -e 's;^.*%[1-9].*$;;'`" = ".$dst" ]; then - echo "$msgprefix:Error: Destination doesn't contain substitution ('%N'): $dst" 1>&2 - exit 1 - fi - if [ ".$expsrc" = ".$src" ]; then - echo "$msgprefix:Error: Sources not found or no asterisk : $src" 1>&2 - exit 1 - fi - else - if [ ! -r "$src" ]; then - echo "$msgprefix:Error: Source not found: $src" 1>&2 - exit 1 - fi - fi - - # determine substitution patterns - if [ ".$opt_e" = .yes ]; then - srcpat=`echo "$src" | sed -e 's/\\./\\\\./g' -e 's/;/\\;/g' -e 's;\\*;\\\\(.*\\\\);g'` - dstpat=`echo "$dst" | sed -e 's;%\([1-9]\);\\\\\1;g'` - fi - - # iterate over source(s) - for onesrc in $expsrc; do - if [ .$opt_e = .yes ]; then - onedst=`echo $onesrc | sed -e "s;$srcpat;$dstpat;"` - else - onedst="$dst" - fi - errorstatus=0 - if [ ".$opt_v" = .yes ]; then - echo "$onesrc -> $onedst" - fi - if [ ".$opt_p" = .yes ]; then - if [ -r $onedst ]; then - if cmp -s $onesrc $onedst; then - if [ ".$opt_t" = .yes ]; then - echo "rm -f $onesrc" 1>&2 - fi - rm -f $onesrc || errorstatus=$? - else - if [ ".$opt_t" = .yes ]; then - echo "mv -f $onesrc $onedst" 1>&2 - fi - mv -f $onesrc $onedst || errorstatus=$? - fi - else - if [ ".$opt_t" = .yes ]; then - echo "mv -f $onesrc $onedst" 1>&2 - fi - mv -f $onesrc $onedst || errorstatus=$? - fi - else - if [ ".$opt_t" = .yes ]; then - echo "mv -f $onesrc $onedst" 1>&2 - fi - mv -f $onesrc $onedst || errorstatus=$? - fi - if [ $errorstatus -ne 0 ]; then - break; - fi - done - exit $errorstatus - ;; - -install ) - ## - ## install -- Install a program, script or datafile - ## Copyright (c) 1997-1999 Ralf S. Engelschall <rse@engelschall.com> - ## Originally written for shtool - ## - - src="$1" - dst="$2" - - # If destination is a directory, append the input filename - if [ -d $dst ]; then - dst=`echo "$dst" | sed -e 's:/$::'` - dstfile=`echo "$src" | sed -e 's;.*/\([^/]*\)$;\1;'` - dst="$dst/$dstfile" - fi - - # Add a possible extension to src and dst - if [ ".$opt_e" != . ]; then - src="$src$opt_e" - dst="$dst$opt_e" - fi - - # Check for correct arguments - if [ ".$src" = ".$dst" ]; then - echo "$msgprefix:Error: source and destination are the same" 1>&2 - exit 1 - fi - - # Make a temp file name in the destination directory - dstdir=`echo $dst | sed -e 's;[^/]*$;;' -e 's;\(.\)/$;\1;' -e 's;^$;.;'` - dsttmp="$dstdir/#INST@$$#" - - # Verbosity - if [ ".$opt_v" = .yes ]; then - echo "$src -> $dst" 1>&2 - fi - - # Copy or move the file name to the temp name - # (because we might be not allowed to change the source) - if [ ".$opt_C" = .yes ]; then - opt_c=yes - fi - if [ ".$opt_c" = .yes ]; then - if [ ".$opt_t" = .yes ]; then - echo "cp $src $dsttmp" 1>&2 - fi - cp $src $dsttmp || exit $? - else - if [ ".$opt_t" = .yes ]; then - echo "mv $src $dsttmp" 1>&2 - fi - mv $src $dsttmp || exit $? - fi - - # Adjust the target file - # (we do chmod last to preserve setuid bits) - if [ ".$opt_s" = .yes ]; then - if [ ".$opt_t" = .yes ]; then - echo "strip $dsttmp" 1>&2 - fi - strip $dsttmp || exit $? - fi - if [ ".$opt_o" != . ]; then - if [ ".$opt_t" = .yes ]; then - echo "chown $opt_o $dsttmp" 1>&2 - fi - chown $opt_o $dsttmp || exit $? - fi - if [ ".$opt_g" != . ]; then - if [ ".$opt_t" = .yes ]; then - echo "chgrp $opt_g $dsttmp" 1>&2 - fi - chgrp $opt_g $dsttmp || exit $? - fi - if [ ".$opt_m" != . ]; then - if [ ".$opt_t" = .yes ]; then - echo "chmod $opt_m $dsttmp" 1>&2 - fi - chmod $opt_m $dsttmp || exit $? - fi - - # Determine whether to do a quick install - # (has to be done _after_ the strip was already done) - quick=no - if [ ".$opt_C" = .yes ]; then - if [ -r $dst ]; then - if cmp -s $src $dst; then - quick=yes - fi - fi - fi - - # Finally install the file to the real destination - if [ $quick = yes ]; then - if [ ".$opt_t" = .yes ]; then - echo "rm -f $dsttmp" 1>&2 - fi - rm -f $dsttmp - else - if [ ".$opt_t" = .yes ]; then - echo "rm -f $dst && mv $dsttmp $dst" 1>&2 - fi - rm -f $dst && mv $dsttmp $dst - fi - ;; - -mkdir ) - ## - ## mkdir -- Make one or more directories - ## Copyright (c) 1996-1999 Ralf S. Engelschall <rse@engelschall.com> - ## Originally written for public domain by Noah Friedman <friedman@prep.ai.mit.edu> - ## Cleaned up and enhanced for shtool - ## - - errstatus=0 - for p in ${1+"$@"}; do - # when the directory already exists... - if [ -d "$p" ]; then - if [ ".$opt_f" = .no ]; then - echo "$msgprefix:Error: file exists: $p" 1>&2 - errstatus=1 - break - else - continue - fi - fi - # when the directory has to be created - if [ ".$opt_p" = .no ]; then - if [ ".$opt_t" = .yes ]; then - echo "mkdir $p" 1>&2 - fi - mkdir $p || errstatus=$? - else - # the smart situation - set fnord `echo ":$p" |\ - sed -e 's/^:\//%/' \ - -e 's/^://' \ - -e 's/\// /g' \ - -e 's/^%/\//'` - shift - pathcomp= - for d in ${1+"$@"}; do - pathcomp="$pathcomp$d" - case "$pathcomp" in - -* ) pathcomp="./$pathcomp" ;; - esac - if [ ! -d "$pathcomp" ]; then - if [ ".$opt_t" = .yes ]; then - echo "mkdir $pathcomp" 1>&2 - fi - mkdir $pathcomp || errstatus=$? - if [ ".$opt_m" != . ]; then - if [ ".$opt_t" = .yes ]; then - echo "chmod $opt_m $pathcomp" 1>&2 - fi - chmod $opt_m $pathcomp || errstatus=$? - fi - fi - pathcomp="$pathcomp/" - done - fi - done - exit $errstatus - ;; - -mkln ) - ## - ## mkln -- Make link with calculation of relative paths - ## Copyright (c) 1999 Ralf S. Engelschall <rse@engelschall.com> - ## Originally written for shtool - ## - - args=$? - srcs="" - while [ $# -gt 1 ]; do - srcs="$srcs $1" - shift - done - dst="$1" - if [ ! -d $dst ]; then - if [ $args -gt 2 ]; then - echo "$msgprefix:Error: multiple sources not allowed when target isn't a directory" 1>&2 - exit 1 - fi - fi - - # determine link options - lnopt="" - if [ ".$opt_f" = .yes ]; then - lnopt="$lnopt -f" - fi - if [ ".$opt_s" = .yes ]; then - lnopt="$lnopt -s" - fi - - # iterate over sources - for src in $srcs; do - # determine if one of the paths is an absolute path, - # because then we _have_ to use an absolute symlink - oneisabs=0 - srcisabs=0 - dstisabs=0 - case $src in - /* ) oneisabs=1; srcisabs=1 ;; - esac - case $dst in - /* ) oneisabs=1; dstisabs=1 ;; - esac - - # split source and destination into dir and base name - if [ -d $src ]; then - srcdir=`echo $src | sed -e 's;/*$;;'` - srcbase="" - else - srcdir=`echo $src | sed -e 's;^[^/]*$;;' -e 's;^\(.*/\)[^/]*$;\1;' -e 's;\(.\)/$;\1;'` - srcbase=`echo $src | sed -e 's;.*/\([^/]*\)$;\1;'` - fi - if [ -d $dst ]; then - dstdir=`echo $dst | sed -e 's;/*$;;'` - dstbase="" - else - dstdir=`echo $dst | sed -e 's;^[^/]*$;;' -e 's;^\(.*/\)[^/]*$;\1;' -e 's;\(.\)/$;\1;'` - dstbase=`echo $dst | sed -e 's;.*/\([^/]*\)$;\1;'` - fi - - # consistency check - if [ ".$dstdir" != . ]; then - if [ ! -d $dstdir ]; then - echo "$msgprefix:Error: destination directory not found: $dstdir" 1>&2 - exit 1 - fi - fi - - # make sure the source is reachable from the destination - if [ $dstisabs = 1 ]; then - if [ $srcisabs = 0 ]; then - if [ -d $srcdir ]; then - srcdir="`cd $srcdir; pwd | sed -e 's;/*$;;'`" - srcisabs=1 - oneisabs=1 - fi - fi - fi - - # split away a common prefix - prefix="" - if [ ".$srcdir" = ".$dstdir" ] && [ ".$srcdir" != . ]; then - prefix="$srcdir/" - srcdir="" - dstdir="" - else - while [ ".$srcdir" != . ] && [ ".$dstdir" != . ]; do - presrc=`echo $srcdir | sed -e 's;^\([^/]*\)/.*;\1;'` - predst=`echo $dstdir | sed -e 's;^\([^/]*\)/.*;\1;'` - if [ ".$presrc" != ".$predst" ]; then - break - fi - prefix="$prefix$presrc/" - srcdir=`echo $srcdir | sed -e 's;^[^/]*/*;;'` - dstdir=`echo $dstdir | sed -e 's;^[^/]*/*;;'` - done - fi - - # destination prefix is just the common prefix - dstpre="$prefix" - - # determine source prefix which is the reverse directory - # step-up corresponding to the destination directory - srcpre="" - if [ $oneisabs = 0 ] || [ ".$prefix" != . -a ".$prefix" != ./ ]; then - pl="$dstdir/" - OIFS="$IFS"; IFS='/' - for pe in $pl; do - [ ".$pe" = . ] && continue - srcpre="../$srcpre" - done - IFS="$OIFS" - else - if [ $srcisabs = 1 ]; then - srcpre="$prefix" - fi - fi - - # determine destination symlink name - if [ ".$dstbase" = . ]; then - if [ ".$srcbase" != . ]; then - dstbase="$srcbase" - else - dstbase=`echo "$prefix$srcdir" | sed -e 's;/*$;;' -e 's;.*/\([^/]*\)$;\1;'` - fi - fi - - # now finalize source and destination directory paths - srcdir=`echo $srcdir | sed -e 's;\([^/]\)$;\1/;'` - dstdir=`echo $dstdir | sed -e 's;\([^/]\)$;\1/;'` - - # run the final link command - if [ ".$opt_t" = .yes ]; then - echo "ln$lnopt $srcpre$srcdir$srcbase $dstpre$dstdir$dstbase" - fi - eval ln$lnopt $srcpre$srcdir$srcbase $dstpre$dstdir$dstbase - done - ;; - -mkshadow ) - ## - ## mkshadow -- Make a shadow tree - ## Copyright (c) 1998-1999 Ralf S. Engelschall <rse@engelschall.com> - ## Originally written for Apache - ## - - # source and destination directory - src=`echo "$1" | sed -e 's:/$::'` - dst=`echo "$2" | sed -e 's:/$::'` - - # check whether source exists - if [ ! -d $src ]; then - echo "$msgprefix:Error: source directory not found: \`$src'" 1>&2 - exit 1 - fi - - # determine if one of the paths is an absolute path, - # because then we have to use an absolute symlink - oneisabs=0 - case $src in - /* ) oneisabs=1 ;; - esac - case $dst in - /* ) oneisabs=1 ;; - esac - - # determine reverse directory for destination directory - dstrevdir='' - if [ $oneisabs = 0 ]; then - # (inlined fp2rp) - OIFS="$IFS"; IFS='/' - for pe in $dst; do - dstrevdir="../$dstrevdir" - done - IFS="$OIFS" - else - src="`cd $src; pwd`"; - fi - - # create directory tree at destination - if [ ! -d $dst ]; then - if [ ".$opt_t" = .yes ]; then - echo "mkdir $dst" 1>&2 - fi - mkdir $dst - fi - if [ ".$opt_a" = .yes ]; then - DIRS=`cd $src; find . -type d -print |\ - sed -e '/^\.$/d' -e 's:^\./::'` - else - DIRS=`cd $src; find . -type d -print |\ - sed -e '/\/CVS/d' -e '/^\.$/d' -e 's:^\./::'` - fi - for dir in $DIRS; do - if [ ".$opt_t" = .yes ]; then - echo "mkdir $dst/$dir" 1>&2 - fi - mkdir $dst/$dir - done - - # fill directory tree with symlinks to files - if [ ".$opt_a" = .yes ]; then - FILES="`cd $src; find . -depth -print |\ - sed -e 's/^\.\///'`" - else - FILES="`cd $src; find . -depth -print |\ - sed -e '/\.o$/d' -e '/\.a$/d' -e '/\.so$/d' \ - -e '/\.cvsignore$/d' -e '/\/CVS/d' \ - -e '/\/\.#/d' -e '/\.orig$/d' \ - -e 's/^\.\///'`" - fi - for file in $FILES; do - # don't use `-type f' above for find because of symlinks - if [ -d "$src/$file" ]; then - continue - fi - basename=`echo $file | sed -e 's:^.*/::'` - dir=`echo $file | sed -e 's:[^/]*$::' -e 's:/$::' -e 's:$:/:' -e 's:^/$::'` - from=`echo "$src/$file" | sed -e 's/^\.\///'` - to="$dst/$dir$basename" - if [ $oneisabs = 0 ]; then - if [ ".$dir" != . ]; then - subdir=`echo $dir | sed -e 's:/$::'` - # (inlined fp2rp) - revdir='' - OIFS="$IFS"; IFS='/' - for pe in $subdir; do - revdir="../$revdir" - done - IFS="$OIFS" - # finalize from - from="$revdir$from" - fi - from="$dstrevdir$from" - fi - if [ ".$opt_v" = .yes ]; then - echo " $to" 1>&2 - fi - if [ ".$opt_t" = .yes ]; then - echo "ln -s $from $to" 1>&2 - fi - ln -s $from $to - done - ;; - -fixperm ) - ## - ## fixperm -- Fix file permissions inside a source tree - ## Copyright (c) 1996-1999 Ralf S. Engelschall <rse@engelschall.com> - ## Originally written for ePerl - ## - - paths="$*" - - # check whether the test command supports the -x option - cat >$tmpfile <<EOT -if [ -x / ] || [ -x /bin ] || [ -x /bin/ls ]; then - exit 0 -fi -exit 1 -EOT - if sh $tmpfile 2>/dev/null; then - minusx="-x" - else - minusx="-r" - fi - rm -f $tmpfile - - # iterate over paths - for p in $paths; do - for file in `find $p -depth -print`; do - if [ -f $file ]; then - if [ $minusx $file ]; then - if [ ".$opt_v" = .yes ]; then - echo "-rwxrwxr-x $file" 2>&1 - fi - if [ ".$opt_t" = .yes ]; then - echo "chmod 775 $file" 2>&1 - fi - chmod 775 $file - else - if [ ".$opt_v" = .yes ]; then - echo "-rw-rw-r-- $file" 2>&1 - fi - if [ ".$opt_t" = .yes ]; then - echo "chmod 664 $file" 2>&1 - fi - chmod 664 $file - fi - continue - fi - if [ -d $file ]; then - if [ ".$opt_v" = .yes ]; then - echo "drwxrwxr-x $file" 2>&1 - fi - if [ ".$opt_t" = .yes ]; then - echo "chmod 775 $file" 2>&1 - fi - chmod 775 $file - continue - fi - if [ ".$opt_v" = .yes ]; then - echo "?????????? $file" 2>&1 - fi - done - done - ;; - -tarball ) - ## - ## tarball -- Roll distribution tarballs - ## Copyright (c) 1999 Ralf S. Engelschall <rse@engelschall.com> - ## Originally written for shtool - ## - - srcs="$*" - - # check whether the test command supports the -x option - cat >$tmpfile <<EOT -if [ -x / ] || [ -x /bin ] || [ -x /bin/ls ]; then - exit 0 -fi -exit 1 -EOT - if sh $tmpfile 2>/dev/null; then - minusx="-x" - else - minusx="-r" - fi - rm -f $tmpfile - - # find the tools - paths="`echo $PATH |\ - sed -e 's%/*:%:%g' -e 's%/*$%%' \ - -e 's/^:/.:/' -e 's/::/:.:/g' -e 's/:$/:./' \ - -e 's/:/ /g'`" - for spec in find:gfind,find tar:gtar,tar tardy:tardy,tarcust; do - prg=`echo $spec | sed -e 's/:.*$//'` - tools=`echo $spec | sed -e 's/^.*://'` - eval "prg_${prg}=''" - # iterate over tools - for tool in `echo $tools | sed -e 's/,/ /g'`; do - # iterate over paths - for path in $paths; do - if [ $minusx "$path/$tool" ] && [ ! -d "$path/$tool" ]; then - eval "prg_${prg}=\"$path/$tool\"" - break - fi - done - eval "val=\$prg_${prg}" - if [ ".$val" != . ]; then - break - fi - done - done - - # expand source paths - exclude='' - for pat in `echo $opt_e | sed 's/,/ /g'`; do - exclude="$exclude | grep -v '$pat'" - done - if [ ".$opt_t" = .yes ]; then - echo "cp /dev/null $tmpfile.lst" 1>&2 - fi - cp /dev/null $tmpfile.lst - for src in $srcs; do - if [ -d $src ]; then - if [ ".$opt_t" = .yes ]; then - echo "(cd $src && $prg_find . -type f -depth -print) | sed -e 's:^\\.\$::' -e 's:^\\./::' | cat $exclude >>$tmpfile.lst" 1>&2 - fi - (cd $src && find . -type f -depth -print) |\ - sed -e 's:^\.$::' -e 's:^\./::' | eval cat $exclude >>$tmpfile.lst - else - if [ ".$opt_t" = .yes ]; then - echo "echo $src >>$tmpfile.lst" 1>&2 - fi - echo $src >>$tmpfile.lst - fi - done - sort <$tmpfile.lst >$tmpfile.lst.n - mv $tmpfile.lst.n $tmpfile.lst - if [ ".$opt_v" = .yes ]; then - cat $tmpfile.lst | sed -e 's/^/ /' 1>&2 - fi - - # determine tarball file and directory name - if [ ".$opt_o" != . ]; then - tarfile="$opt_o" - if [ ".$opt_d" != . ]; then - tarname="$opt_d" - else - tarname=`echo $tarfile | sed -e 's/\.tar.*$//' -e 's;.*/\([^/]*\)$;\1;'` - fi - else - if [ ".$opt_d" != . ]; then - tarname="$opt_d" - elif [ -d "$from" ]; then - tarname=`echo $from | sed -e 's;.*/\([^/]*\)$;\1;'` - else - tarname="out" - fi - tarfile="$tarname.tar" - fi - - # roll the tarball - compress='' - if [ ".$opt_c" != . ]; then - compress="| $opt_c" - fi - if [ ".$prg_tardy" != . ]; then - # the elegant hackers way - tardy_opt="--prefix=$tarname" - tardy_opt="$tardy_opt --user_number=0 --group_number=0" # security! - if [ ".$opt_u" != . ]; then - tardy_opt="$tardy_opt --user_name=$opt_u" - fi - if [ ".$opt_g" != . ]; then - tardy_opt="$tardy_opt --group_name=$opt_g" - fi - if [ ".$opt_t" = .yes ]; then - echo "cat $tmpfile.lst | xargs $prg_tar cf - | $prg_tardy $tardy_opt | cat $compress >$tmpfile.out" 1>&2 - fi - cat $tmpfile.lst |\ - xargs $prg_tar cf - |\ - $prg_tardy $tardy_opt |\ - eval cat $compress >$tmpfile.out - if [ ".$opt_t" = .yes ]; then - echo "cp $tmpfile.out $tarfile" 1>&2 - fi - cp $tmpfile.out $tarfile - else - # the portable standard way - if [ ".$opt_t" = .yes ]; then - echo "mkdir $tmpdir/$tarname" 1>&2 - fi - mkdir $tmpdir/$tarname || exit 1 - if [ ".$opt_t" = .yes ]; then - echo "cat $tmpfile.lst | xargs $prg_tar cf - | (cd $tmpdir/$tarname && $prg_tar xf -)" 1>&2 - fi - cat $tmpfile.lst |\ - xargs $prg_tar cf - |\ - (cd $tmpdir/$tarname && $prg_tar xf -) - if [ ".$opt_u" != . ]; then - if [ ".$opt_t" = .yes ]; then - echo "chown -R $opt_u $tmpdir/$tarname >/dev/null 2>&1" 2>&1 - fi - chown -R $opt_u $tmpdir/$tarname >/dev/null 2>&1 ||\ - echo "$msgprefix:Warning: cannot set user name \`$opt_u' (need root priviledges)" - fi - if [ ".$opt_g" != . ]; then - if [ ".$opt_t" = .yes ]; then - echo "chgrp -R $opt_g $tmpdir/$tarname >/dev/null 2>&1" 2>&1 - fi - chgrp -R $opt_g $tmpdir/$tarname >/dev/null 2>&1 ||\ - echo "$msgprefix:Warning: cannot set group name \`$opt_g' (need root priviledges)" - fi - if [ ".$opt_t" = .yes ]; then - echo "(cd $tmpdir && $prg_find $tarname -type f -depth -print | sort | xargs $prg_tar cf -) | cat $compress >$tmpfile.out" 1>&2 - fi - (cd $tmpdir && $prg_find $tarname -type f -depth -print | sort | xargs $prg_tar cf -) |\ - eval cat $compress >$tmpfile.out - if [ ".$opt_t" = .yes ]; then - echo "cp $tmpfile.out $tarfile" 1>&2 - fi - cp $tmpfile.out $tarfile - if [ ".$opt_t" = .yes ]; then - echo "rm -rf $tmpdir/$tarname" 1>&2 - fi - rm -rf $tmpdir/$tarname - fi - - # cleanup - if [ ".$opt_t" = .yes ]; then - echo "rm -f $tmpfile.lst $tmpfile.out" 1>&2 - fi - rm -f $tmpfile.lst $tmpfile.out - ;; - -guessos ) - ## - ## guessos -- Simple OS/platform guesser - ## Copyright (c) 1996-2000 The Apache Group, http://www.apache.org/ - ## The Apache license applies (see http://www.apache.org/docs/LICENSE) - ## Originally written for Apache - ## - - MACHINE=`(uname -m) 2>/dev/null` || MACHINE="unknown" - RELEASE=`(uname -r) 2>/dev/null` || RELEASE="unknown" - SYSTEM=`(uname -s) 2>/dev/null` || SYSTEM="unknown" - VERSION=`(uname -v) 2>/dev/null` || VERSION="unknown" - - XREL=`(uname -X) 2>/dev/null | grep "^Release" | awk '{print $3}'` - if [ "x$XREL" != "x" ]; then - if [ -f /etc/kconfig ]; then - case "$XREL" in - 4.0|4.1) echo "${MACHINE}-whatever-isc4"; exit 0 ;; - esac - else - case "$XREL" in - 3.2v4.2) - echo "whatever-whatever-sco3"; exit 0 - ;; - 3.2v5.0*) - echo "whatever-whatever-sco5"; exit 0 - ;; - 4.2MP) - if [ "x$VERSION" = "x2.1.1" ]; then - echo "${MACHINE}-whatever-unixware211"; exit 0 - elif [ "x$VERSION" = "x2.1.2" ]; then - echo "${MACHINE}-whatever-unixware212"; exit 0 - else - echo "${MACHINE}-whatever-unixware2"; exit 0 - fi - ;; - 4.2) - echo "whatever-whatever-unixware1"; exit 0 - ;; - 5) - case "$VERSION" in - 7*) echo "${MACHINE}-whatever-unixware7"; exit 0 ;; - esac - ;; - esac - fi - fi - case "${SYSTEM}:${RELEASE}:${VERSION}:${MACHINE}" in - MiNT:*) - echo "m68k-atari-mint"; exit 0 - ;; - A/UX:*) - echo "m68k-apple-aux3"; exit 0 - ;; - AIX:*) - MACH=`echo $MACHINE | sed -e 's;[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F];;'` - echo "${MACH}-ibm-aix${VERSION}.${RELEASE}"; exit 0 - ;; - dgux:*) - echo "${MACHINE}-dg-dgux"; exit 0 - ;; - HI-UX:*) - echo "${MACHINE}-hi-hiux"; exit 0 - ;; - HP-UX:*) - HPUXVER=`echo ${RELEASE}|sed -e 's/[^.]*.[0B]*//'` - echo "${MACHINE}-hp-hpux${HPUXVER}"; exit 0 - ;; - IRIX:*) - if [ -f /usr/lib32/mips4/libm.so ]; then - echo "${MACHINE}/32-sgi-irix${RELEASE}"; exit 0 - else - echo "${MACHINE}-sgi-irix${RELEASE}"; exit 0 - fi - ;; - IRIX64:*) - echo "${MACHINE}/64-sgi-irix${RELEASE}"; exit 0 - ;; - Linux:*) - V='whatever' - case "$MACHINE" in - i?86) V='pc' ;; - esac - R='' - case "$RELEASE" in - [1-9].*) R=`echo $RELEASE | cut -c1` ;; - esac - echo "${MACHINE}-${V}-linux-gnu${R}"; exit 0 - ;; - LynxOS:*) - echo "${MACHINE}-lynx-lynxos"; exit 0 - ;; - BSD/386|BSD/OS:3.*) - echo "${MACHINE}-whatever-bsdi3"; exit 0 - ;; - BSD/386:*:*:*486*|BSD/OS:*:*:*:*486*) - echo "i486-whatever-bsdi"; exit 0 - ;; - BSD/386:*|BSD/OS:*) - echo "${MACHINE}-whatever-bsdi"; exit 0 - ;; - FreeBSD:*) - VERS=`echo ${RELEASE} | sed -e 's/[-(].*//'` - MACH=`/sbin/sysctl -n hw.model` - ARCH='whatever' - case ${MACH} in - *386* ) MACH="i386" ;; - *486* ) MACH="i486" ;; - Pentium\ II*) MACH="i686" ;; - Pentium* ) MACH="i586" ;; - Alpha* ) MACH="alpha" ;; - * ) MACH="$MACHINE" ;; - esac - case ${MACH} in - i[0-9]86 ) ARCH="pc" ;; - esac - echo "${MACH}-${ARCH}-freebsd${VERS}"; exit 0 - ;; - NetBSD:*:*:*486*) - echo "i486-whatever-netbsd${RELEASE}"; exit 0 - ;; - NetBSD:*) - echo "${MACHINE}-whatever-netbsd${RELEASE}"; exit 0 - ;; - OpenBSD:*) - echo "${MACHINE}-whatever-openbsd"; exit 0 - ;; - OSF1:*:*:*alpha*) - VERS=`echo $RELEASE | sed -e 's;^V;;'` - echo "${MACHINE}-dec-osf${VERS}"; exit 0 - ;; - QNX:*) - if [ "$VERSION" -gt 422 ]; then - echo "${MACHINE}-qssl-qnx32" - else - echo "${MACHINE}-qssl-qnx" - fi - exit 0 - ;; - Paragon*:*:*:*) - echo "i860-intel-osf1"; exit 0 - ;; - SunOS:5.*) - VERSION=`echo $RELEASE | sed -e 's;^5\.;;'` - echo "${MACHINE}-sun-solaris2.${VERSION}"; exit 0 - ;; - SunOS:*) - echo "${MACHINE}-sun-sunos4"; exit 0 - ;; - UNIX_System_V:4.*:*) - echo "${MACHINE}-whatever-sysv4"; exit 0 - ;; - unix:3.0.9*:*:88k) - echo "${MACHINE}-encore-sysv4"; exit 0 - ;; - *:4*:R4*:m88k) - echo "${MACHINE}-whatever-sysv4"; exit 0 - ;; - UnixWare:5:99*:*) - # Gemini, beta release of next rev of unixware - echo "${MACHINE}-whatever-unixware212"; exit 0 - ;; - DYNIX/ptx:4*:*) - echo "${MACHINE}-whatever-sysv4"; exit 0 - ;; - *:4.0:3.0:[345][0-9]?? | *:4.0:3.0:3[34]??[/,]* | library:*) - echo "x86-ncr-sysv4"; exit 0 - ;; - ULTRIX:*) - echo "${MACHINE}-unknown-ultrix"; exit 0 - ;; - SINIX-?:* | ReliantUNIX-?:*) - echo "${MACHINE}-siemens-sysv4"; exit 0 - ;; - POSIX*BS2000) - echo "${MACHINE}-siemens-sysv4"; exit 0 - ;; - machten:*) - echo "${MACHINE}-tenon-${SYSTEM}"; exit 0; - ;; - ConvexOS:*:11.*:*) - echo "${MACHINE}-v11-${SYSTEM}"; exit 0; - ;; - UNIX_SV:*:*:maxion) - echo "${MACHINE}-ccur-sysv4"; exit 0; - ;; - PowerMAX_OS:*:*:Night_Hawk) - MACHINE=`uname -p` - echo "${MACHINE}-concurrent-powermax"; exit 0; - ;; - UNIX_SV:*) - if [ -d /usr/nec ];then - echo "mips-nec-sysv4"; exit 0; - fi - ;; - NonStop-UX:4.[02]*:[BC]*:*) - echo "${MACHINE}-tandem-sysv4"; exit 0; - ;; - Rhapsody:*:*:*) - case "${MACHINE}" in - "Power Macintosh") MACHINE=powerpc ;; - esac - echo "${MACHINE}-apple-rhapsody${RELEASE}"; exit 0 - ;; - "Mac OS":*:*:*) - MACHINE=`uname -p` - echo "${MACHINE}-apple-macos${RELEASE}"; exit 0 - ;; - "RISC iX":*) - echo "arm-whatever-riscix"; exit 0; - ;; - *:4.0:2:*) - echo "whatever-unisys-sysv4"; exit 0; - ;; - *:*:dcosx:NILE*) - echo "pyramid-pyramid-svr4"; exit 0; - ;; - *:*:*:"DRS 6000") - echo "drs6000-whatever-whatever"; exit 0; - ;; - AmigaOS:*:*:* ) - echo "${MACHINE}-whatever-${SYSTEM}${RELEASE}"; exit 0 - ;; - esac - - # Now NeXT - ISNEXT=`(hostinfo) 2>/dev/null` - case "$ISNEXT" in - *NeXT*) - # Swiped from a friendly uname clone for NEXT/OPEN Step. - NEXTOSVER="`hostinfo | sed -n 's/.*NeXT Mach \([0-9\.]*\).*/\1/p'`" - if [ "$NEXTOSVER" -gt 3.3 ]; then - NEXTOS="openstep" - else - NEXTOS="nextstep" - fi - NEXTREL="`hostinfo | sed -n 's/.*NeXT Mach \([0-9\.]*\).*/\1/p'`" - NEXTARCH=`arch` - echo "${NEXTARCH}-next-${NEXTOS}${NEXTREL}" ; exit 0 - ;; - esac - - # Fallback - echo "${MACHINE}-whatever-${SYSTEM}/${RELEASE}/${VERSION}" - ;; - -arx ) - ## - ## arx -- Extended archive command - ## Copyright (c) 1999 Ralf S. Engelschall <rse@engelschall.com> - ## Originally written for shtool - ## - - ar_prg="$opt_C" - ar_cmd="$1"; shift - archive="$1"; shift - files="$*" - - # walk through the file list and expand archives members - tmpdir=`echo $archive | sed -e 's;[^/]*$;.arx;'` - nfiles='' - if [ ".$files" != . ]; then - for file in $files; do - if [ ! -f $file ]; then - echo "$msgprefix:Error: input file not found: $file" 1>&2 - exit 1 - fi - case $file in - *.a ) - if [ ! -d $tmpdir ]; then - if [ ".$opt_t" = .yes ]; then - echo "mkdir $tmpdir" 1>&2 - fi - mkdir $tmpdir - fi - case $tmpdir in - .arx ) - from="../$file" - ;; - * ) - dir=`echo $file | sed -e 's;[^/]*$;;' -e 's;\(.\)/$;\1;' -e 's;^$;.;'` - base=`echo $file | sed -e 's;.*/\([^/]*\)$;\1;'` - from="`cd $dir; pwd`/$base" - ;; - esac - if [ ".$opt_t" = .yes ]; then - echo "(cd $tmpdir && $ar_prg x $from)" 1>&2 - fi - (cd $tmpdir && eval $ar_prg x $from) - if [ $? -ne 0 ]; then - echo "$msgprefix:Error: member extraction failed for archive: $file" 1>&2 - exit 1 - fi - for member in - `eval $ar_prg t $file`; do - [ ".$member" = .- ] && continue - nfiles="$nfiles $tmpdir/$member" - done - ;; - * ) - nfiles="$nfiles $file" - ;; - esac - done - fi - - # run the final archive command - if [ ".$opt_t" = .yes ]; then - echo "$ar_prg $ar_cmd $archive $nfiles" 1>&2 - fi - eval $ar_prg $ar_cmd $archive $nfiles - if [ $? -ne 0 ]; then - echo "$msgprefix:Error: archive command failed" 1>&2 - exit $? - fi - - # cleanup and die gracefully - if [ -d $tmpdir ]; then - if [ ".$opt_t" = .yes ]; then - echo "rm -rf $tmpdir" 1>&2 - fi - rm -rf $tmpdir - fi - ;; - -slo ) - ## - ## slo -- Separate linker options by library class - ## Copyright (c) 1998-1999 Ralf S. Engelschall <rse@engelschall.com> - ## Originally written for Apache - ## - - DIFS="$IFS" - - # parse out -L and -l options from command line - DIRS='' - LIBS='' - ARGV='' - optprev='' - for opt - do - # concatenate with previous option if exists - if [ ".$optprev" != . ]; then - opt="${optprev}${opt}"; - optprev='' - fi - # remember options for arg when used stand-alone - if [ ".$opt" = ".-L" -o ".$opt" = ".-l" ]; then - optprev="$opt" - continue; - fi - # split argument into option plus option argument - arg="`echo $opt | cut -c3-`" - opt="`echo $opt | cut -c1-2`" - # store into containers - case $opt in - -L) DIRS="$DIRS:$arg" ;; - -l) LIBS="$LIBS:$arg" ;; - *) ARGV="$ARGV $opt" ;; - esac - done - - # set linker default directories - DIRS_DEFAULT='/lib:/usr/lib' - if [ ".$LD_LIBRARY_PATH" != . ]; then - DIRS_DEFAULT="$DIRS_DEFAULT:$LD_LIBRARY_PATH" - fi - - # sort options by class - DIRS_OBJ='' - LIBS_OBJ='' - DIRS_PIC='' - LIBS_PIC='' - DIRS_DSO='' - LIBS_DSO='' - - # for each library... - OIFS="$IFS" IFS=':' - for lib in $LIBS; do - [ ".$lib" = . ] && continue - - found='no' - found_indefdir='no' - found_type='' - found_dir='' - - # for each directory... - OIFS2="$IFS" IFS=":$DIFS" - for dir in ${DIRS} switch-to-defdirs ${DIRS_DEFAULT}; do - [ ".$dir" = . ] && continue - [ ".$dir" = .switch-to-defdirs ] && found_indefdir=yes - [ ! -d $dir ] && continue - - # search the file - OIFS3="$IFS" IFS="$DIFS" - for file in '' `cd $dir && ls lib${lib}.* 2>/dev/null`; do - [ ".$file" = . ] && continue - case $file in - *.so|*.so.[0-9]*|*.sl|*.sl.[0-9]* ) - found=yes; - found_type=DSO; - break - ;; - *.lo|*.la ) - found=yes; - found_type=PIC - ;; - *.a ) - if [ ".$found_type" = . ]; then - found=yes - found_type=OBJ - fi - ;; - esac - done - IFS="$OIFS3" - if [ ".$found" = .yes ]; then - found_dir="$dir" - break - fi - done - IFS="$OIFS2" - - if [ ".$found" = .yes ]; then - if [ ".$found_indefdir" != .yes ]; then - eval "dirlist=\"\${DIRS_${found_type}}:\"" - if [ ".`echo \"$dirlist\" | fgrep :$found_dir:`" = . ]; then - eval "DIRS_${found_type}=\"\$DIRS_${found_type}:${found_dir}\"" - fi - eval "LIBS_${found_type}=\"\$LIBS_${found_type}:$lib\"" - else - eval "LIBS_${found_type}=\"\$LIBS_${found_type}:$lib\"" - fi - else - LIBS_OBJ="$LIBS_OBJ:$lib" - #dirlist="`echo $DIRS $DIRS_DEFAULT | sed -e 's/:/ /g'`" - #echo "slo:Warning: library \"$lib\" not found in any of the following dirs:" 2>&1 - #echo "slo:Warning: $dirlist" 1>&1 - fi - done - IFS="$OIFS" - - # also pass-through unused dirs even if it's useless - OIFS="$IFS" IFS=':' - for dir in $DIRS; do - dirlist="${DIRS_OBJ}:${DIRS_PIC}:${DIRS_DSO}:" - if [ ".`echo \"$dirlist\" | fgrep :$dir:`" = . ]; then - DIRS_OBJ="$DIRS_OBJ:$dir" - fi - done - IFS="$OIFS" - - # reassemble the options but separated by type - for type in OBJ PIC DSO; do - OIFS="$IFS" IFS=':' - eval "libs=\"\$LIBS_${type}\"" - opts='' - for lib in $libs; do - [ ".$lib" = . ] && continue - opts="$opts -l$lib" - done - eval "LIBS_${type}=\"$opts\"" - - eval "dirs=\"\$DIRS_${type}\"" - opts='' - for dir in $dirs; do - [ ".$dir" = . ] && continue - opts="$opts -L$dir" - done - eval "DIRS_${type}=\"$opts\"" - IFS="$OIFS" - done - - # give back results - for var in ARGV DIRS_OBJ LIBS_OBJ DIRS_PIC LIBS_PIC DIRS_DSO LIBS_DSO; do - eval "val=\"\$${var}\"" - val="`echo $val | sed -e 's/^ *//'`" - echo "SLO_${var}=\"${val}\"" - done - ;; - -scpp ) - ## - ## scpp -- Sharing C Pre-Processor - ## Copyright (c) 1999 Ralf S. Engelschall <rse@engelschall.com> - ## Originally written for GNU pth - ## - - srcs="$*" - output="${opt_o}.n" - - # find a reasonable Awk - awk='' - paths=`echo $PATH |\ - sed -e 's%/*:%:%g' -e 's%/$%%' \ - -e 's/^:/.:/' -e 's/::/:.:/g' -e 's/:$/:./' \ - -e 's/:/ /g'` - for name in gawk nawk awk; do - for path in $paths; do - if [ -r "$path/$name" ]; then - awk="$path/$name" - break - fi - done - if [ ".$awk" != . ]; then - break - fi - done - if [ ".$awk" = . ]; then - echo "$msgprefix:Error: cannot find a reasonable Awk" 1>&2 - exit 1 - fi - - # parse source file(s) - if [ ".$opt_v" = .yes ]; then - echo "Parsing:" | $awk '{ printf("%s", $0); }' 1>&2 - fi - for src in $srcs; do - if [ ".$opt_v" = .yes ]; then - echo $src | $awk '{ printf(" %s", $0); }' 1>&2 - fi - $awk <$src ' - BEGIN { - ln = 0; - fln = 0; - level = 0; - mode = ""; - store = ""; - } - { - ln++; - } - /^#if.*/ { - level++; - } - /^#if [a-zA-Z_][a-zA-Z0-9_]* *$/ { - if ($2 == define) { - mode = "D"; - printf("D:#line %d \"%s\"\n", ln, src); - next; - } - } - /^#endif.*/ { - level--; - if (mode == "D" && level == 0) { - mode = ""; - next; - } - } - /^[a-zA-Z_][a-zA-Z0-9_].*;.*/ { - if ($1 == class) { - printf("V:#line %d \"%s\"\n", ln, src); - printf("V:%s\n", $0); - printf("J:%s\n", $0); - next; - } - } - /^[a-zA-Z_][a-zA-Z0-9_].*=.*/ { - if ($1 == class) { - printf("V:#line %d \"%s\"\n", ln, src); - printf("V:%s\n", $0); - printf("J:%s\n", $0); - next; - } - } - /^[a-zA-Z_][a-zA-Z0-9_]*/ { - if ($1 == class) { - fln = ln; - store = $0; - mode = "F"; - next; - } - } - /^\{ *$/ { - if (mode == "F") { - printf("F:#line %d \"%s\"\n", fln, src); - printf("F:%s;\n", store); - printf("I:%s;\n", store); - store = ""; - mode = ""; - next; - } - } - { - if (mode == "D") - printf("D:%s\n", $0); - else if (mode == "F") - store = store " " $0; - } - ' "src=$src" "define=$opt_D" "class=$opt_C" >>$tmpfile - done - if [ ".$opt_v" = .yes ]; then - echo "" 1>&2 - fi - - # start generating output header - echo "/* $opt_o -- autogenerated from $opt_t, DO NOT EDIT! */" >$output - echo "#line 1 \"$opt_t\"" >>$output - sed <$opt_t -e "1,/^${opt_M} *\$/p" -e 'd' |\ - sed -e "/^${opt_M} *\$/d" >>$output - - # merge in the define blocks - grep '^D:' $tmpfile | sed -e 's/^D://' >>$output - - # generate standard prolog - echo "#line 1 \"_ON_THE_FLY_\"" >>$output - echo "" >>$output - echo "/* make sure the scpp source extensions are skipped */" >>$output - echo "#define $opt_D 0" >>$output - echo "#define $opt_C /**/" >>$output - - # generate namespace hiding for variables - echo "" >>$output - echo "/* move intern variables to hidden namespace */" >>$output - grep '^J:' $tmpfile | sed >>$output \ - -e 's/^J://' \ - -e 's/ */ /g' \ - -e 's/^[^=;]*[ *]\([a-zA-Z0-9_]*\)\[\];.*$/#define \1 __\1/' \ - -e 's/^[^=;]*[ *]\([a-zA-Z0-9_]*\)\[\] =.*$/#define \1 __\1/' \ - -e 's/^[^=;]*[ *]\([a-zA-Z0-9_]*\);.*$/#define \1 __\1/' \ - -e 's/^[^=;]*[ *]\([a-zA-Z0-9_]*\) =.*$/#define \1 __\1/' - - # generate namespace hiding for functions - echo "" >>$output - echo "/* move intern functions to hidden namespace */" >>$output - grep '^I:' $tmpfile | sed >>$output \ - -e 's/^I://' \ - -e 's/\([ (]\) */\1/g' \ - -e 's/ *\([),]\)/\1/g' \ - -e 's/^[^(]*[ *]\([a-zA-Z0-9_]*\)(.*$/#define \1 __\1/' - - # generate prototypes for variables - echo "" >>$output - echo "/* prototypes for intern variables */" >>$output - grep '^V:' $tmpfile | sed >>$output \ - -e 's/^V://' \ - -e 's/ */ /g' \ - -e 's/^\([^=;]*[ *][a-zA-Z0-9_]*\[\]\);.*$/\1;/' \ - -e 's/^\([^=;]*[ *][a-zA-Z0-9_]*\[\]\) =.*$/\1;/' \ - -e 's/^\([^=;]*[ *][a-zA-Z0-9_]*\);.*$/\1;/' \ - -e 's/^\([^=;]*[ *][a-zA-Z0-9_]*\) =.*$/\1;/' \ - -e 's/ ;/;/g' \ - -e "s/^$opt_C /extern /" - - # generate prototypes for functions - echo "" >>$output - echo "/* prototypes for intern functions */" >>$output - grep '^F:' $tmpfile | sed >>$output \ - -e 's/^F://' \ - -e 's/\([ (]\) */\1/g' \ - -e 's/ *\([),]\)/\1/g' \ - -e 's/\([* ]\)[a-zA-Z0-9_]*,/\1,/g' \ - -e 's/\([* ]\)[a-zA-Z0-9_]*);/\1);/g' \ - -e 's/(\*[a-zA-Z0-9_]*)(/(*)(/g' \ - -e 's/\([ (]\) */\1/g' \ - -e 's/ *\([),]\)/\1/g' \ - -e "s/^$opt_C /extern /" - - # finish generating output header - n=`(echo ''; sed <$opt_t -e "1,/^${opt_M} *\$/p" -e 'd') |\ - wc -l | sed -e 's;^ *\([0-9]*\) *$;\1;'` - echo "#line $n \"$opt_t\"" >>$output - sed <$opt_t -e "/^${opt_M} *\$/,\$p" -e 'd' |\ - sed -e "/^${opt_M} *\$/d" >>$output - - # create final output file - if [ -f $opt_o ]; then - if [ ".$opt_p" = .yes ]; then - grep -v '^#line' $opt_o >$tmpfile.o - grep -v '^#line' $output >$tmpfile.n - out_old="$tmpfile.o" - out_new="$tmpfile.n" - else - out_old="$opt_o" - out_new="$output" - fi - if cmp -s $out_old $out_new; then - : - else - cp $output $opt_o - fi - else - cp $output $opt_o - fi - rm -f $output - rm -f $tmpfile $tmpfile.* >/dev/null 2>&1 - ;; - -version ) - ## - ## version -- Generate and maintain a version information file - ## Copyright (c) 1994-1999 Ralf S. Engelschall <rse@engelschall.com> - ## Originally written for ePerl - ## - - LANGUAGE="$opt_l" - NAME="$opt_n" - PREFIX="$opt_p" - FULLVERSION="$opt_s" - INCREASE="$opt_i" - REPORT="$opt_d" - FILE="$1" - - # determine language - if [ ".$LANGUAGE" = .unknown ]; then - case $FILE in - *.txt ) LANGUAGE=txt ;; - *.c ) LANGUAGE=c ;; - *.pl | *.pm ) LANGUAGE=perl ;; - * ) echo "$tool:Error: unknown language type" 1>&2; exit 1 ;; - esac - fi - - # determine prefix from name and vice versa - if [ ".$PREFIX" = . -o ".$PREFIX" = .unknown ]; then - if [ ".$NAME" != . -a ".$NAME" != .unknown ]; then - PREFIX="$NAME" - fi - fi - if [ ".$NAME" = . -o ".$NAME" = .unknown ]; then - if [ ".$PREFIX" != . -a ".$PREFIX" != .unknown ]; then - NAME="$PREFIX" - fi - fi - - # determine version - date=unknown - version=0 - revision=0 - bplevel=0 - if [ ".$FULLVERSION" = .unknown ]; then - if [ -r "$FILE" ]; then - # grep out current information - id=`grep 'Version [0-9]*.[0-9]*[.abps][0-9]* ([0-9]*-[a-zA-Z]*-[0-9]*)' $FILE | \ - head -1 | \ - sed -e 's%.*Version \([0-9]*\)\.\([0-9]*\)\([.abps]\)\([0-9]*\) (\([0-9]*-[a-zA-Z]*-[0-9]*\)).*%\1:\2:\3:\4:\5%'` - version=`echo $id | awk -F: '{ print $1 }'` - revision=`echo $id | awk -F: '{ print $2 }'` - bptype=`echo $id | awk -F: '{ print $3 }'` - bplevel=`echo $id | awk -F: '{ print $4 }'` - date=`echo $id | awk -F: '{ print $5 }'` - if [ .$REPORT = .NO ]; then - case $INCREASE in - b ) bplevel=`expr $bplevel + 1` - bptype=b - ;; - a ) bplevel=`expr $bplevel + 1` - bptype=a - ;; - s ) bplevel=`expr $bplevel + 1` - bptype=s - ;; - P ) bplevel=`expr $bplevel + 1` - bptype=. - ;; - p ) bplevel=`expr $bplevel + 1` - bptype=p - ;; - r ) revision=`expr $revision + 1` - bptype=. - bplevel=0 - ;; - v ) version=`expr $version + 1` - revision=0 - bptype=. - bplevel=0 - ;; - esac - date=calc - fi - FULLVERSION="$version.$revision$bptype$bplevel" - else - # intialise to first version - version=0 - revision=5 - bptype=b - bplevel=0 - date=calc - fi - else - # take given version - V=`echo $FULLVERSION | sed -e 's%\([0-9]*\)\.\([0-9]*\)\([.abps]\)\([0-9]*\).*%\1:\2:\3:\4%'` - version=`echo $V | awk -F: '{ print $1 }'` - revision=`echo $V | awk -F: '{ print $2 }'` - bptype=`echo $V | awk -F: '{ print $3 }'` - bplevel=`echo $V | awk -F: '{ print $4 }'` - date=calc - fi - - # determine hex value of version - case $FULLVERSION in - *.*a* ) - HEX=`echo "$FULLVERSION" | sed -e 's/a.*//' | awk -F. '{ printf("%d%02d", $1, $2); }' && - echo "$FULLVERSION" | sed -e 's/.*a//' | awk '{ printf("0%02d", $1); }'` - ;; - *.*b* ) - HEX=`echo "$FULLVERSION" | sed -e 's/b.*//' | awk -F. '{ printf("%d%02d", $1, $2); }' && - echo "$FULLVERSION" | sed -e 's/.*b//' | awk '{ printf("1%02d", $1); }'` - ;; - *.*.* ) - HEX=`echo "$FULLVERSION" | awk -F. '{ printf("%d%02d2%02d", $1, $2, $3); }'` - ;; - esac - - # determine libtool version - case $FULLVERSION in - *.*a* ) - LTV=`echo "$FULLVERSION" | sed -e 's/a.*//' | awk -F. '{ printf("%d:0", $1*10+$2); }'` - ;; - *.*b* ) - LTV=`echo "$FULLVERSION" | sed -e 's/b.*//' | awk -F. '{ printf("%d:0", $1*10+$2); }'` - ;; - *.*.* ) - LTV=`echo "$FULLVERSION" | awk -F. '{ printf("%d:%d", $1*10+$2, $3); }'` - ;; - esac - - # determine string out of filename - # (don't try to optimize this in any way - portability!) - FILESTR=`echo "$FILE" |\ - tr 'abcdefghijklmnopqrstuvwxyz./%+' \ - 'ABCDEFGHIJKLMNOPQRSTUVWXYZ____' | sed -e 's/-/_/g'` - - # determine date - if [ ".$date" = .calc ]; then - day=`date '+%d'` - month=`date '+%m'` - year=`date '+%Y' 2>/dev/null` - if [ ".$time_year" = . ]; then - year=`date '+%y'` - case $year in - [5-9][0-9]) year="19$year" ;; - [0-4][0-9]) year="20$year" ;; - esac - fi - case $month in - 1|01) month='Jan' ;; - 2|02) month='Feb' ;; - 3|03) month='Mar' ;; - 4|04) month='Apr' ;; - 5|05) month='May' ;; - 6|06) month='Jun' ;; - 7|07) month='Jul' ;; - 8|08) month='Aug' ;; - 9|09) month='Sep' ;; - 10) month='Oct' ;; - 11) month='Nov' ;; - 12) month='Dec' ;; - esac - date="${day}-${month}-${year}" - fi - - if [ .$REPORT != .NO ]; then - case $REPORT in - long ) - echo "$version.$revision$bptype$bplevel ($date)" - ;; - short ) - echo "$version.$revision$bptype$bplevel" - ;; - libtool ) - echo "$LTV" - ;; - hex ) - echo "0x$HEX" - ;; - esac - rm -f $tmpfile >/dev/null 2>&1 - exit 0 - fi - - # create the version file according the the selected language - echo "new version: $version.$revision$bptype$bplevel ($date)" - case $LANGUAGE in - txt ) - cat >$tmpfile <<'EOT' - - This is @NAME@, Version @VERSION@.@REVISION@@BPTYPE@@BPLEVEL@ (@DAY@-@MONTH@-@YEAR@) -EOT - ;; - c ) - cat >$tmpfile <<'EOT' -/* -** @FILE@ -- Version Information -** [automatically generated and maintained by shtool] -*/ - -#ifdef _AS_HEADER - -#ifndef _@FILESTR@ -#define _@FILESTR@ -#define @PREFIX@_VERSION 0x@HEX@ -extern const int @PREFIX@_Version; -extern const char @PREFIX@_VersionStr[]; -extern const char @PREFIX@_Hello[]; -extern const char @PREFIX@_GNUVersion[]; -extern const char @PREFIX@_WhatID[]; -extern const char @PREFIX@_RCSIdentID[]; -extern const char @PREFIX@_WebID[]; -extern const char @PREFIX@_PlainID[]; -#endif /* _@FILESTR@ */ - -#else - -const int @PREFIX@_Version = 0x@HEX@; -const char @PREFIX@_VersionStr[] = "@VERSION@.@REVISION@@BPTYPE@@BPLEVEL@ (@DAY@-@MONTH@-@YEAR@)"; -const char @PREFIX@_Hello[] = "This is @NAME@, Version @VERSION@.@REVISION@@BPTYPE@@BPLEVEL@ (@DAY@-@MONTH@-@YEAR@)"; -const char @PREFIX@_GNUVersion[] = "@NAME@ Version @VERSION@.@REVISION@@BPTYPE@@BPLEVEL@"; -const char @PREFIX@_WhatID[] = "@(#)@NAME@ Version @VERSION@.@REVISION@@BPTYPE@@BPLEVEL@ (@DAY@-@MONTH@-@YEAR@)"; -const char @PREFIX@_RCSIdentID[] = "$Id: shtool,v 1.4 2000/03/31 08:36:19 fielding Exp $"; -const char @PREFIX@_WebID[] = "@NAME@/@VERSION@.@REVISION@@BPTYPE@@BPLEVEL@"; -const char @PREFIX@_PlainID[] = "@VERSION@.@REVISION@@BPTYPE@@BPLEVEL@"; - -#endif -EOT - ;; - perl ) - cat >$tmpfile <<'EOT' -## -## @FILE@ -- Version Information -## [automatically generated and maintained by shtool] -## - -$@PREFIX@_Version = 0x@HEX@; -$@PREFIX@_VersionStr = "@VERSION@.@REVISION@@BPTYPE@@BPLEVEL@ (@DAY@-@MONTH@-@YEAR@)"; -$@PREFIX@_Hello = "This is @NAME@, Version @VERSION@.@REVISION@@BPTYPE@@BPLEVEL@ (@DAY@-@MONTH@-@YEAR@)"; -$@PREFIX@_GNUVersion = "@NAME@ Version @VERSION@.@REVISION@@BPTYPE@@BPLEVEL@"; -$@PREFIX@_WhatID = "@(#)@NAME@ Version @VERSION@.@REVISION@@BPTYPE@@BPLEVEL@ (@DAY@-@MONTH@-@YEAR@)"; -$@PREFIX@_RCSIdentID = "\$Id: shtool,v 1.4 2000/03/31 08:36:19 fielding Exp $/"; -$@PREFIX@_WebID = "@NAME@/@VERSION@.@REVISION@@BPTYPE@@BPLEVEL@"; -$@PREFIX@_PlainID = "@VERSION@.@REVISION@@BPTYPE@@BPLEVEL@"; - -1; -EOT - ;; - esac - - # now create the version file - rm -f $FILE >/dev/null 2>&1 - sed \ - -e "s|@FILE@|$FILE|g" \ - -e "s|@FILESTR@|$FILESTR|g" \ - -e "s|@PREFIX@|$PREFIX|g" \ - -e "s|@NAME@|$NAME|g" \ - -e "s|@HEX@|$HEX|g" \ - -e "s|@VERSION@|$version|g" \ - -e "s|@REVISION@|$revision|g" \ - -e "s|@BPTYPE@|$bptype|g" \ - -e "s|@BPLEVEL@|$bplevel|g" \ - -e "s|@YEAR@|$year|g" \ - -e "s|@MONTH@|$month|g" \ - -e "s|@DAY@|$day|g" <$tmpfile >$FILE - rm -f $tmpfile >/dev/null 2>&1 - exit 0 - ;; - -path ) - ## - ## path -- Deal with program paths - ## Copyright (c) 1998-1999 Ralf S. Engelschall <rse@engelschall.com> - ## Originally written for Apache - ## - - namelist="$*" - - # check whether the test command supports the -x option - cat >$tmpfile <<EOT -if [ -x / ] || [ -x /bin ] || [ -x /bin/ls ]; then - exit 0 -fi -exit 1 -EOT - if sh $tmpfile 2>/dev/null; then - minusx="-x" - else - minusx="-r" - fi - rm -f $tmpfile - - # split path string - paths="`echo $opt_p |\ - sed -e 's/^:/.:/' \ - -e 's/::/:.:/g' \ - -e 's/:$/:./' \ - -e 's/:/ /g'`" - - # SPECIAL REQUEST - # translate forward to reverse path - if [ ".$opt_r" = .yes ]; then - if [ "x$namelist" = "x." ]; then - rp='.' - else - rp='' - for pe in `IFS="$IFS/"; echo $namelist`; do - rp="../$rp" - done - fi - echo $rp | sed -e 's:/$::' - exit 0 - fi - - # SPECIAL REQUEST - # strip out directory or base name - if [ ".$opt_d" = .yes ]; then - echo "$namelist" |\ - sed -e 's;[^/]*$;;' -e 's;\(.\)/$;\1;' - exit 0 - fi - if [ ".$opt_b" = .yes ]; then - echo "$namelist" |\ - sed -e 's;.*/\([^/]*\)$;\1;' - exit 0 - fi - - # MAGIC SITUATION - # Perl Interpreter (perl) - if [ ".$opt_m" = .yes ] && [ ".$namelist" = .perl ]; then - rm -f $tmpfile - touch $tmpfile - c=0 - found=0 - for dir in $paths; do - dir=`echo $dir | sed -e 's;/*$;;'` - for perl in perl5 perl miniperl; do - if [ $minusx "$dir/$perl" ] && [ ! -d "$dir/$perl" ]; then - perl="$dir/$perl" - version=`$perl -v | grep version |\ - sed -e 's/.* version //' -e 's/ built.*//' -e 's/ with.*//'` - versionnum="`echo $version | sed -e 's/\.//g' -e 's/_//g'`" - versionnum=`expr $versionnum - $c` - echo "$versionnum $perl" >>$tmpfile - found=1 - fi - done - c=`expr $c + 1` - done - if [ $found = 1 ]; then - perl="`cat $tmpfile | sort -u | tail -1 | cut '-d ' -f2`" - rm -f $tmpfile - echo "$perl" - exit 0 - fi - exit 1 - fi - - # MAGIC SITUATION - # C pre-processor (cpp) - if [ ".$opt_m" = .yes ] && [ ".$namelist" = .cpp ]; then - cat >$tmpfile.c <<EOT -#include <assert.h> - Syntax Error -EOT - # 1. try the standard cc -E approach - cpp="${CC-cc} -E" - (eval "$cpp $tmpfile.c >/dev/null") 2>$tmpfile.out - my_error=`grep -v '^ *+' $tmpfile.out` - if [ ".$my_error" != . ]; then - # 2. try the cc -E approach and GCC's -traditional-ccp option - cpp="${CC-cc} -E -traditional-cpp" - (eval "$cpp $tmpfile.c >/dev/null") 2>$tmpfile.out - my_error=`grep -v '^ *+' $tmpfile.out` - if [ ".$my_error" != . ]; then - # 3. try a standalone cpp command in path and lib dirs - for path in $paths /lib /usr/lib /usr/local/lib; do - path=`echo $path | sed -e 's;/*$;;'` - if [ $minusx "$path/cpp" ] && [ ! -d "$path/cpp" ]; then - cpp="$path/cpp" - break - fi - done - if [ ".$cpp" != . ]; then - (eval "$cpp $tmpfile.c >/dev/null") 2>$tmpfile.out - my_error=`grep -v '^ *+' $tmpfile.out` - if [ ".$my_error" != . ]; then - # ok, we gave up... - cpp='' - fi - fi - fi - fi - rm -f $tmpfile.c $tmpfile.out - if [ ".$cpp" != . ]; then - echo "$cpp" - exit 0 - fi - exit 1 - fi - - # STANDARD SITUATION - # iterate over names - for name in $namelist; do - # iterate over paths - for path in $paths; do - path=`echo $path | sed -e 's;/*$;;'` - if [ $minusx "$path/$name" ] && [ ! -d "$path/$name" ]; then - if [ ".$opt_s" != .yes ]; then - echo "$path/$name" 2>&1 - fi - exit 0 - fi - done - done - exit 1 - ;; - -esac - -exit 0 - -##EOF## diff --git a/shmem/unix/shm.c b/shmem/unix/shm.c new file mode 100644 index 00000000000..f93efb5fc44 --- /dev/null +++ b/shmem/unix/shm.c @@ -0,0 +1,731 @@ +/* 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_shm.h" +#include "apr_arch_file_io.h" + +#include "apr_general.h" +#include "apr_errno.h" +#include "apr_user.h" +#include "apr_strings.h" +#include "apr_hash.h" + +#if APR_USE_SHMEM_MMAP_SHM +/* + * For portable use, a shared memory object should be identified by a name of + * the form /somename; that is, a null-terminated string of up to NAME_MAX + * (i.e., 255) characters consisting of an initial slash, followed by one or + * more characters, none of which are slashes. + */ +#ifndef NAME_MAX +#define NAME_MAX 255 +#endif + +/* See proc_mutex.c and sem_open for the reason for all this! */ +static unsigned int rshash (const char *p) { + /* hash function from Robert Sedgwicks 'Algorithms in C' book */ + unsigned int b = 378551; + unsigned int a = 63689; + unsigned int retval = 0; + + for( ; *p; p++) { + retval = retval * a + (*p); + a *= b; + } + + return retval; +} + +static const char *make_shm_open_safe_name(const char *filename, + apr_pool_t *pool) +{ + apr_ssize_t flen; + unsigned int h1, h2; + + if (filename == NULL) { + return NULL; + } + + flen = strlen(filename); + h1 = (apr_hashfunc_default(filename, &flen) & 0xffffffff); + h2 = (rshash(filename) & 0xffffffff); + return apr_psprintf(pool, "/ShM.%xH%x", h1, h2); + +} +#endif + +#if APR_USE_SHMEM_SHMGET +static key_t our_ftok(const char *filename) +{ + /* to help avoid collisions while still using + * an easily recreated proj_id */ + apr_ssize_t slen = strlen(filename); + return ftok(filename, + (int)apr_hashfunc_default(filename, &slen)); +} +#endif + +static apr_status_t shm_cleanup_owner(void *m_) +{ + apr_shm_t *m = (apr_shm_t *)m_; + + /* anonymous shared memory */ + if (m->filename == NULL) { +#if APR_USE_SHMEM_MMAP_ZERO || APR_USE_SHMEM_MMAP_ANON + if (munmap(m->base, m->realsize) == -1) { + return errno; + } + return APR_SUCCESS; +#elif APR_USE_SHMEM_SHMGET_ANON + if (shmdt(m->base) == -1) { + return errno; + } + /* This segment will automatically remove itself after all + * references have detached. */ + return APR_SUCCESS; +#endif + } + + /* name-based shared memory */ + else { +#if APR_USE_SHMEM_MMAP_TMP + if (munmap(m->base, m->realsize) == -1) { + return errno; + } + if (access(m->filename, F_OK)) { + return APR_SUCCESS; + } + else { + return apr_file_remove(m->filename, m->pool); + } +#elif APR_USE_SHMEM_MMAP_SHM + if (munmap(m->base, m->realsize) == -1) { + return errno; + } + if (shm_unlink(make_shm_open_safe_name(m->filename, m->pool)) == -1 && errno != ENOENT) { + return errno; + } + return APR_SUCCESS; +#elif APR_USE_SHMEM_SHMGET + /* Indicate that the segment is to be destroyed as soon + * as all processes have detached. This also disallows any + * new attachments to the segment. */ + if (shmctl(m->shmid, IPC_RMID, NULL) == -1 && errno != EINVAL) { + return errno; + } + if (shmdt(m->base) == -1) { + return errno; + } + if (access(m->filename, F_OK)) { + return APR_SUCCESS; + } + else { + return apr_file_remove(m->filename, m->pool); + } +#else + return APR_ENOTIMPL; +#endif + } +} + +APR_DECLARE(apr_status_t) apr_shm_create(apr_shm_t **m, + apr_size_t reqsize, + const char *filename, + apr_pool_t *pool) +{ + apr_shm_t *new_m; + apr_status_t status; +#if APR_USE_SHMEM_SHMGET || APR_USE_SHMEM_SHMGET_ANON + struct shmid_ds shmbuf; + apr_uid_t uid; + apr_gid_t gid; +#endif +#if APR_USE_SHMEM_MMAP_TMP || APR_USE_SHMEM_MMAP_SHM || \ + APR_USE_SHMEM_MMAP_ZERO + int tmpfd; +#endif +#if APR_USE_SHMEM_SHMGET + apr_size_t nbytes; +#endif +#if APR_USE_SHMEM_MMAP_ZERO || APR_USE_SHMEM_SHMGET || \ + APR_USE_SHMEM_MMAP_TMP || APR_USE_SHMEM_MMAP_SHM + apr_file_t *file; /* file where metadata is stored */ +#endif + + /* Check if they want anonymous or name-based shared memory */ + if (filename == NULL) { +#if APR_USE_SHMEM_MMAP_ZERO || APR_USE_SHMEM_MMAP_ANON + new_m = apr_palloc(pool, sizeof(apr_shm_t)); + new_m->pool = pool; + new_m->reqsize = reqsize; + new_m->realsize = reqsize + + APR_ALIGN_DEFAULT(sizeof(apr_size_t)); /* room for metadata */ + new_m->filename = NULL; + +#if APR_USE_SHMEM_MMAP_ZERO + status = apr_file_open(&file, "/dev/zero", APR_FOPEN_READ | APR_FOPEN_WRITE, + APR_FPROT_OS_DEFAULT, pool); + if (status != APR_SUCCESS) { + return status; + } + status = apr_os_file_get(&tmpfd, file); + if (status != APR_SUCCESS) { + return status; + } + + new_m->base = mmap(NULL, new_m->realsize, PROT_READ|PROT_WRITE, + MAP_SHARED, tmpfd, 0); + if (new_m->base == (void *)MAP_FAILED) { + return errno; + } + + status = apr_file_close(file); + if (status != APR_SUCCESS) { + return status; + } + + /* store the real size in the metadata */ + *(apr_size_t*)(new_m->base) = new_m->realsize; + /* metadata isn't usable */ + new_m->usable = (char *)new_m->base + APR_ALIGN_DEFAULT(sizeof(apr_size_t)); + + apr_pool_cleanup_register(new_m->pool, new_m, shm_cleanup_owner, + apr_pool_cleanup_null); + *m = new_m; + return APR_SUCCESS; + +#elif APR_USE_SHMEM_MMAP_ANON + new_m->base = mmap(NULL, new_m->realsize, PROT_READ|PROT_WRITE, + MAP_ANON|MAP_SHARED, -1, 0); + if (new_m->base == (void *)MAP_FAILED) { + return errno; + } + + /* store the real size in the metadata */ + *(apr_size_t*)(new_m->base) = new_m->realsize; + /* metadata isn't usable */ + new_m->usable = (char *)new_m->base + APR_ALIGN_DEFAULT(sizeof(apr_size_t)); + + apr_pool_cleanup_register(new_m->pool, new_m, shm_cleanup_owner, + apr_pool_cleanup_null); + *m = new_m; + return APR_SUCCESS; + +#endif /* APR_USE_SHMEM_MMAP_ZERO */ +#elif APR_USE_SHMEM_SHMGET_ANON + new_m = apr_palloc(pool, sizeof(apr_shm_t)); + new_m->pool = pool; + new_m->reqsize = reqsize; + new_m->realsize = reqsize; + new_m->filename = NULL; + new_m->shmkey = IPC_PRIVATE; + if ((new_m->shmid = shmget(new_m->shmkey, new_m->realsize, + SHM_R | SHM_W | IPC_CREAT)) < 0) { + return errno; + } + + if ((new_m->base = shmat(new_m->shmid, NULL, 0)) == (void *)-1) { + return errno; + } + new_m->usable = new_m->base; + + if (shmctl(new_m->shmid, IPC_STAT, &shmbuf) == -1) { + return errno; + } + apr_uid_current(&uid, &gid, pool); + shmbuf.shm_perm.uid = uid; + shmbuf.shm_perm.gid = gid; + if (shmctl(new_m->shmid, IPC_SET, &shmbuf) == -1) { + return errno; + } + + /* Remove the segment once use count hits zero. + * We will not attach to this segment again, since it is + * anonymous memory, so it is ok to mark it for deletion. + */ + if (shmctl(new_m->shmid, IPC_RMID, NULL) == -1) { + return errno; + } + + apr_pool_cleanup_register(new_m->pool, new_m, shm_cleanup_owner, + apr_pool_cleanup_null); + *m = new_m; + return APR_SUCCESS; +#else + /* It is an error if they want anonymous memory but we don't have it. */ + return APR_ENOTIMPL; /* requested anonymous but we don't have it */ +#endif + } + + /* Name-based shared memory */ + else { + new_m = apr_palloc(pool, sizeof(apr_shm_t)); + new_m->pool = pool; + new_m->reqsize = reqsize; + new_m->filename = apr_pstrdup(pool, filename); +#if APR_USE_SHMEM_MMAP_SHM + const char *shm_name = make_shm_open_safe_name(filename, pool); +#endif +#if APR_USE_SHMEM_MMAP_TMP || APR_USE_SHMEM_MMAP_SHM + new_m->realsize = reqsize + + APR_ALIGN_DEFAULT(sizeof(apr_size_t)); /* room for metadata */ + /* FIXME: Ignore error for now. * + * status = apr_file_remove(file, pool);*/ + status = APR_SUCCESS; + +#if APR_USE_SHMEM_MMAP_TMP + /* FIXME: Is APR_FPROT_OS_DEFAULT sufficient? */ + status = apr_file_open(&file, filename, + APR_FOPEN_READ | APR_FOPEN_WRITE | APR_FOPEN_CREATE | APR_FOPEN_EXCL, + APR_FPROT_OS_DEFAULT, pool); + if (status != APR_SUCCESS) { + return status; + } + + status = apr_os_file_get(&tmpfd, file); + if (status != APR_SUCCESS) { + apr_file_close(file); /* ignore errors, we're failing */ + apr_file_remove(new_m->filename, new_m->pool); + return status; + } + + status = apr_file_trunc(file, new_m->realsize); + if (status != APR_SUCCESS && status != APR_ESPIPE) { + apr_file_close(file); /* ignore errors, we're failing */ + apr_file_remove(new_m->filename, new_m->pool); + return status; + } + + new_m->base = mmap(NULL, new_m->realsize, PROT_READ | PROT_WRITE, + MAP_SHARED, tmpfd, 0); + /* FIXME: check for errors */ + + status = apr_file_close(file); + if (status != APR_SUCCESS) { + return status; + } +#endif /* APR_USE_SHMEM_MMAP_TMP */ +#if APR_USE_SHMEM_MMAP_SHM + /* FIXME: SysV uses 0600... should we? */ + tmpfd = shm_open(shm_name, O_RDWR | O_CREAT | O_EXCL, 0644); + if (tmpfd == -1) { + return errno; + } + + status = apr_os_file_put(&file, &tmpfd, + APR_FOPEN_READ | APR_FOPEN_WRITE | APR_FOPEN_CREATE | APR_FOPEN_EXCL, + pool); + if (status != APR_SUCCESS) { + return status; + } + + status = apr_file_trunc(file, new_m->realsize); + if (status != APR_SUCCESS && status != APR_ESPIPE) { + shm_unlink(shm_name); /* we're failing, remove the object */ + return status; + } + new_m->base = mmap(NULL, new_m->realsize, PROT_READ | PROT_WRITE, + MAP_SHARED, tmpfd, 0); + + /* FIXME: check for errors */ + + status = apr_file_close(file); + if (status != APR_SUCCESS) { + return status; + } +#endif /* APR_USE_SHMEM_MMAP_SHM */ + + /* store the real size in the metadata */ + *(apr_size_t*)(new_m->base) = new_m->realsize; + /* metadata isn't usable */ + new_m->usable = (char *)new_m->base + APR_ALIGN_DEFAULT(sizeof(apr_size_t)); + + apr_pool_cleanup_register(new_m->pool, new_m, shm_cleanup_owner, + apr_pool_cleanup_null); + *m = new_m; + return APR_SUCCESS; + +#elif APR_USE_SHMEM_SHMGET + new_m->realsize = reqsize; + + /* FIXME: APR_FPROT_OS_DEFAULT is too permissive, switch to 600 I think. */ + status = apr_file_open(&file, filename, + APR_FOPEN_WRITE | APR_FOPEN_CREATE | APR_FOPEN_EXCL, + APR_FPROT_OS_DEFAULT, pool); + if (status != APR_SUCCESS) { + return status; + } + + /* ftok() (on solaris at least) requires that the file actually + * exist before calling ftok(). */ + new_m->shmkey = our_ftok(filename); + if (new_m->shmkey == (key_t)-1) { + apr_file_close(file); + return errno; + } + + if ((new_m->shmid = shmget(new_m->shmkey, new_m->realsize, + SHM_R | SHM_W | IPC_CREAT | IPC_EXCL)) < 0) { + apr_file_close(file); + return errno; + } + + if ((new_m->base = shmat(new_m->shmid, NULL, 0)) == (void *)-1) { + apr_file_close(file); + return errno; + } + new_m->usable = new_m->base; + + if (shmctl(new_m->shmid, IPC_STAT, &shmbuf) == -1) { + apr_file_close(file); + return errno; + } + apr_uid_current(&uid, &gid, pool); + shmbuf.shm_perm.uid = uid; + shmbuf.shm_perm.gid = gid; + if (shmctl(new_m->shmid, IPC_SET, &shmbuf) == -1) { + apr_file_close(file); + return errno; + } + + nbytes = sizeof(reqsize); + status = apr_file_write(file, (const void *)&reqsize, + &nbytes); + if (status != APR_SUCCESS) { + apr_file_close(file); + return status; + } + status = apr_file_close(file); + if (status != APR_SUCCESS) { + return status; + } + + apr_pool_cleanup_register(new_m->pool, new_m, shm_cleanup_owner, + apr_pool_cleanup_null); + *m = new_m; + return APR_SUCCESS; + +#else + return APR_ENOTIMPL; +#endif + } +} + +APR_DECLARE(apr_status_t) apr_shm_create_ex(apr_shm_t **m, + apr_size_t reqsize, + const char *filename, + apr_pool_t *p, + apr_int32_t flags) +{ + return apr_shm_create(m, reqsize, filename, p); +} + +APR_DECLARE(apr_status_t) apr_shm_remove(const char *filename, + apr_pool_t *pool) +{ +#if APR_USE_SHMEM_SHMGET + apr_status_t status; + apr_file_t *file; + key_t shmkey; + int shmid; +#endif + +#if APR_USE_SHMEM_MMAP_TMP + return apr_file_remove(filename, pool); +#elif APR_USE_SHMEM_MMAP_SHM + const char *shm_name = make_shm_open_safe_name(filename, pool); + if (shm_unlink(shm_name) == -1) { + return errno; + } + return APR_SUCCESS; +#elif APR_USE_SHMEM_SHMGET + /* Presume that the file already exists; just open for writing */ + status = apr_file_open(&file, filename, APR_FOPEN_WRITE, + APR_FPROT_OS_DEFAULT, pool); + if (status) { + return status; + } + + /* ftok() (on solaris at least) requires that the file actually + * exist before calling ftok(). */ + shmkey = our_ftok(filename); + if (shmkey == (key_t)-1) { + goto shm_remove_failed; + } + + apr_file_close(file); + + if ((shmid = shmget(shmkey, 0, SHM_R | SHM_W)) < 0) { + goto shm_remove_failed; + } + + /* Indicate that the segment is to be destroyed as soon + * as all processes have detached. This also disallows any + * new attachments to the segment. */ + if (shmctl(shmid, IPC_RMID, NULL) == -1) { + goto shm_remove_failed; + } + return apr_file_remove(filename, pool); + +shm_remove_failed: + status = errno; + /* ensure the file has been removed anyway. */ + apr_file_remove(filename, pool); + return status; +#else + + /* No support for anonymous shm */ + return APR_ENOTIMPL; +#endif +} + +APR_DECLARE(apr_status_t) apr_shm_delete(apr_shm_t *m) +{ + if (m->filename) { + return apr_shm_remove(m->filename, m->pool); + } + else { + return APR_ENOTIMPL; + } +} + +APR_DECLARE(apr_status_t) apr_shm_destroy(apr_shm_t *m) +{ + return apr_pool_cleanup_run(m->pool, m, shm_cleanup_owner); +} + +static apr_status_t shm_cleanup_attach(void *m_) +{ + apr_shm_t *m = (apr_shm_t *)m_; + + if (m->filename == NULL) { + /* It doesn't make sense to detach from an anonymous memory segment. */ + return APR_EINVAL; + } + else { +#if APR_USE_SHMEM_MMAP_TMP || APR_USE_SHMEM_MMAP_SHM + if (munmap(m->base, m->realsize) == -1) { + return errno; + } + return APR_SUCCESS; +#elif APR_USE_SHMEM_SHMGET + if (shmdt(m->base) == -1) { + return errno; + } + return APR_SUCCESS; +#else + return APR_ENOTIMPL; +#endif + } +} + +APR_DECLARE(apr_status_t) apr_shm_attach(apr_shm_t **m, + const char *filename, + apr_pool_t *pool) +{ + if (filename == NULL) { + /* It doesn't make sense to attach to a segment if you don't know + * the filename. */ + return APR_EINVAL; + } + else { +#if APR_USE_SHMEM_MMAP_TMP || APR_USE_SHMEM_MMAP_SHM + apr_shm_t *new_m; + apr_status_t status; + int tmpfd; + apr_file_t *file; /* file where metadata is stored */ + apr_size_t nbytes; + + new_m = apr_palloc(pool, sizeof(apr_shm_t)); + new_m->pool = pool; + new_m->filename = apr_pstrdup(pool, filename); +#if APR_USE_SHMEM_MMAP_SHM + const char *shm_name = make_shm_open_safe_name(filename, pool); + + /* FIXME: SysV uses 0600... should we? */ + tmpfd = shm_open(shm_name, O_RDWR, 0644); + if (tmpfd == -1) { + return errno; + } + + status = apr_os_file_put(&file, &tmpfd, + APR_READ | APR_WRITE, + pool); + if (status != APR_SUCCESS) { + return status; + } + +#elif APR_USE_SHMEM_MMAP_TMP + status = apr_file_open(&file, filename, + APR_FOPEN_READ | APR_FOPEN_WRITE, + APR_FPROT_OS_DEFAULT, pool); + if (status != APR_SUCCESS) { + return status; + } + status = apr_os_file_get(&tmpfd, file); + if (status != APR_SUCCESS) { + return status; + } +#else + return APR_ENOTIMPL; +#endif + + nbytes = sizeof(new_m->realsize); + status = apr_file_read(file, (void *)&(new_m->realsize), + &nbytes); + if (status != APR_SUCCESS) { + return status; + } + + status = apr_os_file_get(&tmpfd, file); + if (status != APR_SUCCESS) { + apr_file_close(file); /* ignore errors, we're failing */ + apr_file_remove(new_m->filename, new_m->pool); + return status; + } + + new_m->reqsize = new_m->realsize - sizeof(apr_size_t); + + new_m->base = mmap(NULL, new_m->realsize, PROT_READ | PROT_WRITE, + MAP_SHARED, tmpfd, 0); + /* FIXME: check for errors */ + + status = apr_file_close(file); + if (status != APR_SUCCESS) { + return status; + } + + /* metadata isn't part of the usable segment */ + new_m->usable = (char *)new_m->base + APR_ALIGN_DEFAULT(sizeof(apr_size_t)); + + apr_pool_cleanup_register(new_m->pool, new_m, shm_cleanup_attach, + apr_pool_cleanup_null); + *m = new_m; + return APR_SUCCESS; + +#elif APR_USE_SHMEM_SHMGET + apr_shm_t *new_m; + apr_status_t status; + apr_file_t *file; /* file where metadata is stored */ + apr_size_t nbytes; + + new_m = apr_palloc(pool, sizeof(apr_shm_t)); + + status = apr_file_open(&file, filename, + APR_FOPEN_READ, APR_FPROT_OS_DEFAULT, pool); + if (status != APR_SUCCESS) { + return status; + } + + nbytes = sizeof(new_m->reqsize); + status = apr_file_read(file, (void *)&(new_m->reqsize), + &nbytes); + if (status != APR_SUCCESS) { + return status; + } + status = apr_file_close(file); + if (status != APR_SUCCESS) { + return status; + } + + new_m->filename = apr_pstrdup(pool, filename); + new_m->pool = pool; + new_m->shmkey = our_ftok(filename); + if (new_m->shmkey == (key_t)-1) { + return errno; + } + if ((new_m->shmid = shmget(new_m->shmkey, 0, SHM_R | SHM_W)) == -1) { + return errno; + } + if ((new_m->base = shmat(new_m->shmid, NULL, 0)) == (void *)-1) { + return errno; + } + new_m->usable = new_m->base; + new_m->realsize = new_m->reqsize; + + apr_pool_cleanup_register(new_m->pool, new_m, shm_cleanup_attach, + apr_pool_cleanup_null); + *m = new_m; + return APR_SUCCESS; + +#else + return APR_ENOTIMPL; +#endif + } +} + +APR_DECLARE(apr_status_t) apr_shm_attach_ex(apr_shm_t **m, + const char *filename, + apr_pool_t *pool, + apr_int32_t flags) +{ + return apr_shm_attach(m, filename, pool); +} + +APR_DECLARE(apr_status_t) apr_shm_detach(apr_shm_t *m) +{ + apr_status_t rv = shm_cleanup_attach(m); + apr_pool_cleanup_kill(m->pool, m, shm_cleanup_attach); + return rv; +} + +APR_DECLARE(void *) apr_shm_baseaddr_get(const apr_shm_t *m) +{ + return m->usable; +} + +APR_DECLARE(apr_size_t) apr_shm_size_get(const apr_shm_t *m) +{ + return m->reqsize; +} + +APR_PERMS_SET_IMPLEMENT(shm) +{ +#if APR_USE_SHMEM_SHMGET || APR_USE_SHMEM_SHMGET_ANON + struct shmid_ds shmbuf; + int shmid; + apr_shm_t *m = (apr_shm_t *)theshm; + + if ((shmid = shmget(m->shmkey, 0, SHM_R | SHM_W)) == -1) { + return errno; + } + shmbuf.shm_perm.uid = uid; + shmbuf.shm_perm.gid = gid; + shmbuf.shm_perm.mode = apr_unix_perms2mode(perms); + if (shmctl(shmid, IPC_SET, &shmbuf) == -1) { + return errno; + } + return APR_SUCCESS; +#else + return APR_ENOTIMPL; +#endif +} + +APR_POOL_IMPLEMENT_ACCESSOR(shm) + +APR_DECLARE(apr_status_t) apr_os_shm_get(apr_os_shm_t *osshm, + apr_shm_t *shm) +{ + return APR_ENOTIMPL; +} + +APR_DECLARE(apr_status_t) apr_os_shm_put(apr_shm_t **m, + apr_os_shm_t *osshm, + apr_pool_t *pool) +{ + return APR_ENOTIMPL; +} + diff --git a/shmem/unix/shmem.c b/shmem/unix/shmem.c deleted file mode 100644 index c728f550142..00000000000 --- a/shmem/unix/shmem.c +++ /dev/null @@ -1,156 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#include "mm.h" -#include "apr_general.h" -#include "apr_shmem.h" -#include "apr_errno.h" - -struct shmem_t { - MM *mm; -}; - -ap_status_t ap_shm_init(struct shmem_t **m, ap_size_t reqsize, const char *file, ap_pool_t *cont) -{ - MM *newmm = mm_create(reqsize, file); - if (newmm == NULL) { - return errno; - } - (*m) = mm_malloc(newmm, sizeof(struct shmem_t)); - (*m)->mm = newmm; - return APR_SUCCESS; -} - -ap_status_t ap_shm_destroy(struct shmem_t *m) -{ - mm_destroy(m->mm); - return APR_SUCCESS; -} - -void *ap_shm_malloc(struct shmem_t *c, ap_size_t reqsize) -{ - if (c->mm == NULL) { - return NULL; - } - return mm_malloc(c->mm, reqsize); -} - -void *ap_shm_calloc(struct shmem_t *shared, ap_size_t size) -{ - if (shared == NULL) { - return NULL; - } - return mm_calloc(shared->mm, 1, size); -} - -ap_status_t ap_shm_free(struct shmem_t *shared, void *entity) -{ - mm_free(shared->mm, entity); - return APR_SUCCESS; -} - -ap_status_t ap_get_shm_name(ap_shmem_t *c, ap_shm_name_t **name) -{ -#if APR_USES_ANONYMOUS_SHM - name = NULL; - return APR_ANONYMOUS; -/* Currently, we are not supporting name based shared memory on Unix - * systems. This may change in the future however, so I will leave - * this in here for now. Plus, this gives other platforms a good idea - * of how to proceed. - */ -#elif APR_USES_FILEBASED_SHM -#elif APR_USES_KEYBASED_SHM -#endif -} - -ap_status_t ap_set_shm_name(ap_shmem_t *c, ap_shm_name_t *name) -{ -#if APR_USES_ANONYMOUS_SHM - return APR_ANONYMOUS; -/* Currently, we are not supporting name based shared memory on Unix - * systems. This may change in the future however, so I will leave - * this in here for now. Plus, this gives other platforms a good idea - * of how to proceed. - */ -#elif APR_USES_FILEBASED_SHM -#elif APR_USES_KEYBASED_SHM -#endif -} - -ap_status_t ap_open_shmem(struct shmem_t *c) -{ -#if APR_USES_ANONYMOUS_SHM -/* When using MM, we don't need to open shared memory segments in child - * segments, so just return immediately. - */ - return APR_SUCCESS; -/* Currently, we are not supporting name based shared memory on Unix - * systems. This may change in the future however, so I will leave - * this in here for now. Plus, this gives other platforms a good idea - * of how to proceed. - */ -#elif APR_USES_FILEBASED_SHM -#elif APR_USES_KEYBASED_SHM -#endif -} - -ap_status_t ap_shm_avail(struct shmem_t *c, ap_size_t *size) -{ - *size = mm_available(c); - if (*size == 0) { - return APR_ENOSHMAVAIL; - } - return APR_SUCCESS; -} diff --git a/shmem/win32/shm.c b/shmem/win32/shm.c new file mode 100644 index 00000000000..b01411ebd5e --- /dev/null +++ b/shmem/win32/shm.c @@ -0,0 +1,452 @@ +/* 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_general.h" +#include "apr_errno.h" +#include "apr_file_io.h" +#include "apr_shm.h" +#include "apr_strings.h" +#include "apr_arch_file_io.h" +#include "limits.h" + +typedef struct memblock_t { + apr_size_t size; + apr_size_t length; +} memblock_t; + +struct apr_shm_t { + apr_pool_t *pool; + memblock_t *memblk; + void *usrmem; + apr_size_t size; + apr_size_t length; + HANDLE hMap; + const char *filename; +}; + +static apr_status_t shm_cleanup(void* shm) +{ + apr_status_t rv = APR_SUCCESS; + apr_shm_t *m = shm; + + if (!UnmapViewOfFile(m->memblk)) { + rv = apr_get_os_error(); + } + if (!CloseHandle(m->hMap)) { + rv = rv != APR_SUCCESS ? rv : apr_get_os_error(); + } + if (m->filename) { + /* Remove file if file backed */ + apr_status_t rc = apr_file_remove(m->filename, m->pool); + rv = rv != APR_SUCCESS ? rv : rc; + } + return rv; +} + +/* See if the caller is able to create a map in the global namespace by + * checking if the SE_CREATE_GLOBAL_NAME privilege is enabled. + * + * Prior to APR 1.5.0, named shared memory segments were always created + * in the global segment. However, with recent versions of Windows this + * fails for unprivileged processes. Thus, with older APR, named shared + * memory segments can't be created by unprivileged processes on newer + * Windows. + * + * By checking if the caller has the privilege, shm APIs can decide + * whether to use the Global or Local namespace. + * + * If running on an SDK without the required API definitions *OR* + * some processing failure occurs trying to check the privilege, fall + * back to earlier behavior -- always try to use the Global namespace. + */ +#ifdef SE_CREATE_GLOBAL_NAME +static int can_create_global_maps(void) +{ + BOOL ok, has_priv; + LUID priv_id; + PRIVILEGE_SET privs; + HANDLE hToken; + + ok = OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, TRUE, &hToken); + if (!ok && GetLastError() == ERROR_NO_TOKEN) { + /* no thread-specific access token, so try to get process access token + */ + ok = OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken); + } + + if (ok) { + ok = LookupPrivilegeValue(NULL, SE_CREATE_GLOBAL_NAME, &priv_id); + } + + if (ok) { + privs.PrivilegeCount = 1; + privs.Control = PRIVILEGE_SET_ALL_NECESSARY; + privs.Privilege[0].Luid = priv_id; + privs.Privilege[0].Attributes = SE_PRIVILEGE_ENABLED; + ok = PrivilegeCheck(hToken, &privs, &has_priv); + } + + if (ok && !has_priv) { + return 0; + } + else { + return 1; + } +} +#else /* SE_CREATE_GLOBAL_NAME */ +/* SDK definitions missing */ +static int can_create_global_maps(void) +{ + return 1; +} +#endif /* SE_CREATE_GLOBAL_NAME */ + +APR_DECLARE(apr_status_t) apr_shm_create_ex(apr_shm_t **m, + apr_size_t reqsize, + const char *file, + apr_pool_t *pool, + apr_int32_t flags) +{ + static apr_size_t memblock = 0; + HANDLE hMap, hFile; + apr_status_t rv; + apr_size_t size; + apr_file_t *f; + void *base; + void *mapkey; + DWORD err, sizelo, sizehi; + + reqsize += sizeof(memblock_t); + + if (!memblock) + { + SYSTEM_INFO si; + GetSystemInfo(&si); + memblock = si.dwAllocationGranularity; + } + + /* Compute the granualar multiple of the pagesize */ + size = memblock * (1 + (reqsize - 1) / memblock); + sizelo = (DWORD)size; +#ifdef _WIN64 + sizehi = (DWORD)(size >> 32); +#else + sizehi = 0; +#endif + + if (!file) { + /* Do Anonymous, which must be passed as a duplicated handle */ +#ifndef _WIN32_WCE + hFile = INVALID_HANDLE_VALUE; +#endif + mapkey = NULL; + } + else { + int global; + + /* Do file backed, which is not an inherited handle + * While we could open APR_FOPEN_EXCL, it doesn't seem that Unix + * ever did. Ignore that error here, but fail later when + * we discover we aren't the creator of the file map object. + */ + rv = apr_file_open(&f, file, + APR_FOPEN_READ | APR_FOPEN_WRITE | APR_FOPEN_BINARY | APR_FOPEN_CREATE, + APR_FPROT_UREAD | APR_FPROT_UWRITE, pool); + if ((rv != APR_SUCCESS) + || ((rv = apr_os_file_get(&hFile, f)) != APR_SUCCESS)) { + return rv; + } + rv = apr_file_trunc(f, size); + + /* res_name_from_filename turns file into a pseudo-name + * without slashes or backslashes, and prepends the \global + * or \local prefix on Win2K and later + */ + if (flags & APR_SHM_NS_GLOBAL) { + global = 1; + } + else if (flags & APR_SHM_NS_LOCAL) { + global = 0; + } + else { + global = can_create_global_maps(); + } + mapkey = res_name_from_filename(file, global, pool); + } + +#if APR_HAS_UNICODE_FS + IF_WIN_OS_IS_UNICODE + { + hMap = CreateFileMappingW(hFile, NULL, PAGE_READWRITE, + sizehi, sizelo, mapkey); + } +#endif +#if APR_HAS_ANSI_FS + ELSE_WIN_OS_IS_ANSI + { + hMap = CreateFileMappingA(hFile, NULL, PAGE_READWRITE, + sizehi, sizelo, mapkey); + } +#endif + err = apr_get_os_error(); + + if (file) { + apr_file_close(f); + } + + if (hMap && APR_STATUS_IS_EEXIST(err)) { + CloseHandle(hMap); + return APR_EEXIST; + } + if (!hMap) { + return err; + } + + base = MapViewOfFile(hMap, FILE_MAP_READ | FILE_MAP_WRITE, + 0, 0, size); + if (!base) { + CloseHandle(hMap); + return apr_get_os_error(); + } + + *m = (apr_shm_t *) apr_palloc(pool, sizeof(apr_shm_t)); + (*m)->pool = pool; + (*m)->hMap = hMap; + (*m)->memblk = base; + (*m)->size = size; + + (*m)->usrmem = (char*)base + sizeof(memblock_t); + (*m)->length = reqsize - sizeof(memblock_t);; + + (*m)->memblk->length = (*m)->length; + (*m)->memblk->size = (*m)->size; + (*m)->filename = file ? apr_pstrdup(pool, file) : NULL; + + apr_pool_cleanup_register((*m)->pool, *m, + shm_cleanup, apr_pool_cleanup_null); + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_shm_create(apr_shm_t **m, + apr_size_t reqsize, + const char *file, + apr_pool_t *pool) +{ + return apr_shm_create_ex(m, reqsize, file, pool, 0); +} + +APR_DECLARE(apr_status_t) apr_shm_destroy(apr_shm_t *m) +{ + apr_status_t rv = shm_cleanup(m); + apr_pool_cleanup_kill(m->pool, m, shm_cleanup); + return rv; +} + +APR_DECLARE(apr_status_t) apr_shm_remove(const char *filename, + apr_pool_t *pool) +{ + return apr_file_remove(filename, pool); +} + +APR_DECLARE(apr_status_t) apr_shm_delete(apr_shm_t *m) +{ + if (m->filename) { + return apr_shm_remove(m->filename, m->pool); + } + else { + return APR_ENOTIMPL; + } +} + +static apr_status_t shm_attach_internal(apr_shm_t **m, + const char *file, + apr_pool_t *pool, + int global) +{ + HANDLE hMap; + void *mapkey; + void *base; + + /* res_name_from_filename turns file into a pseudo-name + * without slashes or backslashes, and prepends the \global + * or local prefix on Win2K and later + */ + mapkey = res_name_from_filename(file, global, pool); + +#if APR_HAS_UNICODE_FS + IF_WIN_OS_IS_UNICODE + { +#ifndef _WIN32_WCE + hMap = OpenFileMappingW(FILE_MAP_READ | FILE_MAP_WRITE, FALSE, mapkey); +#else + /* The WCE 3.0 lacks OpenFileMapping. So we emulate one with + * opening the existing shmem and reading its size from the header + */ + hMap = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, + PAGE_READWRITE, 0, sizeof(apr_shm_t), mapkey); +#endif + } +#endif +#if APR_HAS_ANSI_FS + ELSE_WIN_OS_IS_ANSI + { + hMap = OpenFileMappingA(FILE_MAP_READ | FILE_MAP_WRITE, FALSE, mapkey); + } +#endif + + if (!hMap) { + return apr_get_os_error(); + } + + base = MapViewOfFile(hMap, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0); + if (!base) { + CloseHandle(hMap); + return apr_get_os_error(); + } + + *m = (apr_shm_t *) apr_palloc(pool, sizeof(apr_shm_t)); + (*m)->pool = pool; + (*m)->memblk = base; + /* Real (*m)->mem->size could be recovered with VirtualQuery */ + (*m)->size = (*m)->memblk->size; +#if _WIN32_WCE + /* Reopen with real size */ + UnmapViewOfFile(base); + CloseHandle(hMap); + + hMap = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, + PAGE_READWRITE, 0, (*m)->size, mapkey); + if (!hMap) { + return apr_get_os_error(); + } + base = MapViewOfFile(hMap, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0); + if (!base) { + CloseHandle(hMap); + return apr_get_os_error(); + } +#endif + (*m)->hMap = hMap; + (*m)->length = (*m)->memblk->length; + (*m)->usrmem = (char*)base + sizeof(memblock_t); + (*m)->filename = NULL; + + apr_pool_cleanup_register((*m)->pool, *m, + shm_cleanup, apr_pool_cleanup_null); + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_shm_attach_ex(apr_shm_t **m, + const char *file, + apr_pool_t *pool, + apr_int32_t flags) +{ + apr_status_t rv; + int can_create_global; + int try_global_local[3] = {-1, -1, -1}; + int cur; + + if (!file) { + return APR_EINVAL; + } + + if (flags & APR_SHM_NS_LOCAL) { + try_global_local[0] = 0; /* only search local */ + } + else if (flags & APR_SHM_NS_GLOBAL) { + try_global_local[0] = 1; /* only search global */ + } + else { + can_create_global = can_create_global_maps(); + if (!can_create_global) { /* unprivileged process */ + try_global_local[0] = 0; /* search local before global */ + try_global_local[1] = 1; + } + else { + try_global_local[0] = 1; /* search global before local */ + try_global_local[1] = 0; + } + } + + for (cur = 0; try_global_local[cur] != -1; cur++) { + rv = shm_attach_internal(m, file, pool, try_global_local[cur]); + if (!APR_STATUS_IS_ENOENT(rv)) { + break; + } + } + + return rv; +} + +APR_DECLARE(apr_status_t) apr_shm_attach(apr_shm_t **m, + const char *file, + apr_pool_t *pool) +{ + return apr_shm_attach_ex(m, file, pool, 0); +} + +APR_DECLARE(apr_status_t) apr_shm_detach(apr_shm_t *m) +{ + apr_status_t rv = shm_cleanup(m); + apr_pool_cleanup_kill(m->pool, m, shm_cleanup); + return rv; +} + +APR_DECLARE(void *) apr_shm_baseaddr_get(const apr_shm_t *m) +{ + return m->usrmem; +} + +APR_DECLARE(apr_size_t) apr_shm_size_get(const apr_shm_t *m) +{ + return m->length; +} + +APR_PERMS_SET_ENOTIMPL(shm) + +APR_POOL_IMPLEMENT_ACCESSOR(shm) + +APR_DECLARE(apr_status_t) apr_os_shm_get(apr_os_shm_t *osshm, + apr_shm_t *shm) +{ + *osshm = shm->hMap; + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_os_shm_put(apr_shm_t **m, + apr_os_shm_t *osshm, + apr_pool_t *pool) +{ + void* base; + base = MapViewOfFile(*osshm, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0); + if (!base) { + return apr_get_os_error(); + } + + *m = (apr_shm_t *) apr_palloc(pool, sizeof(apr_shm_t)); + (*m)->pool = pool; + (*m)->hMap = *osshm; + (*m)->memblk = base; + (*m)->usrmem = (char*)base + sizeof(memblock_t); + /* Real (*m)->mem->size could be recovered with VirtualQuery */ + (*m)->size = (*m)->memblk->size; + (*m)->length = (*m)->memblk->length; + (*m)->filename = NULL; + + apr_pool_cleanup_register((*m)->pool, *m, + shm_cleanup, apr_pool_cleanup_null); + return APR_SUCCESS; +} + diff --git a/strings/apr_cpystrn.c b/strings/apr_cpystrn.c new file mode 100644 index 00000000000..fb96025a00a --- /dev/null +++ b/strings/apr_cpystrn.c @@ -0,0 +1,315 @@ +/* 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_private.h" +#include "apr_lib.h" + +#if APR_HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#if APR_HAVE_STRING_H +#include <string.h> +#endif +#if APR_HAVE_CTYPE_H +#include <ctype.h> +#endif + +/* + * Apache's "replacement" for the strncpy() function. We roll our + * own to implement these specific changes: + * (1) strncpy() doesn't always null terminate and we want it to. + * (2) strncpy() null fills, which is bogus, esp. when copy 8byte + * strings into 8k blocks. + * (3) Instead of returning the pointer to the beginning of + * the destination string, we return a pointer to the + * terminating '\0' to allow us to "check" for truncation + * (4) If src is NULL, null terminate dst (empty string copy) + * + * apr_cpystrn() follows the same call structure as strncpy(). + */ + +APR_DECLARE(char *) apr_cpystrn(char *dst, const char *src, apr_size_t dst_size) +{ + + char *d = dst, *end; + + if (dst_size == 0) { + return (dst); + } + + if (src) { + end = dst + dst_size - 1; + + for (; d < end; ++d, ++src) { + if (!(*d = *src)) { + return (d); + } + } + } + + *d = '\0'; /* always null terminate */ + + return (d); +} + + +/* + * This function provides a way to parse a generic argument string + * into a standard argv[] form of argument list. It respects the + * usual "whitespace" and quoteing rules. In the future this could + * be expanded to include support for the apr_call_exec command line + * string processing (including converting '+' to ' ' and doing the + * url processing. It does not currently support this function. + * + * token_context: Context from which pool allocations will occur. + * arg_str: Input argument string for conversion to argv[]. + * argv_out: Output location. This is a pointer to an array + * of pointers to strings (ie. &(char *argv[]). + * This value will be allocated from the contexts + * pool and filled in with copies of the tokens + * found during parsing of the arg_str. + */ +APR_DECLARE(apr_status_t) apr_tokenize_to_argv(const char *arg_str, + char ***argv_out, + apr_pool_t *token_context) +{ + const char *cp; + const char *ct; + char *cleaned, *dirty; + int escaped; + int isquoted, numargs = 0, argnum; + +#define SKIP_WHITESPACE(cp) \ + for ( ; *cp == ' ' || *cp == '\t'; ) { \ + cp++; \ + }; + +#define CHECK_QUOTATION(cp,isquoted) \ + isquoted = 0; \ + if (*cp == '"') { \ + isquoted = 1; \ + cp++; \ + } \ + else if (*cp == '\'') { \ + isquoted = 2; \ + cp++; \ + } + +/* DETERMINE_NEXTSTRING: + * At exit, cp will point to one of the following: NULL, SPACE, TAB or QUOTE. + * NULL implies the argument string has been fully traversed. + */ +#define DETERMINE_NEXTSTRING(cp,isquoted) \ + for ( ; *cp != '\0'; cp++) { \ + if ( (*cp == '\\' && (*(cp+1) == ' ' || *(cp+1) == '\t' || \ + *(cp+1) == '"' || *(cp+1) == '\''))) { \ + cp++; \ + continue; \ + } \ + if ( (!isquoted && (*cp == ' ' || *cp == '\t')) \ + || (isquoted == 1 && *cp == '"') \ + || (isquoted == 2 && *cp == '\'') ) { \ + break; \ + } \ + } + +/* REMOVE_ESCAPE_CHARS: + * Compresses the arg string to remove all of the '\' escape chars. + * The final argv strings should not have any extra escape chars in it. + */ +#define REMOVE_ESCAPE_CHARS(cleaned, dirty, escaped) \ + escaped = 0; \ + while(*dirty) { \ + if (!escaped && *dirty == '\\') { \ + escaped = 1; \ + } \ + else { \ + escaped = 0; \ + *cleaned++ = *dirty; \ + } \ + ++dirty; \ + } \ + *cleaned = 0; /* last line of macro... */ + + cp = arg_str; + SKIP_WHITESPACE(cp); + ct = cp; + + /* This is ugly and expensive, but if anyone wants to figure a + * way to support any number of args without counting and + * allocating, please go ahead and change the code. + * + * Must account for the trailing NULL arg. + */ + numargs = 1; + while (*ct != '\0') { + CHECK_QUOTATION(ct, isquoted); + DETERMINE_NEXTSTRING(ct, isquoted); + if (*ct != '\0') { + ct++; + } + numargs++; + SKIP_WHITESPACE(ct); + } + *argv_out = apr_palloc(token_context, numargs * sizeof(char*)); + + /* determine first argument */ + for (argnum = 0; argnum < (numargs-1); argnum++) { + SKIP_WHITESPACE(cp); + CHECK_QUOTATION(cp, isquoted); + ct = cp; + DETERMINE_NEXTSTRING(cp, isquoted); + cp++; + (*argv_out)[argnum] = apr_palloc(token_context, cp - ct); + apr_cpystrn((*argv_out)[argnum], ct, cp - ct); + cleaned = dirty = (*argv_out)[argnum]; + REMOVE_ESCAPE_CHARS(cleaned, dirty, escaped); + } + (*argv_out)[argnum] = NULL; + + return APR_SUCCESS; +} + +/* Filepath_name_get returns the final element of the pathname. + * Using the current platform's filename syntax. + * "/foo/bar/gum" -> "gum" + * "/foo/bar/gum/" -> "" + * "gum" -> "gum" + * "wi\\n32\\stuff" -> "stuff + * + * Corrected Win32 to accept "a/b\\stuff", "a:stuff" + */ + +APR_DECLARE(const char *) apr_filepath_name_get(const char *pathname) +{ + const char path_separator = '/'; + const char *s = strrchr(pathname, path_separator); + +#ifdef WIN32 + const char path_separator_win = '\\'; + const char drive_separator_win = ':'; + const char *s2 = strrchr(pathname, path_separator_win); + + if (s2 > s) s = s2; + + if (!s) s = strrchr(pathname, drive_separator_win); +#endif + + return s ? ++s : pathname; +} + +/* length of dest assumed >= length of src + * collapse in place (src == dest) is legal. + * returns terminating null ptr to dest string. + */ +APR_DECLARE(char *) apr_collapse_spaces(char *dest, const char *src) +{ + while (*src) { + if (!apr_isspace(*src)) + *dest++ = *src; + ++src; + } + *dest = 0; + return (dest); +} + +#if !APR_HAVE_STRDUP +char *strdup(const char *str) +{ + char *sdup; + size_t len = strlen(str) + 1; + + sdup = (char *) malloc(len); + if (sdup == NULL) + return NULL; + memcpy(sdup, str, len); + + return sdup; +} +#endif + +/* The following two routines were donated for SVR4 by Andreas Vogel */ +#if (!APR_HAVE_STRCASECMP && !APR_HAVE_STRICMP) +int strcasecmp(const char *a, const char *b) +{ + const char *p = a; + const char *q = b; + for (p = a, q = b; *p && *q; p++, q++) { + int diff = apr_tolower(*p) - apr_tolower(*q); + if (diff) + return diff; + } + if (*p) + return 1; /* p was longer than q */ + if (*q) + return -1; /* p was shorter than q */ + return 0; /* Exact match */ +} + +#endif + +#if (!APR_HAVE_STRNCASECMP && !APR_HAVE_STRNICMP) +int strncasecmp(const char *a, const char *b, size_t n) +{ + const char *p = a; + const char *q = b; + + for (p = a, q = b; /*NOTHING */ ; p++, q++) { + int diff; + if (p == a + n) + return 0; /* Match up to n characters */ + if (!(*p && *q)) + return *p - *q; + diff = apr_tolower(*p) - apr_tolower(*q); + if (diff) + return diff; + } + /*NOTREACHED */ +} +#endif + +/* The following routine was donated for UTS21 by dwd@bell-labs.com */ +#if (!APR_HAVE_STRSTR) +char *strstr(char *s1, char *s2) +{ + char *p1, *p2; + if (*s2 == '\0') { + /* an empty s2 */ + return(s1); + } + while((s1 = strchr(s1, *s2)) != NULL) { + /* found first character of s2, see if the rest matches */ + p1 = s1; + p2 = s2; + while (*++p1 == *++p2) { + if (*p1 == '\0') { + /* both strings ended together */ + return(s1); + } + } + if (*p2 == '\0') { + /* second string ended, a match */ + break; + } + /* didn't find a match here, try starting at next character in s1 */ + s1++; + } + return(s1); +} +#endif + diff --git a/strings/apr_cstr.c b/strings/apr_cstr.c new file mode 100644 index 00000000000..7717c4406e7 --- /dev/null +++ b/strings/apr_cstr.c @@ -0,0 +1,408 @@ +/* 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_lib.h" +#include "apr_strings.h" +#include "apr_fnmatch.h" +#if 0 +#define APR_WANT_STDIO +#define APR_WANT_STRFUNC +#endif +#include "apr_want.h" +#include "apr_cstr.h" + +APR_DECLARE(void) apr_cstr_split_append(apr_array_header_t *array, + const char *input, + const char *sep_chars, + int chop_whitespace, + apr_pool_t *pool) +{ + char *pats; + char *p; + + pats = apr_pstrdup(pool, input); /* strtok wants non-const data */ + p = apr_cstr_tokenize(sep_chars, &pats); + + while (p) + { + if (chop_whitespace) + { + while (apr_isspace(*p)) + p++; + + { + char *e = p + (strlen(p) - 1); + while ((e >= p) && (apr_isspace(*e))) + e--; + *(++e) = '\0'; + } + } + + if (p[0] != '\0') + APR_ARRAY_PUSH(array, const char *) = p; + + p = apr_cstr_tokenize(sep_chars, &pats); + } + + return; +} + + +APR_DECLARE(apr_array_header_t *) apr_cstr_split(const char *input, + const char *sep_chars, + int chop_whitespace, + apr_pool_t *pool) +{ + apr_array_header_t *a = apr_array_make(pool, 5, sizeof(input)); + apr_cstr_split_append(a, input, sep_chars, chop_whitespace, pool); + return a; +} + + +APR_DECLARE(int) apr_cstr_match_glob_list(const char *str, + const apr_array_header_t *list) +{ + int i; + + for (i = 0; i < list->nelts; i++) + { + const char *this_pattern = APR_ARRAY_IDX(list, i, char *); + + if (apr_fnmatch(this_pattern, str, 0) == APR_SUCCESS) + return TRUE; + } + + return FALSE; +} + +APR_DECLARE(int) apr_cstr_match_list(const char *str, + const apr_array_header_t *list) +{ + int i; + + for (i = 0; i < list->nelts; i++) + { + const char *this_str = APR_ARRAY_IDX(list, i, char *); + + if (strcmp(this_str, str) == 0) + return TRUE; + } + + return FALSE; +} + +APR_DECLARE(char *) apr_cstr_tokenize(const char *sep, char **str) +{ + char *token; + char *next; + char csep; + + /* check parameters */ + if ((sep == NULL) || (str == NULL) || (*str == NULL)) + return NULL; + + /* let APR handle edge cases and multiple separators */ + csep = *sep; + if (csep == '\0' || sep[1] != '\0') + return apr_strtok(NULL, sep, str); + + /* skip characters in sep (will terminate at '\0') */ + token = *str; + while (*token == csep) + ++token; + + if (!*token) /* no more tokens */ + return NULL; + + /* skip valid token characters to terminate token and + * prepare for the next call (will terminate at '\0) + */ + next = strchr(token, csep); + if (next == NULL) + { + *str = token + strlen(token); + } + else + { + *next = '\0'; + *str = next + 1; + } + + return token; +} + +APR_DECLARE(int) apr_cstr_count_newlines(const char *msg) +{ + int count = 0; + const char *p; + + for (p = msg; *p; p++) + { + if (*p == '\n') + { + count++; + if (*(p + 1) == '\r') + p++; + } + else if (*p == '\r') + { + count++; + if (*(p + 1) == '\n') + p++; + } + } + + return count; +} + +#if 0 /* XXX: stringbuf logic is not present in APR */ +APR_DECLARE(char *) apr_cstr_join(const apr_array_header_t *strings, + const char *separator, + apr_pool_t *pool) +{ + svn_stringbuf_t *new_str = svn_stringbuf_create_empty(pool); + size_t sep_len = strlen(separator); + int i; + + for (i = 0; i < strings->nelts; i++) + { + const char *string = APR_ARRAY_IDX(strings, i, const char *); + svn_stringbuf_appendbytes(new_str, string, strlen(string)); + svn_stringbuf_appendbytes(new_str, separator, sep_len); + } + return new_str->data; +} +#endif + +#if !APR_CHARSET_EBCDIC +/* + * Our own known-fast translation table for casecmp by character. + * Only ASCII alpha characters 41-5A are folded to 61-7A, other + * octets (such as extended latin alphabetics) are never case-folded. + * NOTE: Other than Alpha A-Z/a-z, each code point is unique! + */ +static const short ucharmap[] = { + 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, + 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x40, 'a', 'b', 'c', 'd', 'e', 'f', 'g', + 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', + 'x', 'y', 'z', 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, + 0x60, 'a', 'b', 'c', 'd', 'e', 'f', 'g', + 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', + 'x', 'y', 'z', 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, + 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, + 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff +}; +#else /* APR_CHARSET_EBCDIC */ +/* + * Derived from apr-iconv/ccs/cp037.c for EBCDIC case comparison, + * provides unique identity of every char value (strict ISO-646 + * conformance, arbitrary election of an ISO-8859-1 ordering, and + * very arbitrary control code assignments into C1 to achieve + * identity and a reversible mapping of code points), + * then folding the equivalences of ASCII 41-5A into 61-7A, + * presenting comparison results in a somewhat ISO/IEC 10646 + * (ASCII-like) order, depending on the EBCDIC code page in use. + * + * NOTE: Other than Alpha A-Z/a-z, each code point is unique! + */ +static const short ucharmap[] = { + 0x00, 0x01, 0x02, 0x03, 0x9C, 0x09, 0x86, 0x7F, + 0x97, 0x8D, 0x8E, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x9D, 0x85, 0x08, 0x87, + 0x18, 0x19, 0x92, 0x8F, 0x1C, 0x1D, 0x1E, 0x1F, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x0A, 0x17, 0x1B, + 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x05, 0x06, 0x07, + 0x90, 0x91, 0x16, 0x93, 0x94, 0x95, 0x96, 0x04, + 0x98, 0x99, 0x9A, 0x9B, 0x14, 0x15, 0x9E, 0x1A, + 0x20, 0xA0, 0xE2, 0xE4, 0xE0, 0xE1, 0xE3, 0xE5, + 0xE7, 0xF1, 0xA2, 0x2E, 0x3C, 0x28, 0x2B, 0x7C, + 0x26, 0xE9, 0xEA, 0xEB, 0xE8, 0xED, 0xEE, 0xEF, + 0xEC, 0xDF, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0xAC, + 0x2D, 0x2F, 0xC2, 0xC4, 0xC0, 0xC1, 0xC3, 0xC5, + 0xC7, 0xD1, 0xA6, 0x2C, 0x25, 0x5F, 0x3E, 0x3F, + 0xF8, 0xC9, 0xCA, 0xCB, 0xC8, 0xCD, 0xCE, 0xCF, + 0xCC, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22, + 0xD8, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0xAB, 0xBB, 0xF0, 0xFD, 0xFE, 0xB1, + 0xB0, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, + 0x71, 0x72, 0xAA, 0xBA, 0xE6, 0xB8, 0xC6, 0xA4, + 0xB5, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, + 0x79, 0x7A, 0xA1, 0xBF, 0xD0, 0xDD, 0xDE, 0xAE, + 0x5E, 0xA3, 0xA5, 0xB7, 0xA9, 0xA7, 0xB6, 0xBC, + 0xBD, 0xBE, 0x5B, 0x5D, 0xAF, 0xA8, 0xB4, 0xD7, + 0x7B, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0xAD, 0xF4, 0xF6, 0xF2, 0xF3, 0xF5, + 0x7D, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, + 0x71, 0x72, 0xB9, 0xFB, 0xFC, 0xF9, 0xFA, 0xFF, + 0x5C, 0xF7, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, + 0x79, 0x7A, 0xB2, 0xD4, 0xD6, 0xD2, 0xD3, 0xD5, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0xB3, 0xDB, 0xDC, 0xD9, 0xDA, 0x9F +}; +#endif + +APR_DECLARE(int) apr_cstr_casecmp(const char *s1, const char *s2) +{ + const unsigned char *str1 = (const unsigned char *)s1; + const unsigned char *str2 = (const unsigned char *)s2; + for (;;) + { + const int c1 = (int)(*str1); + const int c2 = (int)(*str2); + const int cmp = ucharmap[c1] - ucharmap[c2]; + /* Not necessary to test for !c2, this is caught by cmp */ + if (cmp || !c1) + return cmp; + str1++; + str2++; + } +} + +APR_DECLARE(int) apr_cstr_casecmpn(const char *s1, const char *s2, + apr_size_t n) +{ + const unsigned char *str1 = (const unsigned char *)s1; + const unsigned char *str2 = (const unsigned char *)s2; + while (n--) + { + const int c1 = (int)(*str1); + const int c2 = (int)(*str2); + const int cmp = ucharmap[c1] - ucharmap[c2]; + /* Not necessary to test for !c2, this is caught by cmp */ + if (cmp || !c1) + return cmp; + str1++; + str2++; + } + return 0; +} + +APR_DECLARE(apr_status_t) apr_cstr_strtoui64(apr_uint64_t *n, + const char *str, + apr_uint64_t minval, + apr_uint64_t maxval, + int base) +{ + apr_int64_t val; + char *endptr; + + /* We assume errno is thread-safe. */ + errno = 0; /* APR-0.9 doesn't always set errno */ + + /* ### We're throwing away half the number range here. + * ### APR needs a apr_strtoui64() function. */ + val = apr_strtoi64(str, &endptr, base); + if (errno == EINVAL || endptr == str || str[0] == '\0' || *endptr != '\0') + return APR_EINVAL; + if ((errno == ERANGE && (val == APR_INT64_MIN || val == APR_INT64_MAX)) || + val < 0 || (apr_uint64_t)val < minval || (apr_uint64_t)val > maxval) + return APR_ERANGE; + *n = val; + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_cstr_atoui64(apr_uint64_t *n, const char *str) +{ + return apr_cstr_strtoui64(n, str, 0, APR_UINT64_MAX, 10); +} + +APR_DECLARE(apr_status_t) apr_cstr_atoui(unsigned int *n, const char *str) +{ + apr_uint64_t val; + apr_status_t rv = apr_cstr_strtoui64(&val, str, 0, APR_UINT32_MAX, 10); + if (rv == APR_SUCCESS) + *n = (unsigned int)val; + return rv; +} + +APR_DECLARE(apr_status_t) apr_cstr_strtoi64(apr_int64_t *n, + const char *str, + apr_int64_t minval, + apr_int64_t maxval, + int base) +{ + apr_int64_t val; + char *endptr; + + /* We assume errno is thread-safe. */ + errno = 0; /* APR-0.9 doesn't always set errno */ + + val = apr_strtoi64(str, &endptr, base); + if (errno == EINVAL || endptr == str || str[0] == '\0' || *endptr != '\0') + return APR_EINVAL; + if ((errno == ERANGE && (val == APR_INT64_MIN || val == APR_INT64_MAX)) || + val < minval || val > maxval) + return APR_ERANGE; + *n = val; + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_cstr_atoi64(apr_int64_t *n, const char *str) +{ + return apr_cstr_strtoi64(n, str, APR_INT64_MIN, APR_INT64_MAX, 10); +} + +APR_DECLARE(apr_status_t) apr_cstr_atoi(int *n, const char *str) +{ + apr_int64_t val; + apr_status_t rv; + + rv = apr_cstr_strtoi64(&val, str, APR_INT32_MIN, APR_INT32_MAX, 10); + if (rv == APR_SUCCESS) + *n = (int)val; + return rv; +} + +APR_DECLARE(const char *) +apr_cstr_skip_prefix(const char *str, const char *prefix) +{ + apr_size_t len = strlen(prefix); + + if (strncmp(str, prefix, len) == 0) + { + return str + len; + } + else + { + return NULL; + } +} diff --git a/strings/apr_fnmatch.c b/strings/apr_fnmatch.c new file mode 100644 index 00000000000..7dfa846993b --- /dev/null +++ b/strings/apr_fnmatch.c @@ -0,0 +1,482 @@ +/* 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. + */ + + +/* Derived from The Open Group Base Specifications Issue 7, IEEE Std 1003.1-2008 + * as described in; + * http://pubs.opengroup.org/onlinepubs/9699919799/functions/fnmatch.html + * + * Filename pattern matches defined in section 2.13, "Pattern Matching Notation" + * from chapter 2. "Shell Command Language" + * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_13 + * where; 1. A bracket expression starting with an unquoted <circumflex> '^' + * character CONTINUES to specify a non-matching list; 2. an explicit <period> '.' + * in a bracket expression matching list, e.g. "[.abc]" does NOT match a leading + * <period> in a filename; 3. a <left-square-bracket> '[' which does not introduce + * a valid bracket expression is treated as an ordinary character; 4. a differing + * number of consecutive slashes within pattern and string will NOT match; + * 5. a trailing '\' in FNM_ESCAPE mode is treated as an ordinary '\' character. + * + * Bracket expansion defined in section 9.3.5, "RE Bracket Expression", + * from chapter 9, "Regular Expressions" + * http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap09.html#tag_09_03_05 + * with no support for collating symbols, equivalence class expressions or + * character class expressions. A partial range expression with a leading + * hyphen following a valid range expression will match only the ordinary + * <hyphen> and the ending character (e.g. "[a-m-z]" will match characters + * 'a' through 'm', a <hyphen> '-', or a 'z'). + * + * NOTE: Only POSIX/C single byte locales are correctly supported at this time. + * Notably, non-POSIX locales with FNM_CASEFOLD produce undefined results, + * particularly in ranges of mixed case (e.g. "[A-z]") or spanning alpha and + * nonalpha characters within a range. + * + * XXX comments below indicate porting required for multi-byte character sets + * and non-POSIX locale collation orders; requires mbr* APIs to track shift + * state of pattern and string (rewinding pattern and string repeatedly). + * + * Certain parts of the code assume 0x00-0x3F are unique with any MBCS (e.g. + * UTF-8, SHIFT-JIS, etc). Any implementation allowing '\' as an alternate + * path delimiter must be aware that 0x5C is NOT unique within SHIFT-JIS. + */ + +#include "apr_file_info.h" +#include "apr_fnmatch.h" +#include "apr_tables.h" +#include "apr_lib.h" +#include "apr_strings.h" +#include <string.h> +#if APR_HAVE_CTYPE_H +# include <ctype.h> +#endif + + +/* Most MBCS/collation/case issues handled here. Wildcard '*' is not handled. + * EOS '\0' and the FNM_PATHNAME '/' delimiters are not advanced over, + * however the "\/" sequence is advanced to '/'. + * + * Both pattern and string are **char to support pointer increment of arbitrary + * multibyte characters for the given locale, in a later iteration of this code + */ +static APR_INLINE int fnmatch_ch(const char **pattern, const char **string, int flags) +{ + const char * const mismatch = *pattern; + const int nocase = !!(flags & APR_FNM_CASE_BLIND); + const int escape = !(flags & APR_FNM_NOESCAPE); + const int slash = !!(flags & APR_FNM_PATHNAME); + int result = APR_FNM_NOMATCH; + const char *startch; + int negate; + + if (**pattern == '[') + { + ++*pattern; + + /* Handle negation, either leading ! or ^ operators (never both) */ + negate = ((**pattern == '!') || (**pattern == '^')); + if (negate) + ++*pattern; + + /* ']' is an ordinary character at the start of the range pattern */ + if (**pattern == ']') + goto leadingclosebrace; + + while (**pattern) + { + if (**pattern == ']') { + ++*pattern; + /* XXX: Fix for MBCS character width */ + ++*string; + return (result ^ negate); + } + + if (escape && (**pattern == '\\')) { + ++*pattern; + + /* Patterns must be terminated with ']', not EOS */ + if (!**pattern) + break; + } + + /* Patterns must be terminated with ']' not '/' */ + if (slash && (**pattern == '/')) + break; + +leadingclosebrace: + /* Look at only well-formed range patterns; + * "x-]" is not allowed unless escaped ("x-\]") + * XXX: Fix for locale/MBCS character width + */ + if (((*pattern)[1] == '-') && ((*pattern)[2] != ']')) + { + startch = *pattern; + *pattern += (escape && ((*pattern)[2] == '\\')) ? 3 : 2; + + /* NOT a properly balanced [expr] pattern, EOS terminated + * or ranges containing a slash in FNM_PATHNAME mode pattern + * fall out to to the rewind and test '[' literal code path + */ + if (!**pattern || (slash && (**pattern == '/'))) + break; + + /* XXX: handle locale/MBCS comparison, advance by MBCS char width */ + if ((**string >= *startch) && (**string <= **pattern)) + result = 0; + else if (nocase && (isupper(**string) || isupper(*startch) + || isupper(**pattern)) + && (tolower(**string) >= tolower(*startch)) + && (tolower(**string) <= tolower(**pattern))) + result = 0; + + ++*pattern; + continue; + } + + /* XXX: handle locale/MBCS comparison, advance by MBCS char width */ + if ((**string == **pattern)) + result = 0; + else if (nocase && (isupper(**string) || isupper(**pattern)) + && (tolower(**string) == tolower(**pattern))) + result = 0; + + ++*pattern; + } + + /* NOT a properly balanced [expr] pattern; Rewind + * and reset result to test '[' literal + */ + *pattern = mismatch; + result = APR_FNM_NOMATCH; + } + else if (**pattern == '?') { + /* Optimize '?' match before unescaping **pattern */ + if (!**string || (slash && (**string == '/'))) + return APR_FNM_NOMATCH; + result = 0; + goto fnmatch_ch_success; + } + else if (escape && (**pattern == '\\') && (*pattern)[1]) { + ++*pattern; + } + + /* XXX: handle locale/MBCS comparison, advance by the MBCS char width */ + if (**string == **pattern) + result = 0; + else if (nocase && (isupper(**string) || isupper(**pattern)) + && (tolower(**string) == tolower(**pattern))) + result = 0; + + /* Refuse to advance over trailing slash or nulls + */ + if (!**string || !**pattern || (slash && ((**string == '/') || (**pattern == '/')))) + return result; + +fnmatch_ch_success: + ++*pattern; + ++*string; + return result; +} + + +APR_DECLARE(int) apr_fnmatch(const char *pattern, const char *string, int flags) +{ + static const char dummystring[2] = {' ', 0}; + const int escape = !(flags & APR_FNM_NOESCAPE); + const int slash = !!(flags & APR_FNM_PATHNAME); + const char *strendseg; + const char *dummyptr; + const char *matchptr; + int wild; + /* For '*' wild processing only; surpress 'used before initialization' + * warnings with dummy initialization values; + */ + const char *strstartseg = NULL; + const char *mismatch = NULL; + int matchlen = 0; + + if (*pattern == '*') + goto firstsegment; + + while (*pattern && *string) + { + /* Pre-decode "\/" which has no special significance, and + * match balanced slashes, starting a new segment pattern + */ + if (slash && escape && (*pattern == '\\') && (pattern[1] == '/')) + ++pattern; + if (slash && (*pattern == '/') && (*string == '/')) { + ++pattern; + ++string; + } + +firstsegment: + /* At the beginning of each segment, validate leading period behavior. + */ + if ((flags & APR_FNM_PERIOD) && (*string == '.')) + { + if (*pattern == '.') + ++pattern; + else if (escape && (*pattern == '\\') && (pattern[1] == '.')) + pattern += 2; + else + return APR_FNM_NOMATCH; + ++string; + } + + /* Determine the end of string segment + * + * Presumes '/' character is unique, not composite in any MBCS encoding + */ + if (slash) { + strendseg = strchr(string, '/'); + if (!strendseg) + strendseg = strchr(string, '\0'); + } + else { + strendseg = strchr(string, '\0'); + } + + /* Allow pattern '*' to be consumed even with no remaining string to match + */ + while (*pattern) + { + if ((string > strendseg) + || ((string == strendseg) && (*pattern != '*'))) + break; + + if (slash && ((*pattern == '/') + || (escape && (*pattern == '\\') + && (pattern[1] == '/')))) + break; + + /* Reduce groups of '*' and '?' to n '?' matches + * followed by one '*' test for simplicity + */ + for (wild = 0; ((*pattern == '*') || (*pattern == '?')); ++pattern) + { + if (*pattern == '*') { + wild = 1; + } + else if (string < strendseg) { /* && (*pattern == '?') */ + /* XXX: Advance 1 char for MBCS locale */ + ++string; + } + else { /* (string >= strendseg) && (*pattern == '?') */ + return APR_FNM_NOMATCH; + } + } + + if (wild) + { + strstartseg = string; + mismatch = pattern; + + /* Count fixed (non '*') char matches remaining in pattern + * excluding '/' (or "\/") and '*' + */ + for (matchptr = pattern, matchlen = 0; 1; ++matchlen) + { + if ((*matchptr == '\0') + || (slash && ((*matchptr == '/') + || (escape && (*matchptr == '\\') + && (matchptr[1] == '/'))))) + { + /* Compare precisely this many trailing string chars, + * the resulting match needs no wildcard loop + */ + /* XXX: Adjust for MBCS */ + if (string + matchlen > strendseg) + return APR_FNM_NOMATCH; + + string = strendseg - matchlen; + wild = 0; + break; + } + + if (*matchptr == '*') + { + /* Ensure at least this many trailing string chars remain + * for the first comparison + */ + /* XXX: Adjust for MBCS */ + if (string + matchlen > strendseg) + return APR_FNM_NOMATCH; + + /* Begin first wild comparison at the current position */ + break; + } + + /* Skip forward in pattern by a single character match + * Use a dummy fnmatch_ch() test to count one "[range]" escape + */ + /* XXX: Adjust for MBCS */ + if (escape && (*matchptr == '\\') && matchptr[1]) { + matchptr += 2; + } + else if (*matchptr == '[') { + dummyptr = dummystring; + fnmatch_ch(&matchptr, &dummyptr, flags); + } + else { + ++matchptr; + } + } + } + + /* Incrementally match string against the pattern + */ + while (*pattern && (string < strendseg)) + { + /* Success; begin a new wild pattern search + */ + if (*pattern == '*') + break; + + if (slash && ((*string == '/') + || (*pattern == '/') + || (escape && (*pattern == '\\') + && (pattern[1] == '/')))) + break; + + /* Compare ch's (the pattern is advanced over "\/" to the '/', + * but slashes will mismatch, and are not consumed) + */ + if (!fnmatch_ch(&pattern, &string, flags)) + continue; + + /* Failed to match, loop against next char offset of string segment + * until not enough string chars remain to match the fixed pattern + */ + if (wild) { + /* XXX: Advance 1 char for MBCS locale */ + string = ++strstartseg; + if (string + matchlen > strendseg) + return APR_FNM_NOMATCH; + + pattern = mismatch; + continue; + } + else + return APR_FNM_NOMATCH; + } + } + + if (*string && !(slash && (*string == '/'))) + return APR_FNM_NOMATCH; + + if (*pattern && !(slash && ((*pattern == '/') + || (escape && (*pattern == '\\') + && (pattern[1] == '/'))))) + return APR_FNM_NOMATCH; + } + + /* Where both pattern and string are at EOS, declare success + */ + if (!*string && !*pattern) + return 0; + + /* pattern didn't match to the end of string */ + return APR_FNM_NOMATCH; +} + + +/* This function is an Apache addition + * return non-zero if pattern has any glob chars in it + * @bug Function does not distinguish for FNM_PATHNAME mode, which renders + * a false positive for test[/]this (which is not a range, but + * seperate test[ and ]this segments and no glob.) + * @bug Function does not distinguish for non-FNM_ESCAPE mode. + * @bug Function does not parse []] correctly + * Solution may be to use fnmatch_ch() to walk the patterns? + */ +APR_DECLARE(int) apr_fnmatch_test(const char *pattern) +{ + int nesting; + + nesting = 0; + while (*pattern) { + switch (*pattern) { + case '?': + case '*': + return 1; + + case '\\': + if (*++pattern == '\0') { + return 0; + } + break; + + case '[': /* '[' is only a glob if it has a matching ']' */ + ++nesting; + break; + + case ']': + if (nesting) { + return 1; + } + break; + } + ++pattern; } + return 0; +} + + +/* Find all files matching the specified pattern */ +APR_DECLARE(apr_status_t) apr_match_glob(const char *pattern, + apr_array_header_t **result, + apr_pool_t *p) +{ + apr_dir_t *dir; + apr_finfo_t finfo; + apr_status_t rv; + char *path; + + /* XXX So, this is kind of bogus. Basically, I need to strip any leading + * directories off the pattern, but there is no portable way to do that. + * So, for now we just find the last occurance of '/' and if that doesn't + * return anything, then we look for '\'. This means that we could + * screw up on unix if the pattern is something like "foo\.*" That '\' + * isn't a directory delimiter, it is a part of the filename. To fix this, + * we really need apr_filepath_basename, which will be coming as soon as + * I get to it. rbb + */ + char *idx = strrchr(pattern, '/'); + + if (idx == NULL) { + idx = strrchr(pattern, '\\'); + } + if (idx == NULL) { + path = "."; + } + else { + path = apr_pstrmemdup(p, pattern, idx - pattern); + pattern = idx + 1; + } + + *result = apr_array_make(p, 0, sizeof(char *)); + rv = apr_dir_open(&dir, path, p); + if (rv != APR_SUCCESS) { + return rv; + } + + while (apr_dir_read(&finfo, APR_FINFO_NAME, dir) == APR_SUCCESS) { + if (apr_fnmatch(pattern, finfo.name, 0) == APR_SUCCESS) { + *(const char **)apr_array_push(*result) = apr_pstrdup(p, finfo.name); + } + } + apr_dir_close(dir); + return APR_SUCCESS; +} diff --git a/strings/apr_snprintf.c b/strings/apr_snprintf.c new file mode 100644 index 00000000000..4acbe2fa5b0 --- /dev/null +++ b/strings/apr_snprintf.c @@ -0,0 +1,1407 @@ +/* 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_lib.h" +#include "apr_strings.h" +#include "apr_network_io.h" +#include "apr_portable.h" +#include "apr_errno.h" +#include <math.h> +#if APR_HAVE_CTYPE_H +#include <ctype.h> +#endif +#if APR_HAVE_NETINET_IN_H +#include <netinet/in.h> +#endif +#if APR_HAVE_SYS_SOCKET_H +#include <sys/socket.h> +#endif +#if APR_HAVE_ARPA_INET_H +#include <arpa/inet.h> +#endif +#if APR_HAVE_LIMITS_H +#include <limits.h> +#endif +#if APR_HAVE_STRING_H +#include <string.h> +#endif + +typedef enum { + NO = 0, YES = 1 +} boolean_e; + +#ifndef FALSE +#define FALSE 0 +#endif +#ifndef TRUE +#define TRUE 1 +#endif +#define NUL '\0' + +static const char null_string[] = "(null)"; +#define S_NULL ((char *)null_string) +#define S_NULL_LEN 6 + +#define FLOAT_DIGITS 6 +#define EXPONENT_LENGTH 10 + +/* + * NUM_BUF_SIZE is the size of the buffer used for arithmetic conversions + * + * NOTICE: this is a magic number; do not decrease it + */ +#define NUM_BUF_SIZE 512 + +/* + * cvt - IEEE floating point formatting routines. + * Derived from UNIX V7, Copyright(C) Caldera International Inc. + */ + +/* + * apr_ecvt converts to decimal + * the number of digits is specified by ndigit + * decpt is set to the position of the decimal point + * sign is set to 0 for positive, 1 for negative + */ + +#define NDIG 80 + +/* buf must have at least NDIG bytes */ +static char *apr_cvt(double arg, int ndigits, int *decpt, int *sign, + int eflag, char *buf) +{ + register int r2; + double fi, fj; + register char *p, *p1; + + if (ndigits >= NDIG - 1) + ndigits = NDIG - 2; + r2 = 0; + *sign = 0; + p = &buf[0]; + if (arg < 0) { + *sign = 1; + arg = -arg; + } + arg = modf(arg, &fi); + /* + * Do integer part + */ + if (fi != 0) { + p1 = &buf[NDIG]; + while (p1 > &buf[0] && fi != 0) { + fj = modf(fi / 10, &fi); + *--p1 = (int) ((fj + .03) * 10) + '0'; + r2++; + } + while (p1 < &buf[NDIG]) + *p++ = *p1++; + } + else if (arg > 0) { + while ((fj = arg * 10) < 1) { + arg = fj; + r2--; + } + } + p1 = &buf[ndigits]; + if (eflag == 0) + p1 += r2; + if (p1 < &buf[0]) { + *decpt = -ndigits; + buf[0] = '\0'; + return (buf); + } + *decpt = r2; + while (p <= p1 && p < &buf[NDIG]) { + arg *= 10; + arg = modf(arg, &fj); + *p++ = (int) fj + '0'; + } + if (p1 >= &buf[NDIG]) { + buf[NDIG - 1] = '\0'; + return (buf); + } + p = p1; + *p1 += 5; + while (*p1 > '9') { + *p1 = '0'; + if (p1 > buf) + ++ * --p1; + else { + *p1 = '1'; + (*decpt)++; + if (eflag == 0) { + if (p > buf) + *p = '0'; + p++; + } + } + } + *p = '\0'; + return (buf); +} + +static char *apr_ecvt(double arg, int ndigits, int *decpt, int *sign, char *buf) +{ + return (apr_cvt(arg, ndigits, decpt, sign, 1, buf)); +} + +static char *apr_fcvt(double arg, int ndigits, int *decpt, int *sign, char *buf) +{ + return (apr_cvt(arg, ndigits, decpt, sign, 0, buf)); +} + +/* + * apr_gcvt - Floating output conversion to + * minimal length string + */ + +static char *apr_gcvt(double number, int ndigit, char *buf, boolean_e altform) +{ + int sign, decpt; + register char *p1, *p2; + register int i; + char buf1[NDIG]; + + p1 = apr_ecvt(number, ndigit, &decpt, &sign, buf1); + p2 = buf; + if (sign) + *p2++ = '-'; + for (i = ndigit - 1; i > 0 && p1[i] == '0'; i--) + ndigit--; + if ((decpt >= 0 && decpt - ndigit > 4) + || (decpt < 0 && decpt < -3)) { /* use E-style */ + decpt--; + *p2++ = *p1++; + *p2++ = '.'; + for (i = 1; i < ndigit; i++) + *p2++ = *p1++; + *p2++ = 'e'; + if (decpt < 0) { + decpt = -decpt; + *p2++ = '-'; + } + else + *p2++ = '+'; + if (decpt / 100 > 0) + *p2++ = decpt / 100 + '0'; + if (decpt / 10 > 0) + *p2++ = (decpt % 100) / 10 + '0'; + *p2++ = decpt % 10 + '0'; + } + else { + if (decpt <= 0) { + if (*p1 != '0') + *p2++ = '.'; + while (decpt < 0) { + decpt++; + *p2++ = '0'; + } + } + for (i = 1; i <= ndigit; i++) { + *p2++ = *p1++; + if (i == decpt) + *p2++ = '.'; + } + if (ndigit < decpt) { + while (ndigit++ < decpt) + *p2++ = '0'; + *p2++ = '.'; + } + } + if (p2[-1] == '.' && !altform) + p2--; + *p2 = '\0'; + return (buf); +} + +/* + * The INS_CHAR macro inserts a character in the buffer and writes + * the buffer back to disk if necessary + * It uses the char pointers sp and bep: + * sp points to the next available character in the buffer + * bep points to the end-of-buffer+1 + * While using this macro, note that the nextb pointer is NOT updated. + * + * NOTE: Evaluation of the c argument should not have any side-effects + */ +#define INS_CHAR(c, sp, bep, cc) \ +{ \ + if (sp) { \ + if (sp >= bep) { \ + vbuff->curpos = sp; \ + if (flush_func(vbuff)) \ + return -1; \ + sp = vbuff->curpos; \ + bep = vbuff->endpos; \ + } \ + *sp++ = (c); \ + } \ + cc++; \ +} + +#define NUM(c) (c - '0') + +#define STR_TO_DEC(str, num) \ + num = NUM(*str++); \ + while (apr_isdigit(*str)) \ + { \ + num *= 10 ; \ + num += NUM(*str++); \ + } + +/* + * This macro does zero padding so that the precision + * requirement is satisfied. The padding is done by + * adding '0's to the left of the string that is going + * to be printed. We don't allow precision to be large + * enough that we continue past the start of s. + * + * NOTE: this makes use of the magic info that s is + * always based on num_buf with a size of NUM_BUF_SIZE. + */ +#define FIX_PRECISION(adjust, precision, s, s_len) \ + if (adjust) { \ + apr_size_t p = (precision + 1 < NUM_BUF_SIZE) \ + ? precision : NUM_BUF_SIZE - 1; \ + while (s_len < p) \ + { \ + *--s = '0'; \ + s_len++; \ + } \ + } + +/* + * Macro that does padding. The padding is done by printing + * the character ch. + */ +#define PAD(width, len, ch) \ +do \ +{ \ + INS_CHAR(ch, sp, bep, cc); \ + width--; \ +} \ +while (width > len) + +/* + * Prefix the character ch to the string str + * Increase length + * Set the has_prefix flag + */ +#define PREFIX(str, length, ch) \ + *--str = ch; \ + length++; \ + has_prefix=YES; + + +/* + * Convert num to its decimal format. + * Return value: + * - a pointer to a string containing the number (no sign) + * - len contains the length of the string + * - is_negative is set to TRUE or FALSE depending on the sign + * of the number (always set to FALSE if is_unsigned is TRUE) + * + * The caller provides a buffer for the string: that is the buf_end argument + * which is a pointer to the END of the buffer + 1 (i.e. if the buffer + * is declared as buf[ 100 ], buf_end should be &buf[ 100 ]) + * + * Note: we have 2 versions. One is used when we need to use quads + * (conv_10_quad), the other when we don't (conv_10). We're assuming the + * latter is faster. + */ +static char *conv_10(register apr_int32_t num, register int is_unsigned, + register int *is_negative, char *buf_end, + register apr_size_t *len) +{ + register char *p = buf_end; + register apr_uint32_t magnitude = num; + + if (is_unsigned) { + *is_negative = FALSE; + } + else { + *is_negative = (num < 0); + + /* + * On a 2's complement machine, negating the most negative integer + * results in a number that cannot be represented as a signed integer. + * Here is what we do to obtain the number's magnitude: + * a. add 1 to the number + * b. negate it (becomes positive) + * c. convert it to unsigned + * d. add 1 + */ + if (*is_negative) { + apr_int32_t t = num + 1; + magnitude = ((apr_uint32_t) -t) + 1; + } + } + + /* + * We use a do-while loop so that we write at least 1 digit + */ + do { + register apr_uint32_t new_magnitude = magnitude / 10; + + *--p = (char) (magnitude - new_magnitude * 10 + '0'); + magnitude = new_magnitude; + } + while (magnitude); + + *len = buf_end - p; + return (p); +} + +static char *conv_10_quad(apr_int64_t num, register int is_unsigned, + register int *is_negative, char *buf_end, + register apr_size_t *len) +{ + register char *p = buf_end; + apr_uint64_t magnitude = num; + + /* + * We see if we can use the faster non-quad version by checking the + * number against the largest long value it can be. If <=, we + * punt to the quicker version. + */ + if ((magnitude <= APR_UINT32_MAX && is_unsigned) + || (num <= APR_INT32_MAX && num >= APR_INT32_MIN && !is_unsigned)) + return(conv_10((apr_int32_t)num, is_unsigned, is_negative, buf_end, len)); + + if (is_unsigned) { + *is_negative = FALSE; + } + else { + *is_negative = (num < 0); + + /* + * On a 2's complement machine, negating the most negative integer + * results in a number that cannot be represented as a signed integer. + * Here is what we do to obtain the number's magnitude: + * a. add 1 to the number + * b. negate it (becomes positive) + * c. convert it to unsigned + * d. add 1 + */ + if (*is_negative) { + apr_int64_t t = num + 1; + magnitude = ((apr_uint64_t) -t) + 1; + } + } + + /* + * We use a do-while loop so that we write at least 1 digit + */ + do { + apr_uint64_t new_magnitude = magnitude / 10; + + *--p = (char) (magnitude - new_magnitude * 10 + '0'); + magnitude = new_magnitude; + } + while (magnitude); + + *len = buf_end - p; + return (p); +} + +static char *conv_in_addr(struct in_addr *ia, char *buf_end, apr_size_t *len) +{ + unsigned addr = ntohl(ia->s_addr); + char *p = buf_end; + int is_negative; + apr_size_t sub_len; + + p = conv_10((addr & 0x000000FF) , TRUE, &is_negative, p, &sub_len); + *--p = '.'; + p = conv_10((addr & 0x0000FF00) >> 8, TRUE, &is_negative, p, &sub_len); + *--p = '.'; + p = conv_10((addr & 0x00FF0000) >> 16, TRUE, &is_negative, p, &sub_len); + *--p = '.'; + p = conv_10((addr & 0xFF000000) >> 24, TRUE, &is_negative, p, &sub_len); + + *len = buf_end - p; + return (p); +} + + +/* Must be passed a buffer of size NUM_BUF_SIZE where buf_end points + * to 1 byte past the end of the buffer. */ +static char *conv_apr_sockaddr(apr_sockaddr_t *sa, char *buf_end, apr_size_t *len) +{ + char *p = buf_end; + int is_negative; + apr_size_t sub_len; + char *ipaddr_str; + + p = conv_10(sa->port, TRUE, &is_negative, p, &sub_len); + *--p = ':'; + ipaddr_str = buf_end - NUM_BUF_SIZE; + if (apr_sockaddr_ip_getbuf(ipaddr_str, sa->addr_str_len, sa)) { + /* Should only fail if the buffer is too small, which it + * should not be; but fail safe anyway: */ + *--p = '?'; + *len = buf_end - p; + return p; + } + sub_len = strlen(ipaddr_str); +#if APR_HAVE_IPV6 + if (sa->family == APR_INET6 && + !IN6_IS_ADDR_V4MAPPED(&sa->sa.sin6.sin6_addr)) { + *(p - 1) = ']'; + p -= sub_len + 2; + *p = '['; + memcpy(p + 1, ipaddr_str, sub_len); + } + else +#endif + { + p -= sub_len; + memcpy(p, ipaddr_str, sub_len); + } + + *len = buf_end - p; + return (p); +} + + + +#if APR_HAS_THREADS +static char *conv_os_thread_t(apr_os_thread_t *tid, char *buf_end, apr_size_t *len) +{ + union { + apr_os_thread_t tid; + apr_uint64_t u64; + apr_uint32_t u32; + } u; + int is_negative; + + u.tid = *tid; + switch(sizeof(u.tid)) { + case sizeof(apr_int32_t): + return conv_10(u.u32, TRUE, &is_negative, buf_end, len); + case sizeof(apr_int64_t): + return conv_10_quad(u.u64, TRUE, &is_negative, buf_end, len); + default: + /* not implemented; stick 0 in the buffer */ + return conv_10(0, TRUE, &is_negative, buf_end, len); + } +} +#endif + + + +/* + * Convert a floating point number to a string formats 'f', 'e' or 'E'. + * The result is placed in buf, and len denotes the length of the string + * The sign is returned in the is_negative argument (and is not placed + * in buf). + */ +static char *conv_fp(register char format, register double num, + boolean_e add_dp, int precision, int *is_negative, + char *buf, apr_size_t *len) +{ + register char *s = buf; + register char *p; + int decimal_point; + char buf1[NDIG]; + + if (format == 'f') + p = apr_fcvt(num, precision, &decimal_point, is_negative, buf1); + else /* either e or E format */ + p = apr_ecvt(num, precision + 1, &decimal_point, is_negative, buf1); + + /* + * Check for Infinity and NaN + */ + if (apr_isalpha(*p)) { + *len = strlen(p); + memcpy(buf, p, *len + 1); + *is_negative = FALSE; + return (buf); + } + + if (format == 'f') { + if (decimal_point <= 0) { + *s++ = '0'; + if (precision > 0) { + *s++ = '.'; + while (decimal_point++ < 0) + *s++ = '0'; + } + else if (add_dp) + *s++ = '.'; + } + else { + while (decimal_point-- > 0) + *s++ = *p++; + if (precision > 0 || add_dp) + *s++ = '.'; + } + } + else { + *s++ = *p++; + if (precision > 0 || add_dp) + *s++ = '.'; + } + + /* + * copy the rest of p, the NUL is NOT copied + */ + while (*p) + *s++ = *p++; + + if (format != 'f') { + char temp[EXPONENT_LENGTH]; /* for exponent conversion */ + apr_size_t t_len; + int exponent_is_negative; + + *s++ = format; /* either e or E */ + decimal_point--; + if (decimal_point != 0) { + p = conv_10((apr_int32_t) decimal_point, FALSE, &exponent_is_negative, + &temp[EXPONENT_LENGTH], &t_len); + *s++ = exponent_is_negative ? '-' : '+'; + + /* + * Make sure the exponent has at least 2 digits + */ + if (t_len == 1) + *s++ = '0'; + while (t_len--) + *s++ = *p++; + } + else { + *s++ = '+'; + *s++ = '0'; + *s++ = '0'; + } + } + + *len = s - buf; + return (buf); +} + + +/* + * Convert num to a base X number where X is a power of 2. nbits determines X. + * For example, if nbits is 3, we do base 8 conversion + * Return value: + * a pointer to a string containing the number + * + * The caller provides a buffer for the string: that is the buf_end argument + * which is a pointer to the END of the buffer + 1 (i.e. if the buffer + * is declared as buf[ 100 ], buf_end should be &buf[ 100 ]) + * + * As with conv_10, we have a faster version which is used when + * the number isn't quad size. + */ +static char *conv_p2(register apr_uint32_t num, register int nbits, + char format, char *buf_end, register apr_size_t *len) +{ + register int mask = (1 << nbits) - 1; + register char *p = buf_end; + static const char low_digits[] = "0123456789abcdef"; + static const char upper_digits[] = "0123456789ABCDEF"; + register const char *digits = (format == 'X') ? upper_digits : low_digits; + + do { + *--p = digits[num & mask]; + num >>= nbits; + } + while (num); + + *len = buf_end - p; + return (p); +} + +static char *conv_p2_quad(apr_uint64_t num, register int nbits, + char format, char *buf_end, register apr_size_t *len) +{ + register int mask = (1 << nbits) - 1; + register char *p = buf_end; + static const char low_digits[] = "0123456789abcdef"; + static const char upper_digits[] = "0123456789ABCDEF"; + register const char *digits = (format == 'X') ? upper_digits : low_digits; + + if (num <= APR_UINT32_MAX) + return(conv_p2((apr_uint32_t)num, nbits, format, buf_end, len)); + + do { + *--p = digits[num & mask]; + num >>= nbits; + } + while (num); + + *len = buf_end - p; + return (p); +} + +#if APR_HAS_THREADS +static char *conv_os_thread_t_hex(apr_os_thread_t *tid, char *buf_end, apr_size_t *len) +{ + union { + apr_os_thread_t tid; + apr_uint64_t u64; + apr_uint32_t u32; + } u; + int is_negative; + + u.tid = *tid; + switch(sizeof(u.tid)) { + case sizeof(apr_int32_t): + return conv_p2(u.u32, 4, 'x', buf_end, len); + case sizeof(apr_int64_t): + return conv_p2_quad(u.u64, 4, 'x', buf_end, len); + default: + /* not implemented; stick 0 in the buffer */ + return conv_10(0, TRUE, &is_negative, buf_end, len); + } +} +#endif + +/* + * Do format conversion placing the output in buffer + */ +APR_DECLARE(int) apr_vformatter(int (*flush_func)(apr_vformatter_buff_t *), + apr_vformatter_buff_t *vbuff, const char *fmt, va_list ap) +{ + register char *sp; + register char *bep; + register int cc = 0; + register apr_size_t i; + + register char *s = NULL; + char *q; + apr_size_t s_len = 0; + + register apr_size_t min_width = 0; + apr_size_t precision = 0; + enum { + LEFT, RIGHT + } adjust; + char pad_char; + char prefix_char; + + double fp_num; + apr_int64_t i_quad = 0; + apr_uint64_t ui_quad; + apr_int32_t i_num = 0; + apr_uint32_t ui_num = 0; + + char num_buf[NUM_BUF_SIZE]; + char char_buf[2]; /* for printing %% and %<unknown> */ + + enum var_type_enum { + IS_QUAD, IS_LONG, IS_SHORT, IS_INT + }; + enum var_type_enum var_type = IS_INT; + + /* + * Flag variables + */ + boolean_e alternate_form; + boolean_e print_sign; + boolean_e print_blank; + boolean_e adjust_precision; + boolean_e adjust_width; + int is_negative; + + sp = vbuff->curpos; + bep = vbuff->endpos; + + while (*fmt) { + if (*fmt != '%') { + INS_CHAR(*fmt, sp, bep, cc); + } + else { + /* + * Default variable settings + */ + boolean_e print_something = YES; + adjust = RIGHT; + alternate_form = print_sign = print_blank = NO; + pad_char = ' '; + prefix_char = NUL; + + fmt++; + + /* + * Try to avoid checking for flags, width or precision + */ + if (!apr_islower(*fmt)) { + /* + * Recognize flags: -, #, BLANK, + + */ + for (;; fmt++) { + if (*fmt == '-') + adjust = LEFT; + else if (*fmt == '+') + print_sign = YES; + else if (*fmt == '#') + alternate_form = YES; + else if (*fmt == ' ') + print_blank = YES; + else if (*fmt == '0') + pad_char = '0'; + else + break; + } + + /* + * Check if a width was specified + */ + if (apr_isdigit(*fmt)) { + STR_TO_DEC(fmt, min_width); + adjust_width = YES; + } + else if (*fmt == '*') { + int v = va_arg(ap, int); + fmt++; + adjust_width = YES; + if (v < 0) { + adjust = LEFT; + min_width = (apr_size_t)(-v); + } + else + min_width = (apr_size_t)v; + } + else + adjust_width = NO; + + /* + * Check if a precision was specified + */ + if (*fmt == '.') { + adjust_precision = YES; + fmt++; + if (apr_isdigit(*fmt)) { + STR_TO_DEC(fmt, precision); + } + else if (*fmt == '*') { + int v = va_arg(ap, int); + fmt++; + precision = (v < 0) ? 0 : (apr_size_t)v; + } + else + precision = 0; + } + else + adjust_precision = NO; + } + else + adjust_precision = adjust_width = NO; + + /* + * Modifier check. In same cases, APR_OFF_T_FMT can be + * "lld" and APR_INT64_T_FMT can be "ld" (that is, off_t is + * "larger" than int64). Check that case 1st. + * Note that if APR_OFF_T_FMT is "d", + * the first if condition is never true. If APR_INT64_T_FMT + * is "d' then the second if condition is never true. + */ + if ((sizeof(APR_OFF_T_FMT) > sizeof(APR_INT64_T_FMT)) && + ((sizeof(APR_OFF_T_FMT) == 4 && + fmt[0] == APR_OFF_T_FMT[0] && + fmt[1] == APR_OFF_T_FMT[1]) || + (sizeof(APR_OFF_T_FMT) == 3 && + fmt[0] == APR_OFF_T_FMT[0]) || + (sizeof(APR_OFF_T_FMT) > 4 && + strncmp(fmt, APR_OFF_T_FMT, + sizeof(APR_OFF_T_FMT) - 2) == 0))) { + /* Need to account for trailing 'd' and null in sizeof() */ + var_type = IS_QUAD; + fmt += (sizeof(APR_OFF_T_FMT) - 2); + } + else if ((sizeof(APR_INT64_T_FMT) == 4 && + fmt[0] == APR_INT64_T_FMT[0] && + fmt[1] == APR_INT64_T_FMT[1]) || + (sizeof(APR_INT64_T_FMT) == 3 && + fmt[0] == APR_INT64_T_FMT[0]) || + (sizeof(APR_INT64_T_FMT) > 4 && + strncmp(fmt, APR_INT64_T_FMT, + sizeof(APR_INT64_T_FMT) - 2) == 0)) { + /* Need to account for trailing 'd' and null in sizeof() */ + var_type = IS_QUAD; + fmt += (sizeof(APR_INT64_T_FMT) - 2); + } + else if (*fmt == 'q') { + var_type = IS_QUAD; + fmt++; + } + else if (*fmt == 'l') { + var_type = IS_LONG; + fmt++; + } + else if (*fmt == 'h') { + var_type = IS_SHORT; + fmt++; + } + else { + var_type = IS_INT; + } + + /* + * Argument extraction and printing. + * First we determine the argument type. + * Then, we convert the argument to a string. + * On exit from the switch, s points to the string that + * must be printed, s_len has the length of the string + * The precision requirements, if any, are reflected in s_len. + * + * NOTE: pad_char may be set to '0' because of the 0 flag. + * It is reset to ' ' by non-numeric formats + */ + switch (*fmt) { + case 'u': + if (var_type == IS_QUAD) { + i_quad = va_arg(ap, apr_uint64_t); + s = conv_10_quad(i_quad, 1, &is_negative, + &num_buf[NUM_BUF_SIZE], &s_len); + } + else { + if (var_type == IS_LONG) + i_num = (apr_int32_t) va_arg(ap, apr_uint32_t); + else if (var_type == IS_SHORT) + i_num = (apr_int32_t) (unsigned short) va_arg(ap, unsigned int); + else + i_num = (apr_int32_t) va_arg(ap, unsigned int); + s = conv_10(i_num, 1, &is_negative, + &num_buf[NUM_BUF_SIZE], &s_len); + } + FIX_PRECISION(adjust_precision, precision, s, s_len); + break; + + case 'd': + case 'i': + if (var_type == IS_QUAD) { + i_quad = va_arg(ap, apr_int64_t); + s = conv_10_quad(i_quad, 0, &is_negative, + &num_buf[NUM_BUF_SIZE], &s_len); + } + else { + if (var_type == IS_LONG) + i_num = va_arg(ap, apr_int32_t); + else if (var_type == IS_SHORT) + i_num = (short) va_arg(ap, int); + else + i_num = va_arg(ap, int); + s = conv_10(i_num, 0, &is_negative, + &num_buf[NUM_BUF_SIZE], &s_len); + } + FIX_PRECISION(adjust_precision, precision, s, s_len); + + if (is_negative) + prefix_char = '-'; + else if (print_sign) + prefix_char = '+'; + else if (print_blank) + prefix_char = ' '; + break; + + + case 'o': + if (var_type == IS_QUAD) { + ui_quad = va_arg(ap, apr_uint64_t); + s = conv_p2_quad(ui_quad, 3, *fmt, + &num_buf[NUM_BUF_SIZE], &s_len); + } + else { + if (var_type == IS_LONG) + ui_num = va_arg(ap, apr_uint32_t); + else if (var_type == IS_SHORT) + ui_num = (unsigned short) va_arg(ap, unsigned int); + else + ui_num = va_arg(ap, unsigned int); + s = conv_p2(ui_num, 3, *fmt, + &num_buf[NUM_BUF_SIZE], &s_len); + } + FIX_PRECISION(adjust_precision, precision, s, s_len); + if (alternate_form && *s != '0') { + *--s = '0'; + s_len++; + } + break; + + + case 'x': + case 'X': + if (var_type == IS_QUAD) { + ui_quad = va_arg(ap, apr_uint64_t); + s = conv_p2_quad(ui_quad, 4, *fmt, + &num_buf[NUM_BUF_SIZE], &s_len); + } + else { + if (var_type == IS_LONG) + ui_num = va_arg(ap, apr_uint32_t); + else if (var_type == IS_SHORT) + ui_num = (unsigned short) va_arg(ap, unsigned int); + else + ui_num = va_arg(ap, unsigned int); + s = conv_p2(ui_num, 4, *fmt, + &num_buf[NUM_BUF_SIZE], &s_len); + } + FIX_PRECISION(adjust_precision, precision, s, s_len); + if (alternate_form && ui_num != 0) { + *--s = *fmt; /* 'x' or 'X' */ + *--s = '0'; + s_len += 2; + } + break; + + + case 's': + s = va_arg(ap, char *); + if (s != NULL) { + if (!adjust_precision) { + s_len = strlen(s); + } + else { + /* From the C library standard in section 7.9.6.1: + * ...if the precision is specified, no more then + * that many characters are written. If the + * precision is not specified or is greater + * than the size of the array, the array shall + * contain a null character. + * + * My reading is is precision is specified and + * is less then or equal to the size of the + * array, no null character is required. So + * we can't do a strlen. + * + * This figures out the length of the string + * up to the precision. Once it's long enough + * for the specified precision, we don't care + * anymore. + * + * NOTE: you must do the length comparison + * before the check for the null character. + * Otherwise, you'll check one beyond the + * last valid character. + */ + const char *walk; + + for (walk = s, s_len = 0; + (s_len < precision) && (*walk != '\0'); + ++walk, ++s_len); + } + } + else { + s = S_NULL; + s_len = S_NULL_LEN; + } + pad_char = ' '; + break; + + + case 'f': + case 'e': + case 'E': + fp_num = va_arg(ap, double); + /* + * We use &num_buf[ 1 ], so that we have room for the sign + */ + s = NULL; +#ifdef HAVE_ISNAN + if (isnan(fp_num)) { + s = "nan"; + s_len = 3; + } +#endif +#ifdef HAVE_ISINF + if (!s && isinf(fp_num)) { + s = "inf"; + s_len = 3; + } +#endif + if (!s) { + s = conv_fp(*fmt, fp_num, alternate_form, + (int)((adjust_precision == NO) ? FLOAT_DIGITS : precision), + &is_negative, &num_buf[1], &s_len); + if (is_negative) + prefix_char = '-'; + else if (print_sign) + prefix_char = '+'; + else if (print_blank) + prefix_char = ' '; + } + break; + + + case 'g': + case 'G': + if (adjust_precision == NO) + precision = FLOAT_DIGITS; + else if (precision == 0) + precision = 1; + /* + * * We use &num_buf[ 1 ], so that we have room for the sign + */ + s = apr_gcvt(va_arg(ap, double), (int) precision, &num_buf[1], + alternate_form); + if (*s == '-') + prefix_char = *s++; + else if (print_sign) + prefix_char = '+'; + else if (print_blank) + prefix_char = ' '; + + s_len = strlen(s); + + if (alternate_form && (q = strchr(s, '.')) == NULL) { + s[s_len++] = '.'; + s[s_len] = '\0'; /* delimit for following strchr() */ + } + if (*fmt == 'G' && (q = strchr(s, 'e')) != NULL) + *q = 'E'; + break; + + + case 'c': + char_buf[0] = (char) (va_arg(ap, int)); + s = &char_buf[0]; + s_len = 1; + pad_char = ' '; + break; + + + case '%': + char_buf[0] = '%'; + s = &char_buf[0]; + s_len = 1; + pad_char = ' '; + break; + + + case 'n': + if (var_type == IS_QUAD) + *(va_arg(ap, apr_int64_t *)) = cc; + else if (var_type == IS_LONG) + *(va_arg(ap, long *)) = cc; + else if (var_type == IS_SHORT) + *(va_arg(ap, short *)) = cc; + else + *(va_arg(ap, int *)) = cc; + print_something = NO; + break; + + /* + * This is where we extend the printf format, with a second + * type specifier + */ + case 'p': + switch(*++fmt) { + /* + * If the pointer size is equal to or smaller than the size + * of the largest unsigned int, we convert the pointer to a + * hex number, otherwise we print "%p" to indicate that we + * don't handle "%p". + */ + case 'p': +#if APR_SIZEOF_VOIDP == 8 + if (sizeof(void *) <= sizeof(apr_uint64_t)) { + ui_quad = (apr_uint64_t) va_arg(ap, void *); + s = conv_p2_quad(ui_quad, 4, 'x', + &num_buf[NUM_BUF_SIZE], &s_len); + } +#else + if (sizeof(void *) <= sizeof(apr_uint32_t)) { + ui_num = (apr_uint32_t) va_arg(ap, void *); + s = conv_p2(ui_num, 4, 'x', + &num_buf[NUM_BUF_SIZE], &s_len); + } +#endif + else { + s = "%p"; + s_len = 2; + prefix_char = NUL; + } + pad_char = ' '; + break; + + /* print an apr_sockaddr_t as a.b.c.d:port */ + case 'I': + { + apr_sockaddr_t *sa; + + sa = va_arg(ap, apr_sockaddr_t *); + if (sa != NULL) { + s = conv_apr_sockaddr(sa, &num_buf[NUM_BUF_SIZE], &s_len); + if (adjust_precision && precision < s_len) + s_len = precision; + } + else { + s = S_NULL; + s_len = S_NULL_LEN; + } + pad_char = ' '; + } + break; + + /* print a struct in_addr as a.b.c.d */ + case 'A': + { + struct in_addr *ia; + + ia = va_arg(ap, struct in_addr *); + if (ia != NULL) { + s = conv_in_addr(ia, &num_buf[NUM_BUF_SIZE], &s_len); + if (adjust_precision && precision < s_len) + s_len = precision; + } + else { + s = S_NULL; + s_len = S_NULL_LEN; + } + pad_char = ' '; + } + break; + + /* print the error for an apr_status_t */ + case 'm': + { + apr_status_t *mrv; + + mrv = va_arg(ap, apr_status_t *); + if (mrv != NULL) { + s = apr_strerror(*mrv, num_buf, NUM_BUF_SIZE-1); + s_len = strlen(s); + } + else { + s = S_NULL; + s_len = S_NULL_LEN; + } + pad_char = ' '; + } + break; + + case 'T': +#if APR_HAS_THREADS + { + apr_os_thread_t *tid; + + tid = va_arg(ap, apr_os_thread_t *); + if (tid != NULL) { + s = conv_os_thread_t(tid, &num_buf[NUM_BUF_SIZE], &s_len); + if (adjust_precision && precision < s_len) + s_len = precision; + } + else { + s = S_NULL; + s_len = S_NULL_LEN; + } + pad_char = ' '; + } +#else + char_buf[0] = '0'; + s = &char_buf[0]; + s_len = 1; + pad_char = ' '; +#endif + break; + + case 't': +#if APR_HAS_THREADS + { + apr_os_thread_t *tid; + + tid = va_arg(ap, apr_os_thread_t *); + if (tid != NULL) { + s = conv_os_thread_t_hex(tid, &num_buf[NUM_BUF_SIZE], &s_len); + if (adjust_precision && precision < s_len) + s_len = precision; + } + else { + s = S_NULL; + s_len = S_NULL_LEN; + } + pad_char = ' '; + } +#else + char_buf[0] = '0'; + s = &char_buf[0]; + s_len = 1; + pad_char = ' '; +#endif + break; + + case 'B': + case 'F': + case 'S': + { + char buf[5]; + apr_off_t size = 0; + + if (*fmt == 'B') { + apr_uint32_t *arg = va_arg(ap, apr_uint32_t *); + size = (arg) ? *arg : 0; + } + else if (*fmt == 'F') { + apr_off_t *arg = va_arg(ap, apr_off_t *); + size = (arg) ? *arg : 0; + } + else { + apr_size_t *arg = va_arg(ap, apr_size_t *); + size = (arg) ? *arg : 0; + } + + s = apr_strfsize(size, buf); + s_len = strlen(s); + pad_char = ' '; + } + break; + + case NUL: + /* if %p ends the string, oh well ignore it */ + continue; + + default: + s = "bogus %p"; + s_len = 8; + prefix_char = NUL; + (void)va_arg(ap, void *); /* skip the bogus argument on the stack */ + break; + } + break; + + case NUL: + /* + * The last character of the format string was %. + * We ignore it. + */ + continue; + + + /* + * The default case is for unrecognized %'s. + * We print %<char> to help the user identify what + * option is not understood. + * This is also useful in case the user wants to pass + * the output of format_converter to another function + * that understands some other %<char> (like syslog). + * Note that we can't point s inside fmt because the + * unknown <char> could be preceded by width etc. + */ + default: + char_buf[0] = '%'; + char_buf[1] = *fmt; + s = char_buf; + s_len = 2; + pad_char = ' '; + break; + } + + if (prefix_char != NUL && s != S_NULL && s != char_buf) { + *--s = prefix_char; + s_len++; + } + + if (adjust_width && adjust == RIGHT && min_width > s_len) { + if (pad_char == '0' && prefix_char != NUL) { + INS_CHAR(*s, sp, bep, cc); + s++; + s_len--; + min_width--; + } + PAD(min_width, s_len, pad_char); + } + + /* + * Print the string s. + */ + if (print_something == YES) { + for (i = s_len; i != 0; i--) { + INS_CHAR(*s, sp, bep, cc); + s++; + } + } + + if (adjust_width && adjust == LEFT && min_width > s_len) + PAD(min_width, s_len, pad_char); + } + fmt++; + } + vbuff->curpos = sp; + + return cc; +} + + +static int snprintf_flush(apr_vformatter_buff_t *vbuff) +{ + /* if the buffer fills we have to abort immediately, there is no way + * to "flush" an apr_snprintf... there's nowhere to flush it to. + */ + return -1; +} + + +APR_DECLARE_NONSTD(int) apr_snprintf(char *buf, apr_size_t len, + const char *format, ...) +{ + int cc; + va_list ap; + apr_vformatter_buff_t vbuff; + + if (len == 0) { + /* NOTE: This is a special case; we just want to return the number + * of chars that would be written (minus \0) if the buffer + * size was infinite. We leverage the fact that INS_CHAR + * just does actual inserts iff the buffer pointer is non-NULL. + * In this case, we don't care what buf is; it can be NULL, since + * we don't touch it at all. + */ + vbuff.curpos = NULL; + vbuff.endpos = NULL; + } else { + /* save one byte for nul terminator */ + vbuff.curpos = buf; + vbuff.endpos = buf + len - 1; + } + va_start(ap, format); + cc = apr_vformatter(snprintf_flush, &vbuff, format, ap); + va_end(ap); + if (len != 0) { + *vbuff.curpos = '\0'; + } + return (cc == -1) ? (int)len - 1 : cc; +} + + +APR_DECLARE(int) apr_vsnprintf(char *buf, apr_size_t len, const char *format, + va_list ap) +{ + int cc; + apr_vformatter_buff_t vbuff; + + if (len == 0) { + /* See above note */ + vbuff.curpos = NULL; + vbuff.endpos = NULL; + } else { + /* save one byte for nul terminator */ + vbuff.curpos = buf; + vbuff.endpos = buf + len - 1; + } + cc = apr_vformatter(snprintf_flush, &vbuff, format, ap); + if (len != 0) { + *vbuff.curpos = '\0'; + } + return (cc == -1) ? (int)len - 1 : cc; +} diff --git a/strings/apr_strings.c b/strings/apr_strings.c new file mode 100644 index 00000000000..0ba49c844c6 --- /dev/null +++ b/strings/apr_strings.c @@ -0,0 +1,467 @@ +/* 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. + */ +/* + * Copyright (c) 1990, 1993 + * 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.h" +#include "apr_strings.h" +#include "apr_general.h" +#include "apr_private.h" +#include "apr_lib.h" +#define APR_WANT_STDIO +#define APR_WANT_STRFUNC +#include "apr_want.h" + +#ifdef HAVE_STDDEF_H +#include <stddef.h> /* NULL */ +#endif + +#ifdef HAVE_STDLIB_H +#include <stdlib.h> /* strtol and strtoll */ +#endif + +/** this is used to cache lengths in apr_pstrcat */ +#define MAX_SAVED_LENGTHS 6 + +APR_DECLARE(char *) apr_pstrdup(apr_pool_t *a, const char *s) +{ + char *res; + apr_size_t len; + + if (s == NULL) { + return NULL; + } + len = strlen(s) + 1; + res = apr_pmemdup(a, s, len); + return res; +} + +APR_DECLARE(char *) apr_pstrndup(apr_pool_t *a, const char *s, apr_size_t n) +{ + char *res; + const char *end; + + if (s == NULL) { + return NULL; + } + end = memchr(s, '\0', n); + if (end != NULL) + n = end - s; + res = apr_palloc(a, n + 1); + memcpy(res, s, n); + res[n] = '\0'; + return res; +} + +APR_DECLARE(char *) apr_pstrmemdup(apr_pool_t *a, const char *s, apr_size_t n) +{ + char *res; + + if (s == NULL) { + return NULL; + } + res = apr_palloc(a, n + 1); + memcpy(res, s, n); + res[n] = '\0'; + return res; +} + +APR_DECLARE(void *) apr_pmemdup(apr_pool_t *a, const void *m, apr_size_t n) +{ + void *res; + + if (m == NULL) + return NULL; + res = apr_palloc(a, n); + memcpy(res, m, n); + return res; +} + +APR_DECLARE_NONSTD(char *) apr_pstrcat(apr_pool_t *a, ...) +{ + char *cp, *argp, *res; + apr_size_t saved_lengths[MAX_SAVED_LENGTHS]; + int nargs = 0; + + /* Pass one --- find length of required string */ + + apr_size_t len = 0; + va_list adummy; + + va_start(adummy, a); + + while ((cp = va_arg(adummy, char *)) != NULL) { + apr_size_t cplen = strlen(cp); + if (nargs < MAX_SAVED_LENGTHS) { + saved_lengths[nargs++] = cplen; + } + len += cplen; + } + + va_end(adummy); + + /* Allocate the required string */ + + res = (char *) apr_palloc(a, len + 1); + cp = res; + + /* Pass two --- copy the argument strings into the result space */ + + va_start(adummy, a); + + nargs = 0; + while ((argp = va_arg(adummy, char *)) != NULL) { + if (nargs < MAX_SAVED_LENGTHS) { + len = saved_lengths[nargs++]; + } + else { + len = strlen(argp); + } + + memcpy(cp, argp, len); + cp += len; + } + + va_end(adummy); + + /* Return the result string */ + + *cp = '\0'; + + return res; +} + +APR_DECLARE(char *) apr_pstrcatv(apr_pool_t *a, const struct iovec *vec, + apr_size_t nvec, apr_size_t *nbytes) +{ + apr_size_t i; + apr_size_t len; + const struct iovec *src; + char *res; + char *dst; + + /* Pass one --- find length of required string */ + len = 0; + src = vec; + for (i = nvec; i; i--) { + len += src->iov_len; + src++; + } + if (nbytes) { + *nbytes = len; + } + + /* Allocate the required string */ + res = (char *) apr_palloc(a, len + 1); + + /* Pass two --- copy the argument strings into the result space */ + src = vec; + dst = res; + for (i = nvec; i; i--) { + memcpy(dst, src->iov_base, src->iov_len); + dst += src->iov_len; + src++; + } + + /* Return the result string */ + *dst = '\0'; + + return res; +} + +#if (!APR_HAVE_MEMCHR) +void *memchr(const void *s, int c, size_t n) +{ + const char *cp; + + for (cp = s; n > 0; n--, cp++) { + if (*cp == c) + return (char *) cp; /* Casting away the const here */ + } + + return NULL; +} +#endif + +#ifndef INT64_MAX +#define INT64_MAX APR_INT64_C(0x7fffffffffffffff) +#endif +#ifndef INT64_MIN +#define INT64_MIN (-APR_INT64_C(0x7fffffffffffffff) - APR_INT64_C(1)) +#endif + +APR_DECLARE(apr_status_t) apr_strtoff(apr_off_t *offset, const char *nptr, + char **endptr, int base) +{ + errno = 0; + *offset = APR_OFF_T_STRFN(nptr, endptr, base); + return APR_FROM_OS_ERROR(errno); +} + +APR_DECLARE(apr_int64_t) apr_strtoi64(const char *nptr, char **endptr, int base) +{ +#ifdef APR_INT64_STRFN + errno = 0; + return APR_INT64_STRFN(nptr, endptr, base); +#else + const char *s; + apr_int64_t acc; + apr_int64_t val; + int neg, any; + char c; + + errno = 0; + /* + * Skip white space and pick up leading +/- sign if any. + * If base is 0, allow 0x for hex and 0 for octal, else + * assume decimal; if base is already 16, allow 0x. + */ + s = nptr; + do { + c = *s++; + } while (apr_isspace(c)); + if (c == '-') { + neg = 1; + c = *s++; + } else { + neg = 0; + if (c == '+') + c = *s++; + } + if ((base == 0 || base == 16) && + c == '0' && (*s == 'x' || *s == 'X')) { + c = s[1]; + s += 2; + base = 16; + } + if (base == 0) + base = c == '0' ? 8 : 10; + acc = any = 0; + if (base < 2 || base > 36) { + errno = EINVAL; + if (endptr != NULL) + *endptr = (char *)(any ? s - 1 : nptr); + return acc; + } + + /* The classic bsd implementation requires div/mod operators + * to compute a cutoff. Benchmarking proves that is very, very + * evil to some 32 bit processors. Instead, look for underflow + * in both the mult and add/sub operation. Unlike the bsd impl, + * we also work strictly in a signed int64 word as we haven't + * implemented the unsigned type in win32. + * + * Set 'any' if any `digits' consumed; make it negative to indicate + * overflow. + */ + val = 0; + for ( ; ; c = *s++) { + if (c >= '0' && c <= '9') + c -= '0'; +#if (('Z' - 'A') == 25) + else if (c >= 'A' && c <= 'Z') + c -= 'A' - 10; + else if (c >= 'a' && c <= 'z') + c -= 'a' - 10; +#elif APR_CHARSET_EBCDIC + else if (c >= 'A' && c <= 'I') + c -= 'A' - 10; + else if (c >= 'J' && c <= 'R') + c -= 'J' - 19; + else if (c >= 'S' && c <= 'Z') + c -= 'S' - 28; + else if (c >= 'a' && c <= 'i') + c -= 'a' - 10; + else if (c >= 'j' && c <= 'r') + c -= 'j' - 19; + else if (c >= 's' && c <= 'z') + c -= 'z' - 28; +#else +#error "CANNOT COMPILE apr_strtoi64(), only ASCII and EBCDIC supported" +#endif + else + break; + if (c >= base) + break; + val *= base; + if ( (any < 0) /* already noted an over/under flow - short circuit */ + || (neg && (val > acc || (val -= c) > acc)) /* underflow */ + || (!neg && (val < acc || (val += c) < acc))) { /* overflow */ + any = -1; /* once noted, over/underflows never go away */ +#ifdef APR_STRTOI64_OVERFLOW_IS_BAD_CHAR + break; +#endif + } else { + acc = val; + any = 1; + } + } + + if (any < 0) { + acc = neg ? INT64_MIN : INT64_MAX; + errno = ERANGE; + } else if (!any) { + errno = EINVAL; + } + if (endptr != NULL) + *endptr = (char *)(any ? s - 1 : nptr); + return (acc); +#endif +} + +APR_DECLARE(apr_int64_t) apr_atoi64(const char *buf) +{ + return apr_strtoi64(buf, NULL, 10); +} + +APR_DECLARE(char *) apr_itoa(apr_pool_t *p, int n) +{ + const int BUFFER_SIZE = sizeof(int) * 3 + 2; + char *buf = apr_palloc(p, BUFFER_SIZE); + char *start = buf + BUFFER_SIZE - 1; + int negative; + if (n < 0) { + negative = 1; + n = -n; + } + else { + negative = 0; + } + *start = 0; + do { + *--start = '0' + (n % 10); + n /= 10; + } while (n); + if (negative) { + *--start = '-'; + } + return start; +} + +APR_DECLARE(char *) apr_ltoa(apr_pool_t *p, long n) +{ + const int BUFFER_SIZE = sizeof(long) * 3 + 2; + char *buf = apr_palloc(p, BUFFER_SIZE); + char *start = buf + BUFFER_SIZE - 1; + int negative; + if (n < 0) { + negative = 1; + n = -n; + } + else { + negative = 0; + } + *start = 0; + do { + *--start = (char)('0' + (n % 10)); + n /= 10; + } while (n); + if (negative) { + *--start = '-'; + } + return start; +} + +APR_DECLARE(char *) apr_off_t_toa(apr_pool_t *p, apr_off_t n) +{ + const int BUFFER_SIZE = sizeof(apr_off_t) * 3 + 2; + char *buf = apr_palloc(p, BUFFER_SIZE); + char *start = buf + BUFFER_SIZE - 1; + int negative; + if (n < 0) { + negative = 1; + n = -n; + } + else { + negative = 0; + } + *start = 0; + do { + *--start = '0' + (char)(n % 10); + n /= 10; + } while (n); + if (negative) { + *--start = '-'; + } + return start; +} + +APR_DECLARE(char *) apr_strfsize(apr_off_t size, char *buf) +{ + const char ord[] = "KMGTPE"; + const char *o = ord; + int remain; + + if (size < 0) { + return strcpy(buf, " - "); + } + if (size < 973) { + if (apr_snprintf(buf, 5, "%3d ", (int) size) < 0) + return strcpy(buf, "****"); + return buf; + } + do { + remain = (int)(size & 1023); + size >>= 10; + if (size >= 973) { + ++o; + continue; + } + if (size < 9 || (size == 9 && remain < 973)) { + if ((remain = ((remain * 5) + 256) / 512) >= 10) + ++size, remain = 0; + if (apr_snprintf(buf, 5, "%d.%d%c", (int) size, remain, *o) < 0) + return strcpy(buf, "****"); + return buf; + } + if (remain >= 512) + ++size; + if (apr_snprintf(buf, 5, "%3d%c", (int) size, *o) < 0) + return strcpy(buf, "****"); + return buf; + } while (1); +} + diff --git a/lib/apr_strnatcmp.c b/strings/apr_strnatcmp.c similarity index 82% rename from lib/apr_strnatcmp.c rename to strings/apr_strnatcmp.c index ea29fd1778d..0e960e8a90b 100644 --- a/lib/apr_strnatcmp.c +++ b/strings/apr_strnatcmp.c @@ -22,10 +22,8 @@ #include <ctype.h> #include <string.h> -#include <assert.h> -#include <stdio.h> - -#include "apr_strnatcmp.h" +#include "apr_strings.h" +#include "apr_lib.h" /* for apr_is*() */ #if defined(__GNUC__) # define UNUSED __attribute__((__unused__)) @@ -45,11 +43,11 @@ compare_right(char const *a, char const *b) both numbers to know that they have the same magnitude, so we remember it in BIAS. */ for (;; a++, b++) { - if (!isdigit(*a) && !isdigit(*b)) - return bias; - else if (!isdigit(*a)) + if (!apr_isdigit(*a) && !apr_isdigit(*b)) + break; + else if (!apr_isdigit(*a)) return -1; - else if (!isdigit(*b)) + else if (!apr_isdigit(*b)) return +1; else if (*a < *b) { if (!bias) @@ -58,10 +56,10 @@ compare_right(char const *a, char const *b) if (!bias) bias = +1; } else if (!*a && !*b) - return bias; + break; } - return 0; + return bias; } @@ -71,11 +69,11 @@ compare_left(char const *a, char const *b) /* Compare two left-aligned numbers: the first to have a different value wins. */ for (;; a++, b++) { - if (!isdigit(*a) && !isdigit(*b)) - return 0; - else if (!isdigit(*a)) + if (!apr_isdigit(*a) && !apr_isdigit(*b)) + break; + else if (!apr_isdigit(*a)) return -1; - else if (!isdigit(*b)) + else if (!apr_isdigit(*b)) return +1; else if (*a < *b) return -1; @@ -92,21 +90,19 @@ static int strnatcmp0(char const *a, char const *b, int fold_case) int ai, bi; char ca, cb; int fractional, result; - - assert(a && b); ai = bi = 0; while (1) { ca = a[ai]; cb = b[bi]; /* skip over leading spaces or zeros */ - while (isspace(ca)) + while (apr_isspace(ca)) ca = a[++ai]; - while (isspace(cb)) + while (apr_isspace(cb)) cb = b[++bi]; /* process run of digits */ - if (isdigit(ca) && isdigit(cb)) { + if (apr_isdigit(ca) && apr_isdigit(cb)) { fractional = (ca == '0' || cb == '0'); if (fractional) { @@ -125,8 +121,8 @@ static int strnatcmp0(char const *a, char const *b, int fold_case) } if (fold_case) { - ca = toupper(ca); - cb = toupper(cb); + ca = apr_toupper(ca); + cb = apr_toupper(cb); } if (ca < cb) @@ -140,12 +136,14 @@ static int strnatcmp0(char const *a, char const *b, int fold_case) -int ap_strnatcmp(char const *a, char const *b) { +APR_DECLARE(int) apr_strnatcmp(char const *a, char const *b) +{ return strnatcmp0(a, b, 0); } /* Compare, recognizing numeric string and ignoring case. */ -int ap_strnatcasecmp(char const *a, char const *b) { +APR_DECLARE(int) apr_strnatcasecmp(char const *a, char const *b) +{ return strnatcmp0(a, b, 1); } diff --git a/strings/apr_strtok.c b/strings/apr_strtok.c new file mode 100644 index 00000000000..517b319d47f --- /dev/null +++ b/strings/apr_strtok.c @@ -0,0 +1,56 @@ +/* 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. + */ + +#ifdef HAVE_STDDEF_H +#include <stddef.h> /* for NULL */ +#endif + +#include "apr.h" +#include "apr_strings.h" + +#define APR_WANT_STRFUNC /* for strchr() */ +#include "apr_want.h" + +APR_DECLARE(char *) apr_strtok(char *str, const char *sep, char **last) +{ + char *token; + + if (!str) /* subsequent call */ + str = *last; /* start where we left off */ + + /* skip characters in sep (will terminate at '\0') */ + while (*str && strchr(sep, *str)) + ++str; + + if (!*str) /* no more tokens */ + return NULL; + + token = str; + + /* skip valid token characters to terminate token and + * prepare for the next call (will terminate at '\0) + */ + *last = token + 1; + while (**last && !strchr(sep, **last)) + ++*last; + + if (**last) { + **last = '\0'; + ++*last; + } + + return token; +} diff --git a/strmatch/apr_strmatch.c b/strmatch/apr_strmatch.c new file mode 100644 index 00000000000..e5a0a81b939 --- /dev/null +++ b/strmatch/apr_strmatch.c @@ -0,0 +1,118 @@ +/* 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_strmatch.h" +#include "apr_lib.h" +#define APR_WANT_STRFUNC +#include "apr_want.h" + + +#define NUM_CHARS 256 + +/* + * String searching functions + */ +static const char *match_no_op(const apr_strmatch_pattern *this_pattern, + const char *s, apr_size_t slen) +{ + return s; +} + +static const char *match_boyer_moore_horspool( + const apr_strmatch_pattern *this_pattern, + const char *s, apr_size_t slen) +{ + const char *s_end = s + slen; + apr_size_t *shift = (apr_size_t *)(this_pattern->context); + const char *s_next = s + this_pattern->length - 1; + const char *p_start = this_pattern->pattern; + const char *p_end = p_start + this_pattern->length - 1; + while (s_next < s_end) { + const char *s_tmp = s_next; + const char *p_tmp = p_end; + while (*s_tmp == *p_tmp) { + p_tmp--; + if (p_tmp < p_start) { + return s_tmp; + } + s_tmp--; + } + s_next += shift[(int)*((const unsigned char *)s_next)]; + } + return NULL; +} + +static const char *match_boyer_moore_horspool_nocase( + const apr_strmatch_pattern *this_pattern, + const char *s, apr_size_t slen) +{ + const char *s_end = s + slen; + apr_size_t *shift = (apr_size_t *)(this_pattern->context); + const char *s_next = s + this_pattern->length - 1; + const char *p_start = this_pattern->pattern; + const char *p_end = p_start + this_pattern->length - 1; + while (s_next < s_end) { + const char *s_tmp = s_next; + const char *p_tmp = p_end; + while (apr_tolower(*s_tmp) == apr_tolower(*p_tmp)) { + p_tmp--; + if (p_tmp < p_start) { + return s_tmp; + } + s_tmp--; + } + s_next += shift[(unsigned char)apr_tolower(*s_next)]; + } + return NULL; +} + +APR_DECLARE(const apr_strmatch_pattern *) apr_strmatch_precompile( + apr_pool_t *p, const char *s, + int case_sensitive) +{ + apr_strmatch_pattern *pattern; + apr_size_t i; + apr_size_t *shift; + + pattern = apr_palloc(p, sizeof(*pattern)); + pattern->pattern = s; + pattern->length = strlen(s); + if (pattern->length == 0) { + pattern->compare = match_no_op; + pattern->context = NULL; + return pattern; + } + + shift = (apr_size_t *)apr_palloc(p, sizeof(apr_size_t) * NUM_CHARS); + for (i = 0; i < NUM_CHARS; i++) { + shift[i] = pattern->length; + } + if (case_sensitive) { + pattern->compare = match_boyer_moore_horspool; + for (i = 0; i < pattern->length - 1; i++) { + shift[(unsigned char)s[i]] = pattern->length - i - 1; + } + } + else { + pattern->compare = match_boyer_moore_horspool_nocase; + for (i = 0; i < pattern->length - 1; i++) { + shift[(unsigned char)apr_tolower(s[i])] = pattern->length - i - 1; + } + } + pattern->context = shift; + + return pattern; +} diff --git a/support/os2/waitio.c b/support/os2/waitio.c new file mode 100644 index 00000000000..60530e732ff --- /dev/null +++ b/support/os2/waitio.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_arch_file_io.h" +#include "apr_arch_networkio.h" +#include "apr_errno.h" +#include "apr_support.h" + +apr_status_t apr_wait_for_io_or_timeout(apr_file_t *f, apr_socket_t *s, + int for_read) +{ + if (f) { + return apr_file_pipe_wait(f, for_read ? APR_WAIT_READ : APR_WAIT_WRITE); + } + else if (s) { + return apr_socket_wait(s, for_read ? APR_WAIT_READ : APR_WAIT_WRITE); + } + + /* Didn't specify a file or socket */ + return APR_EINVAL; +} diff --git a/support/unix/waitio.c b/support/unix/waitio.c new file mode 100644 index 00000000000..0d762ea6dd6 --- /dev/null +++ b/support/unix/waitio.c @@ -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. + */ + +#include "apr_arch_file_io.h" +#include "apr_arch_networkio.h" +#include "apr_poll.h" +#include "apr_errno.h" +#include "apr_support.h" + +/* The only case where we don't use wait_for_io_or_timeout is on + * pre-BONE BeOS, so this check should be sufficient and simpler */ +#if !defined(BEOS_R5) && !defined(OS2) && APR_FILES_AS_SOCKETS +#define USE_WAIT_FOR_IO +#endif + +#ifdef USE_WAIT_FOR_IO + +#ifdef WAITIO_USES_POLL + +#ifdef HAVE_POLL_H +#include <poll.h> +#endif +#ifdef HAVE_SYS_POLL_H +#include <sys/poll.h> +#endif + +apr_status_t apr_wait_for_io_or_timeout(apr_file_t *f, apr_socket_t *s, + int for_read) +{ + struct pollfd pfd; + int rc, timeout; + + timeout = f ? f->timeout / 1000 : s->timeout / 1000; + pfd.fd = f ? f->filedes : s->socketdes; + pfd.events = for_read ? POLLIN : POLLOUT; + + do { + rc = poll(&pfd, 1, timeout); + } while (rc == -1 && errno == EINTR); + if (rc == 0) { + return APR_TIMEUP; + } + else if (rc > 0) { + return APR_SUCCESS; + } + else { + return errno; + } +} + +#else /* !WAITIO_USES_POLL */ + +apr_status_t apr_wait_for_io_or_timeout(apr_file_t *f, apr_socket_t *s, + int for_read) +{ + apr_interval_time_t timeout; + apr_pollfd_t pfd; + int type = for_read ? APR_POLLIN : APR_POLLOUT; + apr_pollset_t *pollset; + apr_status_t status; + + /* TODO - timeout should be less each time through this loop */ + if (f) { + pfd.desc_type = APR_POLL_FILE; + pfd.desc.f = f; + + pollset = f->pollset; + if (pollset == NULL) { + status = apr_pollset_create(&(f->pollset), 1, f->pool, 0); + if (status != APR_SUCCESS) { + return status; + } + pollset = f->pollset; + } + timeout = f->timeout; + } + else { + pfd.desc_type = APR_POLL_SOCKET; + pfd.desc.s = s; + + pollset = s->pollset; + timeout = s->timeout; + } + pfd.reqevents = type; + + /* Remove the object if it was in the pollset, then add in the new + * object with the correct reqevents value. Ignore the status result + * on the remove, because it might not be in there (yet). + */ + (void) apr_pollset_remove(pollset, &pfd); + + /* ### check status code */ + (void) apr_pollset_add(pollset, &pfd); + + do { + int numdesc; + const apr_pollfd_t *pdesc; + + status = apr_pollset_poll(pollset, timeout, &numdesc, &pdesc); + + if (numdesc == 1 && (pdesc[0].rtnevents & type) != 0) { + return APR_SUCCESS; + } + } while (APR_STATUS_IS_EINTR(status)); + + return status; +} +#endif /* WAITIO_USES_POLL */ + +#endif /* USE_WAIT_FOR_IO */ diff --git a/tables/apr_hash.c b/tables/apr_hash.c new file mode 100644 index 00000000000..d4567710d66 --- /dev/null +++ b/tables/apr_hash.c @@ -0,0 +1,571 @@ +/* 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_time.h" + +#include "apr_hash.h" + +#if APR_HAVE_STDLIB_H +#include <stdlib.h> +#endif +#if APR_HAVE_STRING_H +#include <string.h> +#endif + +#if APR_POOL_DEBUG && APR_HAVE_STDIO_H +#include <stdio.h> +#endif + +/* + * The internal form of a hash table. + * + * The table is an array indexed by the hash of the key; collisions + * are resolved by hanging a linked list of hash entries off each + * element of the array. Although this is a really simple design it + * isn't too bad given that pools have a low allocation overhead. + */ + +typedef struct apr_hash_entry_t apr_hash_entry_t; + +struct apr_hash_entry_t { + apr_hash_entry_t *next; + unsigned int hash; + const void *key; + apr_ssize_t klen; + const void *val; +}; + +/* + * Data structure for iterating through a hash table. + * + * We keep a pointer to the next hash entry here to allow the current + * hash entry to be freed or otherwise mangled between calls to + * apr_hash_next(). + */ +struct apr_hash_index_t { + apr_hash_t *ht; + apr_hash_entry_t *this, *next; + unsigned int index; +}; + +/* + * The size of the array is always a power of two. We use the maximum + * index rather than the size so that we can use bitwise-AND for + * modular arithmetic. + * The count of hash entries may be greater depending on the chosen + * collision rate. + */ +struct apr_hash_t { + apr_pool_t *pool; + apr_hash_entry_t **array; + apr_hash_index_t iterator; /* For apr_hash_first(NULL, ...) */ + unsigned int count, max, seed; + apr_hashfunc_t hash_func; + apr_hash_entry_t *free; /* List of recycled entries */ +}; + +#define INITIAL_MAX 15 /* tunable == 2^n - 1 */ + + +/* + * Hash creation functions. + */ + +static apr_hash_entry_t **alloc_array(apr_hash_t *ht, unsigned int max) +{ + return apr_pcalloc(ht->pool, sizeof(*ht->array) * (max + 1)); +} + +APR_DECLARE(apr_hash_t *) apr_hash_make(apr_pool_t *pool) +{ + apr_hash_t *ht; + apr_time_t now = apr_time_now(); + + ht = apr_palloc(pool, sizeof(apr_hash_t)); + ht->pool = pool; + ht->free = NULL; + ht->count = 0; + ht->max = INITIAL_MAX; + ht->seed = (unsigned int)((now >> 32) ^ now ^ (apr_uintptr_t)pool ^ + (apr_uintptr_t)ht ^ (apr_uintptr_t)&now) - 1; + ht->array = alloc_array(ht, ht->max); + ht->hash_func = NULL; + + return ht; +} + +APR_DECLARE(apr_hash_t *) apr_hash_make_custom(apr_pool_t *pool, + apr_hashfunc_t hash_func) +{ + apr_hash_t *ht = apr_hash_make(pool); + ht->hash_func = hash_func; + return ht; +} + + +/* + * Hash iteration functions. + */ + +APR_DECLARE(apr_hash_index_t *) apr_hash_next(apr_hash_index_t *hi) +{ + hi->this = hi->next; + while (!hi->this) { + if (hi->index > hi->ht->max) + return NULL; + + hi->this = hi->ht->array[hi->index++]; + } + hi->next = hi->this->next; + return hi; +} + +APR_DECLARE(apr_hash_index_t *) apr_hash_first(apr_pool_t *p, apr_hash_t *ht) +{ + apr_hash_index_t *hi; + if (p) + hi = apr_palloc(p, sizeof(*hi)); + else + hi = &ht->iterator; + + hi->ht = ht; + hi->index = 0; + hi->this = NULL; + hi->next = NULL; + return apr_hash_next(hi); +} + +APR_DECLARE(void) apr_hash_this(apr_hash_index_t *hi, + const void **key, + apr_ssize_t *klen, + void **val) +{ + if (key) *key = hi->this->key; + if (klen) *klen = hi->this->klen; + if (val) *val = (void *)hi->this->val; +} + +APR_DECLARE(const void *) apr_hash_this_key(apr_hash_index_t *hi) +{ + const void *key; + + apr_hash_this(hi, &key, NULL, NULL); + return key; +} + +APR_DECLARE(apr_ssize_t) apr_hash_this_key_len(apr_hash_index_t *hi) +{ + apr_ssize_t klen; + + apr_hash_this(hi, NULL, &klen, NULL); + return klen; +} + +APR_DECLARE(void *) apr_hash_this_val(apr_hash_index_t *hi) +{ + void *val; + + apr_hash_this(hi, NULL, NULL, &val); + return val; +} + +/* + * Expanding a hash table + */ + +static void expand_array(apr_hash_t *ht) +{ + apr_hash_index_t *hi; + apr_hash_entry_t **new_array; + unsigned int new_max; + + new_max = ht->max * 2 + 1; + new_array = alloc_array(ht, new_max); + for (hi = apr_hash_first(NULL, ht); hi; hi = apr_hash_next(hi)) { + unsigned int i = hi->this->hash & new_max; + hi->this->next = new_array[i]; + new_array[i] = hi->this; + } + ht->array = new_array; + ht->max = new_max; +} + +static unsigned int hashfunc_default(const char *char_key, apr_ssize_t *klen, + unsigned int hash) +{ + const unsigned char *key = (const unsigned char *)char_key; + const unsigned char *p; + apr_ssize_t i; + + /* + * This is the popular `times 33' hash algorithm which is used by + * perl and also appears in Berkeley DB. This is one of the best + * known hash functions for strings because it is both computed + * very fast and distributes very well. + * + * The originator may be Dan Bernstein but the code in Berkeley DB + * cites Chris Torek as the source. The best citation I have found + * is "Chris Torek, Hash function for text in C, Usenet message + * <27038@mimsy.umd.edu> in comp.lang.c , October, 1990." in Rich + * Salz's USENIX 1992 paper about INN which can be found at + * <http://citeseer.nj.nec.com/salz92internetnews.html>. + * + * The magic of number 33, i.e. why it works better than many other + * constants, prime or not, has never been adequately explained by + * anyone. So I try an explanation: if one experimentally tests all + * multipliers between 1 and 256 (as I did while writing a low-level + * data structure library some time ago) one detects that even + * numbers are not useable at all. The remaining 128 odd numbers + * (except for the number 1) work more or less all equally well. + * They all distribute in an acceptable way and this way fill a hash + * table with an average percent of approx. 86%. + * + * If one compares the chi^2 values of the variants (see + * Bob Jenkins ``Hashing Frequently Asked Questions'' at + * http://burtleburtle.net/bob/hash/hashfaq.html for a description + * of chi^2), the number 33 not even has the best value. But the + * number 33 and a few other equally good numbers like 17, 31, 63, + * 127 and 129 have nevertheless a great advantage to the remaining + * numbers in the large set of possible multipliers: their multiply + * operation can be replaced by a faster operation based on just one + * shift plus either a single addition or subtraction operation. And + * because a hash function has to both distribute good _and_ has to + * be very fast to compute, those few numbers should be preferred. + * + * -- Ralf S. Engelschall <rse@engelschall.com> + */ + + if (*klen == APR_HASH_KEY_STRING) { + for (p = key; *p; p++) { + hash = hash * 33 + *p; + } + *klen = p - key; + } + else { + for (p = key, i = *klen; i; i--, p++) { + hash = hash * 33 + *p; + } + } + + return hash; +} + +APR_DECLARE_NONSTD(unsigned int) apr_hashfunc_default(const char *char_key, + apr_ssize_t *klen) +{ + return hashfunc_default(char_key, klen, 0); +} + +/* + * This is where we keep the details of the hash function and control + * the maximum collision rate. + * + * If val is non-NULL it creates and initializes a new hash entry if + * there isn't already one there; it returns an updatable pointer so + * that hash entries can be removed. + */ + +static apr_hash_entry_t **find_entry(apr_hash_t *ht, + const void *key, + apr_ssize_t klen, + const void *val) +{ + apr_hash_entry_t **hep, *he; + unsigned int hash; + + if (ht->hash_func) + hash = ht->hash_func(key, &klen); + else + hash = hashfunc_default(key, &klen, ht->seed); + + /* scan linked list */ + for (hep = &ht->array[hash & ht->max], he = *hep; + he; hep = &he->next, he = *hep) { + if (he->hash == hash + && he->klen == klen + && memcmp(he->key, key, klen) == 0) + break; + } + if (he || !val) + return hep; + + /* add a new entry for non-NULL values */ + if ((he = ht->free) != NULL) + ht->free = he->next; + else + he = apr_palloc(ht->pool, sizeof(*he)); + he->next = NULL; + he->hash = hash; + he->key = key; + he->klen = klen; + he->val = val; + *hep = he; + ht->count++; + return hep; +} + +APR_DECLARE(apr_hash_t *) apr_hash_copy(apr_pool_t *pool, + const apr_hash_t *orig) +{ + apr_hash_t *ht; + apr_hash_entry_t *new_vals; + unsigned int i, j; + + ht = apr_palloc(pool, sizeof(apr_hash_t) + + sizeof(*ht->array) * (orig->max + 1) + + sizeof(apr_hash_entry_t) * orig->count); + ht->pool = pool; + ht->free = NULL; + ht->count = orig->count; + ht->max = orig->max; + ht->seed = orig->seed; + ht->hash_func = orig->hash_func; + ht->array = (apr_hash_entry_t **)((char *)ht + sizeof(apr_hash_t)); + + new_vals = (apr_hash_entry_t *)((char *)(ht) + sizeof(apr_hash_t) + + sizeof(*ht->array) * (orig->max + 1)); + j = 0; + for (i = 0; i <= ht->max; i++) { + apr_hash_entry_t **new_entry = &(ht->array[i]); + apr_hash_entry_t *orig_entry = orig->array[i]; + while (orig_entry) { + *new_entry = &new_vals[j++]; + (*new_entry)->hash = orig_entry->hash; + (*new_entry)->key = orig_entry->key; + (*new_entry)->klen = orig_entry->klen; + (*new_entry)->val = orig_entry->val; + new_entry = &((*new_entry)->next); + orig_entry = orig_entry->next; + } + *new_entry = NULL; + } + return ht; +} + +APR_DECLARE(void *) apr_hash_get(apr_hash_t *ht, + const void *key, + apr_ssize_t klen) +{ + apr_hash_entry_t *he; + he = *find_entry(ht, key, klen, NULL); + if (he) + return (void *)he->val; + else + return NULL; +} + +APR_DECLARE(void) apr_hash_set(apr_hash_t *ht, + const void *key, + apr_ssize_t klen, + const void *val) +{ + apr_hash_entry_t **hep; + hep = find_entry(ht, key, klen, val); + if (*hep) { + if (!val) { + /* delete entry */ + apr_hash_entry_t *old = *hep; + *hep = (*hep)->next; + old->next = ht->free; + ht->free = old; + --ht->count; + } + else { + /* replace entry */ + (*hep)->val = val; + /* check that the collision rate isn't too high */ + if (ht->count > ht->max) { + expand_array(ht); + } + } + } + /* else key not present and val==NULL */ +} + +APR_DECLARE(void *) apr_hash_get_or_set(apr_hash_t *ht, + const void *key, + apr_ssize_t klen, + const void *val) +{ + apr_hash_entry_t **hep; + hep = find_entry(ht, key, klen, val); + if (*hep) { + val = (*hep)->val; + /* check that the collision rate isn't too high */ + if (ht->count > ht->max) { + expand_array(ht); + } + return (void *)val; + } + /* else key not present and val==NULL */ + return NULL; +} + +APR_DECLARE(unsigned int) apr_hash_count(apr_hash_t *ht) +{ + return ht->count; +} + +APR_DECLARE(void) apr_hash_clear(apr_hash_t *ht) +{ + apr_hash_index_t *hi; + for (hi = apr_hash_first(NULL, ht); hi; hi = apr_hash_next(hi)) + apr_hash_set(ht, hi->this->key, hi->this->klen, NULL); +} + +APR_DECLARE(apr_hash_t*) apr_hash_overlay(apr_pool_t *p, + const apr_hash_t *overlay, + const apr_hash_t *base) +{ + return apr_hash_merge(p, overlay, base, NULL, NULL); +} + +APR_DECLARE(apr_hash_t *) apr_hash_merge(apr_pool_t *p, + const apr_hash_t *overlay, + const apr_hash_t *base, + void * (*merger)(apr_pool_t *p, + const void *key, + apr_ssize_t klen, + const void *h1_val, + const void *h2_val, + const void *data), + const void *data) +{ + apr_hash_t *res; + apr_hash_entry_t *new_vals = NULL; + apr_hash_entry_t *iter; + apr_hash_entry_t *ent; + unsigned int i, j, k, hash; + +#if APR_POOL_DEBUG + /* we don't copy keys and values, so it's necessary that + * overlay->a.pool and base->a.pool have a life span at least + * as long as p + */ + if (!apr_pool_is_ancestor(overlay->pool, p)) { + fprintf(stderr, + "apr_hash_merge: overlay's pool is not an ancestor of p\n"); + abort(); + } + if (!apr_pool_is_ancestor(base->pool, p)) { + fprintf(stderr, + "apr_hash_merge: base's pool is not an ancestor of p\n"); + abort(); + } +#endif + + res = apr_palloc(p, sizeof(apr_hash_t)); + res->pool = p; + res->free = NULL; + res->hash_func = base->hash_func; + res->count = base->count; + res->max = (overlay->max > base->max) ? overlay->max : base->max; + if (base->count + overlay->count > res->max) { + res->max = res->max * 2 + 1; + } + res->seed = base->seed; + res->array = alloc_array(res, res->max); + if (base->count + overlay->count) { + new_vals = apr_palloc(p, sizeof(apr_hash_entry_t) * + (base->count + overlay->count)); + } + j = 0; + for (k = 0; k <= base->max; k++) { + for (iter = base->array[k]; iter; iter = iter->next) { + i = iter->hash & res->max; + new_vals[j].klen = iter->klen; + new_vals[j].key = iter->key; + new_vals[j].val = iter->val; + new_vals[j].hash = iter->hash; + new_vals[j].next = res->array[i]; + res->array[i] = &new_vals[j]; + j++; + } + } + + for (k = 0; k <= overlay->max; k++) { + for (iter = overlay->array[k]; iter; iter = iter->next) { + if (res->hash_func) + hash = res->hash_func(iter->key, &iter->klen); + else + hash = hashfunc_default(iter->key, &iter->klen, res->seed); + i = hash & res->max; + for (ent = res->array[i]; ent; ent = ent->next) { + if ((ent->klen == iter->klen) && + (memcmp(ent->key, iter->key, iter->klen) == 0)) { + if (merger) { + ent->val = (*merger)(p, iter->key, iter->klen, + iter->val, ent->val, data); + } + else { + ent->val = iter->val; + } + break; + } + } + if (!ent) { + new_vals[j].klen = iter->klen; + new_vals[j].key = iter->key; + new_vals[j].val = iter->val; + new_vals[j].hash = hash; + new_vals[j].next = res->array[i]; + res->array[i] = &new_vals[j]; + res->count++; + j++; + } + } + } + return res; +} + +/* This is basically the following... + * for every element in hash table { + * comp elemeny.key, element.value + * } + * + * Like with apr_table_do, the comp callback is called for each and every + * element of the hash table. + */ +APR_DECLARE(int) apr_hash_do(apr_hash_do_callback_fn_t *comp, + void *rec, const apr_hash_t *ht) +{ + apr_hash_index_t hix; + apr_hash_index_t *hi; + int rv, dorv = 1; + + hix.ht = (apr_hash_t *)ht; + hix.index = 0; + hix.this = NULL; + hix.next = NULL; + + if ((hi = apr_hash_next(&hix))) { + /* Scan the entire table */ + do { + rv = (*comp)(rec, hi->this->key, hi->this->klen, hi->this->val); + } while (rv && (hi = apr_hash_next(hi))); + + if (rv == 0) { + dorv = 0; + } + } + return dorv; +} + +APR_POOL_IMPLEMENT_ACCESSOR(hash) diff --git a/tables/apr_skiplist.c b/tables/apr_skiplist.c new file mode 100644 index 00000000000..5ea8643dbf2 --- /dev/null +++ b/tables/apr_skiplist.c @@ -0,0 +1,852 @@ +/* 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. + */ + +/* + * Modified to use APR and APR pools. + * TODO: Is malloc() better? Will long running skiplists grow too much? + * Keep the skiplist_alloc() and skiplist_free() until we know + * Yeah, if using pools it means some bogus cycles for checks + * (and an useless function call for skiplist_free) which we + * can removed if/when needed. + */ + +#include "apr_skiplist.h" + +typedef struct { + apr_skiplistnode **data; + size_t size, pos; + apr_pool_t *p; +} apr_skiplist_q; + +struct apr_skiplist { + apr_skiplist_compare compare; + apr_skiplist_compare comparek; + int height; + int preheight; + size_t size; + apr_skiplistnode *top; + apr_skiplistnode *bottom; + /* These two are needed for appending */ + apr_skiplistnode *topend; + apr_skiplistnode *bottomend; + apr_skiplist *index; + apr_array_header_t *memlist; + apr_skiplist_q nodes_q, + stack_q; + apr_pool_t *pool; +}; + +struct apr_skiplistnode { + void *data; + apr_skiplistnode *next; + apr_skiplistnode *prev; + apr_skiplistnode *down; + apr_skiplistnode *up; + apr_skiplistnode *previndex; + apr_skiplistnode *nextindex; + apr_skiplist *sl; +}; + +static int get_b_rand(void) +{ + static int ph = 32; /* More bits than we will ever use */ + static int randseq; + if (ph > 31) { /* Num bits in return of rand() */ + ph = 0; + randseq = rand(); + } + return randseq & (1 << ph++); +} + +typedef struct { + size_t size; + apr_array_header_t *list; +} memlist_t; + +typedef struct { + void *ptr; + char inuse; +} chunk_t; + +APR_DECLARE(void *) apr_skiplist_alloc(apr_skiplist *sl, size_t size) +{ + if (sl->pool) { + void *ptr; + int found_size = 0; + int i; + chunk_t *newchunk; + memlist_t *memlist = (memlist_t *)sl->memlist->elts; + for (i = 0; i < sl->memlist->nelts; i++) { + if (memlist->size == size) { + int j; + chunk_t *chunk = (chunk_t *)memlist->list->elts; + found_size = 1; + for (j = 0; j < memlist->list->nelts; j++) { + if (!chunk->inuse) { + chunk->inuse = 1; + return chunk->ptr; + } + chunk++; + } + break; /* no free of this size; punt */ + } + memlist++; + } + /* no free chunks */ + ptr = apr_palloc(sl->pool, size); + if (!ptr) { + return ptr; + } + /* + * is this a new sized chunk? If so, we need to create a new + * array of them. Otherwise, re-use what we already have. + */ + if (!found_size) { + memlist = apr_array_push(sl->memlist); + memlist->size = size; + memlist->list = apr_array_make(sl->pool, 20, sizeof(chunk_t)); + } + newchunk = apr_array_push(memlist->list); + newchunk->ptr = ptr; + newchunk->inuse = 1; + return ptr; + } + else { + return malloc(size); + } +} + +APR_DECLARE(void) apr_skiplist_free(apr_skiplist *sl, void *mem) +{ + if (!sl->pool) { + free(mem); + } + else { + int i; + memlist_t *memlist = (memlist_t *)sl->memlist->elts; + for (i = 0; i < sl->memlist->nelts; i++) { + int j; + chunk_t *chunk = (chunk_t *)memlist->list->elts; + for (j = 0; j < memlist->list->nelts; j++) { + if (chunk->ptr == mem) { + chunk->inuse = 0; + return; + } + chunk++; + } + memlist++; + } + } +} + +static apr_status_t skiplist_qpush(apr_skiplist_q *q, apr_skiplistnode *m) +{ + if (q->pos >= q->size) { + apr_skiplistnode **data; + size_t size = (q->pos) ? q->pos * 2 : 32; + if (q->p) { + data = apr_palloc(q->p, size * sizeof(*data)); + if (data) { + memcpy(data, q->data, q->pos * sizeof(*data)); + } + } + else { + data = realloc(q->data, size * sizeof(*data)); + } + if (!data) { + return APR_ENOMEM; + } + q->data = data; + q->size = size; + } + q->data[q->pos++] = m; + return APR_SUCCESS; +} + +static APR_INLINE apr_skiplistnode *skiplist_qpop(apr_skiplist_q *q) +{ + return (q->pos > 0) ? q->data[--q->pos] : NULL; +} + +static APR_INLINE void skiplist_qclear(apr_skiplist_q *q) +{ + q->pos = 0; +} + +static apr_skiplistnode *skiplist_new_node(apr_skiplist *sl) +{ + apr_skiplistnode *m = skiplist_qpop(&sl->nodes_q); + if (!m) { + if (sl->pool) { + m = apr_palloc(sl->pool, sizeof *m); + } + else { + m = malloc(sizeof *m); + } + } + return m; +} + +static apr_status_t skiplist_put_node(apr_skiplist *sl, apr_skiplistnode *m) +{ + return skiplist_qpush(&sl->nodes_q, m); +} + +static apr_status_t skiplisti_init(apr_skiplist **s, apr_pool_t *p) +{ + apr_skiplist *sl; + if (p) { + sl = apr_pcalloc(p, sizeof(apr_skiplist)); + sl->memlist = apr_array_make(p, 20, sizeof(memlist_t)); + sl->pool = sl->nodes_q.p = sl->stack_q.p = p; + } + else { + sl = calloc(1, sizeof(apr_skiplist)); + if (!sl) { + return APR_ENOMEM; + } + } + *s = sl; + return APR_SUCCESS; +} + +static int indexing_comp(void *a, void *b) +{ + void *ac = (void *) (((apr_skiplist *) a)->compare); + void *bc = (void *) (((apr_skiplist *) b)->compare); + return ((ac < bc) ? -1 : ((ac > bc) ? 1 : 0)); +} + +static int indexing_compk(void *ac, void *b) +{ + void *bc = (void *) (((apr_skiplist *) b)->compare); + return ((ac < bc) ? -1 : ((ac > bc) ? 1 : 0)); +} + +APR_DECLARE(apr_status_t) apr_skiplist_init(apr_skiplist **s, apr_pool_t *p) +{ + apr_skiplist *sl; + skiplisti_init(s, p); + sl = *s; + skiplisti_init(&(sl->index), p); + apr_skiplist_set_compare(sl->index, indexing_comp, indexing_compk); + return APR_SUCCESS; +} + +APR_DECLARE(void) apr_skiplist_set_compare(apr_skiplist *sl, + apr_skiplist_compare comp, + apr_skiplist_compare compk) +{ + if (sl->compare && sl->comparek) { + apr_skiplist_add_index(sl, comp, compk); + } + else { + sl->compare = comp; + sl->comparek = compk; + } +} + +APR_DECLARE(void) apr_skiplist_add_index(apr_skiplist *sl, + apr_skiplist_compare comp, + apr_skiplist_compare compk) +{ + apr_skiplistnode *m; + apr_skiplist *ni; + int icount = 0; + apr_skiplist_find(sl->index, (void *)comp, &m); + if (m) { + return; /* Index already there! */ + } + skiplisti_init(&ni, sl->pool); + apr_skiplist_set_compare(ni, comp, compk); + /* Build the new index... This can be expensive! */ + m = apr_skiplist_insert(sl->index, ni); + while (m->prev) { + m = m->prev; + icount++; + } + for (m = apr_skiplist_getlist(sl); m; apr_skiplist_next(sl, &m)) { + int j = icount - 1; + apr_skiplistnode *nsln; + nsln = apr_skiplist_insert(ni, m->data); + /* skip from main index down list */ + while (j > 0) { + m = m->nextindex; + j--; + } + /* insert this node in the indexlist after m */ + nsln->nextindex = m->nextindex; + if (m->nextindex) { + m->nextindex->previndex = nsln; + } + nsln->previndex = m; + m->nextindex = nsln; + } +} + +static int skiplisti_find_compare(apr_skiplist *sl, void *data, + apr_skiplistnode **ret, + apr_skiplist_compare comp, + int last) +{ + int count = 0; + apr_skiplistnode *m, *found = NULL; + for (m = sl->top; m; count++) { + if (m->next) { + int compared = comp(data, m->next->data); + if (compared == 0) { + found = m = m->next; + if (!last) { + break; + } + continue; + } + if (compared > 0) { + m = m->next; + continue; + } + } + m = m->down; + } + if (found) { + while (found->down) { + found = found->down; + } + *ret = found; + } + else { + *ret = NULL; + } + return count; +} + +static void *find_compare(apr_skiplist *sli, void *data, + apr_skiplistnode **iter, + apr_skiplist_compare comp, + int last) +{ + apr_skiplistnode *m; + apr_skiplist *sl; + if (!comp) { + if (iter) { + *iter = NULL; + } + return NULL; + } + if (comp == sli->compare || !sli->index) { + sl = sli; + } + else { + apr_skiplist_find(sli->index, (void *)comp, &m); + if (!m) { + if (iter) { + *iter = NULL; + } + return NULL; + } + sl = (apr_skiplist *) m->data; + } + skiplisti_find_compare(sl, data, &m, sl->comparek, last); + if (iter) { + *iter = m; + } + return (m) ? m->data : NULL; +} + +APR_DECLARE(void *) apr_skiplist_find_compare(apr_skiplist *sl, void *data, + apr_skiplistnode **iter, + apr_skiplist_compare comp) +{ + return find_compare(sl, data, iter, comp, 0); +} + +APR_DECLARE(void *) apr_skiplist_find(apr_skiplist *sl, void *data, apr_skiplistnode **iter) +{ + return find_compare(sl, data, iter, sl->compare, 0); +} + +APR_DECLARE(void *) apr_skiplist_last_compare(apr_skiplist *sl, void *data, + apr_skiplistnode **iter, + apr_skiplist_compare comp) +{ + return find_compare(sl, data, iter, comp, 1); +} + +APR_DECLARE(void *) apr_skiplist_last(apr_skiplist *sl, void *data, + apr_skiplistnode **iter) +{ + return find_compare(sl, data, iter, sl->compare, 1); +} + + +APR_DECLARE(apr_skiplistnode *) apr_skiplist_getlist(apr_skiplist *sl) +{ + if (!sl->bottom) { + return NULL; + } + return sl->bottom->next; +} + +APR_DECLARE(void *) apr_skiplist_next(apr_skiplist *sl, apr_skiplistnode **iter) +{ + if (!*iter) { + return NULL; + } + *iter = (*iter)->next; + return (*iter) ? ((*iter)->data) : NULL; +} + +APR_DECLARE(void *) apr_skiplist_previous(apr_skiplist *sl, apr_skiplistnode **iter) +{ + if (!*iter) { + return NULL; + } + *iter = (*iter)->prev; + return (*iter) ? ((*iter)->data) : NULL; +} + +APR_DECLARE(void *) apr_skiplist_element(apr_skiplistnode *iter) +{ + return (iter) ? iter->data : NULL; +} + +/* forward declared */ +static int skiplisti_remove(apr_skiplist *sl, apr_skiplistnode *m, + apr_skiplist_freefunc myfree); + +static APR_INLINE int skiplist_height(const apr_skiplist *sl) +{ + /* Skiplists (even empty) always have a top node, although this + * implementation defers its creation until the first insert, or + * deletes it with the last remove. We want the real height here. + */ + return sl->height ? sl->height : 1; +} + +static apr_skiplistnode *insert_compare(apr_skiplist *sl, void *data, + apr_skiplist_compare comp, int add, + apr_skiplist_freefunc myfree) +{ + apr_skiplistnode *m, *p, *tmp, *ret = NULL; + int ch, top_nh, nh = 1; + + ch = skiplist_height(sl); + if (sl->preheight) { + while (nh < sl->preheight && get_b_rand()) { + nh++; + } + } + else { + while (nh <= ch && get_b_rand()) { + nh++; + } + } + top_nh = nh; + + /* Now we have in nh the height at which we wish to insert our new node, + * and in ch the current height: don't create skip paths to the inserted + * element until the walk down through the tree (which decrements ch) + * reaches nh. From there, any walk down pushes the current node on a + * stack (the node(s) after which we would insert) to pop back through + * for insertion later. + */ + m = sl->top; + while (m) { + /* + * To maintain stability, dups (compared == 0) must be added + * AFTER each other. + */ + if (m->next) { + int compared = comp(data, m->next->data); + if (compared == 0) { + if (!add) { + /* Keep the existing element(s) */ + skiplist_qclear(&sl->stack_q); + return NULL; + } + if (add < 0) { + /* Remove this element and continue with the next node + * or the new top if the current one is also removed. + */ + apr_skiplistnode *top = sl->top; + skiplisti_remove(sl, m->next, myfree); + if (top != sl->top) { + m = sl->top; + skiplist_qclear(&sl->stack_q); + ch = skiplist_height(sl); + nh = top_nh; + } + continue; + } + } + if (compared >= 0) { + m = m->next; + continue; + } + } + if (ch <= nh) { + /* push on stack */ + skiplist_qpush(&sl->stack_q, m); + } + m = m->down; + ch--; + } + /* Pop the stack and insert nodes */ + p = NULL; + while ((m = skiplist_qpop(&sl->stack_q))) { + tmp = skiplist_new_node(sl); + tmp->next = m->next; + if (m->next) { + m->next->prev = tmp; + } + m->next = tmp; + tmp->prev = m; + tmp->up = NULL; + tmp->nextindex = tmp->previndex = NULL; + tmp->down = p; + if (p) { + p->up = tmp; + } + else { + /* This sets ret to the bottom-most node we are inserting */ + ret = tmp; + } + tmp->data = data; + tmp->sl = sl; + p = tmp; + } + + /* Now we are sure the node is inserted, grow our tree to 'nh' tall */ + for (; sl->height < nh; sl->height++) { + m = skiplist_new_node(sl); + tmp = skiplist_new_node(sl); + m->up = m->prev = m->nextindex = m->previndex = NULL; + m->next = tmp; + m->down = sl->top; + m->data = NULL; + m->sl = sl; + if (sl->top) { + sl->top->up = m; + } + else { + sl->bottom = sl->bottomend = m; + } + sl->top = sl->topend = tmp->prev = m; + tmp->up = tmp->next = tmp->nextindex = tmp->previndex = NULL; + tmp->down = p; + tmp->data = data; + tmp->sl = sl; + if (p) { + p->up = tmp; + } + else { + /* This sets ret to the bottom-most node we are inserting */ + ret = tmp; + } + p = tmp; + } + if (sl->index != NULL) { + /* + * this is a external insertion, we must insert into each index as + * well + */ + apr_skiplistnode *ni, *li; + li = ret; + for (p = apr_skiplist_getlist(sl->index); p; apr_skiplist_next(sl->index, &p)) { + apr_skiplist *sli = (apr_skiplist *)p->data; + ni = insert_compare(sli, ret->data, sli->compare, 1, NULL); + li->nextindex = ni; + ni->previndex = li; + li = ni; + } + } + sl->size++; + return ret; +} + +APR_DECLARE(apr_skiplistnode *) apr_skiplist_insert_compare(apr_skiplist *sl, void *data, + apr_skiplist_compare comp) +{ + if (!comp) { + return NULL; + } + return insert_compare(sl, data, comp, 0, NULL); +} + +APR_DECLARE(apr_skiplistnode *) apr_skiplist_insert(apr_skiplist *sl, void *data) +{ + return apr_skiplist_insert_compare(sl, data, sl->compare); +} + +APR_DECLARE(apr_skiplistnode *) apr_skiplist_add_compare(apr_skiplist *sl, void *data, + apr_skiplist_compare comp) +{ + if (!comp) { + return NULL; + } + return insert_compare(sl, data, comp, 1, NULL); +} + +APR_DECLARE(apr_skiplistnode *) apr_skiplist_add(apr_skiplist *sl, void *data) +{ + return apr_skiplist_add_compare(sl, data, sl->compare); +} + +APR_DECLARE(apr_skiplistnode *) apr_skiplist_replace_compare(apr_skiplist *sl, + void *data, apr_skiplist_freefunc myfree, + apr_skiplist_compare comp) +{ + if (!comp) { + return NULL; + } + return insert_compare(sl, data, comp, -1, myfree); +} + +APR_DECLARE(apr_skiplistnode *) apr_skiplist_replace(apr_skiplist *sl, + void *data, apr_skiplist_freefunc myfree) +{ + return apr_skiplist_replace_compare(sl, data, myfree, sl->compare); +} + +#if 0 +void skiplist_print_struct(apr_skiplist * sl, char *prefix) +{ + apr_skiplistnode *p, *q; + fprintf(stderr, "Skiplist Structure (height: %d)\n", sl->height); + p = sl->bottom; + while (p) { + q = p; + fprintf(stderr, prefix); + while (q) { + fprintf(stderr, "%p ", q->data); + q = q->up; + } + fprintf(stderr, "\n"); + p = p->next; + } +} +#endif + +static int skiplisti_remove(apr_skiplist *sl, apr_skiplistnode *m, + apr_skiplist_freefunc myfree) +{ + apr_skiplistnode *p; + if (!m) { + return 0; + } + if (m->nextindex) { + skiplisti_remove(m->nextindex->sl, m->nextindex, NULL); + } + while (m->up) { + m = m->up; + } + do { + p = m; + /* take me out of the list */ + p->prev->next = p->next; + if (p->next) { + p->next->prev = p->prev; + } + m = m->down; + /* This only frees the actual data in the bottom one */ + if (!m && myfree && p->data) { + myfree(p->data); + } + skiplist_put_node(sl, p); + } while (m); + sl->size--; + while (sl->top && sl->top->next == NULL) { + /* While the row is empty and we are not on the bottom row */ + p = sl->top; + sl->top = sl->top->down;/* Move top down one */ + if (sl->top) { + sl->top->up = NULL; /* Make it think its the top */ + } + skiplist_put_node(sl, p); + sl->height--; + } + if (!sl->top) { + sl->bottom = sl->bottomend = NULL; + sl->topend = NULL; + } + return skiplist_height(sl); +} + +APR_DECLARE(int) apr_skiplist_remove_node(apr_skiplist *sl, + apr_skiplistnode *iter, + apr_skiplist_freefunc myfree) +{ + apr_skiplistnode *m = iter; + if (!m) { + return 0; + } + while (m->down) { + m = m->down; + } + while (m->previndex) { + m = m->previndex; + } + return skiplisti_remove(sl, m, myfree); +} + +APR_DECLARE(int) apr_skiplist_remove_compare(apr_skiplist *sli, + void *data, + apr_skiplist_freefunc myfree, apr_skiplist_compare comp) +{ + apr_skiplistnode *m; + apr_skiplist *sl; + if (!comp) { + return 0; + } + if (comp == sli->comparek || !sli->index) { + sl = sli; + } + else { + apr_skiplist_find(sli->index, (void *)comp, &m); + if (!m) { + return 0; + } + sl = (apr_skiplist *) m->data; + } + skiplisti_find_compare(sl, data, &m, comp, 0); + if (!m) { + return 0; + } + while (m->previndex) { + m = m->previndex; + } + return skiplisti_remove(sl, m, myfree); +} + +APR_DECLARE(int) apr_skiplist_remove(apr_skiplist *sl, void *data, apr_skiplist_freefunc myfree) +{ + return apr_skiplist_remove_compare(sl, data, myfree, sl->comparek); +} + +APR_DECLARE(void) apr_skiplist_remove_all(apr_skiplist *sl, apr_skiplist_freefunc myfree) +{ + /* + * This must remove even the place holder nodes (bottom though top) + * because we specify in the API that one can free the Skiplist after + * making this call without memory leaks + */ + apr_skiplistnode *m, *p, *u; + m = sl->bottom; + while (m) { + p = m->next; + if (myfree && p && p->data) { + myfree(p->data); + } + do { + u = m->up; + skiplist_put_node(sl, m); + m = u; + } while (m); + m = p; + } + sl->top = sl->bottom = NULL; + sl->topend = sl->bottomend = NULL; + sl->height = 0; + sl->size = 0; +} + +APR_DECLARE(void *) apr_skiplist_pop(apr_skiplist *a, apr_skiplist_freefunc myfree) +{ + apr_skiplistnode *sln; + void *data = NULL; + sln = apr_skiplist_getlist(a); + if (sln) { + data = sln->data; + skiplisti_remove(a, sln, myfree); + } + return data; +} + +APR_DECLARE(void *) apr_skiplist_peek(apr_skiplist *a) +{ + apr_skiplistnode *sln; + sln = apr_skiplist_getlist(a); + if (sln) { + return sln->data; + } + return NULL; +} + +APR_DECLARE(size_t) apr_skiplist_size(const apr_skiplist *sl) +{ + return sl->size; +} + +APR_DECLARE(int) apr_skiplist_height(const apr_skiplist *sl) +{ + return skiplist_height(sl); +} + +APR_DECLARE(int) apr_skiplist_preheight(const apr_skiplist *sl) +{ + return sl->preheight; +} + +APR_DECLARE(void) apr_skiplist_set_preheight(apr_skiplist *sl, int to) +{ + sl->preheight = (to > 0) ? to : 0; +} + +static void skiplisti_destroy(void *vsl) +{ + apr_skiplist_destroy(vsl, NULL); +} + +APR_DECLARE(void) apr_skiplist_destroy(apr_skiplist *sl, apr_skiplist_freefunc myfree) +{ + while (apr_skiplist_pop(sl->index, skiplisti_destroy) != NULL) + ; + apr_skiplist_remove_all(sl, myfree); + if (!sl->pool) { + while (sl->nodes_q.pos) + free(sl->nodes_q.data[--sl->nodes_q.pos]); + free(sl->nodes_q.data); + free(sl->stack_q.data); + free(sl); + } +} + +APR_DECLARE(apr_skiplist *) apr_skiplist_merge(apr_skiplist *sl1, apr_skiplist *sl2) +{ + /* Check integrity! */ + apr_skiplist temp; + struct apr_skiplistnode *b2; + if (sl1->bottomend == NULL || sl1->bottomend->prev == NULL) { + apr_skiplist_remove_all(sl1, NULL); + temp = *sl1; + *sl1 = *sl2; + *sl2 = temp; + /* swap them so that sl2 can be freed normally upon return. */ + return sl1; + } + if(sl2->bottom == NULL || sl2->bottom->next == NULL) { + apr_skiplist_remove_all(sl2, NULL); + return sl1; + } + /* This is what makes it brute force... Just insert :/ */ + b2 = apr_skiplist_getlist(sl2); + while (b2) { + apr_skiplist_insert(sl1, b2->data); + apr_skiplist_next(sl2, &b2); + } + apr_skiplist_remove_all(sl2, NULL); + return sl1; +} diff --git a/tables/apr_tables.c b/tables/apr_tables.c new file mode 100644 index 00000000000..6d9aff88168 --- /dev/null +++ b/tables/apr_tables.c @@ -0,0 +1,1300 @@ +/* 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. + */ + +/* + * Resource allocation code... the code here is responsible for making + * sure that nothing leaks. + * + * rst --- 4/95 --- 6/95 + */ + +#include "apr_private.h" + +#include "apr_general.h" +#include "apr_pools.h" +#include "apr_tables.h" +#include "apr_strings.h" +#include "apr_lib.h" +#if APR_HAVE_STDLIB_H +#include <stdlib.h> +#endif +#if APR_HAVE_STRING_H +#include <string.h> +#endif +#if APR_HAVE_STRINGS_H +#include <strings.h> +#endif + +#if (APR_POOL_DEBUG || defined(MAKE_TABLE_PROFILE)) && APR_HAVE_STDIO_H +#include <stdio.h> +#endif + +/***************************************************************** + * This file contains array and apr_table_t functions only. + */ + +/***************************************************************** + * + * The 'array' functions... + */ + +static void make_array_core(apr_array_header_t *res, apr_pool_t *p, + int nelts, int elt_size, int clear) +{ + /* + * Assure sanity if someone asks for + * array of zero elts. + */ + if (nelts < 1) { + nelts = 1; + } + + if (clear) { + res->elts = apr_pcalloc(p, nelts * elt_size); + } + else { + res->elts = apr_palloc(p, nelts * elt_size); + } + + res->pool = p; + res->elt_size = elt_size; + res->nelts = 0; /* No active elements yet... */ + res->nalloc = nelts; /* ...but this many allocated */ +} + +APR_DECLARE(int) apr_is_empty_array(const apr_array_header_t *a) +{ + return ((a == NULL) || (a->nelts == 0)); +} + +APR_DECLARE(apr_array_header_t *) apr_array_make(apr_pool_t *p, + int nelts, int elt_size) +{ + apr_array_header_t *res; + + res = (apr_array_header_t *) apr_palloc(p, sizeof(apr_array_header_t)); + make_array_core(res, p, nelts, elt_size, 1); + return res; +} + +APR_DECLARE(void) apr_array_clear(apr_array_header_t *arr) +{ + arr->nelts = 0; +} + +APR_DECLARE(void *) apr_array_pop(apr_array_header_t *arr) +{ + if (apr_is_empty_array(arr)) { + return NULL; + } + + return arr->elts + (arr->elt_size * (--arr->nelts)); +} + +APR_DECLARE(void *) apr_array_push(apr_array_header_t *arr) +{ + if (arr->nelts == arr->nalloc) { + int new_size = (arr->nalloc <= 0) ? 1 : arr->nalloc * 2; + char *new_data; + + new_data = apr_palloc(arr->pool, arr->elt_size * new_size); + + memcpy(new_data, arr->elts, arr->nalloc * arr->elt_size); + memset(new_data + arr->nalloc * arr->elt_size, 0, + arr->elt_size * (new_size - arr->nalloc)); + arr->elts = new_data; + arr->nalloc = new_size; + } + + ++arr->nelts; + return arr->elts + (arr->elt_size * (arr->nelts - 1)); +} + +static void *apr_array_push_noclear(apr_array_header_t *arr) +{ + if (arr->nelts == arr->nalloc) { + int new_size = (arr->nalloc <= 0) ? 1 : arr->nalloc * 2; + char *new_data; + + new_data = apr_palloc(arr->pool, arr->elt_size * new_size); + + memcpy(new_data, arr->elts, arr->nalloc * arr->elt_size); + arr->elts = new_data; + arr->nalloc = new_size; + } + + ++arr->nelts; + return arr->elts + (arr->elt_size * (arr->nelts - 1)); +} + +APR_DECLARE(void) apr_array_cat(apr_array_header_t *dst, + const apr_array_header_t *src) +{ + int elt_size = dst->elt_size; + + if (dst->nelts + src->nelts > dst->nalloc) { + int new_size = (dst->nalloc <= 0) ? 1 : dst->nalloc * 2; + char *new_data; + + while (dst->nelts + src->nelts > new_size) { + new_size *= 2; + } + + new_data = apr_pcalloc(dst->pool, elt_size * new_size); + memcpy(new_data, dst->elts, dst->nalloc * elt_size); + + dst->elts = new_data; + dst->nalloc = new_size; + } + + memcpy(dst->elts + dst->nelts * elt_size, src->elts, + elt_size * src->nelts); + dst->nelts += src->nelts; +} + +APR_DECLARE(apr_array_header_t *) apr_array_copy(apr_pool_t *p, + const apr_array_header_t *arr) +{ + apr_array_header_t *res = + (apr_array_header_t *) apr_palloc(p, sizeof(apr_array_header_t)); + make_array_core(res, p, arr->nalloc, arr->elt_size, 0); + + memcpy(res->elts, arr->elts, arr->elt_size * arr->nelts); + res->nelts = arr->nelts; + memset(res->elts + res->elt_size * res->nelts, 0, + res->elt_size * (res->nalloc - res->nelts)); + return res; +} + +/* This cute function copies the array header *only*, but arranges + * for the data section to be copied on the first push or arraycat. + * It's useful when the elements of the array being copied are + * read only, but new stuff *might* get added on the end; we have the + * overhead of the full copy only where it is really needed. + */ + +static APR_INLINE void copy_array_hdr_core(apr_array_header_t *res, + const apr_array_header_t *arr) +{ + res->elts = arr->elts; + res->elt_size = arr->elt_size; + res->nelts = arr->nelts; + res->nalloc = arr->nelts; /* Force overflow on push */ +} + +APR_DECLARE(apr_array_header_t *) + apr_array_copy_hdr(apr_pool_t *p, + const apr_array_header_t *arr) +{ + apr_array_header_t *res; + + res = (apr_array_header_t *) apr_palloc(p, sizeof(apr_array_header_t)); + res->pool = p; + copy_array_hdr_core(res, arr); + return res; +} + +/* The above is used here to avoid consing multiple new array bodies... */ + +APR_DECLARE(apr_array_header_t *) + apr_array_append(apr_pool_t *p, + const apr_array_header_t *first, + const apr_array_header_t *second) +{ + apr_array_header_t *res = apr_array_copy_hdr(p, first); + + apr_array_cat(res, second); + return res; +} + +/* apr_array_pstrcat generates a new string from the apr_pool_t containing + * the concatenated sequence of substrings referenced as elements within + * the array. The string will be empty if all substrings are empty or null, + * or if there are no elements in the array. + * If sep is non-NUL, it will be inserted between elements as a separator. + */ +APR_DECLARE(char *) apr_array_pstrcat(apr_pool_t *p, + const apr_array_header_t *arr, + const char sep) +{ + char *cp, *res, **strpp; + apr_size_t len; + int i; + + if (arr->nelts <= 0 || arr->elts == NULL) { /* Empty table? */ + return (char *) apr_pcalloc(p, 1); + } + + /* Pass one --- find length of required string */ + + len = 0; + for (i = 0, strpp = (char **) arr->elts; ; ++strpp) { + if (strpp && *strpp != NULL) { + len += strlen(*strpp); + } + if (++i >= arr->nelts) { + break; + } + if (sep) { + ++len; + } + } + + /* Allocate the required string */ + + res = (char *) apr_palloc(p, len + 1); + cp = res; + + /* Pass two --- copy the argument strings into the result space */ + + for (i = 0, strpp = (char **) arr->elts; ; ++strpp) { + if (strpp && *strpp != NULL) { + len = strlen(*strpp); + memcpy(cp, *strpp, len); + cp += len; + } + if (++i >= arr->nelts) { + break; + } + if (sep) { + *cp++ = sep; + } + } + + *cp = '\0'; + + /* Return the result string */ + + return res; +} + + +/***************************************************************** + * + * The "table" functions. + */ + +#if APR_CHARSET_EBCDIC +#define CASE_MASK 0xbfbfbfbf +#else +#define CASE_MASK 0xdfdfdfdf +#endif + +#define TABLE_HASH_SIZE 32 +#define TABLE_INDEX_MASK 0x1f +#define TABLE_HASH(key) (TABLE_INDEX_MASK & *(unsigned char *)(key)) +#define TABLE_INDEX_IS_INITIALIZED(t, i) ((t)->index_initialized & (1 << (i))) +#define TABLE_SET_INDEX_INITIALIZED(t, i) ((t)->index_initialized |= (1 << (i))) + +/* Compute the "checksum" for a key, consisting of the first + * 4 bytes, normalized for case-insensitivity and packed into + * an int...this checksum allows us to do a single integer + * comparison as a fast check to determine whether we can + * skip a strcasecmp + */ +#define COMPUTE_KEY_CHECKSUM(key, checksum) \ +{ \ + const char *k = (key); \ + apr_uint32_t c = (apr_uint32_t)*k; \ + (checksum) = c; \ + (checksum) <<= 8; \ + if (c) { \ + c = (apr_uint32_t)*++k; \ + checksum |= c; \ + } \ + (checksum) <<= 8; \ + if (c) { \ + c = (apr_uint32_t)*++k; \ + checksum |= c; \ + } \ + (checksum) <<= 8; \ + if (c) { \ + c = (apr_uint32_t)*++k; \ + checksum |= c; \ + } \ + checksum &= CASE_MASK; \ +} + +/** The opaque string-content table type */ +struct apr_table_t { + /* This has to be first to promote backwards compatibility with + * older modules which cast a apr_table_t * to an apr_array_header_t *... + * they should use the apr_table_elts() function for most of the + * cases they do this for. + */ + /** The underlying array for the table */ + apr_array_header_t a; +#ifdef MAKE_TABLE_PROFILE + /** Who created the array. */ + void *creator; +#endif + /* An index to speed up table lookups. The way this works is: + * - Hash the key into the index: + * - index_first[TABLE_HASH(key)] is the offset within + * the table of the first entry with that key + * - index_last[TABLE_HASH(key)] is the offset within + * the table of the last entry with that key + * - If (and only if) there is no entry in the table whose + * key hashes to index element i, then the i'th bit + * of index_initialized will be zero. (Check this before + * trying to use index_first[i] or index_last[i]!) + */ + apr_uint32_t index_initialized; + int index_first[TABLE_HASH_SIZE]; + int index_last[TABLE_HASH_SIZE]; +}; + +/* keep state for apr_table_getm() */ +typedef struct +{ + apr_pool_t *p; + const char *first; + apr_array_header_t *merged; +} table_getm_t; + +/* + * NOTICE: if you tweak this you should look at is_empty_table() + * and table_elts() in alloc.h + */ +#ifdef MAKE_TABLE_PROFILE +static apr_table_entry_t *do_table_push(const char *func, apr_table_t *t) +{ + if (t->a.nelts == t->a.nalloc) { + fprintf(stderr, "%s: table created by %p hit limit of %u\n", + func ? func : "table_push", t->creator, t->a.nalloc); + } + return (apr_table_entry_t *) apr_array_push_noclear(&t->a); +} +#if defined(__GNUC__) && __GNUC__ >= 2 +#define table_push(t) do_table_push(__FUNCTION__, t) +#else +#define table_push(t) do_table_push(NULL, t) +#endif +#else /* MAKE_TABLE_PROFILE */ +#define table_push(t) ((apr_table_entry_t *) apr_array_push_noclear(&(t)->a)) +#endif /* MAKE_TABLE_PROFILE */ + +APR_DECLARE(const apr_array_header_t *) apr_table_elts(const apr_table_t *t) +{ + return (const apr_array_header_t *)t; +} + +APR_DECLARE(int) apr_is_empty_table(const apr_table_t *t) +{ + return ((t == NULL) || (t->a.nelts == 0)); +} + +APR_DECLARE(apr_table_t *) apr_table_make(apr_pool_t *p, int nelts) +{ + apr_table_t *t = apr_palloc(p, sizeof(apr_table_t)); + + make_array_core(&t->a, p, nelts, sizeof(apr_table_entry_t), 0); +#ifdef MAKE_TABLE_PROFILE + t->creator = __builtin_return_address(0); +#endif + t->index_initialized = 0; + return t; +} + +APR_DECLARE(apr_table_t *) apr_table_copy(apr_pool_t *p, const apr_table_t *t) +{ + apr_table_t *new = apr_palloc(p, sizeof(apr_table_t)); + +#if APR_POOL_DEBUG + /* we don't copy keys and values, so it's necessary that t->a.pool + * have a life span at least as long as p + */ + if (!apr_pool_is_ancestor(t->a.pool, p)) { + fprintf(stderr, "apr_table_copy: t's pool is not an ancestor of p\n"); + abort(); + } +#endif + make_array_core(&new->a, p, t->a.nalloc, sizeof(apr_table_entry_t), 0); + memcpy(new->a.elts, t->a.elts, t->a.nelts * sizeof(apr_table_entry_t)); + new->a.nelts = t->a.nelts; + memcpy(new->index_first, t->index_first, sizeof(int) * TABLE_HASH_SIZE); + memcpy(new->index_last, t->index_last, sizeof(int) * TABLE_HASH_SIZE); + new->index_initialized = t->index_initialized; + return new; +} + +APR_DECLARE(apr_table_t *) apr_table_clone(apr_pool_t *p, const apr_table_t *t) +{ + const apr_array_header_t *array = apr_table_elts(t); + apr_table_entry_t *elts = (apr_table_entry_t *) array->elts; + apr_table_t *new = apr_table_make(p, array->nelts); + int i; + + for (i = 0; i < array->nelts; i++) { + apr_table_add(new, elts[i].key, elts[i].val); + } + + return new; +} + +static void table_reindex(apr_table_t *t) +{ + int i; + int hash; + apr_table_entry_t *next_elt = (apr_table_entry_t *) t->a.elts; + + t->index_initialized = 0; + for (i = 0; i < t->a.nelts; i++, next_elt++) { + hash = TABLE_HASH(next_elt->key); + t->index_last[hash] = i; + if (!TABLE_INDEX_IS_INITIALIZED(t, hash)) { + t->index_first[hash] = i; + TABLE_SET_INDEX_INITIALIZED(t, hash); + } + } +} + +APR_DECLARE(void) apr_table_clear(apr_table_t *t) +{ + t->a.nelts = 0; + t->index_initialized = 0; +} + +APR_DECLARE(const char *) apr_table_get(const apr_table_t *t, const char *key) +{ + apr_table_entry_t *next_elt; + apr_table_entry_t *end_elt; + apr_uint32_t checksum; + int hash; + + if (key == NULL) { + return NULL; + } + + hash = TABLE_HASH(key); + if (!TABLE_INDEX_IS_INITIALIZED(t, hash)) { + return NULL; + } + COMPUTE_KEY_CHECKSUM(key, checksum); + next_elt = ((apr_table_entry_t *) t->a.elts) + t->index_first[hash];; + end_elt = ((apr_table_entry_t *) t->a.elts) + t->index_last[hash]; + + for (; next_elt <= end_elt; next_elt++) { + if ((checksum == next_elt->key_checksum) && + !strcasecmp(next_elt->key, key)) { + return next_elt->val; + } + } + + return NULL; +} + +APR_DECLARE(void) apr_table_set(apr_table_t *t, const char *key, + const char *val) +{ + apr_table_entry_t *next_elt; + apr_table_entry_t *end_elt; + apr_table_entry_t *table_end; + apr_uint32_t checksum; + int hash; + + COMPUTE_KEY_CHECKSUM(key, checksum); + hash = TABLE_HASH(key); + if (!TABLE_INDEX_IS_INITIALIZED(t, hash)) { + t->index_first[hash] = t->a.nelts; + TABLE_SET_INDEX_INITIALIZED(t, hash); + goto add_new_elt; + } + next_elt = ((apr_table_entry_t *) t->a.elts) + t->index_first[hash];; + end_elt = ((apr_table_entry_t *) t->a.elts) + t->index_last[hash]; + table_end =((apr_table_entry_t *) t->a.elts) + t->a.nelts; + + for (; next_elt <= end_elt; next_elt++) { + if ((checksum == next_elt->key_checksum) && + !strcasecmp(next_elt->key, key)) { + + /* Found an existing entry with the same key, so overwrite it */ + + int must_reindex = 0; + apr_table_entry_t *dst_elt = NULL; + + next_elt->val = apr_pstrdup(t->a.pool, val); + + /* Remove any other instances of this key */ + for (next_elt++; next_elt <= end_elt; next_elt++) { + if ((checksum == next_elt->key_checksum) && + !strcasecmp(next_elt->key, key)) { + t->a.nelts--; + if (!dst_elt) { + dst_elt = next_elt; + } + } + else if (dst_elt) { + *dst_elt++ = *next_elt; + must_reindex = 1; + } + } + + /* If we've removed anything, shift over the remainder + * of the table (note that the previous loop didn't + * run to the end of the table, just to the last match + * for the index) + */ + if (dst_elt) { + for (; next_elt < table_end; next_elt++) { + *dst_elt++ = *next_elt; + } + must_reindex = 1; + } + if (must_reindex) { + table_reindex(t); + } + return; + } + } + +add_new_elt: + t->index_last[hash] = t->a.nelts; + next_elt = (apr_table_entry_t *) table_push(t); + next_elt->key = apr_pstrdup(t->a.pool, key); + next_elt->val = apr_pstrdup(t->a.pool, val); + next_elt->key_checksum = checksum; +} + +APR_DECLARE(void) apr_table_setn(apr_table_t *t, const char *key, + const char *val) +{ + apr_table_entry_t *next_elt; + apr_table_entry_t *end_elt; + apr_table_entry_t *table_end; + apr_uint32_t checksum; + int hash; + + COMPUTE_KEY_CHECKSUM(key, checksum); + hash = TABLE_HASH(key); + if (!TABLE_INDEX_IS_INITIALIZED(t, hash)) { + t->index_first[hash] = t->a.nelts; + TABLE_SET_INDEX_INITIALIZED(t, hash); + goto add_new_elt; + } + next_elt = ((apr_table_entry_t *) t->a.elts) + t->index_first[hash];; + end_elt = ((apr_table_entry_t *) t->a.elts) + t->index_last[hash]; + table_end =((apr_table_entry_t *) t->a.elts) + t->a.nelts; + + for (; next_elt <= end_elt; next_elt++) { + if ((checksum == next_elt->key_checksum) && + !strcasecmp(next_elt->key, key)) { + + /* Found an existing entry with the same key, so overwrite it */ + + int must_reindex = 0; + apr_table_entry_t *dst_elt = NULL; + + next_elt->val = (char *)val; + + /* Remove any other instances of this key */ + for (next_elt++; next_elt <= end_elt; next_elt++) { + if ((checksum == next_elt->key_checksum) && + !strcasecmp(next_elt->key, key)) { + t->a.nelts--; + if (!dst_elt) { + dst_elt = next_elt; + } + } + else if (dst_elt) { + *dst_elt++ = *next_elt; + must_reindex = 1; + } + } + + /* If we've removed anything, shift over the remainder + * of the table (note that the previous loop didn't + * run to the end of the table, just to the last match + * for the index) + */ + if (dst_elt) { + for (; next_elt < table_end; next_elt++) { + *dst_elt++ = *next_elt; + } + must_reindex = 1; + } + if (must_reindex) { + table_reindex(t); + } + return; + } + } + +add_new_elt: + t->index_last[hash] = t->a.nelts; + next_elt = (apr_table_entry_t *) table_push(t); + next_elt->key = (char *)key; + next_elt->val = (char *)val; + next_elt->key_checksum = checksum; +} + +APR_DECLARE(void) apr_table_unset(apr_table_t *t, const char *key) +{ + apr_table_entry_t *next_elt; + apr_table_entry_t *end_elt; + apr_table_entry_t *dst_elt; + apr_uint32_t checksum; + int hash; + int must_reindex; + + hash = TABLE_HASH(key); + if (!TABLE_INDEX_IS_INITIALIZED(t, hash)) { + return; + } + COMPUTE_KEY_CHECKSUM(key, checksum); + next_elt = ((apr_table_entry_t *) t->a.elts) + t->index_first[hash]; + end_elt = ((apr_table_entry_t *) t->a.elts) + t->index_last[hash]; + must_reindex = 0; + for (; next_elt <= end_elt; next_elt++) { + if ((checksum == next_elt->key_checksum) && + !strcasecmp(next_elt->key, key)) { + + /* Found a match: remove this entry, plus any additional + * matches for the same key that might follow + */ + apr_table_entry_t *table_end = ((apr_table_entry_t *) t->a.elts) + + t->a.nelts; + t->a.nelts--; + dst_elt = next_elt; + for (next_elt++; next_elt <= end_elt; next_elt++) { + if ((checksum == next_elt->key_checksum) && + !strcasecmp(next_elt->key, key)) { + t->a.nelts--; + } + else { + *dst_elt++ = *next_elt; + } + } + + /* Shift over the remainder of the table (note that + * the previous loop didn't run to the end of the table, + * just to the last match for the index) + */ + for (; next_elt < table_end; next_elt++) { + *dst_elt++ = *next_elt; + } + must_reindex = 1; + break; + } + } + if (must_reindex) { + table_reindex(t); + } +} + +APR_DECLARE(void) apr_table_merge(apr_table_t *t, const char *key, + const char *val) +{ + apr_table_entry_t *next_elt; + apr_table_entry_t *end_elt; + apr_uint32_t checksum; + int hash; + + COMPUTE_KEY_CHECKSUM(key, checksum); + hash = TABLE_HASH(key); + if (!TABLE_INDEX_IS_INITIALIZED(t, hash)) { + t->index_first[hash] = t->a.nelts; + TABLE_SET_INDEX_INITIALIZED(t, hash); + goto add_new_elt; + } + next_elt = ((apr_table_entry_t *) t->a.elts) + t->index_first[hash]; + end_elt = ((apr_table_entry_t *) t->a.elts) + t->index_last[hash]; + + for (; next_elt <= end_elt; next_elt++) { + if ((checksum == next_elt->key_checksum) && + !strcasecmp(next_elt->key, key)) { + + /* Found an existing entry with the same key, so merge with it */ + next_elt->val = apr_pstrcat(t->a.pool, next_elt->val, ", ", + val, NULL); + return; + } + } + +add_new_elt: + t->index_last[hash] = t->a.nelts; + next_elt = (apr_table_entry_t *) table_push(t); + next_elt->key = apr_pstrdup(t->a.pool, key); + next_elt->val = apr_pstrdup(t->a.pool, val); + next_elt->key_checksum = checksum; +} + +APR_DECLARE(void) apr_table_mergen(apr_table_t *t, const char *key, + const char *val) +{ + apr_table_entry_t *next_elt; + apr_table_entry_t *end_elt; + apr_uint32_t checksum; + int hash; + +#if APR_POOL_DEBUG + { + apr_pool_t *pool; + pool = apr_pool_find(key); + if ((pool != (apr_pool_t *)key) + && (!apr_pool_is_ancestor(pool, t->a.pool))) { + fprintf(stderr, "apr_table_mergen: key not in ancestor pool of t\n"); + abort(); + } + pool = apr_pool_find(val); + if ((pool != (apr_pool_t *)val) + && (!apr_pool_is_ancestor(pool, t->a.pool))) { + fprintf(stderr, "apr_table_mergen: val not in ancestor pool of t\n"); + abort(); + } + } +#endif + + COMPUTE_KEY_CHECKSUM(key, checksum); + hash = TABLE_HASH(key); + if (!TABLE_INDEX_IS_INITIALIZED(t, hash)) { + t->index_first[hash] = t->a.nelts; + TABLE_SET_INDEX_INITIALIZED(t, hash); + goto add_new_elt; + } + next_elt = ((apr_table_entry_t *) t->a.elts) + t->index_first[hash];; + end_elt = ((apr_table_entry_t *) t->a.elts) + t->index_last[hash]; + + for (; next_elt <= end_elt; next_elt++) { + if ((checksum == next_elt->key_checksum) && + !strcasecmp(next_elt->key, key)) { + + /* Found an existing entry with the same key, so merge with it */ + next_elt->val = apr_pstrcat(t->a.pool, next_elt->val, ", ", + val, NULL); + return; + } + } + +add_new_elt: + t->index_last[hash] = t->a.nelts; + next_elt = (apr_table_entry_t *) table_push(t); + next_elt->key = (char *)key; + next_elt->val = (char *)val; + next_elt->key_checksum = checksum; +} + +APR_DECLARE(void) apr_table_add(apr_table_t *t, const char *key, + const char *val) +{ + apr_table_entry_t *elts; + apr_uint32_t checksum; + int hash; + + hash = TABLE_HASH(key); + t->index_last[hash] = t->a.nelts; + if (!TABLE_INDEX_IS_INITIALIZED(t, hash)) { + t->index_first[hash] = t->a.nelts; + TABLE_SET_INDEX_INITIALIZED(t, hash); + } + COMPUTE_KEY_CHECKSUM(key, checksum); + elts = (apr_table_entry_t *) table_push(t); + elts->key = apr_pstrdup(t->a.pool, key); + elts->val = apr_pstrdup(t->a.pool, val); + elts->key_checksum = checksum; +} + +APR_DECLARE(void) apr_table_addn(apr_table_t *t, const char *key, + const char *val) +{ + apr_table_entry_t *elts; + apr_uint32_t checksum; + int hash; + +#if APR_POOL_DEBUG + { + if (!apr_pool_is_ancestor(apr_pool_find(key), t->a.pool)) { + fprintf(stderr, "apr_table_addn: key not in ancestor pool of t\n"); + abort(); + } + if (!apr_pool_is_ancestor(apr_pool_find(val), t->a.pool)) { + fprintf(stderr, "apr_table_addn: val not in ancestor pool of t\n"); + abort(); + } + } +#endif + + hash = TABLE_HASH(key); + t->index_last[hash] = t->a.nelts; + if (!TABLE_INDEX_IS_INITIALIZED(t, hash)) { + t->index_first[hash] = t->a.nelts; + TABLE_SET_INDEX_INITIALIZED(t, hash); + } + COMPUTE_KEY_CHECKSUM(key, checksum); + elts = (apr_table_entry_t *) table_push(t); + elts->key = (char *)key; + elts->val = (char *)val; + elts->key_checksum = checksum; +} + +APR_DECLARE(apr_table_t *) apr_table_overlay(apr_pool_t *p, + const apr_table_t *overlay, + const apr_table_t *base) +{ + apr_table_t *res; + +#if APR_POOL_DEBUG + /* we don't copy keys and values, so it's necessary that + * overlay->a.pool and base->a.pool have a life span at least + * as long as p + */ + if (!apr_pool_is_ancestor(overlay->a.pool, p)) { + fprintf(stderr, + "apr_table_overlay: overlay's pool is not an ancestor of p\n"); + abort(); + } + if (!apr_pool_is_ancestor(base->a.pool, p)) { + fprintf(stderr, + "apr_table_overlay: base's pool is not an ancestor of p\n"); + abort(); + } +#endif + + res = apr_palloc(p, sizeof(apr_table_t)); + /* behave like append_arrays */ + res->a.pool = p; + copy_array_hdr_core(&res->a, &overlay->a); + apr_array_cat(&res->a, &base->a); + table_reindex(res); + return res; +} + +/* And now for something completely abstract ... + + * For each key value given as a vararg: + * run the function pointed to as + * int comp(void *r, char *key, char *value); + * on each valid key-value pair in the apr_table_t t that matches the vararg key, + * or once for every valid key-value pair if the vararg list is empty, + * until the function returns false (0) or we finish the table. + * + * Note that we restart the traversal for each vararg, which means that + * duplicate varargs will result in multiple executions of the function + * for each matching key. Note also that if the vararg list is empty, + * only one traversal will be made and will cut short if comp returns 0. + * + * Note that the table_get and table_merge functions assume that each key in + * the apr_table_t is unique (i.e., no multiple entries with the same key). This + * function does not make that assumption, since it (unfortunately) isn't + * true for some of Apache's tables. + * + * Note that rec is simply passed-on to the comp function, so that the + * caller can pass additional info for the task. + * + * ADDENDUM for apr_table_vdo(): + * + * The caching api will allow a user to walk the header values: + * + * apr_status_t apr_cache_el_header_walk(apr_cache_el *el, + * int (*comp)(void *, const char *, const char *), void *rec, ...); + * + * So it can be ..., however from there I use a callback that use a va_list: + * + * apr_status_t (*cache_el_header_walk)(apr_cache_el *el, + * int (*comp)(void *, const char *, const char *), void *rec, va_list); + * + * To pass those ...'s on down to the actual module that will handle walking + * their headers, in the file case this is actually just an apr_table - and + * rather than reimplementing apr_table_do (which IMHO would be bad) I just + * called it with the va_list. For mod_shmem_cache I don't need it since I + * can't use apr_table's, but mod_file_cache should (though a good hash would + * be better, but that's a different issue :). + * + * So to make mod_file_cache easier to maintain, it's a good thing + */ +APR_DECLARE_NONSTD(int) apr_table_do(apr_table_do_callback_fn_t *comp, + void *rec, const apr_table_t *t, ...) +{ + int rv; + + va_list vp; + va_start(vp, t); + rv = apr_table_vdo(comp, rec, t, vp); + va_end(vp); + + return rv; +} + +/* XXX: do the semantics of this routine make any sense? Right now, + * if the caller passed in a non-empty va_list of keys to search for, + * the "early termination" facility only terminates on *that* key; other + * keys will continue to process. Note that this only has any effect + * at all if there are multiple entries in the table with the same key, + * otherwise the called function can never effectively early-terminate + * this function, as the zero return value is effectively ignored. + * + * Note also that this behavior is at odds with the behavior seen if an + * empty va_list is passed in -- in that case, a zero return value terminates + * the entire apr_table_vdo (which is what I think should happen in + * both cases). + * + * If nobody objects soon, I'm going to change the order of the nested + * loops in this function so that any zero return value from the (*comp) + * function will cause a full termination of apr_table_vdo. I'm hesitant + * at the moment because these (funky) semantics have been around for a + * very long time, and although Apache doesn't seem to use them at all, + * some third-party vendor might. I can only think of one possible reason + * the existing semantics would make any sense, and it's very Apache-centric, + * which is this: if (*comp) is looking for matches of a particular + * substring in request headers (let's say it's looking for a particular + * cookie name in the Set-Cookie headers), then maybe it wants to be + * able to stop searching early as soon as it finds that one and move + * on to the next key. That's only an optimization of course, but changing + * the behavior of this function would mean that any code that tried + * to do that would stop working right. + * + * Sigh. --JCW, 06/28/02 + */ +APR_DECLARE(int) apr_table_vdo(apr_table_do_callback_fn_t *comp, + void *rec, const apr_table_t *t, va_list vp) +{ + char *argp; + apr_table_entry_t *elts = (apr_table_entry_t *) t->a.elts; + int vdorv = 1; + + argp = va_arg(vp, char *); + do { + int rv = 1, i; + if (argp) { + /* Scan for entries that match the next key */ + int hash = TABLE_HASH(argp); + if (TABLE_INDEX_IS_INITIALIZED(t, hash)) { + apr_uint32_t checksum; + COMPUTE_KEY_CHECKSUM(argp, checksum); + for (i = t->index_first[hash]; + rv && (i <= t->index_last[hash]); ++i) { + if (elts[i].key && (checksum == elts[i].key_checksum) && + !strcasecmp(elts[i].key, argp)) { + rv = (*comp) (rec, elts[i].key, elts[i].val); + } + } + } + } + else { + /* Scan the entire table */ + for (i = 0; rv && (i < t->a.nelts); ++i) { + if (elts[i].key) { + rv = (*comp) (rec, elts[i].key, elts[i].val); + } + } + } + if (rv == 0) { + vdorv = 0; + } + } while (argp && ((argp = va_arg(vp, char *)) != NULL)); + + return vdorv; +} + +static apr_table_entry_t **table_mergesort(apr_pool_t *pool, + apr_table_entry_t **values, + apr_size_t n) +{ + /* Bottom-up mergesort, based on design in Sedgewick's "Algorithms + * in C," chapter 8 + */ + apr_table_entry_t **values_tmp = + (apr_table_entry_t **)apr_palloc(pool, n * sizeof(apr_table_entry_t*)); + apr_size_t i; + apr_size_t blocksize; + + /* First pass: sort pairs of elements (blocksize=1) */ + for (i = 0; i + 1 < n; i += 2) { + if (strcasecmp(values[i]->key, values[i + 1]->key) > 0) { + apr_table_entry_t *swap = values[i]; + values[i] = values[i + 1]; + values[i + 1] = swap; + } + } + + /* Merge successively larger blocks */ + blocksize = 2; + while (blocksize < n) { + apr_table_entry_t **dst = values_tmp; + apr_size_t next_start; + apr_table_entry_t **swap; + + /* Merge consecutive pairs blocks of the next blocksize. + * Within a block, elements are in sorted order due to + * the previous iteration. + */ + for (next_start = 0; next_start + blocksize < n; + next_start += (blocksize + blocksize)) { + + apr_size_t block1_start = next_start; + apr_size_t block2_start = block1_start + blocksize; + apr_size_t block1_end = block2_start; + apr_size_t block2_end = block2_start + blocksize; + if (block2_end > n) { + /* The last block may be smaller than blocksize */ + block2_end = n; + } + for (;;) { + + /* Merge the next two blocks: + * Pick the smaller of the next element from + * block 1 and the next element from block 2. + * Once either of the blocks is emptied, copy + * over all the remaining elements from the + * other block + */ + if (block1_start == block1_end) { + for (; block2_start < block2_end; block2_start++) { + *dst++ = values[block2_start]; + } + break; + } + else if (block2_start == block2_end) { + for (; block1_start < block1_end; block1_start++) { + *dst++ = values[block1_start]; + } + break; + } + if (strcasecmp(values[block1_start]->key, + values[block2_start]->key) > 0) { + *dst++ = values[block2_start++]; + } + else { + *dst++ = values[block1_start++]; + } + } + } + + /* If n is not a multiple of 2*blocksize, some elements + * will be left over at the end of the array. + */ + for (i = dst - values_tmp; i < n; i++) { + values_tmp[i] = values[i]; + } + + /* The output array of this pass becomes the input + * array of the next pass, and vice versa + */ + swap = values_tmp; + values_tmp = values; + values = swap; + + blocksize += blocksize; + } + + return values; +} + +APR_DECLARE(void) apr_table_compress(apr_table_t *t, unsigned flags) +{ + apr_table_entry_t **sort_array; + apr_table_entry_t **sort_next; + apr_table_entry_t **sort_end; + apr_table_entry_t *table_next; + apr_table_entry_t **last; + int i; + int dups_found; + + if (flags == APR_OVERLAP_TABLES_ADD) { + return; + } + + if (t->a.nelts <= 1) { + return; + } + + /* Copy pointers to all the table elements into an + * array and sort to allow for easy detection of + * duplicate keys + */ + sort_array = (apr_table_entry_t **) + apr_palloc(t->a.pool, t->a.nelts * sizeof(apr_table_entry_t*)); + sort_next = sort_array; + table_next = (apr_table_entry_t *)t->a.elts; + i = t->a.nelts; + do { + *sort_next++ = table_next++; + } while (--i); + + /* Note: the merge is done with mergesort instead of quicksort + * because mergesort is a stable sort and runs in n*log(n) + * time regardless of its inputs (quicksort is quadratic in + * the worst case) + */ + sort_array = table_mergesort(t->a.pool, sort_array, t->a.nelts); + + /* Process any duplicate keys */ + dups_found = 0; + sort_next = sort_array; + sort_end = sort_array + t->a.nelts; + last = sort_next++; + while (sort_next < sort_end) { + if (((*sort_next)->key_checksum == (*last)->key_checksum) && + !strcasecmp((*sort_next)->key, (*last)->key)) { + apr_table_entry_t **dup_last = sort_next + 1; + dups_found = 1; + while ((dup_last < sort_end) && + ((*dup_last)->key_checksum == (*last)->key_checksum) && + !strcasecmp((*dup_last)->key, (*last)->key)) { + dup_last++; + } + dup_last--; /* Elements from last through dup_last, inclusive, + * all have the same key + */ + if (flags == APR_OVERLAP_TABLES_MERGE) { + apr_size_t len = 0; + apr_table_entry_t **next = last; + char *new_val; + char *val_dst; + do { + len += strlen((*next)->val); + len += 2; /* for ", " or trailing null */ + } while (++next <= dup_last); + new_val = (char *)apr_palloc(t->a.pool, len); + val_dst = new_val; + next = last; + for (;;) { + strcpy(val_dst, (*next)->val); + val_dst += strlen((*next)->val); + next++; + if (next > dup_last) { + *val_dst = 0; + break; + } + else { + *val_dst++ = ','; + *val_dst++ = ' '; + } + } + (*last)->val = new_val; + } + else { /* overwrite */ + (*last)->val = (*dup_last)->val; + } + do { + (*sort_next)->key = NULL; + } while (++sort_next <= dup_last); + } + else { + last = sort_next++; + } + } + + /* Shift elements to the left to fill holes left by removing duplicates */ + if (dups_found) { + apr_table_entry_t *src = (apr_table_entry_t *)t->a.elts; + apr_table_entry_t *dst = (apr_table_entry_t *)t->a.elts; + apr_table_entry_t *last_elt = src + t->a.nelts; + do { + if (src->key) { + *dst++ = *src; + } + } while (++src < last_elt); + t->a.nelts -= (int)(last_elt - dst); + } + + table_reindex(t); +} + +static void apr_table_cat(apr_table_t *t, const apr_table_t *s) +{ + const int n = t->a.nelts; + register int idx; + + apr_array_cat(&t->a,&s->a); + + if (n == 0) { + memcpy(t->index_first,s->index_first,sizeof(int) * TABLE_HASH_SIZE); + memcpy(t->index_last, s->index_last, sizeof(int) * TABLE_HASH_SIZE); + t->index_initialized = s->index_initialized; + return; + } + + for (idx = 0; idx < TABLE_HASH_SIZE; ++idx) { + if (TABLE_INDEX_IS_INITIALIZED(s, idx)) { + t->index_last[idx] = s->index_last[idx] + n; + if (!TABLE_INDEX_IS_INITIALIZED(t, idx)) { + t->index_first[idx] = s->index_first[idx] + n; + } + } + } + + t->index_initialized |= s->index_initialized; +} + +APR_DECLARE(void) apr_table_overlap(apr_table_t *a, const apr_table_t *b, + unsigned flags) +{ + if (a->a.nelts + b->a.nelts == 0) { + return; + } + +#if APR_POOL_DEBUG + /* Since the keys and values are not copied, it's required that + * b->a.pool has a lifetime at least as long as a->a.pool. */ + if (!apr_pool_is_ancestor(b->a.pool, a->a.pool)) { + fprintf(stderr, "apr_table_overlap: b's pool is not an ancestor of a's\n"); + abort(); + } +#endif + + apr_table_cat(a, b); + + apr_table_compress(a, flags); +} + +static int table_getm_do(void *v, const char *key, const char *val) +{ + table_getm_t *state = (table_getm_t *) v; + + if (!state->first) { + /** + * The most common case is a single header, and this is covered by + * a fast path that doesn't allocate any memory. On the second and + * subsequent header, an array is created and the array concatenated + * together to form the final value. + */ + state->first = val; + } + else { + const char **elt; + if (!state->merged) { + state->merged = apr_array_make(state->p, 10, sizeof(const char *)); + elt = apr_array_push(state->merged); + *elt = state->first; + } + elt = apr_array_push(state->merged); + *elt = val; + } + return 1; +} + +APR_DECLARE(const char *) apr_table_getm(apr_pool_t *p, const apr_table_t *t, + const char *key) +{ + table_getm_t state; + + state.p = p; + state.first = NULL; + state.merged = NULL; + + apr_table_do(table_getm_do, &state, t, key, NULL); + + if (!state.first) { + return NULL; + } + else if (!state.merged) { + return state.first; + } + else { + return apr_array_pstrcat(p, state.merged, ','); + } +} diff --git a/test/.cvsignore b/test/.cvsignore deleted file mode 100644 index 71ba7393632..00000000000 --- a/test/.cvsignore +++ /dev/null @@ -1,18 +0,0 @@ -Makefile -testmmap -htdigest -ab -proctest -testcontext -testargs -testdso -testoc -testpipe -testshmem -testtime -testthread -client -server -testsock -testproc -testfile diff --git a/test/Makefile.in b/test/Makefile.in index e911abf4d8a..4fb4d94d36e 100644 --- a/test/Makefile.in +++ b/test/Makefile.in @@ -1,165 +1,214 @@ -# Generated automatically from Makefile.in by configure. -#CFLAGS=$(OPTIM) $(CFLAGS1) $(EXTRA_CFLAGS) -#LIBS=$(EXTRA_LIBS) $(LIBS1) -#INCLUDES=$(INCLUDES1) $(INCLUDES0) $(EXTRA_INCLUDES) -#LDFLAGS=$(LDFLAGS1) $(EXTRA_LDFLAGS) - -RM=@RM@ -CC=@CC@ -RANLIB=@RANLIB@ -CFLAGS=@CFLAGS@ @OPTIM@ -LIBS=-L.. -lapr @LIBS@ -LDFLAGS=@LDFLAGS@ $(LIBS) +srcdir = @srcdir@ +VPATH = @srcdir@ + +# PROGRAMS includes all test programs built on this platform. +# STDTEST_PORTABLE +# test programs invoked via standard user interface, run on all platforms +# TESTS +# test modules invoked through the abts suite (./testall) +# STDTEST_NONPORTABLE +# test programs invoked via standard user interface, not portable +# OTHER_PROGRAMS +# programs such as sockperf, that have to be invoked in a special sequence +# or with special parameters +# TESTALL_COMPONENTS +# programs such as globalmutexchild which the various TESTS will invoke +# to validate process creation, pipes, dso mechanisms and so forth + +STDTEST_PORTABLE = \ + testlockperf@EXEEXT@ \ + testmutexscope@EXEEXT@ \ + testall@EXEEXT@ \ + dbd@EXEEXT@ \ + sendfile@EXEEXT@ \ + +TESTS = testtime.lo teststr.lo testvsn.lo testipsub.lo testshm.lo \ + testmmap.lo testud.lo testtable.lo testsleep.lo testpools.lo \ + testfmt.lo testfile.lo testdir.lo testfileinfo.lo testrand.lo \ + testdso.lo testoc.lo testdup.lo testsockets.lo testproc.lo \ + testpoll.lo testlock.lo testsockopt.lo testpipe.lo \ + testthread.lo testhash.lo testargs.lo testnames.lo testuser.lo \ + testpath.lo testenv.lo testprocmutex.lo testfnmatch.lo \ + testatomic.lo testflock.lo testsock.lo testglobalmutex.lo \ + teststrnatcmp.lo testfilecopy.lo testtemp.lo testlfs.lo \ + testcond.lo testuri.lo testmemcache.lo testdate.lo \ + testxlate.lo testdbd.lo testrmm.lo testmd4.lo \ + teststrmatch.lo testpass.lo testcrypto.lo testqueue.lo \ + testbuckets.lo testxml.lo testdbm.lo testuuid.lo testmd5.lo \ + testreslist.lo testbase64.lo testhooks.lo testlfsabi.lo \ + testlfsabi32.lo testlfsabi64.lo testescape.lo testskiplist.lo \ + testsiphash.lo testredis.lo + +OTHER_PROGRAMS = \ + echod@EXEEXT@ \ + sockperf@EXEEXT@ + +TESTALL_COMPONENTS = \ + globalmutexchild@EXEEXT@ \ + libmod_test.la \ + mod_test.la \ + occhild@EXEEXT@ \ + proc_child@EXEEXT@ \ + readchild@EXEEXT@ \ + sockchild@EXEEXT@ \ + testshmproducer@EXEEXT@ \ + testshmconsumer@EXEEXT@ \ + tryread@EXEEXT@ + +PROGRAMS = $(TESTALL_COMPONENTS) $(STDTEST_PORTABLE) $(STDTEST_NONPORTABLE) \ + $(OTHER_PROGRAMS) + +TARGETS = $(PROGRAMS) + +# bring in rules.mk for standard functionality +@INCLUDE_RULES@ + +LOCAL_LIBS=../lib@APR_LIBNAME@.la + +CLEAN_TARGETS = testfile.tmp lfstests/*.bin \ + data/test*.txt data/test*.dat data/apr.testshm.shm + +CLEAN_SUBDIRS = internal + INCDIR=../include -INCLUDES=-I$(INCDIR) - -TARGETS= testfile@EXEEXT@ \ - testproc@EXEEXT@ \ - testsock@EXEEXT@ \ - testthread@EXEEXT@ \ - testtime@EXEEXT@ \ - testargs@EXEEXT@ \ - testcontext@EXEEXT@ \ - testmmap@EXEEXT@ \ - testshmem@EXEEXT@ \ - testpipe@EXEEXT@ \ - testdso@EXEEXT@ \ - testoc@EXEEXT@ \ - mod_test.so - -OBJS= testfile.o \ - testproc.o \ - testsock.o \ - testthread.o \ - testtime.o \ - testargs.o \ - testcontext.o \ - testmmap.o \ - testdso.o \ - testoc.o \ - mod_test.o - -.c.o: - $(CC) -c $(CFLAGS) $(INCLUDES) $< - -all: $(TARGETS) - -testfile@EXEEXT@: testfile.o - $(CC) $(CFLAGS) testfile.o -o testfile@EXEEXT@ $(LDFLAGS) - -testdso@EXEEXT@: testdso.o - $(CC) $(CFLAGS) --export-dynamic -fPIC testdso.o -o testdso@EXEEXT@ $(LDFLAGS) - -testoc@EXEEXT@: testoc.o - $(CC) $(CFLAGS) testoc.o -o testoc@EXEEXT@ $(LDFLAGS) - -mod_test.so: mod_test.o - $(CC) -shared mod_test.o -o mod_test.so - -testargs@EXEEXT@: testargs.o - $(CC) $(CFLAGS) testargs.o -o testargs@EXEEXT@ $(LDFLAGS) - -testcontext@EXEEXT@: testcontext.o - $(CC) $(CFLAGS) testcontext.o -o testcontext@EXEEXT@ $(LDFLAGS) - -testproc@EXEEXT@: testproc.o - $(CC) $(CFLAGS) testproc.o -o testproc@EXEEXT@ $(LDFLAGS) - -testthread@EXEEXT@: testthread.o - $(CC) $(CFLAGS) testthread.o -o testthread@EXEEXT@ $(LDFLAGS) - -testsock@EXEEXT@: testsock.o client.o server.o - $(CC) $(CFLAGS) testsock.o -o testsock@EXEEXT@ $(LDFLAGS) - $(CC) $(CFLAGS) server.o -o server@EXEEXT@ $(LDFLAGS) - $(CC) $(CFLAGS) client.o -o client@EXEEXT@ $(LDFLAGS) - -testtime@EXEEXT@: testtime.o - $(CC) $(CFLAGS) testtime.o -o testtime@EXEEXT@ $(LDFLAGS) - -testmmap@EXEEXT@: testmmap.o - $(CC) $(CFLAGS) testmmap.o -o testmmap@EXEEXT@ $(LDFLAGS) - -testshmem@EXEEXT@: testshmem.o - $(CC) $(CFLAGS) testshmem.o -o testshmem@EXEEXT@ $(LDFLAGS) - -testpipe@EXEEXT@: testpipe.o - $(CC) $(CFLAGS) testpipe.o -o testpipe@EXEEXT@ $(LDFLAGS) - -clean: - $(RM) -f *.o *.a *.so $(TARGETS) - -distclean: clean - -$(RM) -f Makefile - -$(OBJS): Makefile - -# -# We really don't expect end users to use this rule. It works only with -# gcc, and rebuilds Makefile.tmpl. You have to re-run Configure after -# using it. -# -depend: - cp Makefile.in Makefile.in.bak \ - && sed -ne '1,/^# DO NOT REMOVE/p' Makefile.in > Makefile.new \ - && gcc -MM $(INCLUDES) $(CFLAGS) *.c >> Makefile.new \ - && sed -e '1,$$s: $(INCDIR)/: $$(INCDIR)/:g' \ - -e '1,$$s: $(OSDIR)/: $$(OSDIR)/:g' Makefile.new \ - > Makefile.in \ - && rm Makefile.new +INCLUDES=-I$(INCDIR) -I$(srcdir)/../include + +# link programs using -no-install to get real executables not +# libtool wrapper scripts which link an executable when first run. +LINK_PROG = $(LIBTOOL) $(LTFLAGS) --mode=link $(COMPILE) $(LT_LDFLAGS) \ + @LT_NO_INSTALL@ $(ALL_LDFLAGS) -o $@ + +# STDTEST_PORTABLE; + +abts.lo: $(srcdir)/abts.c $(srcdir)/abts.h $(srcdir)/abts_tests.h \ + $(srcdir)/testutil.h + +testutil.lo: $(srcdir)/abts.c $(srcdir)/abts.h $(srcdir)/abts_tests.h \ + $(srcdir)/testutil.h + +OBJECTS_testall = abts.lo testutil.lo $(TESTS) $(LOCAL_LIBS) +testall@EXEEXT@: $(OBJECTS_testall) + $(LINK_PROG) $(OBJECTS_testall) $(ALL_LIBS) +# For VPATH builds; where we have no ./data, copy us some data +# if we wait until 'make check', then 'make; ./testall' fails; + if test ! -d "./data"; then cp -r $(srcdir)/data data; fi + +OBJECTS_testlockperf = testlockperf.lo $(LOCAL_LIBS) +testlockperf@EXEEXT@: $(OBJECTS_testlockperf) + $(LINK_PROG) $(OBJECTS_testlockperf) $(ALL_LIBS) + +OBJECTS_testmutexscope = testmutexscope.lo $(LOCAL_LIBS) +testmutexscope@EXEEXT@: $(OBJECTS_testmutexscope) + $(LINK_PROG) $(OBJECTS_testmutexscope) $(ALL_LIBS) + +# OTHER_PROGRAMS; + +OBJECTS_echod = echod.lo $(LOCAL_LIBS) +echod@EXEEXT@: $(OBJECTS_echod) + $(LINK_PROG) $(OBJECTS_echod) $(ALL_LIBS) + +OBJECTS_sendfile = sendfile.lo $(LOCAL_LIBS) +sendfile@EXEEXT@: $(OBJECTS_sendfile) + $(LINK_PROG) $(OBJECTS_sendfile) $(ALL_LIBS) + +OBJECTS_sockperf = sockperf.lo $(LOCAL_LIBS) +sockperf@EXEEXT@: $(OBJECTS_sockperf) + $(LINK_PROG) $(OBJECTS_sockperf) $(ALL_LIBS) + +# TESTALL_COMPONENTS; + +OBJECTS_globalmutexchild = globalmutexchild.lo $(LOCAL_LIBS) +globalmutexchild@EXEEXT@: $(OBJECTS_globalmutexchild) + $(LINK_PROG) $(OBJECTS_globalmutexchild) $(ALL_LIBS) + +# Note -prefer-pic is only supported with libtool-1.4+ +mod_test.lo: $(srcdir)/mod_test.c + $(LIBTOOL) $(LTFLAGS) --mode=compile $(COMPILE) -prefer-pic -o $@ \ + -c $(srcdir)/mod_test.c + +OBJECTS_mod_test = mod_test.lo +mod_test.la: $(OBJECTS_mod_test) $(LOCAL_LIBS) + $(LIBTOOL) $(LTFLAGS) --mode=link $(COMPILE) -rpath `pwd` -module \ + -avoid-version $(LT_LDFLAGS) $(ALL_LDFLAGS) -o $@ \ + $(OBJECTS_mod_test) $(LOCAL_LIBS) + +OBJECTS_libmod_test = mod_test.lo $(LOCAL_LIBS) +libmod_test.la: $(OBJECTS_libmod_test) + $(LIBTOOL) $(LTFLAGS) --mode=link $(COMPILE) -rpath `pwd` \ + -avoid-version $(LT_LDFLAGS) $(ALL_LDFLAGS) -o $@ \ + $(OBJECTS_libmod_test) $(ALL_LIBS) + +OBJECTS_occhild = occhild.lo $(LOCAL_LIBS) +occhild@EXEEXT@: $(OBJECTS_occhild) + $(LINK_PROG) $(OBJECTS_occhild) $(ALL_LIBS) + +OBJECTS_proc_child = proc_child.lo $(LOCAL_LIBS) +proc_child@EXEEXT@: $(OBJECTS_proc_child) + $(LINK_PROG) $(OBJECTS_proc_child) $(ALL_LIBS) + +OBJECTS_readchild = readchild.lo $(LOCAL_LIBS) +readchild@EXEEXT@: $(OBJECTS_readchild) + $(LINK_PROG) $(OBJECTS_readchild) $(ALL_LIBS) + +OBJECTS_sockchild = sockchild.lo $(LOCAL_LIBS) +sockchild@EXEEXT@: $(OBJECTS_sockchild) + $(LINK_PROG) $(OBJECTS_sockchild) $(ALL_LIBS) + +OBJECTS_testshmconsumer = testshmconsumer.lo $(LOCAL_LIBS) +testshmconsumer@EXEEXT@: $(OBJECTS_testshmconsumer) $(LOCAL_LIBS) + $(LINK_PROG) $(OBJECTS_testshmconsumer) $(ALL_LIBS) + +OBJECTS_testshmproducer = testshmproducer.lo $(LOCAL_LIBS) +testshmproducer@EXEEXT@: $(OBJECTS_testshmproducer) + $(LINK_PROG) $(OBJECTS_testshmproducer) $(ALL_LIBS) + +OBJECTS_tryread = tryread.lo $(LOCAL_LIBS) +tryread@EXEEXT@: $(OBJECTS_tryread) + $(LINK_PROG) $(OBJECTS_tryread) $(ALL_LIBS) + +OBJECTS_dbd = dbd.lo $(LOCAL_LIBS) +dbd@EXEEXT@: $(OBJECTS_dbd) + $(LINK_PROG) $(OBJECTS_dbd) $(APRUTIL_LIBS) + +check: $(TESTALL_COMPONENTS) $(STDTEST_PORTABLE) $(STDTEST_NONPORTABLE) + teststatus=0; \ + progfailed=""; \ + for prog in $(STDTEST_PORTABLE) $(STDTEST_NONPORTABLE); do \ + if test "$$prog" = 'dbd@EXEEXT@'; then \ + for driver in none @apu_dbd_tests@; do \ + if test "$$driver" != 'none'; then \ + @shlibpath_var@="`echo "../dbm/.libs:../dbd/.libs:$$@shlibpath_var@" | sed -e 's/::*$$//'`" \ + ./$$prog $$driver; \ + status=$$?; \ + if test $$status != 0; then \ + teststatus=$$status; \ + progfailed="$$progfailed '$$prog $$driver'"; \ + fi; \ + fi; \ + done; \ + elif test "$$prog" = 'sendfile@EXEEXT@'; then \ + for mode in blocking nonblocking timeout; do \ + @shlibpath_var@="`echo "../dbm/.libs:../dbd/.libs:$$@shlibpath_var@" | sed -e 's/::*$$//'`" \ + ./$$prog client $$mode startserver 127.0.0.1; \ + status=$$?; \ + if test $$status != 0; then \ + teststatus=$$status; \ + progfailed="$$progfailed '$$prog mode $$mode'"; \ + fi; \ + done; \ + else \ + @shlibpath_var@="`echo "../dbm/.libs:../dbd/.libs:$$@shlibpath_var@" | sed -e 's/::*$$//'`" \ + ./$$prog -v; \ + status=$$?; \ + if test $$status != 0; then \ + teststatus=$$status; \ + progfailed="$$progfailed $$prog"; \ + fi; \ + fi; \ + done; \ + if test $$teststatus != 0; then \ + echo "Programs failed:$$progfailed"; \ + fi; \ + exit $$teststatus # DO NOT REMOVE -abc.o: abc.c $(INCDIR)/apr_file_io.h $(INCDIR)/apr_general.h \ - $(INCDIR)/apr.h $(INCDIR)/apr_errno.h $(INCDIR)/apr_time.h -client.o: client.c $(INCDIR)/apr_network_io.h \ - $(INCDIR)/apr_general.h $(INCDIR)/apr.h $(INCDIR)/apr_errno.h \ - $(INCDIR)/apr_file_io.h $(INCDIR)/apr_time.h $(OSDIR)/usr/include/errno.h -mod_test.o: mod_test.c -server.o: server.c $(INCDIR)/apr_network_io.h \ - $(INCDIR)/apr_general.h $(INCDIR)/apr.h $(INCDIR)/apr_errno.h \ - $(INCDIR)/apr_file_io.h $(INCDIR)/apr_time.h -testargs.o: testargs.c $(INCDIR)/apr_file_io.h \ - $(INCDIR)/apr_general.h $(INCDIR)/apr.h $(INCDIR)/apr_errno.h \ - $(INCDIR)/apr_time.h $(INCDIR)/apr_lib.h \ - $(INCDIR)/apr_thread_proc.h $(INCDIR)/apr_getopt.h -testcontext.o: testcontext.c $(INCDIR)/apr_file_io.h \ - $(INCDIR)/apr_general.h $(INCDIR)/apr.h $(INCDIR)/apr_errno.h \ - $(INCDIR)/apr_time.h $(INCDIR)/apr_lib.h \ - $(INCDIR)/apr_thread_proc.h -testdso.o: testdso.c $(INCDIR)/apr_general.h $(INCDIR)/apr.h \ - $(INCDIR)/apr_errno.h $(INCDIR)/apr_pools.h $(INCDIR)/apr_lib.h \ - $(INCDIR)/apr_file_io.h $(INCDIR)/apr_time.h \ - $(INCDIR)/apr_thread_proc.h $(INCDIR)/apr_dso.h -testfile.o: testfile.c $(INCDIR)/apr_file_io.h \ - $(INCDIR)/apr_general.h $(INCDIR)/apr.h $(INCDIR)/apr_errno.h \ - $(INCDIR)/apr_time.h $(INCDIR)/apr_lib.h \ - $(INCDIR)/apr_thread_proc.h -testmmap.o: testmmap.c $(INCDIR)/apr_mmap.h $(INCDIR)/apr_general.h \ - $(INCDIR)/apr.h $(INCDIR)/apr_errno.h $(INCDIR)/apr_network_io.h \ - $(INCDIR)/apr_file_io.h $(INCDIR)/apr_time.h \ - $(INCDIR)/apr_portable.h $(INCDIR)/apr_thread_proc.h \ - $(INCDIR)/apr_lock.h $(INCDIR)/apr_lib.h -testoc.o: testoc.c $(INCDIR)/apr_thread_proc.h \ - $(INCDIR)/apr_file_io.h $(INCDIR)/apr_general.h $(INCDIR)/apr.h \ - $(INCDIR)/apr_errno.h $(INCDIR)/apr_time.h $(INCDIR)/apr_lib.h \ - $(OSDIR)/usr/include/errno.h -testpipe.o: testpipe.c $(INCDIR)/apr_file_io.h \ - $(INCDIR)/apr_general.h $(INCDIR)/apr.h $(INCDIR)/apr_errno.h \ - $(INCDIR)/apr_time.h $(INCDIR)/apr_lib.h \ - $(INCDIR)/apr_thread_proc.h -testproc.o: testproc.c $(INCDIR)/apr_thread_proc.h \ - $(INCDIR)/apr_file_io.h $(INCDIR)/apr_general.h $(INCDIR)/apr.h \ - $(INCDIR)/apr_errno.h $(INCDIR)/apr_time.h $(INCDIR)/apr_lib.h \ - $(OSDIR)/usr/include/errno.h -testshmem.o: testshmem.c $(INCDIR)/apr_shmem.h $(INCDIR)/apr.h \ - $(INCDIR)/apr_general.h $(INCDIR)/apr_errno.h $(INCDIR)/apr_lock.h \ - $(INCDIR)/apr_lib.h $(INCDIR)/apr_file_io.h $(INCDIR)/apr_time.h \ - $(INCDIR)/apr_thread_proc.h $(OSDIR)/usr/include/errno.h -testsock.o: testsock.c $(INCDIR)/apr_thread_proc.h \ - $(INCDIR)/apr_file_io.h $(INCDIR)/apr_general.h $(INCDIR)/apr.h \ - $(INCDIR)/apr_errno.h $(INCDIR)/apr_time.h $(INCDIR)/apr_lib.h -testthread.o: testthread.c $(INCDIR)/apr_thread_proc.h \ - $(INCDIR)/apr_file_io.h $(INCDIR)/apr_general.h $(INCDIR)/apr.h \ - $(INCDIR)/apr_errno.h $(INCDIR)/apr_time.h $(INCDIR)/apr_lock.h \ - $(OSDIR)/usr/include/errno.h -testtime.o: testtime.c $(INCDIR)/apr_time.h $(INCDIR)/apr_general.h \ - $(INCDIR)/apr.h $(INCDIR)/apr_errno.h $(OSDIR)/usr/include/errno.h diff --git a/test/Makefile.win b/test/Makefile.win new file mode 100644 index 00000000000..21344ea0309 --- /dev/null +++ b/test/Makefile.win @@ -0,0 +1,318 @@ +# PROGRAMS includes all test programs built on this platform. +# STDTEST_PORTABLE +# test programs invoked via standard user interface, run on all platforms +# TESTS +# test modules invoked through the abts suite (./testall) +# STDTEST_NONPORTABLE +# test programs invoked via standard user interface, not portable +# OTHER_PROGRAMS +# programs such as sendfile, that have to be invoked in a special sequence +# or with special parameters +# TESTALL_COMPONENTS +# programs such as globalmutexchild which the various TESTS will invoke +# to validate process creation, pipes, dso mechanisms and so forth + +# Windows Specific; +# MODEL +# dynamic or static - refers to which set of bindings are desired +# and controls which libraries (apr-2 or libapr-2) will be linked. +# OUTDIR +# the library path of the libraries, and also the path within test/ +# where all of the tests for that library will be built + +!IFNDEF MODEL +MODEL=dynamic +!ENDIF + +INCDIR=../include + +!IFNDEF OUTDIR +!IF "$(MODEL)" == "static" +OUTDIR=LibR +!ELSE +OUTDIR=Release +!ENDIF + +!IF [$(COMSPEC) /c cl /nologo /? \ + | $(SystemRoot)\System32\find.exe "x64" >NUL ] == 0 +OUTDIR=x64\$(OUTDIR) +!ENDIF +!ENDIF + +!IF !EXIST("$(OUTDIR)\.") +!IF ([$(COMSPEC) /C mkdir $(OUTDIR)] == 0) +!ENDIF +!ENDIF + +!IFNDEF INTDIR +INTDIR=$(OUTDIR) +!ELSE +!IF !EXIST("$(INTDIR)\.") +!IF ([$(COMSPEC) /C mkdir $(INTDIR)] == 0) +!ENDIF +!ENDIF +!ENDIF + +!MESSAGE Building tests into $(OUTDIR) for $(MODEL) + +STDTEST_PORTABLE = \ + $(OUTDIR)\testapp.exe \ + $(OUTDIR)\testall.exe \ + $(OUTDIR)\testlockperf.exe \ + $(OUTDIR)\testmutexscope.exe + +OTHER_PROGRAMS = \ + $(OUTDIR)\echod.exe \ + $(OUTDIR)\sendfile.exe \ + $(OUTDIR)\sockperf.exe + +TESTALL_COMPONENTS = \ + $(OUTDIR)\mod_test.dll \ + $(OUTDIR)\occhild.exe \ + $(OUTDIR)\readchild.exe \ + $(OUTDIR)\proc_child.exe \ + $(OUTDIR)\tryread.exe \ + $(OUTDIR)\sockchild.exe \ + $(OUTDIR)\testshmproducer.exe \ + $(OUTDIR)\testshmconsumer.exe \ + $(OUTDIR)\globalmutexchild.exe + +ALL_TESTS = \ + $(INTDIR)\testargs.obj \ + $(INTDIR)\testatomic.obj \ + $(INTDIR)\testbase64.obj \ + $(INTDIR)\testbuckets.obj \ + $(INTDIR)\testcond.obj \ + $(INTDIR)\testcrypto.obj \ + $(INTDIR)\testdate.obj \ + $(INTDIR)\testdbd.obj \ + $(INTDIR)\testdbm.obj \ + $(INTDIR)\testdir.obj \ + $(INTDIR)\testdso.obj \ + $(INTDIR)\testdup.obj \ + $(INTDIR)\testenv.obj \ + $(INTDIR)\testescape.obj \ + $(INTDIR)\testfile.obj \ + $(INTDIR)\testfilecopy.obj \ + $(INTDIR)\testfileinfo.obj \ + $(INTDIR)\testflock.obj \ + $(INTDIR)\testfmt.obj \ + $(INTDIR)\testfnmatch.obj \ + $(INTDIR)\testglobalmutex.obj \ + $(INTDIR)\testhash.obj \ + $(INTDIR)\testhooks.obj \ + $(INTDIR)\testipsub.obj \ + $(INTDIR)\testlfs.obj \ + $(INTDIR)\testlfsabi.obj \ + $(INTDIR)\testlfsabi32.obj \ + $(INTDIR)\testlfsabi64.obj \ + $(INTDIR)\testlock.obj \ + $(INTDIR)\testmd4.obj \ + $(INTDIR)\testmd5.obj \ + $(INTDIR)\testmemcache.obj \ + $(INTDIR)\testmmap.obj \ + $(INTDIR)\testnames.obj \ + $(INTDIR)\testoc.obj \ + $(INTDIR)\testpass.obj \ + $(INTDIR)\testpath.obj \ + $(INTDIR)\testpipe.obj \ + $(INTDIR)\testpoll.obj \ + $(INTDIR)\testpools.obj \ + $(INTDIR)\testproc.obj \ + $(INTDIR)\testprocmutex.obj \ + $(INTDIR)\testqueue.obj \ + $(INTDIR)\testrand.obj \ + $(INTDIR)\testredis.obj \ + $(INTDIR)\testreslist.obj \ + $(INTDIR)\testrmm.obj \ + $(INTDIR)\testshm.obj \ + $(INTDIR)\testsiphash.obj \ + $(INTDIR)\testsleep.obj \ + $(INTDIR)\testsock.obj \ + $(INTDIR)\testsockets.obj \ + $(INTDIR)\testsockopt.obj \ + $(INTDIR)\teststr.obj \ + $(INTDIR)\teststrmatch.obj \ + $(INTDIR)\teststrnatcmp.obj \ + $(INTDIR)\testskiplist.obj \ + $(INTDIR)\testtable.obj \ + $(INTDIR)\testtemp.obj \ + $(INTDIR)\testthread.obj \ + $(INTDIR)\testtime.obj \ + $(INTDIR)\testud.obj\ + $(INTDIR)\testuri.obj \ + $(INTDIR)\testuser.obj \ + $(INTDIR)\testutil.obj \ + $(INTDIR)\testuuid.obj \ + $(INTDIR)\testvsn.obj \ + $(INTDIR)\testxlate.obj \ + $(INTDIR)\testxml.obj + +CLEAN_DATA = testfile.tmp lfstests\large.bin \ + data\testputs.txt data\testbigfprintf.dat \ + data\testwritev.txt data\testwritev_full.txt \ + data\testflush.dat data\testxthread.dat \ + data\apr.testshm.shm + +CLEAN_BUILDDIRS = Debug Release LibD LibR x64 + +TEST_SUBDIRS = internal + +PROGRAMS = $(TESTALL_COMPONENTS) $(STDTEST_PORTABLE) $(STDTEST_NONPORTABLE) \ + $(OTHER_PROGRAMS) + +TARGETS = $(PROGRAMS) + +# bring in rules.mk for standard functionality +ALL: $(TARGETS) + +CL = cl.exe +LD = link.exe + +!IF "$(MODEL)" == "static" +LOCAL_LIB= ..\$(OUTDIR)\apr-2.lib ..\..\expat\win32\bin\Release\libexpatMT.lib +APP_LIB= ..\$(OUTDIR)\aprapp-2.lib +STATIC_CFLAGS = /D APR_DECLARE_STATIC +!ELSE +LOCAL_LIB= ..\$(OUTDIR)\libapr-2.lib +APP_LIB= ..\$(OUTDIR)\libaprapp-2.lib +STATIC_CFLAGS = +PATH=$(OUTDIR);..\$(OUTDIR);..\..\expat\win32\bin\$(OUTDIR);$(PATH) +!ENDIF + +!IFDEF _DEBUG +DEBUG_CFLAGS = /MDd +!ELSE +DEBUG_CFLAGS = /MD +!ENDIF + +INCLUDES=/I "$(INCDIR)" + +CFLAGS = /nologo /c /W3 /Gm /EHsc /Zi /Od $(INCLUDES) \ + $(STATIC_CFLAGS) $(DEBUG_CFLAGS) /D "BINPATH=$(OUTDIR:\=/)" \ + /D _DEBUG /D WIN32 /Fo"$(INTDIR)/" /FD + +LD_LIBS = kernel32.lib advapi32.lib ws2_32.lib wsock32.lib \ + ole32.lib shell32.lib rpcrt4.lib + +LDFLAGS = /nologo /debug /subsystem:console /incremental:no /nodefaultlib:libcmt + +SHLDFLAGS = /nologo /dll /debug /subsystem:windows /incremental:no + +.c{$(INTDIR)}.obj:: + $(CL) $(CFLAGS) -c $< -Fd$(INTDIR)\ $(INCLUDES) + +# STDTEST_PORTABLE; + +$(OUTDIR)\testall.exe: $(ALL_TESTS) $(INTDIR)\abts.obj $(LOCAL_LIB) + $(LD) $(LDFLAGS) /out:"$@" $** $(LD_LIBS) + @if exist "$@.manifest" \ + mt.exe -manifest "$@.manifest" -outputresource:$@;1 + +$(OUTDIR)\testapp.exe: $(INTDIR)/testapp.obj $(LOCAL_LIB) $(APP_LIB) + $(LD) $(LDFLAGS) /entry:wmainCRTStartup /out:"$@" $** $(LD_LIBS) + @if exist "$@.manifest" \ + mt.exe -manifest "$@.manifest" -outputresource:$@;2 + +$(OUTDIR)\testlockperf.exe: $(INTDIR)\testlockperf.obj $(LOCAL_LIB) + $(LD) $(LDFLAGS) /out:"$@" $** $(LD_LIBS) + @if exist "$@.manifest" \ + mt.exe -manifest "$@.manifest" -outputresource:$@;1 + +$(OUTDIR)\testmutexscope.exe: $(INTDIR)\testmutexscope.obj $(LOCAL_LIB) + $(LD) $(LDFLAGS) /out:"$@" $** $(LD_LIBS) + @if exist "$@.manifest" \ + mt.exe -manifest "$@.manifest" -outputresource:$@;1 + +# OTHER_PROGRAMS; + +$(OUTDIR)\echod.exe: $(INTDIR)\echod.obj $(LOCAL_LIB) + $(LD) $(LDFLAGS) /out:"$@" $** $(LD_LIBS) + @if exist "$@.manifest" \ + mt.exe -manifest "$@.manifest" -outputresource:$@;1 + +$(OUTDIR)\sendfile.exe: $(INTDIR)\sendfile.obj $(LOCAL_LIB) + $(LD) $(LDFLAGS) /out:"$@" $** $(LD_LIBS) + @if exist "$@.manifest" \ + mt.exe -manifest "$@.manifest" -outputresource:$@;1 + +$(OUTDIR)\sockperf.exe: $(INTDIR)\sockperf.obj $(LOCAL_LIB) + $(LD) $(LDFLAGS) /out:"$@" $** $(LD_LIBS) + @if exist "$@.manifest" \ + mt.exe -manifest "$@.manifest" -outputresource:$@;1 + +# TESTALL_COMPONENTS; + +$(OUTDIR)\globalmutexchild.exe: $(INTDIR)\globalmutexchild.obj $(LOCAL_LIB) + $(LD) $(LDFLAGS) /out:"$@" $** $(LD_LIBS) + @if exist "$@.manifest" \ + mt.exe -manifest "$@.manifest" -outputresource:$@;1 + +$(OUTDIR)\mod_test.dll: $(INTDIR)/mod_test.obj $(LOCAL_LIB) + $(LD) $(SHLDFLAGS) /out:"$@" $** \ + /export:print_hello /export:count_reps $(LD_LIBS) + @if exist "$@.manifest" \ + mt.exe -manifest "$@.manifest" -outputresource:$@;2 + +$(OUTDIR)\occhild.exe: $(INTDIR)\occhild.obj $(LOCAL_LIB) + $(LD) $(LDFLAGS) /out:"$@" $** $(LD_LIBS) + @if exist "$@.manifest" \ + mt.exe -manifest "$@.manifest" -outputresource:$@;1 + +$(OUTDIR)\proc_child.exe: $(INTDIR)\proc_child.obj $(LOCAL_LIB) + $(LD) $(LDFLAGS) /out:"$@" $** $(LD_LIBS) + @if exist "$@.manifest" \ + mt.exe -manifest "$@.manifest" -outputresource:$@;1 + +$(OUTDIR)\readchild.exe: $(INTDIR)\readchild.obj $(LOCAL_LIB) + $(LD) $(LDFLAGS) /out:"$@" $** $(LD_LIBS) + @if exist "$@.manifest" \ + mt.exe -manifest "$@.manifest" -outputresource:$@;1 + +$(OUTDIR)\sockchild.exe: $(INTDIR)\sockchild.obj $(LOCAL_LIB) + $(LD) $(LDFLAGS) /out:"$@" $** $(LD_LIBS) + @if exist "$@.manifest" \ + mt.exe -manifest "$@.manifest" -outputresource:$@;1 + +$(OUTDIR)\testshmconsumer.exe: $(INTDIR)\testshmconsumer.obj $(LOCAL_LIB) + $(LD) $(LDFLAGS) /out:"$@" $** $(LD_LIBS) + @if exist "$@.manifest" \ + mt.exe -manifest "$@.manifest" -outputresource:$@;1 + +$(OUTDIR)\testshmproducer.exe: $(INTDIR)\testshmproducer.obj $(LOCAL_LIB) + $(LD) $(LDFLAGS) /out:"$@" $** $(LD_LIBS) + @if exist "$@.manifest" \ + mt.exe -manifest "$@.manifest" -outputresource:$@;1 + +$(OUTDIR)\tryread.exe: $(INTDIR)\tryread.obj $(LOCAL_LIB) + $(LD) $(LDFLAGS) /out:"$@" $** $(LD_LIBS) + @if exist "$@.manifest" \ + mt.exe -manifest "$@.manifest" -outputresource:$@;1 + + +cleandata: + @for %f in ($(CLEAN_DATA)) do @if EXIST %f del /f %f + +clean: cleandata + @if EXIST $(INTDIR)\. rmdir /s /q $(INTDIR) + @if EXIST $(OUTDIR)\. rmdir /s /q $(OUTDIR) + @for %d in ($(TEST_SUBDIRS)) do \ + %COMSPEC% /c "cd %%d && $(MAKE) -f Makefile.win clean" \ + +cleanall: + @for %d in ($(CLEAN_BUILDDIRS) $(INTDIR) $(OUTDIR)) do \ + @if EXIST %d\. rmdir /s /q %d + @for %d in ($(TEST_SUBDIRS)) do \ + %COMSPEC% /c "cd %%d & $(MAKE) -f Makefile.win cleanall" \ + + +check: $(TESTALL_COMPONENTS) $(STDTEST_PORTABLE) $(STDTEST_NONPORTABLE) + @for %p in ($(STDTEST_PORTABLE) $(STDTEST_NONPORTABLE)) do @( \ + echo Testing %p && %p -v || echo %p failed \ + ) + +checkall: check + @for %d in ($(TEST_SUBDIRS)) do \ + %COMSPEC% /c "cd %%d && $(MAKE) -f Makefile.win check" \ + +# DO NOT REMOVE diff --git a/test/NWGNUaprtest b/test/NWGNUaprtest new file mode 100644 index 00000000000..0a8bc01ceb9 --- /dev/null +++ b/test/NWGNUaprtest @@ -0,0 +1,335 @@ +# +# Make sure all needed macro's are defined +# + +# +# Get the 'head' of the build environment if necessary. This includes default +# targets and paths to tools +# + +ifndef EnvironmentDefined +include $(APR_WORK)/build/NWGNUhead.inc +endif + +# +# These directories will be at the beginning of the include list, followed by +# INCDIRS +# +XINCDIRS += \ + $(APR)/include \ + $(APR)/include/arch/netware \ + $(EOLIST) + +# +# These flags will come after CFLAGS +# +XCFLAGS += \ + $(EOLIST) + +# +# These defines will come after DEFINES +# +XDEFINES += \ + $(EOLIST) + +# +# These flags will be added to the link.opt file +# +XLFLAGS += \ + $(EOLIST) + +# +# These values will be appended to the correct variables based on the value of +# RELEASE +# +ifeq "$(RELEASE)" "debug" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +ifeq "$(RELEASE)" "noopt" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +ifeq "$(RELEASE)" "release" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +# +# These are used by the link target if an NLM is being generated +# This is used by the link 'name' directive to name the nlm. If left blank +# TARGET_nlm (see below) will be used. +# +NLM_NAME = aprtest +# +# This is used by the link '-desc ' directive. +# If left blank, NLM_NAME will be used. +# +NLM_DESCRIPTION = NLM is to test the apr layer + +# +# This is used by the '-threadname' directive. If left blank, +# NLM_NAME Thread will be used. +# +NLM_THREAD_NAME = $(NLM_NAME) + +# +# This is used by the '-screenname' directive. If left blank, +# 'Apache for NetWare' Thread will be used. +# +NLM_SCREEN_NAME = $(NLM_NAME) + +# +# If this is specified, it will override VERSION value in +# $(APR_WORK)/build/NWGNUenvironment.inc +# +NLM_VERSION = + +# +# If this is specified, it will override the default of 64K +# +NLM_STACK_SIZE = 524288 + +# +# If this is specified it will be used by the link '-entry' directive +# +NLM_ENTRY_SYM = + +# +# If this is specified it will be used by the link '-exit' directive +# +NLM_EXIT_SYM = + +# +# If this is specified it will be used by the link '-check' directive +# +NLM_CHECK_SYM = + +# +# If this is specified it will be used by the link '-flags' directive +# +NLM_FLAGS = + +# +# If this is specified it will be linked in with the XDCData option in the def +# file instead of the default of $(APR)/misc/netware/apache.xdc. XDCData can +# be disabled by setting APACHE_UNIPROC in the environment +# +XDCDATA = + +# +# Declare all target files (you must add your files here) +# + +# +# If there is an NLM target, put it here +# +TARGET_nlm = \ + $(OBJDIR)/$(NLM_NAME).nlm \ + $(EOLIST) + +# +# If there is an LIB target, put it here +# +TARGET_lib = \ + $(EOLIST) + +# +# These are the OBJ files needed to create the NLM target above. +# Paths must all use the '/' character +# + +FILES_nlm_objs = \ + $(OBJDIR)/abts.o \ + $(OBJDIR)/testargs.o \ + $(OBJDIR)/testatomic.o \ + $(OBJDIR)/testbase64.o \ + $(OBJDIR)/testbuckets.o \ + $(OBJDIR)/testcond.o \ + $(OBJDIR)/testcrypto.o \ + $(OBJDIR)/testdate.o \ + $(OBJDIR)/testdbd.o \ + $(OBJDIR)/testdbm.o \ + $(OBJDIR)/testdir.o \ + $(OBJDIR)/testdup.o \ + $(OBJDIR)/testdso.o \ + $(OBJDIR)/testenv.o \ + $(OBJDIR)/testescape.o \ + $(OBJDIR)/testfilecopy.o \ + $(OBJDIR)/testfileinfo.o \ + $(OBJDIR)/testfile.o \ + $(OBJDIR)/testflock.o \ + $(OBJDIR)/testfmt.o \ + $(OBJDIR)/testfnmatch.o \ + $(OBJDIR)/testglobalmutex.o \ + $(OBJDIR)/testhash.o \ + $(OBJDIR)/testhooks.o \ + $(OBJDIR)/testipsub.o \ + $(OBJDIR)/testlfs.o \ + $(OBJDIR)/testlfsabi.o \ + $(OBJDIR)/testlfsabi32.o \ + $(OBJDIR)/testlfsabi64.o \ + $(OBJDIR)/testlock.o \ + $(OBJDIR)/testmd4.o \ + $(OBJDIR)/testmd5.o \ + $(OBJDIR)/testmmap.o \ + $(OBJDIR)/testmemcache.o \ + $(OBJDIR)/testnames.o \ + $(OBJDIR)/testoc.o \ + $(OBJDIR)/testpass.o \ + $(OBJDIR)/testpath.o \ + $(OBJDIR)/testpipe.o \ + $(OBJDIR)/testpoll.o \ + $(OBJDIR)/testpools.o \ + $(OBJDIR)/testproc.o \ + $(OBJDIR)/testprocmutex.o \ + $(OBJDIR)/testqueue.o \ + $(OBJDIR)/testreslist.o \ + $(OBJDIR)/testrand.o \ + $(OBJDIR)/testrmm.o \ + $(OBJDIR)/testshm.o \ + $(OBJDIR)/testsiphash.o \ + $(OBJDIR)/testskiplist.o \ + $(OBJDIR)/testsleep.o \ + $(OBJDIR)/testsock.o \ + $(OBJDIR)/testsockets.o \ + $(OBJDIR)/testsockopt.o \ + $(OBJDIR)/teststr.o \ + $(OBJDIR)/teststrmatch.o \ + $(OBJDIR)/teststrnatcmp.o \ + $(OBJDIR)/testtable.o \ + $(OBJDIR)/testtemp.o \ + $(OBJDIR)/testthread.o \ + $(OBJDIR)/testtime.o \ + $(OBJDIR)/testud.o \ + $(OBJDIR)/testuri.o \ + $(OBJDIR)/testuser.o \ + $(OBJDIR)/testutil.o \ + $(OBJDIR)/testuuid.o \ + $(OBJDIR)/testvsn.o \ + $(OBJDIR)/testxml.o \ + $(OBJDIR)/testxlate.o \ + $(OBJDIR)/nw_misc.o \ + $(EOLIST) + +# Pending tests + +# +# These are the LIB files needed to create the NLM target above. +# These will be added as a library command in the link.opt file. +# +FILES_nlm_libs = \ + $(PRELUDE) \ + $(EOLIST) + +# +# These are the modules that the above NLM target depends on to load. +# These will be added as a module command in the link.opt file. +# +FILES_nlm_modules = \ + Libc \ + APRLIB \ + $(EOLIST) + +# +# If the nlm has a msg file, put it's path here +# +FILE_nlm_msg = + +# +# If the nlm has a hlp file put it's path here +# +FILE_nlm_hlp = + +# +# If this is specified, it will override the default copyright. +# +FILE_nlm_copyright = + +# +# Any additional imports go here +# +FILES_nlm_Ximports = \ + @$(APR)/aprlib.imp \ + @$(NOVI)/libc.imp \ + $(EOLIST) + +# Include the Winsock imports if Winsock is being used +ifndef USE_STDSOCKETS +FILES_nlm_Ximports += \ + @$(NOVI)/ws2nlm.imp \ + $(EOLIST) +FILES_nlm_imports += \ + WSAStartupRTags \ + WSACleanupRTag \ + $(EOLIST) +endif + +# +# Any symbols exported to here +# +FILES_nlm_exports = \ + $(EOLIST) + +# +# These are the OBJ files needed to create the LIB target above. +# Paths must all use the '/' character +# +FILES_lib_objs = \ + $(EOLIST) + +# +# implement targets and dependancies (leave this section alone) +# + +libs :: $(OBJDIR) $(TARGET_lib) + +nlms :: libs $(TARGET_nlm) + +# +# Updated this target to create necessary directories and copy files to the +# correct place. (See $(APR_WORK)/build/NWGNUhead.inc for examples) +# +install :: nlms FORCE + +# +# Any specialized rules here +# + + +# +# Include the 'tail' makefile that has targets that depend on variables defined +# in this makefile +# + +include $(APRBUILD)/NWGNUtail.inc + diff --git a/test/NWGNUechod b/test/NWGNUechod new file mode 100644 index 00000000000..470c0cd8765 --- /dev/null +++ b/test/NWGNUechod @@ -0,0 +1,253 @@ +# +# Make sure all needed macro's are defined +# + +# +# Get the 'head' of the build environment if necessary. This includes default +# targets and paths to tools +# + +ifndef EnvironmentDefined +include $(APR_WORK)/build/NWGNUhead.inc +endif + +# +# These directories will be at the beginning of the include list, followed by +# INCDIRS +# +XINCDIRS += \ + $(APR)/include \ + $(APR)/include/arch/netware \ + $(EOLIST) + +# +# These flags will come after CFLAGS +# +XCFLAGS += \ + $(EOLIST) + +# +# These defines will come after DEFINES +# +XDEFINES += \ + $(EOLIST) + +# +# These flags will be added to the link.opt file +# +XLFLAGS += \ + $(EOLIST) + +# +# These values will be appended to the correct variables based on the value of +# RELEASE +# +ifeq "$(RELEASE)" "debug" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +ifeq "$(RELEASE)" "noopt" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +ifeq "$(RELEASE)" "release" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +# +# These are used by the link target if an NLM is being generated +# This is used by the link 'name' directive to name the nlm. If left blank +# TARGET_nlm (see below) will be used. +# +NLM_NAME = echod + +# +# This is used by the link '-desc ' directive. +# If left blank, NLM_NAME will be used. +# +NLM_DESCRIPTION = Echo Daemon NLM to test socket performance + +# +# This is used by the '-threadname' directive. If left blank, +# NLM_NAME Thread will be used. +# +NLM_THREAD_NAME = $(NLM_NAME) + +# +# This is used by the '-screenname' directive. If left blank, +# 'Apache for NetWare' Thread will be used. +# +NLM_SCREEN_NAME = $(NLM_NAME) + +# +# If this is specified, it will override VERSION value in +# $(APR_WORK)/build/NWGNUenvironment.inc +# +NLM_VERSION = + +# +# If this is specified, it will override the default of 64K +# +NLM_STACK_SIZE = + +# +# If this is specified it will be used by the link '-entry' directive +# +NLM_ENTRY_SYM = + +# +# If this is specified it will be used by the link '-exit' directive +# +NLM_EXIT_SYM = + +# +# If this is specified it will be used by the link '-check' directive +# +NLM_CHECK_SYM = + +# +# If this is specified it will be used by the link '-flags' directive +# +NLM_FLAGS = AUTOUNLOAD, PSEUDOPREEMPTION, MULTIPLE + +# +# If this is specified it will be linked in with the XDCData option in the def +# file instead of the default of $(APR)/misc/netware/apache.xdc. XDCData can +# be disabled by setting APACHE_UNIPROC in the environment +# +XDCDATA = + +# +# Declare all target files (you must add your files here) +# + +# +# If there is an NLM target, put it here +# +TARGET_nlm = \ + $(OBJDIR)/$(NLM_NAME).nlm \ + $(EOLIST) + +# +# If there is an LIB target, put it here +# +TARGET_lib = \ + $(EOLIST) + +# +# These are the OBJ files needed to create the NLM target above. +# Paths must all use the '/' character +# +FILES_nlm_objs = \ + $(OBJDIR)/$(NLM_NAME).o \ + $(OBJDIR)/nw_misc.o \ + $(EOLIST) + +# +# These are the LIB files needed to create the NLM target above. +# These will be added as a library command in the link.opt file. +# +FILES_nlm_libs = \ + $(PRELUDE) \ + $(EOLIST) + +# +# These are the modules that the above NLM target depends on to load. +# These will be added as a module command in the link.opt file. +# +FILES_nlm_modules = \ + aprlib \ + libc \ + $(EOLIST) + +# +# If the nlm has a msg file, put it's path here +# +FILE_nlm_msg = + +# +# If the nlm has a hlp file put it's path here +# +FILE_nlm_hlp = + +# +# If this is specified, it will override the default copyright. +# +FILE_nlm_copyright = + +# +# Any additional imports go here +# +FILES_nlm_Ximports = \ + @$(APR)/aprlib.imp \ + @$(NOVI)/libc.imp \ + $(EOLIST) + +# +# Any symbols exported to here +# +FILES_nlm_exports = \ + $(EOLIST) + +# +# These are the OBJ files needed to create the LIB target above. +# Paths must all use the '/' character +# +FILES_lib_objs = \ + $(EOLIST) + +# +# implement targets and dependancies (leave this section alone) +# + +libs :: $(OBJDIR) $(TARGET_lib) + +nlms :: libs $(TARGET_nlm) + +# +# Updated this target to create necessary directories and copy files to the +# correct place. (See $(APR_WORK)/build/NWGNUhead.inc for examples) +# +install :: nlms FORCE + +# +# Any specialized rules here +# + +# +# Include the 'tail' makefile that has targets that depend on variables defined +# in this makefile +# + +include $(APRBUILD)/NWGNUtail.inc + diff --git a/test/NWGNUglobalmutexchild b/test/NWGNUglobalmutexchild new file mode 100644 index 00000000000..9a1518a63fc --- /dev/null +++ b/test/NWGNUglobalmutexchild @@ -0,0 +1,254 @@ +# +# Make sure all needed macro's are defined +# + +# +# Get the 'head' of the build environment if necessary. This includes default +# targets and paths to tools +# + +ifndef EnvironmentDefined +include $(APR_WORK)/build/NWGNUhead.inc +endif + +# +# These directories will be at the beginning of the include list, followed by +# INCDIRS +# +XINCDIRS += \ + $(APR)/include \ + $(APR)/include/arch/netware \ + $(EOLIST) + +# +# These flags will come after CFLAGS +# +XCFLAGS += \ + $(EOLIST) + +# +# These defines will come after DEFINES +# +XDEFINES += \ + $(EOLIST) + +# +# These flags will be added to the link.opt file +# +XLFLAGS += \ + $(EOLIST) + +# +# These values will be appended to the correct variables based on the value of +# RELEASE +# +ifeq "$(RELEASE)" "debug" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +ifeq "$(RELEASE)" "noopt" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) + + $(EOLIST) +endif + +ifeq "$(RELEASE)" "release" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +# +# These are used by the link target if an NLM is being generated +# This is used by the link 'name' directive to name the nlm. If left blank +# TARGET_nlm (see below) will be used. +# +NLM_NAME = globalmutexchild + +# +# This is used by the link '-desc ' directive. +# If left blank, NLM_NAME will be used. +# +NLM_DESCRIPTION = child NLM to test the global Mutex layer + +# +# This is used by the '-threadname' directive. If left blank, +# NLM_NAME Thread will be used. +# +NLM_THREAD_NAME = $(NLM_NAME) + +# +# This is used by the '-screenname' directive. If left blank, +# 'Apache for NetWare' Thread will be used. +# +NLM_SCREEN_NAME = DEFAULT + +# +# If this is specified, it will override VERSION value in +# $(APR_WORK)/build/NWGNUenvironment.inc +# +NLM_VERSION = + +# +# If this is specified, it will override the default of 64K +# +NLM_STACK_SIZE = + +# +# If this is specified it will be used by the link '-entry' directive +# +NLM_ENTRY_SYM = + +# +# If this is specified it will be used by the link '-exit' directive +# +NLM_EXIT_SYM = + +# +# If this is specified it will be used by the link '-check' directive +# +NLM_CHECK_SYM = + +# +# If this is specified it will be used by the link '-flags' directive +# +NLM_FLAGS = AUTOUNLOAD, PSEUDOPREEMPTION, MULTIPLE + +# +# If this is specified it will be linked in with the XDCData option in the def +# file instead of the default of $(APR)/misc/netware/apache.xdc. XDCData can +# be disabled by setting APACHE_UNIPROC in the environment +# +XDCDATA = + +# +# Declare all target files (you must add your files here) +# + +# +# If there is an NLM target, put it here +# +TARGET_nlm = \ + $(OBJDIR)/$(NLM_NAME).nlm \ + $(EOLIST) + +# +# If there is an LIB target, put it here +# +TARGET_lib = \ + $(EOLIST) + +# +# These are the OBJ files needed to create the NLM target above. +# Paths must all use the '/' character +# +FILES_nlm_objs = \ + $(OBJDIR)/$(NLM_NAME).o \ + $(EOLIST) + +# +# These are the LIB files needed to create the NLM target above. +# These will be added as a library command in the link.opt file. +# +FILES_nlm_libs = \ + $(PRELUDE) \ + $(EOLIST) + +# +# These are the modules that the above NLM target depends on to load. +# These will be added as a module command in the link.opt file. +# +FILES_nlm_modules = \ + aprlib \ + libc \ + $(EOLIST) + +# +# If the nlm has a msg file, put it's path here +# +FILE_nlm_msg = + +# +# If the nlm has a hlp file put it's path here +# +FILE_nlm_hlp = + +# +# If this is specified, it will override the default copyright. +# +FILE_nlm_copyright = + +# +# Any additional imports go here +# +FILES_nlm_Ximports = \ + @$(APR)/aprlib.imp \ + @$(NOVI)/libc.imp \ + $(EOLIST) + +# +# Any symbols exported to here +# +FILES_nlm_exports = \ + $(EOLIST) + +# +# These are the OBJ files needed to create the LIB target above. +# Paths must all use the '/' character +# +FILES_lib_objs = \ + $(EOLIST) + +# +# implement targets and dependancies (leave this section alone) +# + +libs :: $(OBJDIR) $(TARGET_lib) + +nlms :: libs $(TARGET_nlm) + +# +# Updated this target to create necessary directories and copy files to the +# correct place. (See $(APR_WORK)/build/NWGNUhead.inc for examples) +# +install :: nlms FORCE + +# +# Any specialized rules here +# + +# +# Include the 'tail' makefile that has targets that depend on variables defined +# in this makefile +# + +include $(APRBUILD)/NWGNUtail.inc + diff --git a/test/NWGNUmakefile b/test/NWGNUmakefile new file mode 100644 index 00000000000..350e6652e7d --- /dev/null +++ b/test/NWGNUmakefile @@ -0,0 +1,264 @@ +# +# Declare the sub-directories to be built here +# + +SUBDIRS = \ + $(EOLIST) + +# +# Get the 'head' of the build environment. This includes default targets and +# paths to tools +# + +include $(APR_WORK)/build/NWGNUhead.inc + +# +# build this level's files + +# +# Make sure all needed macro's are defined +# + + +# +# These directories will be at the beginning of the include list, followed by +# INCDIRS +# +XINCDIRS += \ + $(EOLIST) + +# +# These flags will come after CFLAGS +# +XCFLAGS += \ + $(EOLIST) + +# +# These defines will come after DEFINES +# +XDEFINES += \ + $(EOLIST) + +# +# These flags will be added to the link.opt file +# +XLFLAGS += \ + $(EOLIST) + +# +# These values will be appended to the correct variables based on the value of +# RELEASE +# +ifeq "$(RELEASE)" "debug" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +ifeq "$(RELEASE)" "noopt" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +ifeq "$(RELEASE)" "release" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +# +# These are used by the link target if an NLM is being generated +# This is used by the link 'name' directive to name the nlm. If left blank +# TARGET_nlm (see below) will be used. +# +NLM_NAME = + +# +# This is used by the link '-desc ' directive. +# If left blank, NLM_NAME will be used. +# +NLM_DESCRIPTION = NLM is to test the apr layer + +# +# This is used by the '-threadname' directive. If left blank, +# NLM_NAME Thread will be used. +# +NLM_THREAD_NAME = + +# +# This is used by the '-screenname' directive. If left blank, +# 'Apache for NetWare' Thread will be used. +# +NLM_SCREEN_NAME = + +# +# If this is specified, it will override VERSION value in +# $(APR_WORK)/build/NWGNUenvironment.inc +# +NLM_VERSION = + +# +# If this is specified, it will override the default of 64K +# +NLM_STACK_SIZE = + +# +# If this is specified it will be used by the link '-entry' directive +# +NLM_ENTRY_SYM = + +# +# If this is specified it will be used by the link '-exit' directive +# +NLM_EXIT_SYM = + +# +# If this is specified it will be used by the link '-check' directive +# +NLM_CHECK_SYM = + +# +# If this is specified it will be used by the link '-flags' directive +# +NLM_FLAGS = + +# +# If this is specified it will be linked in with the XDCData option in the def +# file instead of the default of $(APR)/misc/netware/apache.xdc. XDCData can +# be disabled by setting APACHE_UNIPROC in the environment +# +XDCDATA = + +# +# Declare all target files (you must add your files here) +# + +# +# If there is an NLM target, put it here +# +TARGET_nlm = \ + $(OBJDIR)/aprtest.nlm \ + $(OBJDIR)/echod.nlm \ + $(OBJDIR)/globalmutexchild.nlm \ + $(OBJDIR)/mod_test.nlm \ + $(OBJDIR)/proc_child.nlm \ + $(OBJDIR)/readchild.nlm \ + $(OBJDIR)/sockchild.nlm \ + $(OBJDIR)/sockperf.nlm \ + $(OBJDIR)/testatmc.nlm \ + $(OBJDIR)/tryread.nlm \ + $(EOLIST) +# +# If there is an LIB target, put it here +# +TARGET_lib = \ + $(EOLIST) + +# +# These are the OBJ files needed to create the NLM target above. +# Paths must all use the '/' character +# +FILES_nlm_objs = \ + $(EOLIST) + +# +# These are the LIB files needed to create the NLM target above. +# These will be added as a library command in the link.opt file. +# +FILES_nlm_libs = \ + $(EOLIST) + +# +# These are the modules that the above NLM target depends on to load. +# These will be added as a module command in the link.opt file. +# +FILES_nlm_modules = \ + aprlib \ + $(EOLIST) + +# +# If the nlm has a msg file, put it's path here +# +FILE_nlm_msg = + +# +# If the nlm has a hlp file put it's path here +# +FILE_nlm_hlp = + +# +# If this is specified, it will override the default copyright. +# +FILE_nlm_copyright = + +# +# Any additional imports go here +# +FILES_nlm_Ximports = \ + $(EOLIST) + +# +# Any symbols exported to here +# +FILES_nlm_exports = \ + $(EOLIST) + +# +# These are the OBJ files needed to create the LIB target above. +# Paths must all use the '/' character +# +FILES_lib_objs = \ + $(EOLIST) + +# +# implement targets and dependancies (leave this section alone) +# + +libs :: $(OBJDIR) $(TARGET_lib) + +nlms :: libs $(TARGET_nlm) + +# +# Updated this target to create necessary directories and copy files to the +# correct place. (See $(APR_WORK)/build/NWGNUhead.inc for examples) +# +install :: nlms FORCE + $(call COPY,$(OBJDIR)/*.nlm,$(INSTALLBASE)/) + $(call COPYR,data,$(INSTALLBASE)/data/) + +# +# Any specialized rules here +# + +# +# Include the 'tail' makefile that has targets that depend on variables defined +# in this makefile +# + +include $(APRBUILD)/NWGNUtail.inc + diff --git a/test/NWGNUmod_test b/test/NWGNUmod_test new file mode 100644 index 00000000000..a69f4eab832 --- /dev/null +++ b/test/NWGNUmod_test @@ -0,0 +1,254 @@ +# +# Make sure all needed macro's are defined +# + +# +# Get the 'head' of the build environment if necessary. This includes default +# targets and paths to tools +# + +ifndef EnvironmentDefined +include $(APR_WORK)/build/NWGNUhead.inc +endif + +# +# These directories will be at the beginning of the include list, followed by +# INCDIRS +# +XINCDIRS += \ + $(APR)/include \ + $(APR)/include/arch/netware \ + $(EOLIST) + +# +# These flags will come after CFLAGS +# +XCFLAGS += \ + $(EOLIST) + +# +# These defines will come after DEFINES +# +XDEFINES += \ + $(EOLIST) + +# +# These flags will be added to the link.opt file +# +XLFLAGS += \ + $(EOLIST) + +# +# These values will be appended to the correct variables based on the value of +# RELEASE +# +ifeq "$(RELEASE)" "debug" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +ifeq "$(RELEASE)" "noopt" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +ifeq "$(RELEASE)" "release" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +# +# These are used by the link target if an NLM is being generated +# This is used by the link 'name' directive to name the nlm. If left blank +# TARGET_nlm (see below) will be used. +# +NLM_NAME = mod_test + +# +# This is used by the link '-desc ' directive. +# If left blank, NLM_NAME will be used. +# +NLM_DESCRIPTION = DSO NLM to test the apr DSO loading layer + +# +# This is used by the '-threadname' directive. If left blank, +# NLM_NAME Thread will be used. +# +NLM_THREAD_NAME = mod_test + +# +# This is used by the '-screenname' directive. If left blank, +# 'Apache for NetWare' Thread will be used. +# +NLM_SCREEN_NAME = DEFAULT + +# +# If this is specified, it will override VERSION value in +# $(APR_WORK)/build/NWGNUenvironment.inc +# +NLM_VERSION = + +# +# If this is specified, it will override the default of 64K +# +NLM_STACK_SIZE = + +# +# If this is specified it will be used by the link '-entry' directive +# +NLM_ENTRY_SYM = + +# +# If this is specified it will be used by the link '-exit' directive +# +NLM_EXIT_SYM = + +# +# If this is specified it will be used by the link '-check' directive +# +NLM_CHECK_SYM = + +# +# If this is specified it will be used by the link '-flags' directive +# +NLM_FLAGS = + +# +# If this is specified it will be linked in with the XDCData option in the def +# file instead of the default of $(APR)/misc/netware/apache.xdc. XDCData can +# be disabled by setting APACHE_UNIPROC in the environment +# +XDCDATA = + +# +# Declare all target files (you must add your files here) +# + +# +# If there is an NLM target, put it here +# +TARGET_nlm = \ + $(OBJDIR)/mod_test.nlm \ + $(EOLIST) + +# +# If there is an LIB target, put it here +# +TARGET_lib = \ + $(EOLIST) + +# +# These are the OBJ files needed to create the NLM target above. +# Paths must all use the '/' character +# +FILES_nlm_objs = \ + $(OBJDIR)/mod_test.o \ + $(EOLIST) + +# +# These are the LIB files needed to create the NLM target above. +# These will be added as a library command in the link.opt file. +# +FILES_nlm_libs = \ + $(PRELUDE) \ + $(EOLIST) + +# +# These are the modules that the above NLM target depends on to load. +# These will be added as a module command in the link.opt file. +# +FILES_nlm_modules = \ + aprlib \ + libc \ + $(EOLIST) + +# +# If the nlm has a msg file, put it's path here +# +FILE_nlm_msg = + +# +# If the nlm has a hlp file put it's path here +# +FILE_nlm_hlp = + +# +# If this is specified, it will override the default copyright. +# +FILE_nlm_copyright = + +# +# Any additional imports go here +# +FILES_nlm_Ximports = \ + @$(APR)/aprlib.imp \ + @$(NOVI)/libc.imp \ + $(EOLIST) + +# +# Any symbols exported to here +# +FILES_nlm_exports = \ + print_hello \ + count_reps \ + $(EOLIST) + +# +# These are the OBJ files needed to create the LIB target above. +# Paths must all use the '/' character +# +FILES_lib_objs = \ + $(EOLIST) + +# +# implement targets and dependancies (leave this section alone) +# + +libs :: $(OBJDIR) $(TARGET_lib) + +nlms :: libs $(TARGET_nlm) + +# +# Updated this target to create necessary directories and copy files to the +# correct place. (See $(APR_WORK)/build/NWGNUhead.inc for examples) +# +install :: nlms FORCE + +# +# Any specialized rules here +# + +# +# Include the 'tail' makefile that has targets that depend on variables defined +# in this makefile +# + +include $(APRBUILD)/NWGNUtail.inc + diff --git a/test/NWGNUproc_child b/test/NWGNUproc_child new file mode 100644 index 00000000000..423089c8ab6 --- /dev/null +++ b/test/NWGNUproc_child @@ -0,0 +1,252 @@ +# +# Make sure all needed macro's are defined +# + +# +# Get the 'head' of the build environment if necessary. This includes default +# targets and paths to tools +# + +ifndef EnvironmentDefined +include $(APR_WORK)/build/NWGNUhead.inc +endif + +# +# These directories will be at the beginning of the include list, followed by +# INCDIRS +# +XINCDIRS += \ + $(APR)/include \ + $(APR)/include/arch/netware \ + $(EOLIST) + +# +# These flags will come after CFLAGS +# +XCFLAGS += \ + $(EOLIST) + +# +# These defines will come after DEFINES +# +XDEFINES += \ + $(EOLIST) + +# +# These flags will be added to the link.opt file +# +XLFLAGS += \ + $(EOLIST) + +# +# These values will be appended to the correct variables based on the value of +# RELEASE +# +ifeq "$(RELEASE)" "debug" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +ifeq "$(RELEASE)" "noopt" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +ifeq "$(RELEASE)" "release" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +# +# These are used by the link target if an NLM is being generated +# This is used by the link 'name' directive to name the nlm. If left blank +# TARGET_nlm (see below) will be used. +# +NLM_NAME = proc_child + +# +# This is used by the link '-desc ' directive. +# If left blank, NLM_NAME will be used. +# +NLM_DESCRIPTION = child NLM to test the proc layer + +# +# This is used by the '-threadname' directive. If left blank, +# NLM_NAME Thread will be used. +# +NLM_THREAD_NAME = $(NLM_NAME) + +# +# This is used by the '-screenname' directive. If left blank, +# 'Apache for NetWare' Thread will be used. +# +NLM_SCREEN_NAME = DEFAULT + +# +# If this is specified, it will override VERSION value in +# $(APR_WORK)/build/NWGNUenvironment.inc +# +NLM_VERSION = + +# +# If this is specified, it will override the default of 64K +# +NLM_STACK_SIZE = + +# +# If this is specified it will be used by the link '-entry' directive +# +NLM_ENTRY_SYM = + +# +# If this is specified it will be used by the link '-exit' directive +# +NLM_EXIT_SYM = + +# +# If this is specified it will be used by the link '-check' directive +# +NLM_CHECK_SYM = + +# +# If this is specified it will be used by the link '-flags' directive +# +NLM_FLAGS = AUTOUNLOAD, PSEUDOPREEMPTION, MULTIPLE + +# +# If this is specified it will be linked in with the XDCData option in the def +# file instead of the default of $(APR)/misc/netware/apache.xdc. XDCData can +# be disabled by setting APACHE_UNIPROC in the environment +# +XDCDATA = + +# +# Declare all target files (you must add your files here) +# + +# +# If there is an NLM target, put it here +# +TARGET_nlm = \ + $(OBJDIR)/$(NLM_NAME).nlm \ + $(EOLIST) + +# +# If there is an LIB target, put it here +# +TARGET_lib = \ + $(EOLIST) + +# +# These are the OBJ files needed to create the NLM target above. +# Paths must all use the '/' character +# +FILES_nlm_objs = \ + $(OBJDIR)/$(NLM_NAME).o \ + $(EOLIST) + +# +# These are the LIB files needed to create the NLM target above. +# These will be added as a library command in the link.opt file. +# +FILES_nlm_libs = \ + $(PRELUDE) \ + $(EOLIST) + +# +# These are the modules that the above NLM target depends on to load. +# These will be added as a module command in the link.opt file. +# +FILES_nlm_modules = \ + aprlib \ + libc \ + $(EOLIST) + +# +# If the nlm has a msg file, put it's path here +# +FILE_nlm_msg = + +# +# If the nlm has a hlp file put it's path here +# +FILE_nlm_hlp = + +# +# If this is specified, it will override the default copyright. +# +FILE_nlm_copyright = + +# +# Any additional imports go here +# +FILES_nlm_Ximports = \ + @$(APR)/aprlib.imp \ + @$(NOVI)/libc.imp \ + $(EOLIST) + +# +# Any symbols exported to here +# +FILES_nlm_exports = \ + $(EOLIST) + +# +# These are the OBJ files needed to create the LIB target above. +# Paths must all use the '/' character +# +FILES_lib_objs = \ + $(EOLIST) + +# +# implement targets and dependancies (leave this section alone) +# + +libs :: $(OBJDIR) $(TARGET_lib) + +nlms :: libs $(TARGET_nlm) + +# +# Updated this target to create necessary directories and copy files to the +# correct place. (See $(APR_WORK)/build/NWGNUhead.inc for examples) +# +install :: nlms FORCE + +# +# Any specialized rules here +# + +# +# Include the 'tail' makefile that has targets that depend on variables defined +# in this makefile +# + +include $(APRBUILD)/NWGNUtail.inc + diff --git a/test/NWGNUreadchild b/test/NWGNUreadchild new file mode 100644 index 00000000000..451407f9452 --- /dev/null +++ b/test/NWGNUreadchild @@ -0,0 +1,252 @@ +# +# Make sure all needed macro's are defined +# + +# +# Get the 'head' of the build environment if necessary. This includes default +# targets and paths to tools +# + +ifndef EnvironmentDefined +include $(APR_WORK)/build/NWGNUhead.inc +endif + +# +# These directories will be at the beginning of the include list, followed by +# INCDIRS +# +XINCDIRS += \ + $(APR)/include \ + $(APR)/include/arch/netware \ + $(EOLIST) + +# +# These flags will come after CFLAGS +# +XCFLAGS += \ + $(EOLIST) + +# +# These defines will come after DEFINES +# +XDEFINES += \ + $(EOLIST) + +# +# These flags will be added to the link.opt file +# +XLFLAGS += \ + $(EOLIST) + +# +# These values will be appended to the correct variables based on the value of +# RELEASE +# +ifeq "$(RELEASE)" "debug" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +ifeq "$(RELEASE)" "noopt" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +ifeq "$(RELEASE)" "release" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +# +# These are used by the link target if an NLM is being generated +# This is used by the link 'name' directive to name the nlm. If left blank +# TARGET_nlm (see below) will be used. +# +NLM_NAME = readchild + +# +# This is used by the link '-desc ' directive. +# If left blank, NLM_NAME will be used. +# +NLM_DESCRIPTION = child NLM to test the pipe layer + +# +# This is used by the '-threadname' directive. If left blank, +# NLM_NAME Thread will be used. +# +NLM_THREAD_NAME = $(NLM_NAME) + +# +# This is used by the '-screenname' directive. If left blank, +# 'Apache for NetWare' Thread will be used. +# +NLM_SCREEN_NAME = DEFAULT + +# +# If this is specified, it will override VERSION value in +# $(APR_WORK)/build/NWGNUenvironment.inc +# +NLM_VERSION = + +# +# If this is specified, it will override the default of 64K +# +NLM_STACK_SIZE = + +# +# If this is specified it will be used by the link '-entry' directive +# +NLM_ENTRY_SYM = + +# +# If this is specified it will be used by the link '-exit' directive +# +NLM_EXIT_SYM = + +# +# If this is specified it will be used by the link '-check' directive +# +NLM_CHECK_SYM = + +# +# If this is specified it will be used by the link '-flags' directive +# +NLM_FLAGS = AUTOUNLOAD, PSEUDOPREEMPTION, MULTIPLE + +# +# If this is specified it will be linked in with the XDCData option in the def +# file instead of the default of $(APR)/misc/netware/apache.xdc. XDCData can +# be disabled by setting APACHE_UNIPROC in the environment +# +XDCDATA = + +# +# Declare all target files (you must add your files here) +# + +# +# If there is an NLM target, put it here +# +TARGET_nlm = \ + $(OBJDIR)/$(NLM_NAME).nlm \ + $(EOLIST) + +# +# If there is an LIB target, put it here +# +TARGET_lib = \ + $(EOLIST) + +# +# These are the OBJ files needed to create the NLM target above. +# Paths must all use the '/' character +# +FILES_nlm_objs = \ + $(OBJDIR)/$(NLM_NAME).o \ + $(EOLIST) + +# +# These are the LIB files needed to create the NLM target above. +# These will be added as a library command in the link.opt file. +# +FILES_nlm_libs = \ + $(PRELUDE) \ + $(EOLIST) + +# +# These are the modules that the above NLM target depends on to load. +# These will be added as a module command in the link.opt file. +# +FILES_nlm_modules = \ + aprlib \ + libc \ + $(EOLIST) + +# +# If the nlm has a msg file, put it's path here +# +FILE_nlm_msg = + +# +# If the nlm has a hlp file put it's path here +# +FILE_nlm_hlp = + +# +# If this is specified, it will override the default copyright. +# +FILE_nlm_copyright = + +# +# Any additional imports go here +# +FILES_nlm_Ximports = \ + @$(APR)/aprlib.imp \ + @$(NOVI)/libc.imp \ + $(EOLIST) + +# +# Any symbols exported to here +# +FILES_nlm_exports = \ + $(EOLIST) + +# +# These are the OBJ files needed to create the LIB target above. +# Paths must all use the '/' character +# +FILES_lib_objs = \ + $(EOLIST) + +# +# implement targets and dependancies (leave this section alone) +# + +libs :: $(OBJDIR) $(TARGET_lib) + +nlms :: libs $(TARGET_nlm) + +# +# Updated this target to create necessary directories and copy files to the +# correct place. (See $(APR_WORK)/build/NWGNUhead.inc for examples) +# +install :: nlms FORCE + +# +# Any specialized rules here +# + +# +# Include the 'tail' makefile that has targets that depend on variables defined +# in this makefile +# + +include $(APRBUILD)/NWGNUtail.inc + diff --git a/test/NWGNUsockchild b/test/NWGNUsockchild new file mode 100644 index 00000000000..5ed87ab218b --- /dev/null +++ b/test/NWGNUsockchild @@ -0,0 +1,252 @@ +# +# Make sure all needed macro's are defined +# + +# +# Get the 'head' of the build environment if necessary. This includes default +# targets and paths to tools +# + +ifndef EnvironmentDefined +include $(APR_WORK)/build/NWGNUhead.inc +endif + +# +# These directories will be at the beginning of the include list, followed by +# INCDIRS +# +XINCDIRS += \ + $(APR)/include \ + $(APR)/include/arch/netware \ + $(EOLIST) + +# +# These flags will come after CFLAGS +# +XCFLAGS += \ + $(EOLIST) + +# +# These defines will come after DEFINES +# +XDEFINES += \ + $(EOLIST) + +# +# These flags will be added to the link.opt file +# +XLFLAGS += \ + $(EOLIST) + +# +# These values will be appended to the correct variables based on the value of +# RELEASE +# +ifeq "$(RELEASE)" "debug" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +ifeq "$(RELEASE)" "noopt" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +ifeq "$(RELEASE)" "release" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +# +# These are used by the link target if an NLM is being generated +# This is used by the link 'name' directive to name the nlm. If left blank +# TARGET_nlm (see below) will be used. +# +NLM_NAME = sockchild + +# +# This is used by the link '-desc ' directive. +# If left blank, NLM_NAME will be used. +# +NLM_DESCRIPTION = socket NLM to test sockets + +# +# This is used by the '-threadname' directive. If left blank, +# NLM_NAME Thread will be used. +# +NLM_THREAD_NAME = $(NLM_NAME) + +# +# This is used by the '-screenname' directive. If left blank, +# 'Apache for NetWare' Thread will be used. +# +NLM_SCREEN_NAME = DEFAULT + +# +# If this is specified, it will override VERSION value in +# $(APR_WORK)/build/NWGNUenvironment.inc +# +NLM_VERSION = + +# +# If this is specified, it will override the default of 64K +# +NLM_STACK_SIZE = + +# +# If this is specified it will be used by the link '-entry' directive +# +NLM_ENTRY_SYM = + +# +# If this is specified it will be used by the link '-exit' directive +# +NLM_EXIT_SYM = + +# +# If this is specified it will be used by the link '-check' directive +# +NLM_CHECK_SYM = + +# +# If this is specified it will be used by the link '-flags' directive +# +NLM_FLAGS = AUTOUNLOAD, PSEUDOPREEMPTION, MULTIPLE + +# +# If this is specified it will be linked in with the XDCData option in the def +# file instead of the default of $(APR)/misc/netware/apache.xdc. XDCData can +# be disabled by setting APACHE_UNIPROC in the environment +# +XDCDATA = + +# +# Declare all target files (you must add your files here) +# + +# +# If there is an NLM target, put it here +# +TARGET_nlm = \ + $(OBJDIR)/$(NLM_NAME).nlm \ + $(EOLIST) + +# +# If there is an LIB target, put it here +# +TARGET_lib = \ + $(EOLIST) + +# +# These are the OBJ files needed to create the NLM target above. +# Paths must all use the '/' character +# +FILES_nlm_objs = \ + $(OBJDIR)/$(NLM_NAME).o \ + $(EOLIST) + +# +# These are the LIB files needed to create the NLM target above. +# These will be added as a library command in the link.opt file. +# +FILES_nlm_libs = \ + $(PRELUDE) \ + $(EOLIST) + +# +# These are the modules that the above NLM target depends on to load. +# These will be added as a module command in the link.opt file. +# +FILES_nlm_modules = \ + aprlib \ + libc \ + $(EOLIST) + +# +# If the nlm has a msg file, put it's path here +# +FILE_nlm_msg = + +# +# If the nlm has a hlp file put it's path here +# +FILE_nlm_hlp = + +# +# If this is specified, it will override the default copyright. +# +FILE_nlm_copyright = + +# +# Any additional imports go here +# +FILES_nlm_Ximports = \ + @$(APR)/aprlib.imp \ + @$(NOVI)/libc.imp \ + $(EOLIST) + +# +# Any symbols exported to here +# +FILES_nlm_exports = \ + $(EOLIST) + +# +# These are the OBJ files needed to create the LIB target above. +# Paths must all use the '/' character +# +FILES_lib_objs = \ + $(EOLIST) + +# +# implement targets and dependancies (leave this section alone) +# + +libs :: $(OBJDIR) $(TARGET_lib) + +nlms :: libs $(TARGET_nlm) + +# +# Updated this target to create necessary directories and copy files to the +# correct place. (See $(APR_WORK)/build/NWGNUhead.inc for examples) +# +install :: nlms FORCE + +# +# Any specialized rules here +# + +# +# Include the 'tail' makefile that has targets that depend on variables defined +# in this makefile +# + +include $(APRBUILD)/NWGNUtail.inc + diff --git a/test/NWGNUsockperf b/test/NWGNUsockperf new file mode 100644 index 00000000000..db6486af4e6 --- /dev/null +++ b/test/NWGNUsockperf @@ -0,0 +1,253 @@ +# +# Make sure all needed macro's are defined +# + +# +# Get the 'head' of the build environment if necessary. This includes default +# targets and paths to tools +# + +ifndef EnvironmentDefined +include $(APR_WORK)/build/NWGNUhead.inc +endif + +# +# These directories will be at the beginning of the include list, followed by +# INCDIRS +# +XINCDIRS += \ + $(APR)/include \ + $(APR)/include/arch/netware \ + $(EOLIST) + +# +# These flags will come after CFLAGS +# +XCFLAGS += \ + $(EOLIST) + +# +# These defines will come after DEFINES +# +XDEFINES += \ + $(EOLIST) + +# +# These flags will be added to the link.opt file +# +XLFLAGS += \ + $(EOLIST) + +# +# These values will be appended to the correct variables based on the value of +# RELEASE +# +ifeq "$(RELEASE)" "debug" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +ifeq "$(RELEASE)" "noopt" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +ifeq "$(RELEASE)" "release" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +# +# These are used by the link target if an NLM is being generated +# This is used by the link 'name' directive to name the nlm. If left blank +# TARGET_nlm (see below) will be used. +# +NLM_NAME = sockperf + +# +# This is used by the link '-desc ' directive. +# If left blank, NLM_NAME will be used. +# +NLM_DESCRIPTION = socket NLM to test socket performance + +# +# This is used by the '-threadname' directive. If left blank, +# NLM_NAME Thread will be used. +# +NLM_THREAD_NAME = $(NLM_NAME) + +# +# This is used by the '-screenname' directive. If left blank, +# 'Apache for NetWare' Thread will be used. +# +NLM_SCREEN_NAME = $(NLM_NAME) + +# +# If this is specified, it will override VERSION value in +# $(APR_WORK)/build/NWGNUenvironment.inc +# +NLM_VERSION = + +# +# If this is specified, it will override the default of 64K +# +NLM_STACK_SIZE = + +# +# If this is specified it will be used by the link '-entry' directive +# +NLM_ENTRY_SYM = + +# +# If this is specified it will be used by the link '-exit' directive +# +NLM_EXIT_SYM = + +# +# If this is specified it will be used by the link '-check' directive +# +NLM_CHECK_SYM = + +# +# If this is specified it will be used by the link '-flags' directive +# +NLM_FLAGS = AUTOUNLOAD, PSEUDOPREEMPTION, MULTIPLE + +# +# If this is specified it will be linked in with the XDCData option in the def +# file instead of the default of $(APR)/misc/netware/apache.xdc. XDCData can +# be disabled by setting APACHE_UNIPROC in the environment +# +XDCDATA = + +# +# Declare all target files (you must add your files here) +# + +# +# If there is an NLM target, put it here +# +TARGET_nlm = \ + $(OBJDIR)/$(NLM_NAME).nlm \ + $(EOLIST) + +# +# If there is an LIB target, put it here +# +TARGET_lib = \ + $(EOLIST) + +# +# These are the OBJ files needed to create the NLM target above. +# Paths must all use the '/' character +# +FILES_nlm_objs = \ + $(OBJDIR)/$(NLM_NAME).o \ + $(OBJDIR)/nw_misc.o \ + $(EOLIST) + +# +# These are the LIB files needed to create the NLM target above. +# These will be added as a library command in the link.opt file. +# +FILES_nlm_libs = \ + $(PRELUDE) \ + $(EOLIST) + +# +# These are the modules that the above NLM target depends on to load. +# These will be added as a module command in the link.opt file. +# +FILES_nlm_modules = \ + aprlib \ + libc \ + $(EOLIST) + +# +# If the nlm has a msg file, put it's path here +# +FILE_nlm_msg = + +# +# If the nlm has a hlp file put it's path here +# +FILE_nlm_hlp = + +# +# If this is specified, it will override the default copyright. +# +FILE_nlm_copyright = + +# +# Any additional imports go here +# +FILES_nlm_Ximports = \ + @$(APR)/aprlib.imp \ + @$(NOVI)/libc.imp \ + $(EOLIST) + +# +# Any symbols exported to here +# +FILES_nlm_exports = \ + $(EOLIST) + +# +# These are the OBJ files needed to create the LIB target above. +# Paths must all use the '/' character +# +FILES_lib_objs = \ + $(EOLIST) + +# +# implement targets and dependancies (leave this section alone) +# + +libs :: $(OBJDIR) $(TARGET_lib) + +nlms :: libs $(TARGET_nlm) + +# +# Updated this target to create necessary directories and copy files to the +# correct place. (See $(APR_WORK)/build/NWGNUhead.inc for examples) +# +install :: nlms FORCE + +# +# Any specialized rules here +# + +# +# Include the 'tail' makefile that has targets that depend on variables defined +# in this makefile +# + +include $(APRBUILD)/NWGNUtail.inc + diff --git a/test/NWGNUtestatmc b/test/NWGNUtestatmc new file mode 100644 index 00000000000..977fd8bfcc0 --- /dev/null +++ b/test/NWGNUtestatmc @@ -0,0 +1,255 @@ +# +# Make sure all needed macro's are defined +# + +# +# Get the 'head' of the build environment if necessary. This includes default +# targets and paths to tools +# + +ifndef EnvironmentDefined +include $(APR_WORK)/build/NWGNUhead.inc +endif + +# +# These directories will be at the beginning of the include list, followed by +# INCDIRS +# +XINCDIRS += \ + $(APR)/include \ + $(APR)/include/arch/netware \ + $(EOLIST) + +# +# These flags will come after CFLAGS +# +XCFLAGS += \ + $(EOLIST) + +# +# These defines will come after DEFINES +# +XDEFINES += \ + $(EOLIST) + +# +# These flags will be added to the link.opt file +# +XLFLAGS += \ + $(EOLIST) + +# +# These values will be appended to the correct variables based on the value of +# RELEASE +# +ifeq "$(RELEASE)" "debug" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +ifeq "$(RELEASE)" "noopt" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +ifeq "$(RELEASE)" "release" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +# +# These are used by the link target if an NLM is being generated +# This is used by the link 'name' directive to name the nlm. If left blank +# TARGET_nlm (see below) will be used. +# +NLM_NAME = testatmc +# +# This is used by the link '-desc ' directive. +# If left blank, NLM_NAME will be used. +# +NLM_DESCRIPTION = NLM is to test the atomic functions + +# +# This is used by the '-threadname' directive. If left blank, +# NLM_NAME Thread will be used. +# +NLM_THREAD_NAME = $(NLM_NAME) + +# +# This is used by the '-screenname' directive. If left blank, +# 'Apache for NetWare' Thread will be used. +# +NLM_SCREEN_NAME = $(NLM_NAME) + +# +# If this is specified, it will override VERSION value in +# $(APR_WORK)/build/NWGNUenvironment.inc +# +NLM_VERSION = + +# +# If this is specified, it will override the default of 64K +# +NLM_STACK_SIZE = + +# +# If this is specified it will be used by the link '-entry' directive +# +NLM_ENTRY_SYM = + +# +# If this is specified it will be used by the link '-exit' directive +# +NLM_EXIT_SYM = + +# +# If this is specified it will be used by the link '-check' directive +# +NLM_CHECK_SYM = + +# +# If this is specified it will be used by the link '-flags' directive +# +NLM_FLAGS = + +# +# If this is specified it will be linked in with the XDCData option in the def +# file instead of the default of $(APR)/misc/netware/apache.xdc. XDCData can +# be disabled by setting APACHE_UNIPROC in the environment +# +XDCDATA = + +# +# Declare all target files (you must add your files here) +# + +# +# If there is an NLM target, put it here +# +TARGET_nlm = \ + $(OBJDIR)/$(NLM_NAME).nlm \ + $(EOLIST) + +# +# If there is an LIB target, put it here +# +TARGET_lib = \ + $(EOLIST) + +# +# These are the OBJ files needed to create the NLM target above. +# Paths must all use the '/' character +# +FILES_nlm_objs = \ + $(OBJDIR)/testatomic.o \ + $(OBJDIR)/nw_misc.o \ + $(EOLIST) + +# Pending tests + +# +# These are the LIB files needed to create the NLM target above. +# These will be added as a library command in the link.opt file. +# +FILES_nlm_libs = \ + $(PRELUDE) \ + $(EOLIST) + +# +# These are the modules that the above NLM target depends on to load. +# These will be added as a module command in the link.opt file. +# +FILES_nlm_modules = \ + aprlib \ + libc \ + $(EOLIST) + +# +# If the nlm has a msg file, put it's path here +# +FILE_nlm_msg = + +# +# If the nlm has a hlp file put it's path here +# +FILE_nlm_hlp = + +# +# If this is specified, it will override the default copyright. +# +FILE_nlm_copyright = + +# +# Any additional imports go here +# +FILES_nlm_Ximports = \ + @$(APR)/aprlib.imp \ + @$(NOVI)/libc.imp \ + $(EOLIST) + +# +# Any symbols exported to here +# +FILES_nlm_exports = \ + $(EOLIST) + +# +# These are the OBJ files needed to create the LIB target above. +# Paths must all use the '/' character +# +FILES_lib_objs = \ + $(EOLIST) + +# +# implement targets and dependancies (leave this section alone) +# + +libs :: $(OBJDIR) $(TARGET_lib) + +nlms :: libs $(TARGET_nlm) + +# +# Updated this target to create necessary directories and copy files to the +# correct place. (See $(APR_WORK)/build/NWGNUhead.inc for examples) +# +install :: nlms FORCE + +# +# Any specialized rules here +# + + +# +# Include the 'tail' makefile that has targets that depend on variables defined +# in this makefile +# + +include $(APRBUILD)/NWGNUtail.inc + diff --git a/test/NWGNUtryread b/test/NWGNUtryread new file mode 100644 index 00000000000..f18d20d32a8 --- /dev/null +++ b/test/NWGNUtryread @@ -0,0 +1,253 @@ +# +# Make sure all needed macro's are defined +# + +# +# Get the 'head' of the build environment if necessary. This includes default +# targets and paths to tools +# + +ifndef EnvironmentDefined +include $(APR_WORK)/build/NWGNUhead.inc +endif + +# +# These directories will be at the beginning of the include list, followed by +# INCDIRS +# +XINCDIRS += \ + $(APR)/include \ + $(APR)/include/arch/netware \ + $(EOLIST) + +# +# These flags will come after CFLAGS +# +XCFLAGS += \ + $(EOLIST) + +# +# These defines will come after DEFINES +# +XDEFINES += \ + $(EOLIST) + +# +# These flags will be added to the link.opt file +# +XLFLAGS += \ + $(EOLIST) + +# +# These values will be appended to the correct variables based on the value of +# RELEASE +# +ifeq "$(RELEASE)" "debug" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +ifeq "$(RELEASE)" "noopt" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +ifeq "$(RELEASE)" "release" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +# +# These are used by the link target if an NLM is being generated +# This is used by the link 'name' directive to name the nlm. If left blank +# TARGET_nlm (see below) will be used. +# +NLM_NAME = tryread + +# +# This is used by the link '-desc ' directive. +# If left blank, NLM_NAME will be used. +# +NLM_DESCRIPTION = reader NLM to test flock + +# +# This is used by the '-threadname' directive. If left blank, +# NLM_NAME Thread will be used. +# +NLM_THREAD_NAME = $(NLM_NAME) + +# +# This is used by the '-screenname' directive. If left blank, +# 'Apache for NetWare' Thread will be used. +# +NLM_SCREEN_NAME = DEFAULT + +# +# If this is specified, it will override VERSION value in +# $(APR_WORK)/build/NWGNUenvironment.inc +# +NLM_VERSION = + +# +# If this is specified, it will override the default of 64K +# +NLM_STACK_SIZE = + +# +# If this is specified it will be used by the link '-entry' directive +# +NLM_ENTRY_SYM = + +# +# If this is specified it will be used by the link '-exit' directive +# +NLM_EXIT_SYM = + +# +# If this is specified it will be used by the link '-check' directive +# +NLM_CHECK_SYM = + +# +# If this is specified it will be used by the link '-flags' directive +# +NLM_FLAGS = AUTOUNLOAD, PSEUDOPREEMPTION, MULTIPLE + +# +# If this is specified it will be linked in with the XDCData option in the def +# file instead of the default of $(APR)/misc/netware/apache.xdc. XDCData can +# be disabled by setting APACHE_UNIPROC in the environment +# +XDCDATA = + +# +# Declare all target files (you must add your files here) +# + +# +# If there is an NLM target, put it here +# +TARGET_nlm = \ + $(OBJDIR)/$(NLM_NAME).nlm \ + $(EOLIST) + +# +# If there is an LIB target, put it here +# +TARGET_lib = \ + $(EOLIST) + +# +# These are the OBJ files needed to create the NLM target above. +# Paths must all use the '/' character +# +FILES_nlm_objs = \ + $(OBJDIR)/$(NLM_NAME).o \ + $(EOLIST) + +# +# These are the LIB files needed to create the NLM target above. +# These will be added as a library command in the link.opt file. +# +FILES_nlm_libs = \ + $(PRELUDE) \ + $(EOLIST) + +# +# These are the modules that the above NLM target depends on to load. +# These will be added as a module command in the link.opt file. +# +FILES_nlm_modules = \ + aprlib \ + libc \ + $(EOLIST) + +# +# If the nlm has a msg file, put it's path here +# +FILE_nlm_msg = + +# +# If the nlm has a hlp file put it's path here +# +FILE_nlm_hlp = + +# +# If this is specified, it will override the default copyright. +# +FILE_nlm_copyright = + +# +# Any additional imports go here +# +FILES_nlm_Ximports = \ + @$(APR)/aprlib.imp \ + @$(NOVI)/libc.imp \ + $(EOLIST) + +# +# Any symbols exported to here +# +FILES_nlm_exports = \ + $(EOLIST) + +# +# These are the OBJ files needed to create the LIB target above. +# Paths must all use the '/' character +# +FILES_lib_objs = \ + $(EOLIST) + +# +# implement targets and dependancies (leave this section alone) +# + +libs :: $(OBJDIR) $(TARGET_lib) + +nlms :: libs $(TARGET_nlm) + +# +# Updated this target to create necessary directories and copy files to the +# correct place. (See $(APR_WORK)/build/NWGNUhead.inc for examples) +# +install :: nlms FORCE + +# +# Any specialized rules here +# + +# +# Include the 'tail' makefile that has targets that depend on variables defined +# in this makefile +# + +include $(APRBUILD)/NWGNUtail.inc + + diff --git a/test/README b/test/README new file mode 100644 index 00000000000..408a6a22ed8 --- /dev/null +++ b/test/README @@ -0,0 +1,332 @@ +Writing APR tests + +All APR tests should be executable in 2 ways, as an individual program, or +as a part of the full test suite. The full test suite is controlled with +the testall program. At the beginning of the testall.c file, there is an +array of functions called tests. The testall program loops through this +array calling each function. Each function returns a CuSuite variable, which +is then added to the SuiteList. Once all Suites have been added, the SuiteList +is executed, and the output is printed to the screen. All functions in the +array should follow the same basic format: + +The Full Suite +-------------- + +/* The driver function. This must return a CuSuite variable, which will + * then be used to actually run the tests. Essentially, all Suites are a + * collection of tests. The driver will take each Suite, and put it in a + * SuiteList, which is a collection of Suites. + */ +CuSuite *testtime(void) +{ + /* The actual suite, this must be created for each test program. Please + * give it a useful name, that will inform the user of the feature being + * tested. + */ + CuSuite *suite = CuSuiteNew("Test Time"); + + /* Each function must be added to the suite. Each function represents + * a single test. It is possible to test multiple features in a single + * function, although no tests currently do that. + */ + SUITE_ADD_TEST(suite, test_now); + SUITE_ADD_TEST(suite, test_gmtstr); + SUITE_ADD_TEST(suite, test_localstr); + SUITE_ADD_TEST(suite, test_exp_get_gmt); + SUITE_ADD_TEST(suite, test_exp_get_lt); + SUITE_ADD_TEST(suite, test_imp_gmt); + SUITE_ADD_TEST(suite, test_rfcstr); + SUITE_ADD_TEST(suite, test_ctime); + SUITE_ADD_TEST(suite, test_strftime); + SUITE_ADD_TEST(suite, test_strftimesmall); + SUITE_ADD_TEST(suite, test_exp_tz); + SUITE_ADD_TEST(suite, test_strftimeoffset); + + /* You must return the suite so that the driver knows which suites to + * run. + */ + return suite; +} + +Building the full driver +------------------------ + +All you need to do to build the full driver is run: + + make + +To run it, run: + + ./testall + +Running individual tests +------------------------ + +It is not possible to build individual tests, however it is possible to +run individual tests. When running the test suite, specify the name of the +tests that you want to run on the command line. For example: + + ./testall teststr testrand + +Will run the Strings and Random generator tests. + +Reading the test suite output +----------------------------- + +Once you run the test suite, you will get output like: + +All APR Tests: + Test Strings: .... + Test Time: ............ + +16 tests run: 16 passed, 0 failed, 0 not implemented. + +Known test failures are documented in ../STATUS. + +There are a couple of things to look at with this. First, if you look at the +first function in this document, you should notice that the string passed to +the CuSuiteNew function is in the output. That is why the string should +explain the feature you are testing. + +Second, this test passed completely. This is obvious in two ways. First, and +most obvious, the summary line tells you that 16 tests were run and 16 tests +passed. However, the results can also be found in the lines above. Every +'.' in the output represents a passed test. + +If a test fails, the output will look like: + +All APR Tests: + Test Strings: .... + Test Time: ..F......... + +16 tests run: 15 passed, 1 failed, 0 not implemented. + +This is not very useful, because you don't know which test failed. However, +once you know that a test failed, you can run the suite again, with the +-v option. If you do this, you will get something like: + +All APR Tests: + Test Strings: .... + Test Time: ..F......... + +16 tests run: 15 passed, 1 failed, 0 not implemented. +Failed tests: +1) test_localstr: assert failed + +In this case, we know the test_localstr function failed, and there is an +Assert in this that failed (I modified the test to fail for this document). +Now, you can look at what that test does, and why it would have failed. + +There is one other possible output for the test suite (run with -v): + +All APR Tests: + Test Strings: .... + Test Time: ..N......... + +16 tests run: 15 passed, 0 failed, 1 not implemented. + +Not Implemented tests: + +Not Implemented tests: +1) test_localstr: apr_time_exp_lt not implemented on this platform + +The 'N' means that a function has returned APR_ENOTIMPL. This should be +treated as an error, and the function should be implemented as soon as +possible. + +Adding New test Suites to the full driver +------------------------------------------- + +To add a new Suite to the full driver, you must make a couple of modifications. + +1) Edit test_apr.h, and add the prototype for the function. +2) Edit testall.c, and add the function and name to the tests array. +3) Edit Makefile.in, and add the .lo file to the testall target. + +Once those four things are done, your tests will automatically be added +to the suite. + +Writting an ABTS unit test +-------------------------- + +The aim of this quick and dirty Howto is to give a short introduction +to APR (Apache Portable Runtime) unit tests, and how to write +one. During my Google's Summer of Code 2005 project, I discovered a +small bug in the APR-Util's date parsing routines, and I needed to +write a unit test for the fixed code. I decided to write this +documentation because I did not find any. Thanks to Garrett Rooney for +his help on writing the unit test ! + +The APR and APR-Util libraries provide a platform independent API for +software developers. They contain a lot of modules, including network +programming, threads, string and memory management, etc. All these +functions need to be heavily tested so that developers can be sure the +library is reliable. + +The ABTS give APR developers the ability to build a complete test +suite for the bunch of tests they wrote, which can then be ran under +various platforms. In this Howto, I will try teach you how to write an +ABTS unit test. + +As you may probably know, a unit test is a simple routine which tests +a very specific feature of the tested software or library. To build a +unit test, you need three different things : + + * the to-be-tested function, + * the input data that will be given to the function, + * the expected output data. + +The principle of a unit test is very simple : for each entry in your +set of input data, we pass it to our function, fetch what the function +returned and compare it to the corresponding expected output data. Of +course, the more edge cases you can test, the better your input data +set is. + +The ABTS aims to quicken the write of unit test, and make them +available to the whole test suite by providing a set of preprocessor +macros. Adding a unit test to a test suite can be easily done by the +following piece of code : + +abts_suite *testdaterfc(abts_suite *suite) +{ + suite = ADD_SUITE(suite); + abts_run_test(suite, test_date_rfc, NULL); + + return suite; +} + +Where test_date_rfc is the name of the function performing the +test. Writing such a function is, in the light of the explanation I +just gave, pretty much easy too. As I said, we need to check every +entry of our input data set. That gives us a loop. For each loop +iteration, we call our to-be-tested function, grab its result and +compare the returned value with the expected one. + +Test functions must have the following prototype : + +static void my_test_function(abts_case *tc, void *data); + +The comparison step is performed by the ABTS, thus giving the +whole test suite the correct behavior if your unit test fails. Here +comes a list of the available test methods : + +ABTS_INT_EQUAL(tc, a, b) +ABTS_INT_NEQUAL(tc, a, b) +ABTS_STR_EQUAL(tc, a, b) +ABTS_STR_NEQUAL(tc, a, b, c) +ABTS_PTR_NOTNULL(tc, b) +ABTS_PTR_EQUAL(tc, a, b) +ABTS_TRUE(tc, b) +ABTS_FAIL(tc, b) +ABTS_NOT_IMPL(tc, b) +ABTS_ASSERT(tc, a, b) + +The first argument, tc is a reference to the unit test currently +processed by the test suite (passed to your test function). The other +parameters are the data to be tested. For example, the following line +will never make your unit test fail : + +ABTS_INT_EQUAL(tc, 1, 1); + +See, it's easy ! Let's take a look at the complete example : +testdaterfc. We want to test our date string parser. For this, we will +use some chosen date strings (from mail headers for example) written +in various formats but that should all be handled by our function, and +their equivalents in correct RFC822 format. + +The function we want to test returns an apr_time_t}, which will be +directly given as input to the apr_rfc822_date() function, thus +producing the corresponding RFC822 date string. All we need to do +after this is to call the correct test method from the ABTS macros ! + +You can take a look at the apr-util/test/testdaterfc.c file for the +complete source code of this unit test. + +Although this Howto is very small and mostly dedicated to the +testdaterfc unit test, I hope you'll find it useful. Good luck ! + +Writing tests for CuTest (no longer used) +----------------------------------------- + +There are a couple of rules for writing good tests for the test suite. + +1) All tests can determine for themselves if it passed or not. This means +that there is no reason for the person running the test suite to interpret +the results of the tests. +2) Never use printf to add to the output of the test suite. The suite +library should be able to print all of the information required to debug +a problem. +3) Functions should be tested with both positive and negative tests. This +means that you should test things that should both succeed and fail. +4) Just checking the return code does _NOT_ make a useful test. You must +check to determine that the test actually did what you expected it to do. + +An example test +--------------- + +Finally, we will look at a quick test: + +/* All tests are passed a CuTest variable. This is how the suite determines + * if the test succeeded or failed. + */ +static void test_localstr(CuTest *tc) +{ + apr_status_t rv; + apr_time_exp_t xt; + time_t os_now; + + rv = apr_time_exp_lt(&xt, now); + os_now = now / APR_USEC_PER_SEC; + + /* If the function can return APR_ENOTIMPL, then you should check for it. + * This allows platform implementors to know if they have to implement + * the function. + */ + if (rv == APR_ENOTIMPL) { + CuNotImpl(tc, "apr_time_exp_lt"); + } + + /* It often helps to ensure that the return code was APR_SUCESS. If it + * wasn't, then we know the test failed. + */ + CuAssertTrue(tc, rv == APR_SUCCESS); + + /* Now that we know APR thinks it worked properly, we need to check the + * output to ensure that we got what we expected. + */ + CuAssertStrEquals(tc, "2002-08-14 12:05:36.186711 -25200 [257 Sat] DST", + print_time(p, &xt)); +} + +Notice, the same test can fail for any of a number of reasons. The first +test to fail ends the test. + +CuTest +------ + +CuTest is an open source test suite written by Asim Jalis. It has been +released under the zlib/libpng license. That license can be found in the +CuTest.c and CuTest.h files. + +The version of CuTest that is included in the APR test suite has been modified +from the original distribution in the following ways: + +1) The original distribution does not have a -v flag, the details are always +printed. +2) The NotImplemented result does not exist. +3) SuiteLists do not exist. In the original distribution, you can add suites +to suites, but it just adds the tests in the first suite to the list of tests +in the original suite. The output wasn't as detailed as I wanted, so I created +SuiteLists. + +The first two modifications have been sent to the original author of CuTest, +but they have not been integrated into the base distribution. The SuiteList +changes will be sent to the original author soon. + +The modified version of CuTest is not currently in any CVS or Subversion +server. In time, it will be hosted at rkbloom.net. + +There are currently no docs for how to write tests, but the teststr and +testtime programs should give an idea of how it is done. In time, a document +should be written to define how tests are written. + diff --git a/test/ab_apr.dsp b/test/ab_apr.dsp deleted file mode 100644 index 522b6312ca4..00000000000 --- a/test/ab_apr.dsp +++ /dev/null @@ -1,90 +0,0 @@ -# Microsoft Developer Studio Project File - Name="ab_apr" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 5.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Console Application" 0x0103 - -CFG=ab_apr - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "ab_apr.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "ab_apr.mak" CFG="ab_apr - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "ab_apr - Win32 Release" (based on "Win32 (x86) Console Application") -!MESSAGE "ab_apr - Win32 Debug" (based on "Win32 (x86) Console Application") -!MESSAGE - -# Begin Project -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -RSC=rc.exe - -!IF "$(CFG)" == "ab_apr - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /W3 /GX /O2 /I "..\include" /I "..\..\include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD BASE RSC /l 0x409 /d "NDEBUG" -# ADD RSC /l 0x409 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 -# ADD LINK32 ..\Release\aprlib.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"..\Release\ab_apr.exe" - -!ELSEIF "$(CFG)" == "ab_apr - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "ab_apr__" -# PROP BASE Intermediate_Dir "ab_apr__" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "ab_apr" -# PROP Intermediate_Dir "ab_apr" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /I "..\include" /I "..\..\include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FD /c -# SUBTRACT CPP /Fr /YX /Yc /Yu -# ADD BASE RSC /l 0x409 /d "_DEBUG" -# ADD RSC /l 0x409 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept -# ADD LINK32 ..\Debug\aprlib.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"..\Debug\ab_apr.exe" /pdbtype:sept - -!ENDIF - -# Begin Target - -# Name "ab_apr - Win32 Release" -# Name "ab_apr - Win32 Debug" -# Begin Source File - -SOURCE=.\ab_apr.c -# End Source File -# End Target -# End Project diff --git a/test/abc.c b/test/abc.c deleted file mode 100644 index eeb215e6ae7..00000000000 --- a/test/abc.c +++ /dev/null @@ -1,28 +0,0 @@ -#include <stdio.h> -#include <fcntl.h> -#include <sys/types.h> -#include "apr_file_io.h" -#include "apr_general.h" - -int main(int argc, char *argv[]) -{ - ap_file_t *fd = NULL; - char ch; - int status = 0; - ap_pool_t *context; - - ap_create_pool(&context, NULL); - - ap_open(&fd, argv[1], APR_READ, -1, context); - - while (!status) { - status = ap_getc(&ch, fd); - if (status == APR_EOF ) - fprintf(stdout, "EOF, YEAH!!!!!!!!!\n"); - else if (status == APR_SUCCESS) - fprintf(stdout, "%c", ch); - else - fprintf(stdout, " Big error, NOooooooooo!\n"); - } - return 1; -} diff --git a/test/abts.c b/test/abts.c new file mode 100644 index 00000000000..cab2e1aa094 --- /dev/null +++ b/test/abts.c @@ -0,0 +1,435 @@ +/* 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 "abts.h" +#include "abts_tests.h" +#include "testutil.h" + +#define ABTS_STAT_SIZE 6 +static char status[ABTS_STAT_SIZE] = {'|', '/', '-', '|', '\\', '-'}; +static int curr_char; +static int verbose = 0; +static int exclude = 0; +static int quiet = 0; +static int list_tests = 0; + +const char **testlist = NULL; + +static int find_test_name(const char *testname) { + int i; + for (i = 0; testlist[i] != NULL; i++) { + if (!strcmp(testlist[i], testname)) { + return 1; + } + } + return 0; +} + +/* Determine if the test should be run at all */ +static int should_test_run(const char *testname) { + int found = 0; + if (list_tests == 1) { + return 0; + } + if (testlist == NULL) { + return 1; + } + found = find_test_name(testname); + if ((found && !exclude) || (!found && exclude)) { + return 1; + } + return 0; +} + +static void reset_status(void) +{ + curr_char = 0; +} + +static void update_status(void) +{ + if (!quiet) { + curr_char = (curr_char + 1) % ABTS_STAT_SIZE; + fprintf(stdout, "\b%c", status[curr_char]); + fflush(stdout); + } +} + +static void end_suite(abts_suite *suite) +{ + if (suite != NULL) { + sub_suite *last = suite->tail; + if (!quiet) { + fprintf(stdout, "\b"); + fflush(stdout); + } + if (last->failed == 0) { + fprintf(stdout, "SUCCESS\n"); + fflush(stdout); + } + else { + fprintf(stdout, "FAILED %d of %d\n", last->failed, last->num_test); + fflush(stdout); + } + } +} + +abts_suite *abts_add_suite(abts_suite *suite, const char *suite_name_full) +{ + sub_suite *subsuite; + char *p; + const char *suite_name; + curr_char = 0; + + /* Only end the suite if we actually ran it */ + if (suite && suite->tail &&!suite->tail->not_run) { + end_suite(suite); + } + + subsuite = malloc(sizeof(*subsuite)); + subsuite->num_test = 0; + subsuite->failed = 0; + subsuite->next = NULL; + /* suite_name_full may be an absolute path depending on __FILE__ + * expansion */ + suite_name = strrchr(suite_name_full, '/'); + if (!suite_name) { + suite_name = strrchr(suite_name_full, '\\'); + } + if (suite_name) { + suite_name++; + } else { + suite_name = suite_name_full; + } + p = strrchr(suite_name, '.'); + if (p) { + subsuite->name = memcpy(calloc(p - suite_name + 1, 1), + suite_name, p - suite_name); + } + else { + subsuite->name = suite_name; + } + + if (list_tests) { + fprintf(stdout, "%s\n", subsuite->name); + } + + subsuite->not_run = 0; + + if (suite == NULL) { + suite = malloc(sizeof(*suite)); + suite->head = subsuite; + suite->tail = subsuite; + } + else { + suite->tail->next = subsuite; + suite->tail = subsuite; + } + + if (!should_test_run(subsuite->name)) { + subsuite->not_run = 1; + return suite; + } + + reset_status(); + fprintf(stdout, "%-20s: ", subsuite->name); + update_status(); + fflush(stdout); + + return suite; +} + +void abts_run_test(abts_suite *ts, test_func f, void *value) +{ + abts_case tc; + sub_suite *ss; + + if (!should_test_run(ts->tail->name)) { + return; + } + ss = ts->tail; + + tc.failed = 0; + tc.suite = ss; + + ss->num_test++; + update_status(); + + f(&tc, value); + + if (tc.failed) { + ss->failed++; + } +} + +static int report(abts_suite *suite) +{ + int count = 0; + sub_suite *dptr; + + if (suite && suite->tail &&!suite->tail->not_run) { + end_suite(suite); + } + + for (dptr = suite->head; dptr; dptr = dptr->next) { + count += dptr->failed; + } + + if (list_tests) { + return 0; + } + + if (count == 0) { + printf("All tests passed.\n"); + return 0; + } + + dptr = suite->head; + fprintf(stdout, "%-15s\t\tTotal\tFail\tFailed %%\n", "Failed Tests"); + fprintf(stdout, "===================================================\n"); + while (dptr != NULL) { + if (dptr->failed != 0) { + float percent = ((float)dptr->failed / (float)dptr->num_test); + fprintf(stdout, "%-15s\t\t%5d\t%4d\t%6.2f%%\n", dptr->name, + dptr->num_test, dptr->failed, percent * 100); + } + dptr = dptr->next; + } + return 1; +} + +void abts_log_message(const char *fmt, ...) +{ + va_list args; + update_status(); + + if (verbose) { + va_start(args, fmt); + vfprintf(stderr, fmt, args); + va_end(args); + fprintf(stderr, "\n"); + fflush(stderr); + } +} + +void abts_int_equal(abts_case *tc, const int expected, const int actual, int lineno) +{ + update_status(); + if (tc->failed) return; + + if (expected == actual) return; + + tc->failed = TRUE; + if (verbose) { + fprintf(stderr, "Line %d: expected <%d>, but saw <%d>\n", lineno, expected, actual); + fflush(stderr); + } +} + +void abts_int_nequal(abts_case *tc, const int expected, const int actual, int lineno) +{ + update_status(); + if (tc->failed) return; + + if (expected != actual) return; + + tc->failed = TRUE; + if (verbose) { + fprintf(stderr, "Line %d: expected something other than <%d>, but saw <%d>\n", + lineno, expected, actual); + fflush(stderr); + } +} + +void abts_size_equal(abts_case *tc, size_t expected, size_t actual, int lineno) +{ + update_status(); + if (tc->failed) return; + + if (expected == actual) return; + + tc->failed = TRUE; + if (verbose) { + /* Note that the comparison is type-exact, reporting must be a best-fit */ + fprintf(stderr, "Line %d: expected %lu, but saw %lu\n", lineno, + (unsigned long)expected, (unsigned long)actual); + fflush(stderr); + } +} + +void abts_str_equal(abts_case *tc, const char *expected, const char *actual, int lineno) +{ + update_status(); + if (tc->failed) return; + + if (!expected && !actual) return; + if (expected && actual) + if (!strcmp(expected, actual)) return; + + tc->failed = TRUE; + if (verbose) { + fprintf(stderr, "Line %d: expected <%s>, but saw <%s>\n", lineno, expected, actual); + fflush(stderr); + } +} + +void abts_str_nequal(abts_case *tc, const char *expected, const char *actual, + size_t n, int lineno) +{ + update_status(); + if (tc->failed) return; + + if (!strncmp(expected, actual, n)) return; + + tc->failed = TRUE; + if (verbose) { + fprintf(stderr, "Line %d: expected something other than <%s>, but saw <%s>\n", + lineno, expected, actual); + fflush(stderr); + } +} + +void abts_ptr_notnull(abts_case *tc, const void *ptr, int lineno) +{ + update_status(); + if (tc->failed) return; + + if (ptr != NULL) return; + + tc->failed = TRUE; + if (verbose) { + fprintf(stderr, "Line %d: expected non-NULL, but saw NULL\n", lineno); + fflush(stderr); + } +} + +void abts_ptr_equal(abts_case *tc, const void *expected, const void *actual, int lineno) +{ + update_status(); + if (tc->failed) return; + + if (expected == actual) return; + + tc->failed = TRUE; + if (verbose) { + fprintf(stderr, "Line %d: expected <%p>, but saw <%p>\n", lineno, expected, actual); + fflush(stderr); + } +} + +void abts_fail(abts_case *tc, const char *message, int lineno) +{ + update_status(); + if (tc->failed) return; + + tc->failed = TRUE; + if (verbose) { + fprintf(stderr, "Line %d: %s\n", lineno, message); + fflush(stderr); + } +} + +void abts_assert(abts_case *tc, const char *message, int condition, int lineno) +{ + update_status(); + if (tc->failed) return; + + if (condition) return; + + tc->failed = TRUE; + if (verbose) { + fprintf(stderr, "Line %d: %s\n", lineno, message); + fflush(stderr); + } +} + +void abts_true(abts_case *tc, int condition, int lineno) +{ + update_status(); + if (tc->failed) return; + + if (condition) return; + + tc->failed = TRUE; + if (verbose) { + fprintf(stderr, "Line %d: Condition is false, but expected true\n", lineno); + fflush(stderr); + } +} + +void abts_not_impl(abts_case *tc, const char *message, int lineno) +{ + update_status(); + + tc->suite->not_impl++; + if (verbose) { + fprintf(stderr, "Line %d: %s\n", lineno, message); + fflush(stderr); + } +} + +int main(int argc, const char *const argv[]) { + int i; + int rv; + int list_provided = 0; + abts_suite *suite = NULL; + + initialize(); + + quiet = !isatty(STDOUT_FILENO); + + for (i = 1; i < argc; i++) { + if (!strcmp(argv[i], "-v")) { + verbose = 1; + continue; + } + if (!strcmp(argv[i], "-x")) { + exclude = 1; + continue; + } + if (!strcmp(argv[i], "-l")) { + list_tests = 1; + continue; + } + if (!strcmp(argv[i], "-q")) { + quiet = 1; + continue; + } + if (argv[i][0] == '-') { + fprintf(stderr, "Invalid option: `%s'\n", argv[i]); + exit(1); + } + list_provided = 1; + } + + if (list_provided) { + /* Waste a little space here, because it is easier than counting the + * number of tests listed. Besides it is at most three char *. + */ + testlist = calloc(argc + 1, sizeof(char *)); + for (i = 1; i < argc; i++) { + testlist[i - 1] = argv[i]; + } + } + + for (i = 0; i < (sizeof(alltests) / sizeof(struct testlist *)); i++) { + suite = alltests[i].func(suite); + } + + rv = report(suite); + return rv; +} + diff --git a/test/abts.h b/test/abts.h new file mode 100644 index 00000000000..7385ca95728 --- /dev/null +++ b/test/abts.h @@ -0,0 +1,108 @@ +/* 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. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#ifdef WIN32 +#include <io.h> +#else +#include <unistd.h> +#endif + +#ifndef ABTS_H +#define ABTS_H + +#ifndef FALSE +#define FALSE 0 +#endif +#ifndef TRUE +#define TRUE 1 +#endif + +struct sub_suite { + const char *name; + int num_test; + int failed; + int not_run; + int not_impl; + struct sub_suite *next; +}; +typedef struct sub_suite sub_suite; + +struct abts_suite { + sub_suite *head; + sub_suite *tail; +}; +typedef struct abts_suite abts_suite; + +struct abts_case { + int failed; + sub_suite *suite; +}; +typedef struct abts_case abts_case; + +typedef void (*test_func)(abts_case *tc, void *data); + +#define ADD_SUITE(suite) abts_add_suite(suite, __FILE__); + +abts_suite *abts_add_suite(abts_suite *suite, const char *suite_name); +void abts_run_test(abts_suite *ts, test_func f, void *value); +void abts_log_message(const char *fmt, ...); + +void abts_int_equal(abts_case *tc, const int expected, const int actual, int lineno); +void abts_int_nequal(abts_case *tc, const int expected, const int actual, int lineno); +void abts_str_equal(abts_case *tc, const char *expected, const char *actual, int lineno); +void abts_str_nequal(abts_case *tc, const char *expected, const char *actual, + size_t n, int lineno); +void abts_ptr_notnull(abts_case *tc, const void *ptr, int lineno); +void abts_ptr_equal(abts_case *tc, const void *expected, const void *actual, int lineno); +void abts_true(abts_case *tc, int condition, int lineno); +void abts_fail(abts_case *tc, const char *message, int lineno); +void abts_not_impl(abts_case *tc, const char *message, int lineno); +void abts_assert(abts_case *tc, const char *message, int condition, int lineno); +void abts_size_equal(abts_case *tc, size_t expected, size_t actual, int lineno); + +/* Convenience macros. Ryan hates these! */ +#define ABTS_INT_EQUAL(a, b, c) abts_int_equal(a, b, c, __LINE__) +#define ABTS_INT_NEQUAL(a, b, c) abts_int_nequal(a, b, c, __LINE__) +#define ABTS_STR_EQUAL(a, b, c) abts_str_equal(a, b, c, __LINE__) +#define ABTS_STR_NEQUAL(a, b, c, d) abts_str_nequal(a, b, c, d, __LINE__) +#define ABTS_PTR_NOTNULL(a, b) abts_ptr_notnull(a, b, __LINE__) +#define ABTS_PTR_EQUAL(a, b, c) abts_ptr_equal(a, b, c, __LINE__) +#define ABTS_TRUE(a, b) abts_true(a, b, __LINE__); +#define ABTS_FAIL(a, b) abts_fail(a, b, __LINE__); +#define ABTS_NOT_IMPL(a, b) abts_not_impl(a, b, __LINE__); +#define ABTS_ASSERT(a, b, c) abts_assert(a, b, c, __LINE__); + +#define ABTS_SIZE_EQUAL(a, b, c) abts_size_equal(a, b, c, __LINE__) + + +abts_suite *run_tests(abts_suite *suite); +abts_suite *run_tests1(abts_suite *suite); + + +#endif + +#ifdef __cplusplus +} +#endif + diff --git a/test/abts_tests.h b/test/abts_tests.h new file mode 100644 index 00000000000..bfd83cf428d --- /dev/null +++ b/test/abts_tests.h @@ -0,0 +1,96 @@ +/* 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. + */ + +#ifndef APR_TEST_INCLUDES +#define APR_TEST_INCLUDES + +#include "abts.h" +#include "testutil.h" + +const struct testlist { + abts_suite *(*func)(abts_suite *suite); +} alltests[] = { + {testatomic}, + {testdir}, + {testdso}, + {testdup}, + {testenv}, + {testescape}, + {testfile}, + {testfilecopy}, + {testfileinfo}, + {testflock}, + {testfmt}, + {testfnmatch}, + {testgetopt}, +#if 0 /* not ready yet due to API issues */ + {testglobalmutex}, +#endif + {testhash}, + {testhooks}, + {testipsub}, + {testlock}, + {testcond}, + {testlfs}, + {testmmap}, + {testnames}, + {testoc}, + {testpath}, + {testpipe}, + {testpoll}, + {testpool}, + {testproc}, + {testprocmutex}, + {testrand}, + {testsleep}, + {testshm}, + {testsock}, + {testsockets}, + {testsockopt}, + {teststr}, + {teststrnatcmp}, + {testtable}, + {testtemp}, + {testthread}, + {testtime}, + {testud}, + {testuser}, + {testvsn}, + {teststrmatch}, + {testuri}, + {testuuid}, + {testbuckets}, + {testpass}, + {testbase64}, + {testmd4}, + {testmd5}, + {testcrypto}, + {testdbd}, + {testdate}, + {testmemcache}, + {testredis}, + {testxml}, + {testxlate}, + {testrmm}, + {testdbm}, + {testqueue}, + {testreslist}, + {testlfsabi}, + {testskiplist}, + {testsiphash} +}; + +#endif /* APR_TEST_INCLUDES */ diff --git a/test/client.c b/test/client.c deleted file mode 100644 index cd78ce11142..00000000000 --- a/test/client.c +++ /dev/null @@ -1,195 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#include <stdlib.h> -#include "apr_network_io.h" -#include "apr_errno.h" -#include "apr_general.h" -#include "errno.h" - -#define STRLEN 15 - -int main(int argc, char *argv[]) -{ - ap_pool_t *context; - ap_socket_t *sock; - ap_ssize_t length; - ap_status_t stat; - char datasend[STRLEN] = "Send data test"; - char datarecv[STRLEN]; - char *local_ipaddr, *remote_ipaddr; - char *dest = "127.0.0.1"; - ap_uint32_t local_port, remote_port; - ap_interval_time_t read_timeout = -1; - - setbuf(stdout, NULL); - if (argc > 1) { - dest = argv[1]; - } - - if (argc > 2) { - read_timeout = AP_USEC_PER_SEC * atoi(argv[2]); - } - - fprintf(stdout, "Initializing........."); - if (ap_initialize() != APR_SUCCESS) { - fprintf(stderr, "Something went wrong\n"); - exit(-1); - } - fprintf(stdout, "OK\n"); - atexit(ap_terminate); - - fprintf(stdout, "Creating context......."); - if (ap_create_pool(&context, NULL) != APR_SUCCESS) { - fprintf(stderr, "Something went wrong\n"); - exit(-1); - } - fprintf(stdout, "OK\n"); - - fprintf(stdout, "\tClient: Creating new socket......."); - if (ap_create_tcp_socket(&sock, context) != APR_SUCCESS) { - fprintf(stderr, "Couldn't create socket\n"); - exit(-1); - } - fprintf(stdout, "OK\n"); - - if (read_timeout == -1) { - fprintf(stdout, "\tClient: Setting socket option NONBLOCK......."); - if (ap_setsocketopt(sock, APR_SO_NONBLOCK, 1) != APR_SUCCESS) { - ap_close_socket(sock); - fprintf(stderr, "Couldn't set socket option\n"); - exit(-1); - } - fprintf(stdout, "OK\n"); - } - - fprintf(stdout, "\tClient: Setting port for socket......."); - if (ap_set_remote_port(sock, 8021) != APR_SUCCESS) { - ap_close_socket(sock); - fprintf(stderr, "Couldn't set the port correctly\n"); - exit(-1); - } - fprintf(stdout, "OK\n"); - - fprintf(stdout, "\tClient: Connecting to socket......."); - - do { - stat = ap_connect(sock, dest); - } while (stat == APR_ECONNREFUSED); - - if (stat != APR_SUCCESS) { - ap_close_socket(sock); - fprintf(stderr, "Could not connect %d\n", stat); - fflush(stderr); - exit(-1); - } - fprintf(stdout, "OK\n"); - - ap_get_remote_ipaddr(&remote_ipaddr, sock); - ap_get_remote_port(&remote_port, sock); - ap_get_local_ipaddr(&local_ipaddr, sock); - ap_get_local_port(&local_port, sock); - fprintf(stdout, "\tClient socket: %s:%u -> %s:%u\n", local_ipaddr, local_port, remote_ipaddr, remote_port); - - fprintf(stdout, "\tClient: Trying to send data over socket......."); - length = STRLEN; - if (ap_send(sock, datasend, &length) != APR_SUCCESS) { - ap_close_socket(sock); - fprintf(stderr, "Problem sending data\n"); - exit(-1); - } - fprintf(stdout, "OK\n"); - - if (read_timeout != -1) { - fprintf(stdout, "\tClient: Setting read timeout......."); - stat = ap_setsocketopt(sock, APR_SO_TIMEOUT, read_timeout); - if (stat) { - fprintf(stderr, "Problem setting timeout: %d\n", stat); - exit(-1); - } - fprintf(stdout, "OK\n"); - } - - length = STRLEN; - fprintf(stdout, "\tClient: Trying to receive data over socket......."); - - if ((stat = ap_recv(sock, datarecv, &length)) != APR_SUCCESS) { - ap_close_socket(sock); - fprintf(stderr, "Problem receiving data: %d\n", stat); - exit(-1); - } - if (strcmp(datarecv, "Recv data test")) { - ap_close_socket(sock); - fprintf(stderr, "I did not receive the correct data %s\n", datarecv); - exit(-1); - } - fprintf(stdout, "OK\n"); - - fprintf(stdout, "\tClient: Shutting down socket......."); - if (ap_shutdown(sock, APR_SHUTDOWN_WRITE) != APR_SUCCESS) { - ap_close_socket(sock); - fprintf(stderr, "Could not shutdown socket\n"); - exit(-1); - } - fprintf(stdout, "OK\n"); - - fprintf(stdout, "\tClient: Closing down socket......."); - if (ap_close_socket(sock) != APR_SUCCESS) { - fprintf(stderr, "Could not shutdown socket\n"); - exit(-1); - } - fprintf(stdout, "OK\n"); - - return 1; -} diff --git a/test/client.dsp b/test/client.dsp deleted file mode 100644 index 2afd1150a16..00000000000 --- a/test/client.dsp +++ /dev/null @@ -1,90 +0,0 @@ -# Microsoft Developer Studio Project File - Name="client" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 5.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Console Application" 0x0103 - -CFG=client - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "client.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "client.mak" CFG="client - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "client - Win32 Release" (based on "Win32 (x86) Console Application") -!MESSAGE "client - Win32 Debug" (based on "Win32 (x86) Console Application") -!MESSAGE - -# Begin Project -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -RSC=rc.exe - -!IF "$(CFG)" == "client - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /W3 /GX /O2 /I "..\include" /I "..\..\include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD BASE RSC /l 0x409 /d "NDEBUG" -# ADD RSC /l 0x409 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 -# ADD LINK32 ..\Release\aprlib.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"..\Release\client.exe" - -!ELSEIF "$(CFG)" == "client - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "client__" -# PROP BASE Intermediate_Dir "client__" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "client" -# PROP Intermediate_Dir "client" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /I "..\include" /I "..\..\include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "HAVE_STDIO_H" /FD /c -# SUBTRACT CPP /YX /Yc /Yu -# ADD BASE RSC /l 0x409 /d "_DEBUG" -# ADD RSC /l 0x409 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept -# ADD LINK32 ..\Debug\aprlib.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"..\Debug\client.exe" /pdbtype:sept - -!ENDIF - -# Begin Target - -# Name "client - Win32 Release" -# Name "client - Win32 Debug" -# Begin Source File - -SOURCE=.\client.c -# End Source File -# End Target -# End Project diff --git a/test/data/billion-laughs.xml b/test/data/billion-laughs.xml new file mode 100644 index 00000000000..3af89ae4dc7 --- /dev/null +++ b/test/data/billion-laughs.xml @@ -0,0 +1,36 @@ +<?xml version="1.0"?> +<!DOCTYPE billion [ +<!ELEMENT billion (#PCDATA)> +<!ENTITY laugh0 "ha"> +<!ENTITY laugh1 "&laugh0;&laugh0;"> +<!ENTITY laugh2 "&laugh1;&laugh1;"> +<!ENTITY laugh3 "&laugh2;&laugh2;"> +<!ENTITY laugh4 "&laugh3;&laugh3;"> +<!ENTITY laugh5 "&laugh4;&laugh4;"> +<!ENTITY laugh6 "&laugh5;&laugh5;"> +<!ENTITY laugh7 "&laugh6;&laugh6;"> +<!ENTITY laugh8 "&laugh7;&laugh7;"> +<!ENTITY laugh9 "&laugh8;&laugh8;"> +<!ENTITY laugh10 "&laugh9;&laugh9;"> +<!ENTITY laugh11 "&laugh10;&laugh10;"> +<!ENTITY laugh12 "&laugh11;&laugh11;"> +<!ENTITY laugh13 "&laugh12;&laugh12;"> +<!ENTITY laugh14 "&laugh13;&laugh13;"> +<!ENTITY laugh15 "&laugh14;&laugh14;"> +<!ENTITY laugh16 "&laugh15;&laugh15;"> +<!ENTITY laugh17 "&laugh16;&laugh16;"> +<!ENTITY laugh18 "&laugh17;&laugh17;"> +<!ENTITY laugh19 "&laugh18;&laugh18;"> +<!ENTITY laugh20 "&laugh19;&laugh19;"> +<!ENTITY laugh21 "&laugh20;&laugh20;"> +<!ENTITY laugh22 "&laugh21;&laugh21;"> +<!ENTITY laugh23 "&laugh22;&laugh22;"> +<!ENTITY laugh24 "&laugh23;&laugh23;"> +<!ENTITY laugh25 "&laugh24;&laugh24;"> +<!ENTITY laugh26 "&laugh25;&laugh25;"> +<!ENTITY laugh27 "&laugh26;&laugh26;"> +<!ENTITY laugh28 "&laugh27;&laugh27;"> +<!ENTITY laugh29 "&laugh28;&laugh28;"> +<!ENTITY laugh30 "&laugh29;&laugh29;"> +]> +<billion>&laugh30;</billion> diff --git a/test/data/file_datafile.txt b/test/data/file_datafile.txt new file mode 100644 index 00000000000..1651a3293f6 --- /dev/null +++ b/test/data/file_datafile.txt @@ -0,0 +1 @@ +This is the file data file. \ No newline at end of file diff --git a/test/data/mmap_datafile.txt b/test/data/mmap_datafile.txt new file mode 100644 index 00000000000..50f47a609ed --- /dev/null +++ b/test/data/mmap_datafile.txt @@ -0,0 +1 @@ +This is the MMAP data file. diff --git a/test/dbd.c b/test/dbd.c new file mode 100644 index 00000000000..dc2b1fb2401 --- /dev/null +++ b/test/dbd.c @@ -0,0 +1,409 @@ +/* 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 "apu.h" +#include "apr_pools.h" +#include "apr_dbd.h" + +#include <stdio.h> + +#define TEST(msg,func) \ + printf("======== %s ========\n", msg); \ + rv = func(pool, sql, driver); \ + if (rv != 0) { \ + printf("Error in %s: rc=%d\n\n", msg, rv); \ + } \ + else { \ + printf("%s test successful\n\n", msg); \ + } \ + fflush(stdout); + +static int create_table(apr_pool_t* pool, apr_dbd_t* handle, + const apr_dbd_driver_t* driver) +{ + int rv = 0; + int nrows; + const char *statement = "CREATE TABLE apr_dbd_test (" + "col1 varchar(40) not null," + "col2 varchar(40)," + "col3 integer)" ; + rv = apr_dbd_query(driver, handle, &nrows, statement); + return rv; +} +static int drop_table(apr_pool_t* pool, apr_dbd_t* handle, + const apr_dbd_driver_t* driver) +{ + int rv = 0; + int nrows; + const char *statement = "DROP TABLE apr_dbd_test" ; + rv = apr_dbd_query(driver, handle, &nrows, statement); + return rv; +} +static int insert_rows(apr_pool_t* pool, apr_dbd_t* handle, + const apr_dbd_driver_t* driver) +{ + int i; + int rv = 0; + int nrows; + int nerrors = 0; + const char *statement = + "INSERT into apr_dbd_test (col1) values ('foo');" + "INSERT into apr_dbd_test values ('wibble', 'other', 5);" + "INSERT into apr_dbd_test values ('wibble', 'nothing', 5);" + "INSERT into apr_dbd_test values ('qwerty', 'foo', 0);" + "INSERT into apr_dbd_test values ('asdfgh', 'bar', 1);" + ; + rv = apr_dbd_query(driver, handle, &nrows, statement); + if (rv) { + const char* stmt[] = { + "INSERT into apr_dbd_test (col1) values ('foo');", + "INSERT into apr_dbd_test values ('wibble', 'other', 5);", + "INSERT into apr_dbd_test values ('wibble', 'nothing', 5);", + "INSERT into apr_dbd_test values ('qwerty', 'foo', 0);", + "INSERT into apr_dbd_test values ('asdfgh', 'bar', 1);", + NULL + }; + printf("Compound insert failed; trying statements one-by-one\n") ; + for (i=0; stmt[i] != NULL; ++i) { + statement = stmt[i]; + rv = apr_dbd_query(driver, handle, &nrows, statement); + if (rv) { + nerrors++; + } + } + if (nerrors) { + printf("%d single inserts failed too.\n", nerrors) ; + } + } + return rv; +} +static int invalid_op(apr_pool_t* pool, apr_dbd_t* handle, + const apr_dbd_driver_t* driver) +{ + int rv = 0; + int nrows; + const char *statement = "INSERT into apr_dbd_test1 (col2) values ('foo')" ; + rv = apr_dbd_query(driver, handle, &nrows, statement); + printf("invalid op returned %d (should be nonzero). Error msg follows\n", rv); + printf("'%s'\n", apr_dbd_error(driver, handle, rv)); + statement = "INSERT into apr_dbd_test (col1, col2) values ('bar', 'foo')" ; + rv = apr_dbd_query(driver, handle, &nrows, statement); + printf("valid op returned %d (should be zero; error shouldn't affect subsequent ops)\n", rv); + return rv; +} +static int select_sequential(apr_pool_t* pool, apr_dbd_t* handle, + const apr_dbd_driver_t* driver) +{ + int rv = 0; + int i = 0; + int n; + const char* entry; + const char* statement = "SELECT * FROM apr_dbd_test ORDER BY col1, col2"; + apr_dbd_results_t *res = NULL; + apr_dbd_row_t *row = NULL; + rv = apr_dbd_select(driver,pool,handle,&res,statement,0); + if (rv) { + printf("Select failed: %s", apr_dbd_error(driver, handle, rv)); + return rv; + } + for (rv = apr_dbd_get_row(driver, pool, res, &row, -1); + rv == 0; + rv = apr_dbd_get_row(driver, pool, res, &row, -1)) { + printf("ROW %d: ", ++i) ; + for (n = 0; n < apr_dbd_num_cols(driver, res); ++n) { + entry = apr_dbd_get_entry(driver, row, n); + if (entry == NULL) { + printf("(null) ") ; + } + else { + printf("%s ", entry); + } + } + fputs("\n", stdout); + } + return (rv == -1) ? 0 : 1; +} +static int select_random(apr_pool_t* pool, apr_dbd_t* handle, + const apr_dbd_driver_t* driver) +{ + int rv = 0; + int n; + const char* entry; + const char* statement = "SELECT * FROM apr_dbd_test ORDER BY col1, col2"; + apr_dbd_results_t *res = NULL; + apr_dbd_row_t *row = NULL; + rv = apr_dbd_select(driver,pool,handle,&res,statement,1); + if (rv) { + printf("Select failed: %s", apr_dbd_error(driver, handle, rv)); + return rv; + } + rv = apr_dbd_get_row(driver, pool, res, &row, 5) ; + if (rv) { + printf("get_row failed: %s", apr_dbd_error(driver, handle, rv)); + return rv; + } + printf("ROW 5: "); + for (n = 0; n < apr_dbd_num_cols(driver, res); ++n) { + entry = apr_dbd_get_entry(driver, row, n); + if (entry == NULL) { + printf("(null) ") ; + } + else { + printf("%s ", entry); + } + } + fputs("\n", stdout); + rv = apr_dbd_get_row(driver, pool, res, &row, 1) ; + if (rv) { + printf("get_row failed: %s", apr_dbd_error(driver, handle, rv)); + return rv; + } + printf("ROW 1: "); + for (n = 0; n < apr_dbd_num_cols(driver, res); ++n) { + entry = apr_dbd_get_entry(driver, row, n); + if (entry == NULL) { + printf("(null) ") ; + } + else { + printf("%s ", entry); + } + } + fputs("\n", stdout); + rv = apr_dbd_get_row(driver, pool, res, &row, 11) ; + if (rv != -1) { + printf("Oops! get_row out of range but thinks it succeeded!\n%s\n", + apr_dbd_error(driver, handle, rv)); + return -1; + } + rv = 0; + + return rv; +} +static int test_transactions(apr_pool_t* pool, apr_dbd_t* handle, + const apr_dbd_driver_t* driver) +{ + int rv = 0; + int nrows; + apr_dbd_transaction_t *trans = NULL; + const char* statement; + + /* trans 1 - error out early */ + printf("Transaction 1\n"); + rv = apr_dbd_transaction_start(driver, pool, handle, &trans); + if (rv) { + printf("Start transaction failed!\n%s\n", + apr_dbd_error(driver, handle, rv)); + return rv; + } + statement = "UPDATE apr_dbd_test SET col2 = 'failed'"; + rv = apr_dbd_query(driver, handle, &nrows, statement); + if (rv) { + printf("Update failed: '%s'\n", apr_dbd_error(driver, handle, rv)); + apr_dbd_transaction_end(driver, pool, trans); + return rv; + } + printf("%d rows updated\n", nrows); + + statement = "INSERT INTO apr_dbd_test1 (col3) values (3)"; + rv = apr_dbd_query(driver, handle, &nrows, statement); + if (!rv) { + printf("Oops, invalid op succeeded but shouldn't!\n"); + } + statement = "INSERT INTO apr_dbd_test values ('zzz', 'aaa', 3)"; + rv = apr_dbd_query(driver, handle, &nrows, statement); + printf("Valid insert returned %d. Should be nonzero (fail) because transaction is bad\n", rv) ; + + rv = apr_dbd_transaction_end(driver, pool, trans); + if (rv) { + printf("End transaction failed!\n%s\n", + apr_dbd_error(driver, handle, rv)); + return rv; + } + printf("Transaction ended (should be rollback) - viewing table\n" + "A column of \"failed\" indicates transaction failed (no rollback)\n"); + select_sequential(pool, handle, driver); + + /* trans 2 - complete successfully */ + printf("Transaction 2\n"); + rv = apr_dbd_transaction_start(driver, pool, handle, &trans); + if (rv) { + printf("Start transaction failed!\n%s\n", + apr_dbd_error(driver, handle, rv)); + return rv; + } + statement = "UPDATE apr_dbd_test SET col2 = 'success'"; + rv = apr_dbd_query(driver, handle, &nrows, statement); + if (rv) { + printf("Update failed: '%s'\n", apr_dbd_error(driver, handle, rv)); + apr_dbd_transaction_end(driver, pool, trans); + return rv; + } + printf("%d rows updated\n", nrows); + statement = "INSERT INTO apr_dbd_test values ('aaa', 'zzz', 3)"; + rv = apr_dbd_query(driver, handle, &nrows, statement); + printf("Valid insert returned %d. Should be zero (OK)\n", rv) ; + rv = apr_dbd_transaction_end(driver, pool, trans); + if (rv) { + printf("End transaction failed!\n%s\n", + apr_dbd_error(driver, handle, rv)); + return rv; + } + printf("Transaction ended (should be commit) - viewing table\n"); + select_sequential(pool, handle, driver); + return rv; +} +static int test_pselect(apr_pool_t* pool, apr_dbd_t* handle, + const apr_dbd_driver_t* driver) +{ + int rv = 0; + int i, n; + const char *query = + "SELECT * FROM apr_dbd_test WHERE col3 <= %s or col1 = 'bar'" ; + const char *label = "lowvalues"; + apr_dbd_prepared_t *statement = NULL; + apr_dbd_results_t *res = NULL; + apr_dbd_row_t *row = NULL; + const char *entry = NULL; + + rv = apr_dbd_prepare(driver, pool, handle, query, label, &statement); + if (rv) { + printf("Prepare statement failed!\n%s\n", + apr_dbd_error(driver, handle, rv)); + return rv; + } + rv = apr_dbd_pvselect(driver, pool, handle, &res, statement, 0, "3", NULL); + if (rv) { + printf("Exec of prepared statement failed!\n%s\n", + apr_dbd_error(driver, handle, rv)); + return rv; + } + i = 0; + printf("Selecting rows where col3 <= 3 and bar row where it's unset.\nShould show four rows.\n"); + for (rv = apr_dbd_get_row(driver, pool, res, &row, -1); + rv == 0; + rv = apr_dbd_get_row(driver, pool, res, &row, -1)) { + printf("ROW %d: ", ++i) ; + for (n = 0; n < apr_dbd_num_cols(driver, res); ++n) { + entry = apr_dbd_get_entry(driver, row, n); + if (entry == NULL) { + printf("(null) ") ; + } + else { + printf("%s ", entry); + } + } + fputs("\n", stdout); + } + return (rv == -1) ? 0 : 1; +} +static int test_pquery(apr_pool_t* pool, apr_dbd_t* handle, + const apr_dbd_driver_t* driver) +{ + int rv = 0; + const char *query = "INSERT INTO apr_dbd_test VALUES (%s, %s, %d)"; + apr_dbd_prepared_t *statement = NULL; + const char *label = "testpquery"; + int nrows; + apr_dbd_transaction_t *trans =0; + + rv = apr_dbd_prepare(driver, pool, handle, query, label, &statement); + /* rv = apr_dbd_prepare(driver, pool, handle, query, NULL, &statement); */ + if (rv) { + printf("Prepare statement failed!\n%s\n", + apr_dbd_error(driver, handle, rv)); + return rv; + } + apr_dbd_transaction_start(driver, pool, handle, &trans); + rv = apr_dbd_pvquery(driver, pool, handle, &nrows, statement, + "prepared", "insert", "2", NULL); + apr_dbd_transaction_end(driver, pool, trans); + if (rv) { + printf("Exec of prepared statement failed!\n%s\n", + apr_dbd_error(driver, handle, rv)); + return rv; + } + printf("Showing table (should now contain row \"prepared insert 2\")\n"); + select_sequential(pool, handle, driver); + return rv; +} +int main(int argc, char** argv) +{ + const char *name; + const char *params; + apr_pool_t *pool = NULL; + apr_dbd_t *sql = NULL; + const apr_dbd_driver_t *driver = NULL; + char errbuf[256]; + int rv; + + apr_initialize(); + apr_pool_create(&pool, NULL); + + if (argc >= 2 && argc <= 3) { + name = argv[1]; + params = ( argc == 3 ) ? argv[2] : ""; + apr_dbd_init(pool); + setbuf(stdout,NULL); + rv = apr_dbd_get_driver(pool, name, &driver); + switch (rv) { + case APR_SUCCESS: + printf("Loaded %s driver OK.\n", name); + break; + case APR_EDSOOPEN: + printf("Failed to load driver file apr_dbd_%s.so\n", name); + goto finish; + case APR_ESYMNOTFOUND: + printf("Failed to load driver apr_dbd_%s_driver.\n", name); + goto finish; + case APR_ENOTIMPL: + printf("No driver available for %s.\n", name); + goto finish; + default: /* it's a bug if none of the above happen */ + printf("Internal error loading %s.\n", name); + printf("(%d)%s\n", rv, apr_strerror(rv, errbuf, sizeof errbuf)); + goto finish; + } + rv = apr_dbd_open(driver, pool, params, &sql); + switch (rv) { + case APR_SUCCESS: + printf("Opened %s[%s] OK\n", name, params); + break; + case APR_EGENERAL: + printf("Failed to open %s[%s]\n", name, params); + goto finish; + default: /* it's a bug if none of the above happen */ + printf("Internal error opening %s[%s]\n", name, params); + goto finish; + } + TEST("create table", create_table); + TEST("insert rows", insert_rows); + TEST("invalid op", invalid_op); + TEST("select random", select_random); + TEST("select sequential", select_sequential); + TEST("transactions", test_transactions); + TEST("prepared select", test_pselect); + TEST("prepared query", test_pquery); + TEST("drop table", drop_table); + apr_dbd_close(driver, sql); + } + else { + fprintf(stderr, "Usage: %s driver-name [params]\n", argv[0]); + } +finish: + apr_pool_destroy(pool); + apr_terminate(); + return 0; +} diff --git a/test/echod.c b/test/echod.c new file mode 100644 index 00000000000..052e47d8796 --- /dev/null +++ b/test/echod.c @@ -0,0 +1,134 @@ +/* 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. + */ + +/* Simple echo daemon, designed to be used for network throughput + * benchmarks. The aim is to allow us to monitor changes in performance + * of APR networking code, nothing more. + */ + +#include <stdio.h> +#include <stdlib.h> /* for atexit() */ + +#include "apr.h" +#include "apr_network_io.h" +#include "apr_strings.h" + +#define BUF_SIZE 4096 + +static void reportError(const char *msg, apr_status_t rv, + apr_pool_t *pool) +{ + fprintf(stderr, "%s\nError: %d\n'%s'\n", msg, rv, + apr_psprintf(pool, "%pm", &rv)); +} + +static apr_status_t talkTalk(apr_socket_t *socket, apr_pool_t *parent) +{ + apr_pool_t *pool; + apr_size_t len; + char *buf; + apr_status_t rv; + + if (apr_pool_create(&pool, parent) != APR_SUCCESS) + return APR_ENOPOOL; + + + buf = apr_palloc(pool, BUF_SIZE); + if (!buf) + return ENOMEM; + + do { + len = BUF_SIZE; + rv = apr_socket_recv(socket, buf, &len); + if (APR_STATUS_IS_EOF(rv) || len == 0 || rv != APR_SUCCESS) + break; + rv = apr_socket_send(socket, buf, &len); + if (len == 0 || rv != APR_SUCCESS) + break; + } while (rv == APR_SUCCESS); + + apr_pool_clear(pool); + return APR_SUCCESS; +} + +static apr_status_t glassToWall(apr_port_t port, apr_pool_t *parent) +{ + apr_sockaddr_t *sockAddr; + apr_socket_t *listener, *accepted; + apr_status_t rv; + + rv = apr_socket_create(&listener, APR_INET, SOCK_STREAM, APR_PROTO_TCP, + parent); + if (rv != APR_SUCCESS) { + reportError("Unable to create socket", rv, parent); + return rv; + } + + rv = apr_sockaddr_info_get(&sockAddr, "127.0.0.1", APR_UNSPEC, + port, 0, parent); + if (rv != APR_SUCCESS) { + reportError("Unable to get socket info", rv, parent); + apr_socket_close(listener); + return rv; + } + + if ((rv = apr_socket_bind(listener, sockAddr)) != APR_SUCCESS || + (rv = apr_socket_listen(listener, 5)) != APR_SUCCESS) { + reportError("Unable to bind or listen to socket", rv, parent); + apr_socket_close(listener); + return rv; + } + + for (;;) { + rv = apr_socket_accept(&accepted, listener, parent); + if (rv != APR_SUCCESS) { + reportError("Error accepting on socket", rv, parent); + break; + } + printf("\tAnswering connection\n"); + rv = talkTalk(accepted, parent); + apr_socket_close(accepted); + printf("\tConnection closed\n"); + if (rv != APR_SUCCESS) + break; + } + + apr_socket_close(listener); + return APR_SUCCESS; +} + +int main(int argc, char **argv) +{ + apr_pool_t *pool; + apr_port_t theport = 4747; + + printf("APR Test Application: echod\n"); + + apr_initialize(); + atexit(apr_terminate); + + apr_pool_create(&pool, NULL); + + if (argc >= 2) { + printf("argc = %d, port = '%s'\n", argc, argv[1]); + theport = atoi(argv[1]); + } + + fprintf(stdout, "Starting to listen on port %d\n", theport); + glassToWall(theport, pool); + + return 0; +} diff --git a/test/globalmutexchild.c b/test/globalmutexchild.c new file mode 100644 index 00000000000..4b8737b02bd --- /dev/null +++ b/test/globalmutexchild.c @@ -0,0 +1,64 @@ +/* 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 "testglobalmutex.h" +#include "apr_pools.h" +#include "apr_file_io.h" +#include "apr_general.h" +#include "apr_global_mutex.h" +#include "apr_strings.h" +#include "apr.h" + +#if APR_HAVE_STDLIB_H +#include <stdlib.h> +#endif + + +int main(int argc, const char * const argv[]) +{ + apr_pool_t *p; + int i = 0; + apr_lockmech_e mech; + apr_global_mutex_t *global_lock; + apr_status_t rv; + + apr_initialize(); + atexit(apr_terminate); + + apr_pool_create(&p, NULL); + if (argc >= 2) { + mech = (apr_lockmech_e)apr_strtoi64(argv[1], NULL, 0); + } + else { + mech = APR_LOCK_DEFAULT; + } + rv = apr_global_mutex_create(&global_lock, LOCKNAME, mech, p); + if (rv != APR_SUCCESS) { + exit(-rv); + } + apr_global_mutex_child_init(&global_lock, LOCKNAME, p); + + while (1) { + apr_global_mutex_lock(global_lock); + if (i == MAX_ITER) { + apr_global_mutex_unlock(global_lock); + exit(i); + } + i++; + apr_global_mutex_unlock(global_lock); + } + exit(0); +} diff --git a/test/htdigest.dsp b/test/htdigest.dsp deleted file mode 100644 index a0f8f0bf363..00000000000 --- a/test/htdigest.dsp +++ /dev/null @@ -1,90 +0,0 @@ -# Microsoft Developer Studio Project File - Name="htdigest" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 5.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Console Application" 0x0103 - -CFG=htdigest - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "htdigest.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "htdigest.mak" CFG="htdigest - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "htdigest - Win32 Release" (based on\ - "Win32 (x86) Console Application") -!MESSAGE "htdigest - Win32 Debug" (based on "Win32 (x86) Console Application") -!MESSAGE - -# Begin Project -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -RSC=rc.exe - -!IF "$(CFG)" == "htdigest - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /W3 /GX /O2 /I "..\include" /I "..\..\include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD BASE RSC /l 0x409 /d "NDEBUG" -# ADD RSC /l 0x409 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 -# ADD LINK32 ..\lib\Debug\lib.lib ..\misc\win32\Debug\misc.lib ..\threadproc\win32\Debug\threadproc.lib ..\file_io\win32\Debug\file_io.lib ..\time\win32\Debug\time.lib ..\locks\win32\Debug\locks.lib ..\network_io\win32\Debug\network_io.lib ..\signal\win32\Debug\signal.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 - -!ELSEIF "$(CFG)" == "htdigest - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "htdigest" -# PROP BASE Intermediate_Dir "htdigest" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "htdigest" -# PROP Intermediate_Dir "htdigest" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /I "..\include" /I "..\..\include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD BASE RSC /l 0x409 /d "_DEBUG" -# ADD RSC /l 0x409 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept -# ADD LINK32 ..\lib\Debug\lib.lib ..\misc\win32\Debug\misc.lib ..\threadproc\win32\Debug\threadproc.lib ..\file_io\win32\Debug\file_io.lib ..\time\win32\Debug\time.lib ..\locks\win32\Debug\locks.lib ..\network_io\win32\Debug\network_io.lib ..\signal\win32\Debug\signal.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept - -!ENDIF - -# Begin Target - -# Name "htdigest - Win32 Release" -# Name "htdigest - Win32 Debug" -# Begin Source File - -SOURCE=.\htdigest.c -# End Source File -# End Target -# End Project diff --git a/test/internal/Makefile.in b/test/internal/Makefile.in new file mode 100644 index 00000000000..b1f6c6a6c43 --- /dev/null +++ b/test/internal/Makefile.in @@ -0,0 +1,37 @@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +NONPORTABLE = \ + testregex@EXEEXT@ + +PROGRAMS = \ + +TARGETS = $(PROGRAMS) $(NONPORTABLE) + +# bring in rules.mk for standard functionality +@INCLUDE_RULES@ + +LOCAL_LIBS=../../lib@APR_LIBNAME@.la + +CLEAN_TARGETS = testregex@EXEEXT@ + +INCDIR=../../include +INCLUDES=-I$(INCDIR) + +CFLAGS=$(MY_CFLAGS) + +all: $(PROGRAMS) $(NONPORTABLE) + +check: $(PROGRAMS) $(NONPORTABLE) + for prog in $(PROGRAMS) $(NONPORTABLE); do \ + ./$$prog; \ + if test $$i = 255; then \ + echo "$$prog failed"; \ + break; \ + fi \ + done + +testregex@EXEEXT@: testregex.lo $(LOCAL_LIBS) + $(LINK) testregex.lo $(LOCAL_LIBS) $(ALL_LIBS) + +# DO NOT REMOVE diff --git a/test/internal/Makefile.win b/test/internal/Makefile.win new file mode 100644 index 00000000000..a881f078108 --- /dev/null +++ b/test/internal/Makefile.win @@ -0,0 +1,109 @@ +# PROGRAMS includes all test programs built on this platform. +# STDTEST_PORTABLE +# test programs invoked via standard user interface, run on all platforms +# STDTEST_NONPORTABLE +# test programs invoked via standard user interface, not portable +# OTHER_PROGRAMS +# programs such as sendfile, that have to be invoked in a special sequence +# or with special parameters + +!IFNDEF MODEL +MODEL=dynamic +!ENDIF + +INCDIR=../../include + +!IFNDEF OUTDIR +!IF "$(MODEL)" == "static" +OUTDIR=LibR +!ELSE +OUTDIR=Release +!ENDIF + +!IF [$(COMSPEC) /c cl /nologo /? | find "x64" >NUL ] == 0 +OUTDIR=x64\$(OUTDIR) +!ENDIF +!ENDIF + +!IF !EXIST("$(OUTDIR)\.") +!IF ([$(COMSPEC) /C mkdir $(OUTDIR)] == 0) +!ENDIF +!ENDIF + +!IFNDEF INTDIR +INTDIR=$(OUTDIR) +!ELSE +!IF !EXIST("$(INTDIR)\.") +!IF ([$(COMSPEC) /C mkdir $(INTDIR)] == 0) +!ENDIF +!ENDIF +!ENDIF + +!MESSAGE Building tests into $(OUTDIR) for $(MODEL) + +NONPORTABLE = \ + $(OUTDIR)\testucs.exe + +CLEAN_BUILDDIRS = Release Debug 9x x64 + +PROGRAMS = + +TARGETS = $(PROGRAMS) $(NONPORTABLE) + +# bring in rules.mk for standard functionality +ALL: $(TARGETS) + +CL = cl.exe +LD = link.exe + +!IF "$(MODEL)" == "static" +LOCAL_LIB= ..\..\$(OUTDIR)\apr-1.lib +STATIC_CFLAGS = /D APR_DECLARE_STATIC +!ELSE +LOCAL_LIB= ..\..\$(OUTDIR)\libapr-1.lib +STATIC_CFLAGS = +!ENDIF + +!IFDEF _DEBUG +DEBUG_CFLAGS = /MDd +!ELSE +DEBUG_CFLAGS = /MD +!ENDIF + +INCLUDES=/I "$(INCDIR)" + +CFLAGS = /nologo /c /W3 /Gm /EHsc /Zi /Od $(INCLUDES) \ + $(STATIC_CFLAGS) $(DEBUG_CFLAGS) /D "BINPATH=$(OUTDIR:\=/)" \ + /D _DEBUG /D WIN32 /Fo"$(INTDIR)/" /FD + +LD_LIBS = kernel32.lib advapi32.lib ws2_32.lib wsock32.lib \ + ole32.lib shell32.lib rpcrt4.lib + +LDFLAGS = /nologo /debug /subsystem:console /incremental:no +SHLDFLAGS = /nologo /dll /debug /subsystem:windows /incremental:no + +.c{$(INTDIR)}.obj: + $(CL) $(CFLAGS) -c $< -Fd$(INTDIR)\ $(INCLUDES) + +$(OUTDIR)\testucs.exe: $(INTDIR)\testucs.obj $(LOCAL_LIB) + $(LD) $(LDFLAGS) /out:"$@" $** $(LD_LIBS) + @if exist "$@.manifest" \ + mt.exe -manifest "$@.manifest" -outputresource:$@;1 + + +clean: + @if EXIST $(INTDIR)\. rmdir /s /q $(INTDIR) + @if EXIST $(OUTDIR)\. rmdir /s /q $(OUTDIR) + +cleanall: + @for %d in ($(CLEAN_BUILDDIRS)) do @if EXIST %d\. rmdir /s /q %d + + +PATH=$(OUTDIR);..\..\$(OUTDIR);$(PATH) + +check: $(NONPORTABLE) + @for %p in ($(NONPORTABLE)) do @( \ + echo Testing %p && %p || echo %p failed \ + ) + +# DO NOT REMOVE diff --git a/test/internal/testregex.c b/test/internal/testregex.c new file mode 100644 index 00000000000..20dcfdebe7b --- /dev/null +++ b/test/internal/testregex.c @@ -0,0 +1,91 @@ +/* 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_strings.h" +#include "apr_pools.h" +#include "apr_general.h" +#include "apr_hash.h" +#include "apr_lib.h" +#include "apr_time.h" +#include <regex.h> +#include <stdio.h> +#include <stdlib.h> + +int main( int argc, char** argv) { + apr_pool_t *context; + regex_t regex; + int rc; + int i; + int iters; + apr_time_t now; + apr_time_t end; + apr_hash_t *h; + + + if (argc !=4 ) { + fprintf(stderr, "Usage %s match string #iterations\n",argv[0]); + return -1; + } + iters = atoi( argv[3]); + + apr_initialize() ; + atexit(apr_terminate); + if (apr_pool_create(&context, NULL) != APR_SUCCESS) { + fprintf(stderr, "Something went wrong\n"); + exit(-1); + } + rc = regcomp( ®ex, argv[1], REG_EXTENDED|REG_NOSUB); + + + if (rc) { + char errbuf[2000]; + regerror(rc, ®ex,errbuf,2000); + fprintf(stderr,"Couldn't compile regex ;(\n%s\n ",errbuf); + return -1; + } + if ( regexec( ®ex, argv[2], 0, NULL,0) == 0 ) { + fprintf(stderr,"Match\n"); + } + else { + fprintf(stderr,"No Match\n"); + } + now = apr_time_now(); + for (i=0;i<iters;i++) { + regexec( ®ex, argv[2], 0, NULL,0) ; + } + end=apr_time_now(); + puts(apr_psprintf( context, "Time to run %d regex's %8lld\n",iters,end-now)); + h = apr_hash_make( context); + for (i=0;i<70;i++) { + apr_hash_set(h,apr_psprintf(context, "%dkey",i),APR_HASH_KEY_STRING,"1"); + } + now = apr_time_now(); + for (i=0;i<iters;i++) { + apr_hash_get( h, argv[2], APR_HASH_KEY_STRING); + } + end=apr_time_now(); + puts(apr_psprintf( context, "Time to run %d hash (no find)'s %8lld\n",iters,end-now)); + apr_hash_set(h, argv[2],APR_HASH_KEY_STRING,"1"); + now = apr_time_now(); + for (i=0;i<iters;i++) { + apr_hash_get( h, argv[2], APR_HASH_KEY_STRING); + } + end=apr_time_now(); + puts(apr_psprintf( context, "Time to run %d hash (find)'s %8lld\n",iters,end-now)); + + return 0; +} diff --git a/test/internal/testucs.c b/test/internal/testucs.c new file mode 100644 index 00000000000..bf8874e48b7 --- /dev/null +++ b/test/internal/testucs.c @@ -0,0 +1,348 @@ +/* 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 "arch/win32/apr_arch_utf8.h" +#include <wchar.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> + +struct testval { + unsigned char n[8]; + apr_size_t nl; + wchar_t w[4]; + apr_size_t wl; +}; + +#ifdef FOR_REFERENCE +/* For reference; a table of invalid utf-8 encoded ucs-2/ucs-4 sequences. + * The table consists of start, end pairs for all invalid ranges. + * NO_UCS2_PAIRS will pass the reservered D800-DFFF values, halting at FFFF + * FULL_UCS4_MAPPER represents all 31 bit values to 7FFF FFFF + * + * We already tested these, because we ensure there is a 1:1 mapping across + * the entire range of byte values in each position of 1 to 6 byte sequences. + */ +struct testval malformed[] = [ + [[0x80,], 1,], /* 10000000 64 invalid leading continuation values */ + [[0xBF,], 1,], /* 10111111 64 invalid leading continuation values */ + [[0xC0,0x80], 2,], /* overshort mapping of 0000 */ + [[0xC1,0xBF], 2,], /* overshort mapping of 007F */ + [[0xE0,0x80,0x80,], 3,], /* overshort mapping of 0000 */ + [[0xE0,0x9F,0xBF,], 3,], /* overshort mapping of 07FF */ +#ifndef NO_UCS2_PAIRS + [[0xED,0xA0,0x80,], 3,], /* unexpected mapping of UCS-2 literal D800 */ + [[0xED,0xBF,0xBF,], 3,], /* unexpected mapping of UCS-2 literal DFFF */ +#endif + [[0xF0,0x80,0x80,0x80,], 4,], /* overshort mapping of 0000 */ + [[0xF0,0x8F,0xBF,0xBF,], 4,], /* overshort mapping of FFFF */ +#ifdef NO_UCS2_PAIRS + [[0xF0,0x90,0x80,0x80,], 4,], /* invalid too large value 0001 0000 */ + [[0xF4,0x8F,0xBF,0xBF,], 4,], /* invalid too large value 0010 FFFF */ +#endif +#ifndef FULL_UCS4_MAPPER + [[0xF4,0x90,0x80,0x80,], 4,], /* invalid too large value 0011 0000 */ + [[0xF7,0xBF,0xBF,0xBF,], 4,], /* invalid too large value 001F FFFF */ +#endif + [[0xF8,0x80,0x80,0x80,0x80,], 5,], /* overshort mapping of 0000 0000 */ + [[0xF8,0x87,0xBF,0xBF,0xBF,], 5,], /* overshort mapping of 001F FFFF */ +#ifndef FULL_UCS4_MAPPER + [[0xF8,0x88,0x80,0x80,0x80,], 5,], /* invalid too large value 0020 0000 */ + [[0xFB,0xBF,0xBF,0xBF,0xBF,], 5,], /* invalid too large value 03FF FFFF */ +#endif + [[0xFC,0x80,0x80,0x80,0x80,0x80,], 6,], /* overshort mapping 0000 0000 */ + [[0xFC,0x83,0xBF,0xBF,0xBF,0xBF,], 6,], /* overshort mapping 03FF FFFF */ +#ifndef FULL_UCS4_MAPPER + [[0xFC,0x84,0x80,0x80,0x80,0x80,], 6,], /* overshort mapping 0400 0000 */ + [[0xFD,0xBF,0xBF,0xBF,0xBF,0xBF,], 6,], /* overshort mapping 7FFF FFFF */ +#endif + [[0xFE,], 1,], /* 11111110 invalid "too large" value, no 7 byte seq */ + [[0xFF,], 1,], /* 11111111 invalid "too large" value, no 8 byte seq */ +]; +#endif /* FOR_REFERENCE */ + +void displaynw(struct testval *f, struct testval *l) +{ + char x[80], *t = x; + int i; + for (i = 0; i < f->nl; ++i) + t += sprintf(t, "%02X ", f->n[i]); + *(t++) = '-'; + for (i = 0; i < l->nl; ++i) + t += sprintf(t, " %02X", l->n[i]); + *(t++) = ' '; + *(t++) = '='; + *(t++) = ' '; + for (i = 0; i < f->wl; ++i) + t += sprintf(t, "%04X ", f->w[i]); + *(t++) = '-'; + for (i = 0; i < l->wl; ++i) + t += sprintf(t, " %04X", l->w[i]); + *t = '\0'; + puts(x); +} + +/* + * Test every possible byte value. + * If the test passes or fails at this byte value we are done. + * Otherwise iterate test_nrange again, appending another byte. + */ +void test_nrange(struct testval *p) +{ + struct testval f, l, s; + apr_status_t rc; + int success = 0; + + memcpy (&s, p, sizeof(s)); + ++s.nl; + + do { + apr_size_t nl = s.nl, wl = sizeof(s.w) / 2; + rc = apr_conv_utf8_to_ucs2(s.n, &nl, s.w, &wl); + s.wl = (sizeof(s.w) / 2) - wl; + if (!nl && rc == APR_SUCCESS) { + if (!success) { + memcpy(&f, &s, sizeof(s)); + success = -1; + } + else { + if (s.wl != l.wl + || memcmp(s.w, l.w, (s.wl - 1) * 2) != 0 + || s.w[s.wl - 1] != l.w[l.wl - 1] + 1) { + displaynw(&f, &l); + memcpy(&f, &s, sizeof(s)); + } + } + memcpy(&l, &s, sizeof(s)); + } + else { + if (success) { + displaynw(&f, &l); + success = 0; + } + if (rc == APR_INCOMPLETE) { + test_nrange(&s); + } + } + } while (++s.n[s.nl - 1]); + + if (success) { + displaynw(&f, &l); + success = 0; + } +} + +/* + * Test every possible word value. + * Once we are finished, retest every possible word value. + * if the test fails on the following null word, iterate test_nrange + * again, appending another word. + * This assures the output order of the two tests are in sync. + */ +void test_wrange(struct testval *p) +{ + struct testval f, l, s; + apr_status_t rc; + int success = 0; + + memcpy (&s, p, sizeof(s)); + ++s.wl; + + do { + apr_size_t nl = sizeof(s.n), wl = s.wl; + rc = apr_conv_ucs2_to_utf8(s.w, &wl, s.n, &nl); + s.nl = sizeof(s.n) - nl; + if (!wl && rc == APR_SUCCESS) { + if (!success) { + memcpy(&f, &s, sizeof(s)); + success = -1; + } + else { + if (s.nl != l.nl + || memcmp(s.n, l.n, s.nl - 1) != 0 + || s.n[s.nl - 1] != l.n[l.nl - 1] + 1) { + displaynw(&f, &l); + memcpy(&f, &s, sizeof(s)); + } + } + memcpy(&l, &s, sizeof(s)); + } + else { + if (success) { + displaynw(&f, &l); + success = 0; + } + } + } while (++s.w[s.wl - 1]); + + if (success) { + displaynw(&f, &l); + success = 0; + } + + do { + apr_size_t wl = s.wl, nl = sizeof(s.n); + rc = apr_conv_ucs2_to_utf8(s.w, &wl, s.n, &nl); + s.nl = sizeof(s.n) - s.nl; + if (rc == APR_INCOMPLETE) { + test_wrange(&s); + } + } while (++s.w[s.wl - 1]); +} + +/* + * Test every possible byte value. + * If the test passes or fails at this byte value we are done. + * Otherwise iterate test_nrange again, appending another byte. + */ +void test_ranges() +{ + struct testval ntest, wtest; + apr_status_t nrc, wrc; + apr_size_t inlen; + unsigned long matches = 0; + + memset(&ntest, 0, sizeof(ntest)); + ++ntest.nl; + + memset(&wtest, 0, sizeof(wtest)); + ++wtest.wl; + + do { + do { + inlen = ntest.nl; + ntest.wl = sizeof(ntest.w) / 2; + nrc = apr_conv_utf8_to_ucs2(ntest.n, &inlen, ntest.w, &ntest.wl); + if (nrc == APR_SUCCESS) { + ntest.wl = (sizeof(ntest.w) / 2) - ntest.wl; + break; + } + if (nrc == APR_INCOMPLETE) { + ++ntest.nl; + if (ntest.nl > 6) { + printf ("\n\nUnexpected utf8 sequence of >6 bytes;\n"); + exit(255); + } + continue; + } + else { + while (!(++ntest.n[ntest.nl - 1])) { + if (!(--ntest.nl)) + break; + } + } + } while (ntest.nl); + + do { + inlen = wtest.wl; + wtest.nl = sizeof(wtest.n); + wrc = apr_conv_ucs2_to_utf8(wtest.w, &inlen, wtest.n, &wtest.nl); + if (wrc == APR_SUCCESS) { + wtest.nl = sizeof(wtest.n) - wtest.nl; + break; + } + else { + if (!(++wtest.w[wtest.wl - 1])) { + if (wtest.wl == 1) + ++wtest.wl; + else + ++wtest.w[0]; + + /* On the second pass, ensure lead word is incomplete */ + do { + inlen = 1; + wtest.nl = sizeof(wtest.n); + if (apr_conv_ucs2_to_utf8(wtest.w, &inlen, wtest.n, &wtest.nl) + == APR_INCOMPLETE) + break; + if (!(++wtest.w[0])) { + wtest.wl = 0; + break; + } + } while (1); + } + } + } while (wtest.wl); + + if (!ntest.nl && !wtest.wl) + break; + + /* Identical? */ + if ((wtest.nl != ntest.nl) + || (memcmp(wtest.n, ntest.n, ntest.nl) != 0) + || (wtest.wl != ntest.wl) + || (memcmp(ntest.w, wtest.w, wtest.wl * 2) != 0)) { + printf ("\n\nMismatch of w/n conversion at;\n"); + displaynw(&ntest, &wtest); + exit(255); + } + ++matches; + + while (!(++ntest.n[ntest.nl - 1])) { + if (!(--ntest.nl)) + break; + } + + if (!(++wtest.w[wtest.wl - 1])) { + if (wtest.wl == 1) + ++wtest.wl; + else + ++wtest.w[0]; + + /* On the second pass, ensure lead word is incomplete */ + do { + inlen = 1; + wtest.nl = sizeof(wtest.n); + if (apr_conv_ucs2_to_utf8(wtest.w, &inlen, wtest.n, &wtest.nl) + == APR_INCOMPLETE) + break; + if (!(++wtest.w[0])) { + wtest.wl = 0; + break; + } + } while (1); + } + } while (wtest.wl || ntest.nl); + + printf ("\n\nutf8 and ucs2 sequences of %lu transformations matched OK.\n", + matches); +} + +/* + * Syntax: testucs [w|n] + * + * If no arg or arg is not recognized, run equality sequence test. + */ +int main(int argc, char **argv) +{ + struct testval s; + memset (&s, 0, sizeof(s)); + + if (argc >= 2 && apr_tolower(*argv[1]) != 'w') { + printf ("\n\nTesting Narrow Char Ranges\n"); + test_nrange(&s); + } + else if (argc >= 2 && apr_tolower(*argv[1]) != 'n') { + printf ("\n\nTesting Wide Char Ranges\n"); + test_wrange(&s); + } + else { + test_ranges(); + } + return 0; +} diff --git a/test/mod_test.c b/test/mod_test.c index 088d748420c..2178e94059c 100644 --- a/test/mod_test.c +++ b/test/mod_test.c @@ -1,17 +1,32 @@ -#include <stdio.h> +/* 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. + */ -int goodbyes = 0; +#include "apr_strings.h" -void print_hello(void) +void print_hello(char str[256]); +int count_reps(int reps); + +void print_hello(char str[256]) { - fprintf(stdout,"Hello - I'm a DSO!\n"); + apr_cpystrn(str, "Hello - I'm a DSO!\n", strlen("Hello - I'm a DSO!\n") + 1); } -int print_goodbye(int reps) +int count_reps(int reps) { int i = 0; - for (i = 0;i < reps; i++) { - fprintf (stdout, "Goodbye from the DSO! (%d of %d)\n", i+1, reps); - } - goodbyes = reps; + for (i = 0;i < reps; i++); + return i; } diff --git a/test/nw_misc.c b/test/nw_misc.c new file mode 100644 index 00000000000..b45f9516dce --- /dev/null +++ b/test/nw_misc.c @@ -0,0 +1,23 @@ +#include <stdio.h> +#include <stdlib.h> +#include <screen.h> +/* +#include "testutil.h" +*/ + +/* function to keep the screen open if not launched from bash */ +void _NonAppStop( void ) +{ + if (getenv("_IN_NETWARE_BASH_") == NULL) { + printf("\r\n<Press any key to close screen> "); + getcharacter(); + } +} + +/* +static void test_not_impl(CuTest *tc) +{ + CuNotImpl(tc, "Test not implemented on this platform yet"); +} +*/ + diff --git a/test/occhild.c b/test/occhild.c new file mode 100644 index 00000000000..a96885d8271 --- /dev/null +++ b/test/occhild.c @@ -0,0 +1,26 @@ +#include "apr.h" +#include "apr_file_io.h" +#include "apr.h" + +#if APR_HAVE_STDLIB_H +#include <stdlib.h> +#endif + +int main(void) +{ + char buf[256]; + apr_file_t *err; + apr_pool_t *p; + + apr_initialize(); + atexit(apr_terminate); + + apr_pool_create(&p, NULL); + apr_file_open_stdin(&err, p); + + while (1) { + apr_size_t length = 256; + apr_file_read(err, buf, &length); + } + exit(0); /* just to keep the compiler happy */ +} diff --git a/test/proc_child.c b/test/proc_child.c new file mode 100644 index 00000000000..6cfc8fc9fb4 --- /dev/null +++ b/test/proc_child.c @@ -0,0 +1,21 @@ +#include "apr.h" +#include <stdio.h> +#if APR_HAVE_UNISTD_H +#include <unistd.h> +#endif +#if APR_HAVE_IO_H +#include <io.h> +#endif +#include <stdlib.h> + +int main(void) +{ + char buf[256]; + int bytes; + + bytes = (int)read(STDIN_FILENO, buf, 256); + if (bytes > 0) + write(STDOUT_FILENO, buf, (unsigned int)bytes); + + return 0; /* just to keep the compiler happy */ +} diff --git a/test/readchild.c b/test/readchild.c new file mode 100644 index 00000000000..f8443cceb8e --- /dev/null +++ b/test/readchild.c @@ -0,0 +1,46 @@ +/* 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 <stdlib.h> + +#include "apr_file_io.h" + +int main(int argc, char *argv[]) +{ + apr_file_t *in, *out; + apr_size_t nbytes, total_bytes; + apr_pool_t *p; + char buf[128]; + apr_status_t rv; + + apr_initialize(); + atexit(apr_terminate); + apr_pool_create(&p, NULL); + + apr_file_open_stdin(&in, p); + apr_file_open_stdout(&out, p); + + total_bytes = 0; + nbytes = sizeof(buf); + while ((rv = apr_file_read(in, buf, &nbytes)) == APR_SUCCESS) { + total_bytes += nbytes; + nbytes = sizeof(buf); + } + + apr_file_printf(out, "%" APR_SIZE_T_FMT " bytes were read\n", + total_bytes); + return 0; +} diff --git a/test/sendfile.c b/test/sendfile.c new file mode 100644 index 00000000000..f8de309846a --- /dev/null +++ b/test/sendfile.c @@ -0,0 +1,770 @@ +/* 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 <assert.h> +#include <errno.h> +#include <signal.h> +#include <stdlib.h> +#include <string.h> +#include "apr_network_io.h" +#include "apr_errno.h" +#include "apr_general.h" +#include "apr_poll.h" +#include "apr_thread_proc.h" + +#include "testutil.h" + +#if !APR_HAS_SENDFILE +int main(void) +{ + fprintf(stderr, + "This program won't work on this platform because there is no " + "support for sendfile().\n"); + return 0; +} +#else /* !APR_HAS_SENDFILE */ + +#define FILE_LENGTH 200000 + +#define FILE_DATA_CHAR '0' + +#define HDR1 "1234567890ABCD\n" +#define HDR2 "EFGH\n" +#define HDR3_LEN 80000 +#define HDR3_CHAR '^' +#define TRL1 "IJKLMNOPQRSTUVWXYZ\n" +#define TRL2 "!@#$%&*()\n" +#define TRL3_LEN 90000 +#define TRL3_CHAR '@' + +#define TESTSF_PORT 8021 + +#define TESTFILE "testsf.dat" + +typedef enum {BLK, NONBLK, TIMEOUT} client_socket_mode_t; + +static void aprerr(const char *fn, apr_status_t rv) +{ + char buf[120]; + + fprintf(stderr, "%s->%d/%s\n", + fn, rv, apr_strerror(rv, buf, sizeof buf)); + exit(1); +} + +static void apr_setup(apr_pool_t *p, apr_socket_t **sock, int *family) +{ + apr_status_t rv; + + *sock = NULL; + rv = apr_socket_create(sock, *family, SOCK_STREAM, 0, p); + if (rv != APR_SUCCESS) { + aprerr("apr_socket_create()", rv); + } + + if (*family == APR_UNSPEC) { + apr_sockaddr_t *localsa; + + rv = apr_socket_addr_get(&localsa, APR_LOCAL, *sock); + if (rv != APR_SUCCESS) { + aprerr("apr_socket_addr_get()", rv); + } + *family = localsa->family; + } +} + +static void create_testfile(apr_pool_t *p, const char *fname) +{ + apr_file_t *f = NULL; + apr_status_t rv; + char buf[120]; + int i; + apr_finfo_t finfo; + + printf("Creating a test file...\n"); + rv = apr_file_open(&f, fname, + APR_FOPEN_CREATE | APR_FOPEN_WRITE | APR_FOPEN_TRUNCATE | APR_FOPEN_BUFFERED, + APR_FPROT_UREAD | APR_FPROT_UWRITE, p); + if (rv) { + aprerr("apr_file_open()", rv); + } + + buf[0] = FILE_DATA_CHAR; + buf[1] = '\0'; + for (i = 0; i < FILE_LENGTH; i++) { + /* exercise apr_file_putc() and apr_file_puts() on buffered files */ + if ((i % 2) == 0) { + rv = apr_file_putc(buf[0], f); + if (rv) { + aprerr("apr_file_putc()", rv); + } + } + else { + rv = apr_file_puts(buf, f); + if (rv) { + aprerr("apr_file_puts()", rv); + } + } + } + + rv = apr_file_close(f); + if (rv) { + aprerr("apr_file_close()", rv); + } + + rv = apr_stat(&finfo, fname, APR_FINFO_NORM, p); + if (rv != APR_SUCCESS && ! APR_STATUS_IS_INCOMPLETE(rv)) { + aprerr("apr_stat()", rv); + } + + if (finfo.size != FILE_LENGTH) { + fprintf(stderr, + "test file %s should be %ld-bytes long\n" + "instead it is %ld-bytes long\n", + fname, + (long int)FILE_LENGTH, + (long int)finfo.size); + exit(1); + } +} + +static void spawn_server(apr_pool_t *p, apr_proc_t *out_proc) +{ + apr_proc_t proc = {0}; + apr_procattr_t *procattr; + apr_status_t rv; + const char *args[3]; + + rv = apr_procattr_create(&procattr, p); + if (rv != APR_SUCCESS) { + aprerr("apr_procattr_create()", rv); + } + + rv = apr_procattr_io_set(procattr, APR_CHILD_BLOCK, APR_CHILD_BLOCK, + APR_CHILD_BLOCK); + if (rv != APR_SUCCESS) { + aprerr("apr_procattr_io_set()", rv); + } + + rv = apr_procattr_cmdtype_set(procattr, APR_PROGRAM_ENV); + if (rv != APR_SUCCESS) { + aprerr("apr_procattr_cmdtype_set()", rv); + } + + rv = apr_procattr_error_check_set(procattr, 1); + if (rv != APR_SUCCESS) { + aprerr("apr_procattr_error_check_set()", rv); + } + + args[0] = "sendfile" EXTENSION; + args[1] = "server"; + args[2] = NULL; + rv = apr_proc_create(&proc, TESTBINPATH "sendfile" EXTENSION, args, NULL, procattr, p); + if (rv != APR_SUCCESS) { + aprerr("apr_proc_create()", rv); + } + + *out_proc = proc; +} + +static int client(apr_pool_t *p, client_socket_mode_t socket_mode, + const char *host, int start_server) +{ + apr_status_t rv, tmprv; + apr_socket_t *sock; + char buf[120]; + apr_file_t *f = NULL; + apr_size_t len; + apr_size_t expected_len; + apr_off_t current_file_offset; + apr_hdtr_t hdtr; + struct iovec headers[3]; + struct iovec trailers[3]; + apr_size_t bytes_read; + apr_pollset_t *pset; + apr_int32_t nsocks; + int connect_tries = 1; + int i; + int family; + apr_sockaddr_t *destsa; + apr_proc_t server; + apr_interval_time_t connect_retry_interval = apr_time_from_msec(50); + + if (start_server) { + spawn_server(p, &server); + connect_tries = 5; /* give it a chance to start up */ + } + + create_testfile(p, TESTFILE); + + rv = apr_file_open(&f, TESTFILE, APR_FOPEN_READ, 0, p); + if (rv != APR_SUCCESS) { + aprerr("apr_file_open()", rv); + } + + if (!host) { + host = "127.0.0.1"; + } + family = APR_INET; + rv = apr_sockaddr_info_get(&destsa, host, family, TESTSF_PORT, 0, p); + if (rv != APR_SUCCESS) { + aprerr("apr_sockaddr_info_get()", rv); + } + + while (connect_tries--) { + apr_setup(p, &sock, &family); + rv = apr_socket_connect(sock, destsa); + if (connect_tries && APR_STATUS_IS_ECONNREFUSED(rv)) { + apr_status_t tmprv = apr_socket_close(sock); + if (tmprv != APR_SUCCESS) { + aprerr("apr_socket_close()", tmprv); + } + apr_sleep(connect_retry_interval); + connect_retry_interval *= 2; + } + else { + break; + } + } + if (rv != APR_SUCCESS) { + aprerr("apr_socket_connect()", rv); + } + + switch(socket_mode) { + case BLK: + /* leave it blocking */ + break; + case NONBLK: + /* set it non-blocking */ + rv = apr_socket_opt_set(sock, APR_SO_NONBLOCK, 1); + if (rv != APR_SUCCESS) { + aprerr("apr_socket_opt_set(APR_SO_NONBLOCK)", rv); + } + break; + case TIMEOUT: + /* set a timeout */ + rv = apr_socket_timeout_set(sock, 100 * APR_USEC_PER_SEC); + if (rv != APR_SUCCESS) { + aprerr("apr_socket_opt_set(APR_SO_NONBLOCK)", rv); + exit(1); + } + break; + default: + assert(1 != 1); + } + + printf("Sending the file...\n"); + + hdtr.headers = headers; + hdtr.numheaders = 3; + hdtr.headers[0].iov_base = HDR1; + hdtr.headers[0].iov_len = strlen(hdtr.headers[0].iov_base); + hdtr.headers[1].iov_base = HDR2; + hdtr.headers[1].iov_len = strlen(hdtr.headers[1].iov_base); + hdtr.headers[2].iov_base = malloc(HDR3_LEN); + assert(hdtr.headers[2].iov_base); + memset(hdtr.headers[2].iov_base, HDR3_CHAR, HDR3_LEN); + hdtr.headers[2].iov_len = HDR3_LEN; + + hdtr.trailers = trailers; + hdtr.numtrailers = 3; + hdtr.trailers[0].iov_base = TRL1; + hdtr.trailers[0].iov_len = strlen(hdtr.trailers[0].iov_base); + hdtr.trailers[1].iov_base = TRL2; + hdtr.trailers[1].iov_len = strlen(hdtr.trailers[1].iov_base); + hdtr.trailers[2].iov_base = malloc(TRL3_LEN); + memset(hdtr.trailers[2].iov_base, TRL3_CHAR, TRL3_LEN); + assert(hdtr.trailers[2].iov_base); + hdtr.trailers[2].iov_len = TRL3_LEN; + + expected_len = + strlen(HDR1) + strlen(HDR2) + HDR3_LEN + + strlen(TRL1) + strlen(TRL2) + TRL3_LEN + + FILE_LENGTH; + + if (socket_mode == BLK) { + current_file_offset = 0; + len = FILE_LENGTH; + rv = apr_socket_sendfile(sock, f, &hdtr, ¤t_file_offset, &len, 0); + if (rv != APR_SUCCESS) { + aprerr("apr_socket_sendfile()", rv); + } + + printf("apr_socket_sendfile() updated offset with %ld\n", + (long int)current_file_offset); + + printf("apr_socket_sendfile() updated len with %ld\n", + (long int)len); + + printf("bytes really sent: %" APR_SIZE_T_FMT "\n", + expected_len); + + if (len != expected_len) { + fprintf(stderr, "apr_socket_sendfile() didn't report the correct " + "number of bytes sent!\n"); + exit(1); + } + } + else { + /* non-blocking... wooooooo */ + apr_size_t total_bytes_sent; + apr_pollfd_t pfd; + + pset = NULL; + rv = apr_pollset_create(&pset, 1, p, 0); + assert(!rv); + pfd.p = p; + pfd.desc_type = APR_POLL_SOCKET; + pfd.reqevents = APR_POLLOUT; + pfd.rtnevents = 0; + pfd.desc.s = sock; + pfd.client_data = NULL; + + rv = apr_pollset_add(pset, &pfd); + assert(!rv); + + total_bytes_sent = 0; + current_file_offset = 0; + len = FILE_LENGTH; + do { + apr_size_t tmplen; + + tmplen = len; /* bytes remaining to send from the file */ + printf("Calling apr_socket_sendfile()...\n"); + printf("Headers (%d):\n", hdtr.numheaders); + for (i = 0; i < hdtr.numheaders; i++) { + printf("\t%ld bytes (%c)\n", + (long)hdtr.headers[i].iov_len, + *(char *)hdtr.headers[i].iov_base); + } + printf("File: %ld bytes from offset %ld\n", + (long)tmplen, (long)current_file_offset); + printf("Trailers (%d):\n", hdtr.numtrailers); + for (i = 0; i < hdtr.numtrailers; i++) { + printf("\t%ld bytes\n", + (long)hdtr.trailers[i].iov_len); + } + + rv = apr_socket_sendfile(sock, f, &hdtr, ¤t_file_offset, &tmplen, 0); + printf("apr_socket_sendfile()->%d, sent %ld bytes\n", rv, (long)tmplen); + if (rv) { + if (APR_STATUS_IS_EAGAIN(rv)) { + assert(tmplen == 0); + nsocks = 1; + tmprv = apr_pollset_poll(pset, -1, &nsocks, NULL); + assert(!tmprv); + assert(nsocks == 1); + /* continue; */ + } + } + + total_bytes_sent += tmplen; + + /* Adjust hdtr to compensate for partially-written + * data. + */ + + /* First, skip over any header data which might have + * been written. + */ + while (tmplen && hdtr.numheaders) { + if (tmplen >= hdtr.headers[0].iov_len) { + tmplen -= hdtr.headers[0].iov_len; + --hdtr.numheaders; + ++hdtr.headers; + } + else { + hdtr.headers[0].iov_len -= tmplen; + hdtr.headers[0].iov_base = + (char*) hdtr.headers[0].iov_base + tmplen; + tmplen = 0; + } + } + + /* Now, skip over any file data which might have been + * written. + */ + + if (tmplen <= len) { + current_file_offset += tmplen; + len -= tmplen; + tmplen = 0; + } + else { + tmplen -= len; + len = 0; + current_file_offset = 0; + } + + /* Last, skip over any trailer data which might have + * been written. + */ + + while (tmplen && hdtr.numtrailers) { + if (tmplen >= hdtr.trailers[0].iov_len) { + tmplen -= hdtr.trailers[0].iov_len; + --hdtr.numtrailers; + ++hdtr.trailers; + } + else { + hdtr.trailers[0].iov_len -= tmplen; + hdtr.trailers[0].iov_base = + (char *)hdtr.trailers[0].iov_base + tmplen; + tmplen = 0; + } + } + + } while (total_bytes_sent < expected_len && + (rv == APR_SUCCESS || + (APR_STATUS_IS_EAGAIN(rv) && socket_mode != TIMEOUT))); + if (total_bytes_sent != expected_len) { + fprintf(stderr, + "client problem: sent %ld of %ld bytes\n", + (long)total_bytes_sent, (long)expected_len); + exit(1); + } + + if (rv) { + fprintf(stderr, + "client problem: rv %d\n", + rv); + exit(1); + } + } + + current_file_offset = 0; + rv = apr_file_seek(f, APR_CUR, ¤t_file_offset); + if (rv != APR_SUCCESS) { + aprerr("apr_file_seek()", rv); + } + + printf("After apr_socket_sendfile(), the kernel file pointer is " + "at offset %ld.\n", + (long int)current_file_offset); + + rv = apr_socket_shutdown(sock, APR_SHUTDOWN_WRITE); + if (rv != APR_SUCCESS) { + aprerr("apr_socket_shutdown()", rv); + } + + /* in case this is the non-blocking test, set socket timeout; + * we're just waiting for EOF */ + + rv = apr_socket_timeout_set(sock, apr_time_from_sec(3)); + if (rv != APR_SUCCESS) { + aprerr("apr_socket_timeout_set()", rv); + } + + bytes_read = 1; + rv = apr_socket_recv(sock, buf, &bytes_read); + if (rv != APR_EOF) { + aprerr("apr_socket_recv() (expected APR_EOF)", rv); + } + if (bytes_read != 0) { + fprintf(stderr, "We expected to get 0 bytes read with APR_EOF\n" + "but instead we read %ld bytes.\n", + (long int)bytes_read); + exit(1); + } + + printf("client: apr_socket_sendfile() worked as expected!\n"); + + rv = apr_file_remove(TESTFILE, p); + if (rv != APR_SUCCESS) { + aprerr("apr_file_remove()", rv); + } + + if (start_server) { + apr_exit_why_e exitwhy; + apr_size_t nbytes; + char responsebuf[1024]; + int exitcode; + + rv = apr_file_pipe_timeout_set(server.out, apr_time_from_sec(2)); + if (rv != APR_SUCCESS) { + aprerr("apr_file_pipe_timeout_set()", rv); + } + nbytes = sizeof(responsebuf); + rv = apr_file_read(server.out, responsebuf, &nbytes); + if (rv != APR_SUCCESS) { + aprerr("apr_file_read() messages from server", rv); + } + printf("%.*s", (int)nbytes, responsebuf); + rv = apr_proc_wait(&server, &exitcode, &exitwhy, APR_WAIT); + if (rv != APR_CHILD_DONE) { + aprerr("apr_proc_wait() (expected APR_CHILD_DONE)", rv); + } + if (exitcode != 0) { + fprintf(stderr, "sendfile server returned %d\n", exitcode); + exit(1); + } + } + + return 0; +} + +static int server(apr_pool_t *p) +{ + apr_status_t rv; + apr_socket_t *sock; + char buf[120]; + int i; + apr_socket_t *newsock = NULL; + apr_size_t bytes_read; + apr_sockaddr_t *localsa; + int family; + + family = APR_INET; + apr_setup(p, &sock, &family); + + rv = apr_socket_opt_set(sock, APR_SO_REUSEADDR, 1); + if (rv != APR_SUCCESS) { + aprerr("apr_socket_opt_set()", rv); + } + + rv = apr_sockaddr_info_get(&localsa, NULL, family, TESTSF_PORT, 0, p); + if (rv != APR_SUCCESS) { + aprerr("apr_sockaddr_info_get()", rv); + } + + rv = apr_socket_bind(sock, localsa); + if (rv != APR_SUCCESS) { + aprerr("apr_socket_bind()", rv); + } + + rv = apr_socket_listen(sock, 5); + if (rv != APR_SUCCESS) { + aprerr("apr_socket_listen()", rv); + } + + printf("Waiting for a client to connect...\n"); + + rv = apr_socket_accept(&newsock, sock, p); + if (rv != APR_SUCCESS) { + aprerr("apr_socket_accept()", rv); + } + + printf("Processing a client...\n"); + + assert(sizeof buf > strlen(HDR1)); + bytes_read = strlen(HDR1); + rv = apr_socket_recv(newsock, buf, &bytes_read); + if (rv != APR_SUCCESS) { + aprerr("apr_socket_recv()", rv); + } + if (bytes_read != strlen(HDR1)) { + fprintf(stderr, "wrong data read (1)\n"); + exit(1); + } + if (memcmp(buf, HDR1, strlen(HDR1))) { + fprintf(stderr, "wrong data read (2)\n"); + fprintf(stderr, "received: `%.*s'\nexpected: `%s'\n", + (int)bytes_read, buf, HDR1); + exit(1); + } + + assert(sizeof buf > strlen(HDR2)); + bytes_read = strlen(HDR2); + rv = apr_socket_recv(newsock, buf, &bytes_read); + if (rv != APR_SUCCESS) { + aprerr("apr_socket_recv()", rv); + } + if (bytes_read != strlen(HDR2)) { + fprintf(stderr, "wrong data read (3)\n"); + exit(1); + } + if (memcmp(buf, HDR2, strlen(HDR2))) { + fprintf(stderr, "wrong data read (4)\n"); + fprintf(stderr, "received: `%.*s'\nexpected: `%s'\n", + (int)bytes_read, buf, HDR2); + exit(1); + } + + for (i = 0; i < HDR3_LEN; i++) { + bytes_read = 1; + rv = apr_socket_recv(newsock, buf, &bytes_read); + if (rv != APR_SUCCESS) { + aprerr("apr_socket_recv()", rv); + } + if (bytes_read != 1) { + fprintf(stderr, "apr_socket_recv()->%ld bytes instead of 1\n", + (long int)bytes_read); + exit(1); + } + if (buf[0] != HDR3_CHAR) { + fprintf(stderr, + "problem with data read (byte %d of hdr 3):\n", + i); + fprintf(stderr, "read `%c' (0x%x) from client; expected " + "`%c'\n", + buf[0], buf[0], HDR3_CHAR); + exit(1); + } + } + + for (i = 0; i < FILE_LENGTH; i++) { + bytes_read = 1; + rv = apr_socket_recv(newsock, buf, &bytes_read); + if (rv != APR_SUCCESS) { + aprerr("apr_socket_recv()", rv); + } + if (bytes_read != 1) { + fprintf(stderr, "apr_socket_recv()->%ld bytes instead of 1\n", + (long int)bytes_read); + exit(1); + } + if (buf[0] != FILE_DATA_CHAR) { + fprintf(stderr, + "problem with data read (byte %d of file):\n", + i); + fprintf(stderr, "read `%c' (0x%x) from client; expected " + "`%c'\n", + buf[0], buf[0], FILE_DATA_CHAR); + exit(1); + } + } + + assert(sizeof buf > strlen(TRL1)); + bytes_read = strlen(TRL1); + rv = apr_socket_recv(newsock, buf, &bytes_read); + if (rv != APR_SUCCESS) { + aprerr("apr_socket_recv()", rv); + } + if (bytes_read != strlen(TRL1)) { + fprintf(stderr, "wrong data read (5)\n"); + exit(1); + } + if (memcmp(buf, TRL1, strlen(TRL1))) { + fprintf(stderr, "wrong data read (6)\n"); + fprintf(stderr, "received: `%.*s'\nexpected: `%s'\n", + (int)bytes_read, buf, TRL1); + exit(1); + } + + assert(sizeof buf > strlen(TRL2)); + bytes_read = strlen(TRL2); + rv = apr_socket_recv(newsock, buf, &bytes_read); + if (rv != APR_SUCCESS) { + aprerr("apr_socket_recv()", rv); + } + if (bytes_read != strlen(TRL2)) { + fprintf(stderr, "wrong data read (7)\n"); + exit(1); + } + if (memcmp(buf, TRL2, strlen(TRL2))) { + fprintf(stderr, "wrong data read (8)\n"); + fprintf(stderr, "received: `%.*s'\nexpected: `%s'\n", + (int)bytes_read, buf, TRL2); + exit(1); + } + + for (i = 0; i < TRL3_LEN; i++) { + bytes_read = 1; + rv = apr_socket_recv(newsock, buf, &bytes_read); + if (rv != APR_SUCCESS) { + aprerr("apr_socket_recv()", rv); + } + if (bytes_read != 1) { + fprintf(stderr, "apr_socket_recv()->%ld bytes instead of 1\n", + (long int)bytes_read); + exit(1); + } + if (buf[0] != TRL3_CHAR) { + fprintf(stderr, + "problem with data read (byte %d of trl 3):\n", + i); + fprintf(stderr, "read `%c' (0x%x) from client; expected " + "`%c'\n", + buf[0], buf[0], TRL3_CHAR); + exit(1); + } + } + + bytes_read = 1; + rv = apr_socket_recv(newsock, buf, &bytes_read); + if (rv != APR_EOF) { + aprerr("apr_socket_recv() (expected APR_EOF)", rv); + } + if (bytes_read != 0) { + fprintf(stderr, "We expected to get 0 bytes read with APR_EOF\n" + "but instead we read %ld bytes (%c).\n", + (long int)bytes_read, buf[0]); + exit(1); + } + + printf("server: apr_socket_sendfile() worked as expected!\n"); + + return 0; +} + +int main(int argc, char *argv[]) +{ + apr_pool_t *p; + apr_status_t rv; + +#ifdef SIGPIPE + signal(SIGPIPE, SIG_IGN); +#endif + + rv = apr_initialize(); + if (rv != APR_SUCCESS) { + aprerr("apr_initialize()", rv); + } + + atexit(apr_terminate); + + rv = apr_pool_create(&p, NULL); + if (rv != APR_SUCCESS) { + aprerr("apr_pool_create()", rv); + } + + if (argc >= 2 && !strcmp(argv[1], "client")) { + const char *host = NULL; + int mode = BLK; + int start_server = 0; + int i; + + for (i = 2; i < argc; i++) { + if (!strcmp(argv[i], "blocking")) { + mode = BLK; + } + else if (!strcmp(argv[i], "timeout")) { + mode = TIMEOUT; + } + else if (!strcmp(argv[i], "nonblocking")) { + mode = NONBLK; + } + else if (!strcmp(argv[i], "startserver")) { + start_server = 1; + } + else { + host = argv[i]; + } + } + return client(p, mode, host, start_server); + } + else if (argc == 2 && !strcmp(argv[1], "server")) { + return server(p); + } + + fprintf(stderr, + "Usage: %s client {blocking|nonblocking|timeout} [startserver] [server-host]\n" + " %s server\n", + argv[0], argv[0]); + return -1; +} + +#endif /* !APR_HAS_SENDFILE */ diff --git a/test/server.c b/test/server.c deleted file mode 100644 index 3207915f699..00000000000 --- a/test/server.c +++ /dev/null @@ -1,214 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#include <stdlib.h> -#include "apr_network_io.h" -#include "apr_errno.h" -#include "apr_general.h" - -#define STRLEN 15 - -int main(int argc, char *argv[]) -{ - ap_pool_t *context; - ap_socket_t *sock; - ap_socket_t *sock2; - ap_ssize_t length; - ap_int32_t rv; - ap_pollfd_t *sdset; - char datasend[STRLEN]; - char datarecv[STRLEN] = "Recv data test"; - char *local_ipaddr, *remote_ipaddr; - ap_uint32_t local_port, remote_port; - - fprintf(stdout, "Initializing........."); - if (ap_initialize() != APR_SUCCESS) { - fprintf(stderr, "Something went wrong\n"); - exit(-1); - } - fprintf(stdout, "OK\n"); - atexit(ap_terminate); - - fprintf(stdout, "Creating context......."); - if (ap_create_pool(&context, NULL) != APR_SUCCESS) { - fprintf(stderr, "Could not create a context\n"); - exit(-1); - } - fprintf(stdout, "OK\n"); - - fprintf(stdout, "\tServer: Creating new socket......."); - if (ap_create_tcp_socket(&sock, context) != APR_SUCCESS) { - fprintf(stderr, "Couldn't create socket\n"); - exit(-1); - } - fprintf(stdout, "OK\n"); - - fprintf(stdout, "\tServer: Setting socket option NONBLOCK......."); - if (ap_setsocketopt(sock, APR_SO_NONBLOCK, 1) != APR_SUCCESS) { - ap_close_socket(sock); - fprintf(stderr, "Couldn't set socket option\n"); - exit(-1); - } - fprintf(stdout, "OK\n"); - - fprintf(stdout, "\tServer: Setting port for socket......."); - if (ap_set_local_port(sock, 8021) != APR_SUCCESS) { - ap_close_socket(sock); - fprintf(stderr, "Couldn't set the port correctly\n"); - exit(-1); - } - fprintf(stdout, "OK\n"); - - fprintf(stdout, "\tServer: Binding socket to port......."); - if (ap_bind(sock) != APR_SUCCESS) { - ap_close_socket(sock); - fprintf(stderr, "Could not bind\n"); - exit(-1); - } - fprintf(stdout, "OK\n"); - - fprintf(stdout, "\tServer: Listening to socket......."); - if (ap_listen(sock, 8021) != APR_SUCCESS) { - ap_close_socket(sock); - fprintf(stderr, "Could not listen\n"); - exit(-1); - } - fprintf(stdout, "OK\n"); - - fprintf(stdout, "\tServer: Setting up socket for polling......."); - ap_setup_poll(&sdset, 1, context); - ap_add_poll_socket(sdset, sock, APR_POLLIN); - fprintf(stdout, "OK\n"); - - fprintf(stdout, "\tServer: Beginning to poll for socket......."); - rv = 1; - if (ap_poll(sdset, &rv, -1) != APR_SUCCESS) { - ap_close_socket(sock); - fprintf(stderr, "Select caused an error\n"); - exit(-1); - } - else if (rv == 0) { - ap_close_socket(sock); - fprintf(stderr, "I should not return until rv == 1\n"); - exit(-1); - } - fprintf(stdout, "OK\n"); - - fprintf(stdout, "\tServer: Accepting a connection......."); - if (ap_accept(&sock2, sock, context) != APR_SUCCESS) { - ap_close_socket(sock); - fprintf(stderr, "Could not accept connection.\n"); - exit(-1); - } - fprintf(stdout, "OK\n"); - - ap_get_remote_ipaddr(&remote_ipaddr, sock2); - ap_get_remote_port(&remote_port, sock2); - ap_get_local_ipaddr(&local_ipaddr, sock2); - ap_get_local_port(&local_port, sock2); - fprintf(stdout, "\tServer socket: %s:%u -> %s:%u\n", local_ipaddr, local_port, remote_ipaddr, remote_port); - - length = STRLEN; - fprintf(stdout, "\tServer: Trying to recv data from socket......."); - if (ap_recv(sock2, datasend, &length) != APR_SUCCESS) { - ap_close_socket(sock); - ap_close_socket(sock2); - fprintf(stderr, "Problem recving data\n"); - exit(-1); - } - if (strcmp(datasend, "Send data test")) { - ap_close_socket(sock); - ap_close_socket(sock2); - fprintf(stderr, "I did not receive the correct data %s\n", datarecv); - exit(-1); - } - fprintf(stdout, "OK\n"); - - length = STRLEN; - fprintf(stdout, "\tServer: Sending data over socket......."); - if (ap_send(sock2, datarecv, &length) != APR_SUCCESS) { - ap_close_socket(sock); - ap_close_socket(sock2); - fprintf(stderr, "Problem sending data\n"); - exit(-1); - } - fprintf(stdout, "OK\n"); - - fprintf(stdout, "\tServer: Shutting down accepte socket......."); - if (ap_shutdown(sock2, APR_SHUTDOWN_READ) != APR_SUCCESS) { - ap_close_socket(sock); - ap_close_socket(sock2); - fprintf(stderr, "Problem shutting down\n"); - exit(-1); - } - fprintf(stdout, "OK\n"); - - fprintf(stdout, "\tServer: closing duplicate socket......."); - if (ap_close_socket(sock2) != APR_SUCCESS) { - ap_close_socket(sock); - fprintf(stderr, "Problem closing down\n"); - exit(-1); - } - fprintf(stdout, "OK\n"); - - fprintf(stdout, "\tServer: closing original socket......."); - if (ap_close_socket(sock) != APR_SUCCESS) { - fprintf(stderr, "Problem closing down\n"); - exit(-1); - } - fprintf(stdout, "OK\n"); - - return 1; -} - diff --git a/test/server.dsp b/test/server.dsp deleted file mode 100644 index 219546b8c28..00000000000 --- a/test/server.dsp +++ /dev/null @@ -1,90 +0,0 @@ -# Microsoft Developer Studio Project File - Name="server" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 5.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Console Application" 0x0103 - -CFG=server - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "server.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "server.mak" CFG="server - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "server - Win32 Release" (based on "Win32 (x86) Console Application") -!MESSAGE "server - Win32 Debug" (based on "Win32 (x86) Console Application") -!MESSAGE - -# Begin Project -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -RSC=rc.exe - -!IF "$(CFG)" == "server - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /W3 /GX /O2 /I "..\include" /I "..\..\include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD BASE RSC /l 0x409 /d "NDEBUG" -# ADD RSC /l 0x409 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 -# ADD LINK32 ..\Release\aprlib.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"..\Release\server.exe" - -!ELSEIF "$(CFG)" == "server - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "server__" -# PROP BASE Intermediate_Dir "server__" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "server" -# PROP Intermediate_Dir "server" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /I "..\include" /I "..\..\include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "HAVE_STDIO_H" /FD /c -# SUBTRACT CPP /YX /Yc /Yu -# ADD BASE RSC /l 0x409 /d "_DEBUG" -# ADD RSC /l 0x409 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept -# ADD LINK32 ..\Debug\aprlib.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"..\Debug\server.exe" /pdbtype:sept - -!ENDIF - -# Begin Target - -# Name "server - Win32 Release" -# Name "server - Win32 Debug" -# Begin Source File - -SOURCE=.\server.c -# End Source File -# End Target -# End Project diff --git a/test/sockchild.c b/test/sockchild.c new file mode 100644 index 00000000000..a1116af2bdc --- /dev/null +++ b/test/sockchild.c @@ -0,0 +1,90 @@ +/* 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 <stdlib.h> +#include "testsock.h" +#include "apr_network_io.h" +#include "apr_pools.h" + +int main(int argc, char *argv[]) +{ + apr_pool_t *p; + apr_socket_t *sock; + apr_status_t rv; + apr_sockaddr_t *remote_sa; + + apr_initialize(); + atexit(apr_terminate); + apr_pool_create(&p, NULL); + + if (argc < 3) { + exit(-1); + } + + rv = apr_sockaddr_info_get(&remote_sa, argv[2], APR_UNSPEC, 8021, 0, p); + if (rv != APR_SUCCESS) { + exit(-1); + } + + if (apr_socket_create(&sock, remote_sa->family, SOCK_STREAM, 0, + p) != APR_SUCCESS) { + exit(-1); + } + + rv = apr_socket_timeout_set(sock, apr_time_from_sec(3)); + if (rv) { + exit(-1); + } + + apr_socket_connect(sock, remote_sa); + + if (!strcmp("read", argv[1])) { + char datarecv[STRLEN]; + apr_size_t length = STRLEN; + apr_status_t rv; + + memset(datarecv, 0, STRLEN); + rv = apr_socket_recv(sock, datarecv, &length); + apr_socket_close(sock); + if (APR_STATUS_IS_TIMEUP(rv)) { + exit(SOCKET_TIMEOUT); + } + + if (strcmp(datarecv, DATASTR)) { + exit(-1); + } + + exit((int)length); + } + else if (!strcmp("write", argv[1]) + || !strcmp("write_after_delay", argv[1])) { + apr_size_t length = strlen(DATASTR); + + if (!strcmp("write_after_delay", argv[1])) { + apr_sleep(apr_time_from_sec(2)); + } + + apr_socket_send(sock, DATASTR, &length); + + apr_socket_close(sock); + exit((int)length); + } + else if (!strcmp("close", argv[1])) { + apr_socket_close(sock); + exit(0); + } + exit(-1); +} diff --git a/test/sockperf.c b/test/sockperf.c new file mode 100644 index 00000000000..a18d8ba3f98 --- /dev/null +++ b/test/sockperf.c @@ -0,0 +1,256 @@ +/* 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. + */ + +/* sockperf.c + * This simple network client tries to connect to an echo daemon (echod) + * listening on a port it supplies, then time how long it takes to + * reply with packets of varying sizes. + * It prints results once completed. + * + * To run, + * + * ./echod & + * ./sockperf + */ + +#include <stdio.h> +#include <stdlib.h> /* for atexit() */ + +#include "apr.h" +#include "apr_network_io.h" +#include "apr_strings.h" + +#define MAX_ITERS 10 +#define TEST_SIZE 1024 + +struct testSet { + char c; + apr_size_t size; + int iters; +} testRuns[] = { + { 'a', 1, 3 }, + { 'b', 4, 3 }, + { 'c', 16, 5 }, + { 'd', 64, 5 }, + { 'e', 256, 10 }, +}; + +struct testResult { + int size; + int iters; + apr_time_t msecs[MAX_ITERS]; + apr_time_t avg; +}; + +static apr_int16_t testPort = 4747; +static apr_sockaddr_t *sockAddr = NULL; + +static void reportError(const char *msg, apr_status_t rv, + apr_pool_t *pool) +{ + fprintf(stderr, "%s\n", msg); + if (rv != APR_SUCCESS) + fprintf(stderr, "Error: %d\n'%s'\n", rv, + apr_psprintf(pool, "%pm", &rv)); + +} + +static void closeConnection(apr_socket_t *sock) +{ + apr_size_t len = 0; + apr_socket_send(sock, NULL, &len); +} + +static apr_status_t sendRecvBuffer(apr_time_t *t, const char *buf, + apr_size_t size, apr_pool_t *pool) +{ + apr_socket_t *sock; + apr_status_t rv; + apr_size_t len = size, thistime = size; + char *recvBuf; + apr_time_t testStart = apr_time_now(), testEnd; + int i; + + if (! sockAddr) { + rv = apr_sockaddr_info_get(&sockAddr, "127.0.0.1", APR_UNSPEC, + testPort, 0, pool); + if (rv != APR_SUCCESS) { + reportError("Unable to get socket info", rv, pool); + return rv; + } + + /* make sure we can connect to daemon before we try tests */ + + rv = apr_socket_create(&sock, APR_INET, SOCK_STREAM, APR_PROTO_TCP, + pool); + if (rv != APR_SUCCESS) { + reportError("Unable to create IPv4 stream socket", rv, pool); + return rv; + } + + rv = apr_socket_connect(sock, sockAddr); + if (rv != APR_SUCCESS) { + reportError("Unable to connect to echod!", rv, pool); + apr_socket_close(sock); + return rv; + } + apr_socket_close(sock); + + } + + recvBuf = apr_palloc(pool, size); + if (! recvBuf) { + reportError("Unable to allocate buffer", ENOMEM, pool); + return ENOMEM; + } + + *t = 0; + + /* START! */ + testStart = apr_time_now(); + rv = apr_socket_create(&sock, APR_INET, SOCK_STREAM, APR_PROTO_TCP, + pool); + if (rv != APR_SUCCESS) { + reportError("Unable to create IPv4 stream socket", rv, pool); + return rv; + } + + rv = apr_socket_connect(sock, sockAddr); + if (rv != APR_SUCCESS) { + reportError("Unable to connect to echod!", rv, pool); + apr_socket_close(sock); + return rv; + } + + for (i = 0; i < 3; i++) { + + len = size; + thistime = size; + + rv = apr_socket_send(sock, buf, &len); + if (rv != APR_SUCCESS || len != size) { + reportError(apr_psprintf(pool, + "Unable to send data correctly (iteration %d of 3)", + i) , rv, pool); + closeConnection(sock); + apr_socket_close(sock); + return rv; + } + + do { + len = thistime; + rv = apr_socket_recv(sock, &recvBuf[size - thistime], &len); + if (rv != APR_SUCCESS) { + reportError("Error receiving from socket", rv, pool); + break; + } + thistime -= len; + } while (thistime); + } + + closeConnection(sock); + apr_socket_close(sock); + testEnd = apr_time_now(); + /* STOP! */ + + if (thistime) { + reportError("Received less than we sent :-(", rv, pool); + return rv; + } + if (strncmp(recvBuf, buf, size) != 0) { + reportError("Received corrupt data :-(", 0, pool); + printf("We sent:\n%s\nWe received:\n%s\n", buf, recvBuf); + return EINVAL; + } + *t = testEnd - testStart; + return APR_SUCCESS; +} + +static apr_status_t runTest(struct testSet *ts, struct testResult *res, + apr_pool_t *pool) +{ + char *buffer; + apr_status_t rv; + int i; + apr_size_t sz = ts->size * TEST_SIZE; + + buffer = apr_palloc(pool, sz); + if (!buffer) { + reportError("Unable to allocate buffer", ENOMEM, pool); + return ENOMEM; + } + memset(buffer, ts->c, sz); + + res->iters = ts->iters > MAX_ITERS ? MAX_ITERS : ts->iters; + + for (i = 0; i < res->iters; i++) { + apr_time_t iterTime; + rv = sendRecvBuffer(&iterTime, buffer, sz, pool); + if (rv != APR_SUCCESS) { + res->iters = i; + break; + } + res->msecs[i] = iterTime; + } + + return rv; +} + +int main(int argc, char **argv) +{ + apr_pool_t *pool; + apr_status_t rv; + int i; + int nTests = sizeof(testRuns) / sizeof(testRuns[0]); + struct testResult *results; + + printf("APR Test Application: sockperf\n"); + + apr_initialize(); + atexit(apr_terminate); + + apr_pool_create(&pool, NULL); + + results = (struct testResult *)apr_pcalloc(pool, + sizeof(*results) * nTests); + + for (i = 0; i < nTests; i++) { + printf("Test -> %c\n", testRuns[i].c); + results[i].size = testRuns[i].size * (apr_size_t)TEST_SIZE; + rv = runTest(&testRuns[i], &results[i], pool); + if (rv != APR_SUCCESS) { + /* error already reported */ + exit(1); + } + } + + printf("Tests Complete!\n"); + for (i = 0; i < nTests; i++) { + int j; + apr_time_t totTime = 0; + printf("%10d byte block:\n", results[i].size); + printf("\t%2d iterations : ", results[i].iters); + for (j = 0; j < results[i].iters; j++) { + printf("%6" APR_TIME_T_FMT, results[i].msecs[j]); + totTime += results[i].msecs[j]; + } + printf("<\n"); + printf("\t Average: %6" APR_TIME_T_FMT "\n", + totTime / results[i].iters); + } + + return 0; +} diff --git a/test/testall.dsw b/test/testall.dsw new file mode 100644 index 00000000000..c56452a0a89 --- /dev/null +++ b/test/testall.dsw @@ -0,0 +1,137 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "apr"="..\apr.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "aprapp"="..\build\aprapp.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name preaprapp + End Project Dependency +}}} + +############################################################################### + +Project: "libapr"="..\libapr.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "libaprapp"="..\build\libaprapp.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name prelibaprapp + End Project Dependency +}}} + +############################################################################### + +Project: "preaprapp"="..\build\preaprapp.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name apr + End Project Dependency +}}} + +############################################################################### + +Project: "prelibaprapp"="..\build\prelibaprapp.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name libapr + End Project Dependency +}}} + +############################################################################### + +Project: "testdll"=".\testdll.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name libapr + End Project Dependency + Begin Project Dependency + Project_Dep_Name libaprapp + End Project Dependency +}}} + +############################################################################### + +Project: "testlib"=".\testlib.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name apr + End Project Dependency + Begin Project Dependency + Project_Dep_Name aprapp + End Project Dependency +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/test/testapp.c b/test/testapp.c new file mode 100644 index 00000000000..77607aa388f --- /dev/null +++ b/test/testapp.c @@ -0,0 +1,10 @@ +#include <apr.h> +#include <apr_general.h> + +int main(int argc, const char * const * argv, const char * const *env) +{ + apr_app_initialize(&argc, &argv, &env); + + + apr_terminate(); +} diff --git a/test/testarg.dsp b/test/testarg.dsp deleted file mode 100644 index a9caadec0d4..00000000000 --- a/test/testarg.dsp +++ /dev/null @@ -1,91 +0,0 @@ -# Microsoft Developer Studio Project File - Name="testarg" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 5.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Console Application" 0x0103 - -CFG=testarg - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "testarg.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "testarg.mak" CFG="testarg - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "testarg - Win32 Release" (based on "Win32 (x86) Console Application") -!MESSAGE "testarg - Win32 Debug" (based on "Win32 (x86) Console Application") -!MESSAGE - -# Begin Project -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -RSC=rc.exe - -!IF "$(CFG)" == "testarg - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /W3 /GX /O2 /I "..\include" /I "..\..\include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD BASE RSC /l 0x409 /d "NDEBUG" -# ADD RSC /l 0x409 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 -# ADD LINK32 ..\Release\aprlib.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"..\Release\testarg.exe" -# SUBTRACT LINK32 /debug - -!ELSEIF "$(CFG)" == "testarg - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "testarg_" -# PROP BASE Intermediate_Dir "testarg_" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "testarg" -# PROP Intermediate_Dir "testarg" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /I "..\include" /I "..\..\include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FD /c -# SUBTRACT CPP /YX /Yc /Yu -# ADD BASE RSC /l 0x409 /d "_DEBUG" -# ADD RSC /l 0x409 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept -# ADD LINK32 ..\Debug\aprlib.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"..\Debug\testarg.exe" /pdbtype:sept - -!ENDIF - -# Begin Target - -# Name "testarg - Win32 Release" -# Name "testarg - Win32 Debug" -# Begin Source File - -SOURCE=.\testargs.c -# End Source File -# End Target -# End Project diff --git a/test/testargs.c b/test/testargs.c index 52ddf668feb..405b3bed6d1 100644 --- a/test/testargs.c +++ b/test/testargs.c @@ -1,96 +1,236 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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_file_io.h" #include "apr_errno.h" #include "apr_general.h" -#include "apr_lib.h" #include "apr_getopt.h" -#include <stdio.h> -#include <stdlib.h> -#ifdef BEOS -#include <unistd.h> -#endif +#include "apr_strings.h" +#include "testutil.h" -int main(int argc, char * const argv[]) +static void format_arg(char *str, char option, const char *arg) { - ap_pool_t *context; - ap_int32_t data; + if (arg) { + apr_snprintf(str, 8196, "%soption: %c with %s\n", str, option, arg); + } + else { + apr_snprintf(str, 8196, "%soption: %c\n", str, option); + } +} - ap_initialize(); - atexit(ap_terminate); - ap_create_pool(&context, NULL); +static void unknown_arg(void *str, const char *err, ...) +{ + va_list va; - while (ap_getopt(argc, argv, "abc:d::", &data, context) == APR_SUCCESS) { - switch(data) { + va_start(va, err); + apr_vsnprintf(str, 8196, err, va); + va_end(va); +} + +static void no_options_found(abts_case *tc, void *data) +{ + int largc = 5; + const char * const largv[] = {"testprog", "-a", "-b", "-c", "-d"}; + apr_getopt_t *opt; + apr_status_t rv; + char ch; + const char *opt_arg; + char str[8196]; + + str[0] = '\0'; + rv = apr_getopt_init(&opt, p, largc, largv); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + while (apr_getopt(opt, "abcd", &ch, &opt_arg) == APR_SUCCESS) { + switch (ch) { + case 'a': + case 'b': + case 'c': + case 'd': + default: + format_arg(str, ch, opt_arg); + } + } + ABTS_STR_EQUAL(tc, "option: a\n" + "option: b\n" + "option: c\n" + "option: d\n", str); +} + +static void no_options(abts_case *tc, void *data) +{ + int largc = 5; + const char * const largv[] = {"testprog", "-a", "-b", "-c", "-d"}; + apr_getopt_t *opt; + apr_status_t rv; + char ch; + const char *opt_arg; + char str[8196]; + + str[0] = '\0'; + rv = apr_getopt_init(&opt, p, largc, largv); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + opt->errfn = unknown_arg; + opt->errarg = str; + + while (apr_getopt(opt, "efgh", &ch, &opt_arg) == APR_SUCCESS) { + switch (ch) { case 'a': case 'b': - printf("option %c\n", data); - break; case 'c': - printf("option %c with %s\n", data, ap_optarg); - break; case 'd': - printf("option %c", data); - if (ap_optarg) { - printf(" with %s\n", ap_optarg); - } - else { - printf("\n"); - } + format_arg(str, ch, opt_arg); + break; + default: + break; + } + } + ABTS_STR_EQUAL(tc, "testprog: illegal option -- a\n", str); +} + +static void required_option(abts_case *tc, void *data) +{ + int largc = 3; + const char * const largv[] = {"testprog", "-a", "foo"}; + apr_getopt_t *opt; + apr_status_t rv; + char ch; + const char *opt_arg; + char str[8196]; + + str[0] = '\0'; + rv = apr_getopt_init(&opt, p, largc, largv); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + opt->errfn = unknown_arg; + opt->errarg = str; + + while (apr_getopt(opt, "a:", &ch, &opt_arg) == APR_SUCCESS) { + switch (ch) { + case 'a': + format_arg(str, ch, opt_arg); + break; + default: + break; + } + } + ABTS_STR_EQUAL(tc, "option: a with foo\n", str); +} + +static void required_option_notgiven(abts_case *tc, void *data) +{ + int largc = 2; + const char * const largv[] = {"testprog", "-a"}; + apr_getopt_t *opt; + apr_status_t rv; + char ch; + const char *opt_arg; + char str[8196]; + + str[0] = '\0'; + rv = apr_getopt_init(&opt, p, largc, largv); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + opt->errfn = unknown_arg; + opt->errarg = str; + + while (apr_getopt(opt, "a:", &ch, &opt_arg) == APR_SUCCESS) { + switch (ch) { + case 'a': + format_arg(str, ch, opt_arg); + break; + default: + break; + } + } + ABTS_STR_EQUAL(tc, "testprog: option requires an argument -- a\n", str); +} + +static void optional_option(abts_case *tc, void *data) +{ + int largc = 3; + const char * const largv[] = {"testprog", "-a", "foo"}; + apr_getopt_t *opt; + apr_status_t rv; + char ch; + const char *opt_arg; + char str[8196]; + + str[0] = '\0'; + rv = apr_getopt_init(&opt, p, largc, largv); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + opt->errfn = unknown_arg; + opt->errarg = str; + + while (apr_getopt(opt, "a::", &ch, &opt_arg) == APR_SUCCESS) { + switch (ch) { + case 'a': + format_arg(str, ch, opt_arg); + break; + default: break; } } - return 1; + ABTS_STR_EQUAL(tc, "option: a with foo\n", str); +} + +static void optional_option_notgiven(abts_case *tc, void *data) +{ + int largc = 2; + const char * const largv[] = {"testprog", "-a"}; + apr_getopt_t *opt; + apr_status_t rv; + char ch; + const char *opt_arg; + char str[8196]; + + str[0] = '\0'; + rv = apr_getopt_init(&opt, p, largc, largv); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + opt->errfn = unknown_arg; + opt->errarg = str; + + while (apr_getopt(opt, "a::", &ch, &opt_arg) == APR_SUCCESS) { + switch (ch) { + case 'a': + format_arg(str, ch, opt_arg); + break; + default: + break; + } + } +#if 0 +/* Our version of getopt doesn't allow for optional arguments. */ + ABTS_STR_EQUAL(tc, "option: a\n", str); +#endif + ABTS_STR_EQUAL(tc, "testprog: option requires an argument -- a\n", str); +} + +abts_suite *testgetopt(abts_suite *suite) +{ + suite = ADD_SUITE(suite) + + abts_run_test(suite, no_options, NULL); + abts_run_test(suite, no_options_found, NULL); + abts_run_test(suite, required_option, NULL); + abts_run_test(suite, required_option_notgiven, NULL); + abts_run_test(suite, optional_option, NULL); + abts_run_test(suite, optional_option_notgiven, NULL); + + return suite; } diff --git a/test/testatomic.c b/test/testatomic.c new file mode 100644 index 00000000000..4bf2caa4688 --- /dev/null +++ b/test/testatomic.c @@ -0,0 +1,536 @@ +/* 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 "testutil.h" +#include "apr_strings.h" +#include "apr_thread_proc.h" +#include "apr_errno.h" +#include "apr_general.h" +#include "apr_atomic.h" +#include "apr_time.h" + +/* Use pthread_setconcurrency where it is available and not a nullop, + * i.e. platforms using M:N or M:1 thread models: */ +#if APR_HAS_THREADS && \ + ((defined(SOLARIS2) && SOLARIS2 > 6) || defined(_AIX)) +/* also HP-UX, IRIX? ... */ +#define HAVE_PTHREAD_SETCONCURRENCY +#endif + +#ifdef HAVE_PTHREAD_SETCONCURRENCY +#include <pthread.h> +#endif + +static void test_init(abts_case *tc, void *data) +{ + APR_ASSERT_SUCCESS(tc, "Could not initliaze atomics", apr_atomic_init(p)); +} + +static void test_set32(abts_case *tc, void *data) +{ + apr_uint32_t y32; + apr_atomic_set32(&y32, 2); + ABTS_INT_EQUAL(tc, 2, y32); +} + +static void test_read32(abts_case *tc, void *data) +{ + apr_uint32_t y32; + apr_atomic_set32(&y32, 2); + ABTS_INT_EQUAL(tc, 2, apr_atomic_read32(&y32)); +} + +static void test_dec32(abts_case *tc, void *data) +{ + apr_uint32_t y32; + int rv; + + apr_atomic_set32(&y32, 2); + + rv = apr_atomic_dec32(&y32); + ABTS_INT_EQUAL(tc, 1, y32); + ABTS_ASSERT(tc, "atomic_dec returned zero when it shouldn't", rv != 0); + + rv = apr_atomic_dec32(&y32); + ABTS_INT_EQUAL(tc, 0, y32); + ABTS_ASSERT(tc, "atomic_dec didn't returned zero when it should", rv == 0); +} + +static void test_xchg32(abts_case *tc, void *data) +{ + apr_uint32_t oldval; + apr_uint32_t y32; + + apr_atomic_set32(&y32, 100); + oldval = apr_atomic_xchg32(&y32, 50); + + ABTS_INT_EQUAL(tc, 100, oldval); + ABTS_INT_EQUAL(tc, 50, y32); +} + +static void test_xchgptr(abts_case *tc, void *data) +{ + int a; + void *ref = "little piggy"; + void *target_ptr = ref; + void *old_ptr; + + old_ptr = apr_atomic_xchgptr(&target_ptr, &a); + ABTS_PTR_EQUAL(tc, ref, old_ptr); + ABTS_PTR_EQUAL(tc, &a, (void *) target_ptr); +} + +static void test_cas_equal(abts_case *tc, void *data) +{ + apr_uint32_t casval = 0; + apr_uint32_t oldval; + + oldval = apr_atomic_cas32(&casval, 12, 0); + ABTS_INT_EQUAL(tc, 0, oldval); + ABTS_INT_EQUAL(tc, 12, casval); +} + +static void test_cas_equal_nonnull(abts_case *tc, void *data) +{ + apr_uint32_t casval = 12; + apr_uint32_t oldval; + + oldval = apr_atomic_cas32(&casval, 23, 12); + ABTS_INT_EQUAL(tc, 12, oldval); + ABTS_INT_EQUAL(tc, 23, casval); +} + +static void test_cas_notequal(abts_case *tc, void *data) +{ + apr_uint32_t casval = 12; + apr_uint32_t oldval; + + oldval = apr_atomic_cas32(&casval, 23, 2); + ABTS_INT_EQUAL(tc, 12, oldval); + ABTS_INT_EQUAL(tc, 12, casval); +} + +static void test_casptr_equal(abts_case *tc, void *data) +{ + int a; + void *target_ptr = NULL; + void *old_ptr; + + old_ptr = apr_atomic_casptr(&target_ptr, &a, NULL); + ABTS_PTR_EQUAL(tc, NULL, old_ptr); + ABTS_PTR_EQUAL(tc, &a, (void *) target_ptr); +} + +static void test_casptr_equal_nonnull(abts_case *tc, void *data) +{ + int a, b; + void *target_ptr = &a; + void *old_ptr; + + old_ptr = apr_atomic_casptr(&target_ptr, &b, &a); + ABTS_PTR_EQUAL(tc, &a, old_ptr); + ABTS_PTR_EQUAL(tc, &b, (void *) target_ptr); +} + +static void test_casptr_notequal(abts_case *tc, void *data) +{ + int a, b; + void *target_ptr = &a; + void *old_ptr; + + old_ptr = apr_atomic_casptr(&target_ptr, &a, &b); + ABTS_PTR_EQUAL(tc, &a, old_ptr); + ABTS_PTR_EQUAL(tc, &a, (void *) target_ptr); +} + +static void test_add32(abts_case *tc, void *data) +{ + apr_uint32_t oldval; + apr_uint32_t y32; + + apr_atomic_set32(&y32, 23); + oldval = apr_atomic_add32(&y32, 4); + ABTS_INT_EQUAL(tc, 23, oldval); + ABTS_INT_EQUAL(tc, 27, y32); +} + +static void test_add32_neg(abts_case *tc, void *data) +{ + apr_uint32_t oldval; + apr_uint32_t y32; + + apr_atomic_set32(&y32, 23); + oldval = apr_atomic_add32(&y32, -10); + ABTS_INT_EQUAL(tc, 23, oldval); + ABTS_INT_EQUAL(tc, 13, y32); +} + +static void test_inc32(abts_case *tc, void *data) +{ + apr_uint32_t oldval; + apr_uint32_t y32; + + apr_atomic_set32(&y32, 23); + oldval = apr_atomic_inc32(&y32); + ABTS_INT_EQUAL(tc, 23, oldval); + ABTS_INT_EQUAL(tc, 24, y32); +} + +static void test_set_add_inc_sub(abts_case *tc, void *data) +{ + apr_uint32_t y32; + + apr_atomic_set32(&y32, 0); + apr_atomic_add32(&y32, 20); + apr_atomic_inc32(&y32); + apr_atomic_sub32(&y32, 10); + + ABTS_INT_EQUAL(tc, 11, y32); +} + +static void test_wrap_zero(abts_case *tc, void *data) +{ + apr_uint32_t y32; + apr_uint32_t rv; + apr_uint32_t minus1 = (apr_uint32_t)-1; + char *str; + + apr_atomic_set32(&y32, 0); + rv = apr_atomic_dec32(&y32); + + ABTS_ASSERT(tc, "apr_atomic_dec32 on zero returned zero.", rv != 0); + str = apr_psprintf(p, "zero wrap failed: 0 - 1 = %d", y32); + ABTS_ASSERT(tc, str, y32 == minus1); +} + +static void test_inc_neg1(abts_case *tc, void *data) +{ + apr_uint32_t y32 = (apr_uint32_t)-1; + apr_uint32_t minus1 = (apr_uint32_t)-1; + apr_uint32_t rv; + char *str; + + rv = apr_atomic_inc32(&y32); + + ABTS_ASSERT(tc, "apr_atomic_inc32 didn't return the old value.", rv == minus1); + str = apr_psprintf(p, "zero wrap failed: -1 + 1 = %d", y32); + ABTS_ASSERT(tc, str, y32 == 0); +} + + +#if APR_HAS_THREADS + +void *APR_THREAD_FUNC thread_func_mutex(apr_thread_t *thd, void *data); +void *APR_THREAD_FUNC thread_func_atomic(apr_thread_t *thd, void *data); + +apr_thread_mutex_t *thread_lock; +volatile apr_uint32_t mutex_locks = 0; +volatile apr_uint32_t atomic_ops = 0; +apr_status_t exit_ret_val = 123; /* just some made up number to check on later */ + +#define NUM_THREADS 40 +#define NUM_ITERATIONS 20000 + +void *APR_THREAD_FUNC thread_func_mutex(apr_thread_t *thd, void *data) +{ + int i; + + for (i = 0; i < NUM_ITERATIONS; i++) { + apr_thread_mutex_lock(thread_lock); + mutex_locks++; + apr_thread_mutex_unlock(thread_lock); + } + apr_thread_exit(thd, exit_ret_val); + return NULL; +} + +void *APR_THREAD_FUNC thread_func_atomic(apr_thread_t *thd, void *data) +{ + int i; + + for (i = 0; i < NUM_ITERATIONS ; i++) { + apr_atomic_inc32(&atomic_ops); + apr_atomic_add32(&atomic_ops, 2); + apr_atomic_dec32(&atomic_ops); + apr_atomic_dec32(&atomic_ops); + } + apr_thread_exit(thd, exit_ret_val); + return NULL; +} + +static void test_atomics_threaded(abts_case *tc, void *data) +{ + apr_thread_t *t1[NUM_THREADS]; + apr_thread_t *t2[NUM_THREADS]; + apr_status_t rv; + int i; + +#ifdef HAVE_PTHREAD_SETCONCURRENCY + pthread_setconcurrency(8); +#endif + + rv = apr_thread_mutex_create(&thread_lock, APR_THREAD_MUTEX_DEFAULT, p); + APR_ASSERT_SUCCESS(tc, "Could not create lock", rv); + + for (i = 0; i < NUM_THREADS; i++) { + apr_status_t r1, r2; + r1 = apr_thread_create(&t1[i], NULL, thread_func_mutex, NULL, p); + r2 = apr_thread_create(&t2[i], NULL, thread_func_atomic, NULL, p); + ABTS_ASSERT(tc, "Failed creating threads", !r1 && !r2); + } + + for (i = 0; i < NUM_THREADS; i++) { + apr_status_t s1, s2; + apr_thread_join(&s1, t1[i]); + apr_thread_join(&s2, t2[i]); + + ABTS_ASSERT(tc, "Invalid return value from thread_join", + s1 == exit_ret_val && s2 == exit_ret_val); + } + + ABTS_INT_EQUAL(tc, NUM_THREADS * NUM_ITERATIONS, mutex_locks); + ABTS_INT_EQUAL(tc, NUM_THREADS * NUM_ITERATIONS, + apr_atomic_read32(&atomic_ops)); + + rv = apr_thread_mutex_destroy(thread_lock); + ABTS_ASSERT(tc, "Failed creating threads", rv == APR_SUCCESS); +} + +#undef NUM_THREADS +#define NUM_THREADS 7 + +typedef struct tbox_t tbox_t; + +struct tbox_t { + abts_case *tc; + apr_uint32_t *mem; + apr_uint32_t preval; + apr_uint32_t postval; + apr_uint32_t loop; + void (*func)(tbox_t *box); +}; + +static APR_INLINE void busyloop_read32(tbox_t *tbox) +{ + apr_uint32_t val; + + do { + val = apr_atomic_read32(tbox->mem); + + if (val != tbox->preval) + apr_thread_yield(); + else + break; + } while (1); +} + +static void busyloop_set32(tbox_t *tbox) +{ + do { + busyloop_read32(tbox); + apr_atomic_set32(tbox->mem, tbox->postval); + } while (--tbox->loop); +} + +static void busyloop_add32(tbox_t *tbox) +{ + apr_uint32_t val; + + do { + busyloop_read32(tbox); + val = apr_atomic_add32(tbox->mem, tbox->postval); + apr_thread_mutex_lock(thread_lock); + ABTS_INT_EQUAL(tbox->tc, val, tbox->preval); + apr_thread_mutex_unlock(thread_lock); + } while (--tbox->loop); +} + +static void busyloop_sub32(tbox_t *tbox) +{ + do { + busyloop_read32(tbox); + apr_atomic_sub32(tbox->mem, tbox->postval); + } while (--tbox->loop); +} + +static void busyloop_inc32(tbox_t *tbox) +{ + apr_uint32_t val; + + do { + busyloop_read32(tbox); + val = apr_atomic_inc32(tbox->mem); + apr_thread_mutex_lock(thread_lock); + ABTS_INT_EQUAL(tbox->tc, val, tbox->preval); + apr_thread_mutex_unlock(thread_lock); + } while (--tbox->loop); +} + +static void busyloop_dec32(tbox_t *tbox) +{ + apr_uint32_t val; + + do { + busyloop_read32(tbox); + val = apr_atomic_dec32(tbox->mem); + apr_thread_mutex_lock(thread_lock); + ABTS_INT_NEQUAL(tbox->tc, 0, val); + apr_thread_mutex_unlock(thread_lock); + } while (--tbox->loop); +} + +static void busyloop_cas32(tbox_t *tbox) +{ + apr_uint32_t val; + + do { + do { + val = apr_atomic_cas32(tbox->mem, tbox->postval, tbox->preval); + + if (val != tbox->preval) + apr_thread_yield(); + else + break; + } while (1); + } while (--tbox->loop); +} + +static void busyloop_xchg32(tbox_t *tbox) +{ + apr_uint32_t val; + + do { + busyloop_read32(tbox); + val = apr_atomic_xchg32(tbox->mem, tbox->postval); + apr_thread_mutex_lock(thread_lock); + ABTS_INT_EQUAL(tbox->tc, val, tbox->preval); + apr_thread_mutex_unlock(thread_lock); + } while (--tbox->loop); +} + +static void *APR_THREAD_FUNC thread_func_busyloop(apr_thread_t *thd, void *data) +{ + tbox_t *tbox = data; + + tbox->func(tbox); + + apr_thread_exit(thd, 0); + + return NULL; +} + +static void test_atomics_busyloop_threaded(abts_case *tc, void *data) +{ + unsigned int i; + apr_status_t rv; + apr_uint32_t count = 0; + tbox_t tbox[NUM_THREADS]; + apr_thread_t *thread[NUM_THREADS]; + + rv = apr_thread_mutex_create(&thread_lock, APR_THREAD_MUTEX_DEFAULT, p); + APR_ASSERT_SUCCESS(tc, "Could not create lock", rv); + + /* get ready */ + for (i = 0; i < NUM_THREADS; i++) { + tbox[i].tc = tc; + tbox[i].mem = &count; + tbox[i].loop = 50; + } + + tbox[0].preval = 98; + tbox[0].postval = 3891; + tbox[0].func = busyloop_add32; + + tbox[1].preval = 3989; + tbox[1].postval = 1010; + tbox[1].func = busyloop_sub32; + + tbox[2].preval = 2979; + tbox[2].postval = 0; /* not used */ + tbox[2].func = busyloop_inc32; + + tbox[3].preval = 2980; + tbox[3].postval = 16384; + tbox[3].func = busyloop_set32; + + tbox[4].preval = 16384; + tbox[4].postval = 0; /* not used */ + tbox[4].func = busyloop_dec32; + + tbox[5].preval = 16383; + tbox[5].postval = 1048576; + tbox[5].func = busyloop_cas32; + + tbox[6].preval = 1048576; + tbox[6].postval = 98; /* goto tbox[0] */ + tbox[6].func = busyloop_xchg32; + + /* get set */ + for (i = 0; i < NUM_THREADS; i++) { + rv = apr_thread_create(&thread[i], NULL, thread_func_busyloop, + &tbox[i], p); + ABTS_ASSERT(tc, "Failed creating thread", rv == APR_SUCCESS); + } + + /* go! */ + apr_atomic_set32(tbox->mem, 98); + + for (i = 0; i < NUM_THREADS; i++) { + apr_status_t retval; + rv = apr_thread_join(&retval, thread[i]); + ABTS_ASSERT(tc, "Thread join failed", rv == APR_SUCCESS); + ABTS_ASSERT(tc, "Invalid return value from thread_join", retval == 0); + } + + ABTS_INT_EQUAL(tbox->tc, 98, count); + + rv = apr_thread_mutex_destroy(thread_lock); + ABTS_ASSERT(tc, "Failed creating threads", rv == APR_SUCCESS); +} + +#endif /* !APR_HAS_THREADS */ + +abts_suite *testatomic(abts_suite *suite) +{ + suite = ADD_SUITE(suite) + + abts_run_test(suite, test_init, NULL); + abts_run_test(suite, test_set32, NULL); + abts_run_test(suite, test_read32, NULL); + abts_run_test(suite, test_dec32, NULL); + abts_run_test(suite, test_xchg32, NULL); + abts_run_test(suite, test_xchgptr, NULL); + abts_run_test(suite, test_cas_equal, NULL); + abts_run_test(suite, test_cas_equal_nonnull, NULL); + abts_run_test(suite, test_cas_notequal, NULL); + abts_run_test(suite, test_casptr_equal, NULL); + abts_run_test(suite, test_casptr_equal_nonnull, NULL); + abts_run_test(suite, test_casptr_notequal, NULL); + abts_run_test(suite, test_add32, NULL); + abts_run_test(suite, test_add32_neg, NULL); + abts_run_test(suite, test_inc32, NULL); + abts_run_test(suite, test_set_add_inc_sub, NULL); + abts_run_test(suite, test_wrap_zero, NULL); + abts_run_test(suite, test_inc_neg1, NULL); + +#if APR_HAS_THREADS + abts_run_test(suite, test_atomics_threaded, NULL); + abts_run_test(suite, test_atomics_busyloop_threaded, NULL); +#endif + + return suite; +} + diff --git a/test/testbase64.c b/test/testbase64.c new file mode 100644 index 00000000000..92cccb712f0 --- /dev/null +++ b/test/testbase64.c @@ -0,0 +1,84 @@ +/* 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 <assert.h> +#include <stdio.h> +#include <stdlib.h> + +#include "apr_base64.h" + +#include "abts.h" +#include "testutil.h" + +static struct { + const char *orig; + const char *enc; +} base64_tbl[] = +{ + {"", ""}, + {"H", "SA=="}, + {"He", "SGU="}, + {"Hel", "SGVs"}, + {"Hell", "SGVsbA=="}, + {"Hello", "SGVsbG8="}, + {"Hello World", "SGVsbG8gV29ybGQ="}, + {"\xff\xff\xff\xff", "/////w=="}, +}; +static int num_base64 = sizeof(base64_tbl) / sizeof(base64_tbl[0]); + +static void test_base64(abts_case *tc, void *data) +{ + apr_pool_t *pool; + int i; + + apr_pool_create(&pool, NULL); + + for (i = 0; i < num_base64; i++) { + char *enc; + int orig_len, enc_len, b64_len, b64_enc_len; + + apr_pool_clear(pool); + + orig_len = strlen(base64_tbl[i].orig); + enc_len = strlen(base64_tbl[i].enc); + + /* includes + 1 for term null */ + b64_enc_len = apr_base64_encode_len(orig_len); + ABTS_ASSERT(tc, "base 64 exp. length", (enc_len == (b64_enc_len - 1))); + + enc = apr_palloc(pool, b64_enc_len); + + b64_len = apr_base64_encode(enc, base64_tbl[i].orig, orig_len); + + ABTS_ASSERT(tc, "base 64 encoded length", (b64_enc_len == b64_len)); + ABTS_ASSERT(tc, "base 64 encoded matches expected output", + (memcmp(enc, base64_tbl[i].enc, b64_enc_len) == 0)); + + enc = apr_pbase64_encode(pool, base64_tbl[i].orig); + ABTS_ASSERT(tc, "base 64 encoded from pool matches expected output", + (strcmp(enc, base64_tbl[i].enc) == 0)); + ABTS_ASSERT(tc, "base 64 length", strlen(enc) == strlen(base64_tbl[i].enc)); + } +} + +abts_suite *testbase64(abts_suite *suite) +{ + suite = ADD_SUITE(suite); + + abts_run_test(suite, test_base64, NULL); + + return suite; +} diff --git a/test/testbuckets.c b/test/testbuckets.c new file mode 100644 index 00000000000..077a139361d --- /dev/null +++ b/test/testbuckets.c @@ -0,0 +1,535 @@ +/* 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 "abts.h" +#include "testutil.h" +#include "apr_buckets.h" +#include "apr_strings.h" + +static void test_create(abts_case *tc, void *data) +{ + apr_bucket_alloc_t *ba; + apr_bucket_brigade *bb; + + ba = apr_bucket_alloc_create(p); + bb = apr_brigade_create(p, ba); + + ABTS_ASSERT(tc, "new brigade not NULL", bb != NULL); + ABTS_ASSERT(tc, "new brigade is empty", APR_BRIGADE_EMPTY(bb)); + + apr_brigade_destroy(bb); + apr_bucket_alloc_destroy(ba); +} + +static void test_simple(abts_case *tc, void *data) +{ + apr_bucket_alloc_t *ba; + apr_bucket_brigade *bb; + apr_bucket *fb, *tb; + + ba = apr_bucket_alloc_create(p); + bb = apr_brigade_create(p, ba); + + fb = APR_BRIGADE_FIRST(bb); + ABTS_ASSERT(tc, "first bucket of empty brigade is sentinel", + fb == APR_BRIGADE_SENTINEL(bb)); + + fb = apr_bucket_flush_create(ba); + APR_BRIGADE_INSERT_HEAD(bb, fb); + + ABTS_ASSERT(tc, "first bucket of brigade is flush", + APR_BRIGADE_FIRST(bb) == fb); + + ABTS_ASSERT(tc, "bucket after flush is sentinel", + APR_BUCKET_NEXT(fb) == APR_BRIGADE_SENTINEL(bb)); + + tb = apr_bucket_transient_create("aaa", 3, ba); + APR_BUCKET_INSERT_BEFORE(fb, tb); + + ABTS_ASSERT(tc, "bucket before flush now transient", + APR_BUCKET_PREV(fb) == tb); + ABTS_ASSERT(tc, "bucket after transient is flush", + APR_BUCKET_NEXT(tb) == fb); + ABTS_ASSERT(tc, "bucket before transient is sentinel", + APR_BUCKET_PREV(tb) == APR_BRIGADE_SENTINEL(bb)); + + apr_brigade_cleanup(bb); + + ABTS_ASSERT(tc, "cleaned up brigade was empty", APR_BRIGADE_EMPTY(bb)); + + apr_brigade_destroy(bb); + apr_bucket_alloc_destroy(ba); +} + +static apr_bucket_brigade *make_simple_brigade(apr_bucket_alloc_t *ba, + const char *first, + const char *second) +{ + apr_bucket_brigade *bb = apr_brigade_create(p, ba); + apr_bucket *e; + + e = apr_bucket_transient_create(first, strlen(first), ba); + APR_BRIGADE_INSERT_TAIL(bb, e); + + e = apr_bucket_transient_create(second, strlen(second), ba); + APR_BRIGADE_INSERT_TAIL(bb, e); + + return bb; +} + +/* tests that 'bb' flattens to string 'expect'. */ +static void flatten_match(abts_case *tc, const char *ctx, + apr_bucket_brigade *bb, + const char *expect) +{ + apr_size_t elen = strlen(expect); + char *buf = malloc(elen); + apr_size_t len = elen; + char msg[200]; + + sprintf(msg, "%s: flatten brigade", ctx); + APR_ASSERT_SUCCESS(tc, msg, apr_brigade_flatten(bb, buf, &len)); + sprintf(msg, "%s: length match (%ld not %ld)", ctx, + (long)len, (long)elen); + ABTS_ASSERT(tc, msg, len == elen); + sprintf(msg, "%s: result match", msg); + ABTS_STR_NEQUAL(tc, expect, buf, len); + free(buf); +} + +static void test_flatten(abts_case *tc, void *data) +{ + apr_bucket_alloc_t *ba = apr_bucket_alloc_create(p); + apr_bucket_brigade *bb; + + bb = make_simple_brigade(ba, "hello, ", "world"); + + flatten_match(tc, "flatten brigade", bb, "hello, world"); + + apr_brigade_destroy(bb); + apr_bucket_alloc_destroy(ba); +} + +static int count_buckets(apr_bucket_brigade *bb) +{ + apr_bucket *e; + int count = 0; + + for (e = APR_BRIGADE_FIRST(bb); + e != APR_BRIGADE_SENTINEL(bb); + e = APR_BUCKET_NEXT(e)) { + count++; + } + + return count; +} + +static void test_split(abts_case *tc, void *data) +{ + apr_bucket_alloc_t *ba = apr_bucket_alloc_create(p); + apr_bucket_brigade *bb, *bb2; + apr_bucket *e; + + bb = make_simple_brigade(ba, "hello, ", "world"); + + /* split at the "world" bucket */ + e = APR_BRIGADE_LAST(bb); + bb2 = apr_brigade_split(bb, e); + + ABTS_ASSERT(tc, "split brigade contains one bucket", + count_buckets(bb2) == 1); + ABTS_ASSERT(tc, "original brigade contains one bucket", + count_buckets(bb) == 1); + + flatten_match(tc, "match original brigade", bb, "hello, "); + flatten_match(tc, "match split brigade", bb2, "world"); + + apr_brigade_destroy(bb2); + apr_brigade_destroy(bb); + apr_bucket_alloc_destroy(ba); +} + +#define COUNT 3000 +#define THESTR "hello" + +static void test_bwrite(abts_case *tc, void *data) +{ + apr_bucket_alloc_t *ba = apr_bucket_alloc_create(p); + apr_bucket_brigade *bb = apr_brigade_create(p, ba); + apr_off_t length; + int n; + + for (n = 0; n < COUNT; n++) { + APR_ASSERT_SUCCESS(tc, "brigade_write", + apr_brigade_write(bb, NULL, NULL, + THESTR, sizeof THESTR)); + } + + APR_ASSERT_SUCCESS(tc, "determine brigade length", + apr_brigade_length(bb, 1, &length)); + + ABTS_ASSERT(tc, "brigade has correct length", + length == (COUNT * sizeof THESTR)); + + apr_brigade_destroy(bb); + apr_bucket_alloc_destroy(ba); +} + +static void test_splitline(abts_case *tc, void *data) +{ + apr_bucket_alloc_t *ba = apr_bucket_alloc_create(p); + apr_bucket_brigade *bin, *bout; + + bin = make_simple_brigade(ba, "blah blah blah-", + "end of line.\nfoo foo foo"); + bout = apr_brigade_create(p, ba); + + APR_ASSERT_SUCCESS(tc, "split line", + apr_brigade_split_line(bout, bin, + APR_BLOCK_READ, 100)); + + flatten_match(tc, "split line", bout, "blah blah blah-end of line.\n"); + flatten_match(tc, "remainder", bin, "foo foo foo"); + + apr_brigade_destroy(bout); + apr_brigade_destroy(bin); + apr_bucket_alloc_destroy(ba); +} + +/* Test that bucket E has content EDATA of length ELEN. */ +static void test_bucket_content(abts_case *tc, + apr_bucket *e, + const char *edata, + apr_size_t elen) +{ + const char *adata; + apr_size_t alen; + + APR_ASSERT_SUCCESS(tc, "read from bucket", + apr_bucket_read(e, &adata, &alen, + APR_BLOCK_READ)); + + ABTS_ASSERT(tc, "read expected length", alen == elen); + ABTS_STR_NEQUAL(tc, edata, adata, elen); +} + +static void test_splits(abts_case *tc, void *ctx) +{ + apr_bucket_alloc_t *ba = apr_bucket_alloc_create(p); + apr_bucket_brigade *bb; + apr_bucket *e; + char *str = "alphabeta"; + int n; + + bb = apr_brigade_create(p, ba); + + APR_BRIGADE_INSERT_TAIL(bb, + apr_bucket_immortal_create(str, 9, ba)); + APR_BRIGADE_INSERT_TAIL(bb, + apr_bucket_transient_create(str, 9, ba)); + APR_BRIGADE_INSERT_TAIL(bb, + apr_bucket_heap_create(strdup(str), 9, free, ba)); + APR_BRIGADE_INSERT_TAIL(bb, + apr_bucket_pool_create(apr_pstrdup(p, str), 9, p, + ba)); + + ABTS_ASSERT(tc, "four buckets inserted", count_buckets(bb) == 4); + + /* now split each of the buckets after byte 5 */ + for (n = 0, e = APR_BRIGADE_FIRST(bb); n < 4; n++) { + ABTS_ASSERT(tc, "reached end of brigade", + e != APR_BRIGADE_SENTINEL(bb)); + ABTS_ASSERT(tc, "split bucket OK", + apr_bucket_split(e, 5) == APR_SUCCESS); + e = APR_BUCKET_NEXT(e); + ABTS_ASSERT(tc, "split OK", e != APR_BRIGADE_SENTINEL(bb)); + e = APR_BUCKET_NEXT(e); + } + + ABTS_ASSERT(tc, "four buckets split into eight", + count_buckets(bb) == 8); + + for (n = 0, e = APR_BRIGADE_FIRST(bb); n < 4; n++) { + const char *data; + apr_size_t len; + + APR_ASSERT_SUCCESS(tc, "read alpha from bucket", + apr_bucket_read(e, &data, &len, APR_BLOCK_READ)); + ABTS_ASSERT(tc, "read 5 bytes", len == 5); + ABTS_STR_NEQUAL(tc, "alpha", data, 5); + + e = APR_BUCKET_NEXT(e); + + APR_ASSERT_SUCCESS(tc, "read beta from bucket", + apr_bucket_read(e, &data, &len, APR_BLOCK_READ)); + ABTS_ASSERT(tc, "read 4 bytes", len == 4); + ABTS_STR_NEQUAL(tc, "beta", data, 5); + + e = APR_BUCKET_NEXT(e); + } + + /* now delete the "alpha" buckets */ + for (n = 0, e = APR_BRIGADE_FIRST(bb); n < 4; n++) { + apr_bucket *f; + + ABTS_ASSERT(tc, "reached end of brigade", + e != APR_BRIGADE_SENTINEL(bb)); + f = APR_BUCKET_NEXT(e); + apr_bucket_delete(e); + e = APR_BUCKET_NEXT(f); + } + + ABTS_ASSERT(tc, "eight buckets reduced to four", + count_buckets(bb) == 4); + + flatten_match(tc, "flatten beta brigade", bb, + "beta" "beta" "beta" "beta"); + + apr_brigade_destroy(bb); + apr_bucket_alloc_destroy(ba); +} + +#define TIF_FNAME "testfile.txt" + +static void test_insertfile(abts_case *tc, void *ctx) +{ + apr_bucket_alloc_t *ba = apr_bucket_alloc_create(p); + apr_bucket_brigade *bb; + const apr_off_t bignum = (APR_INT64_C(2) << 32) + 424242; + apr_off_t count; + apr_file_t *f; + apr_bucket *e; + + ABTS_ASSERT(tc, "open test file", + apr_file_open(&f, TIF_FNAME, + APR_FOPEN_WRITE | APR_FOPEN_TRUNCATE + | APR_FOPEN_CREATE | APR_FOPEN_SPARSE, + APR_FPROT_OS_DEFAULT, p) == APR_SUCCESS); + + if (apr_file_trunc(f, bignum)) { + apr_file_close(f); + apr_file_remove(TIF_FNAME, p); + ABTS_NOT_IMPL(tc, "Skipped: could not create large file"); + return; + } + + bb = apr_brigade_create(p, ba); + + e = apr_brigade_insert_file(bb, f, 0, bignum, p); + + ABTS_ASSERT(tc, "inserted file was not at end of brigade", + e == APR_BRIGADE_LAST(bb)); + + /* check that the total size of inserted buckets is equal to the + * total size of the file. */ + count = 0; + + for (e = APR_BRIGADE_FIRST(bb); + e != APR_BRIGADE_SENTINEL(bb); + e = APR_BUCKET_NEXT(e)) { + ABTS_ASSERT(tc, "bucket size sane", e->length != (apr_size_t)-1); + count += e->length; + } + + ABTS_ASSERT(tc, "total size of buckets incorrect", count == bignum); + + apr_brigade_destroy(bb); + + /* Truncate the file to zero size before close() so that we don't + * actually write out the large file if we are on a non-sparse file + * system - like Mac OS X's HFS. Otherwise, pity the poor user who + * has to wait for the 8GB file to be written to disk. + */ + apr_file_trunc(f, 0); + + apr_file_close(f); + apr_bucket_alloc_destroy(ba); + apr_file_remove(TIF_FNAME, p); +} + +/* Make a test file named FNAME, and write CONTENTS to it. */ +static apr_file_t *make_test_file(abts_case *tc, const char *fname, + const char *contents) +{ + apr_file_t *f; + + ABTS_ASSERT(tc, "create test file", + apr_file_open(&f, fname, + APR_FOPEN_READ|APR_FOPEN_WRITE|APR_FOPEN_TRUNCATE|APR_FOPEN_CREATE, + APR_FPROT_OS_DEFAULT, p) == APR_SUCCESS); + + ABTS_ASSERT(tc, "write test file contents", + apr_file_puts(contents, f) == APR_SUCCESS); + + return f; +} + +static void test_manyfile(abts_case *tc, void *data) +{ + apr_bucket_alloc_t *ba = apr_bucket_alloc_create(p); + apr_bucket_brigade *bb = apr_brigade_create(p, ba); + apr_file_t *f; + + f = make_test_file(tc, "manyfile.bin", + "world" "hello" "brave" " ,\n"); + + apr_brigade_insert_file(bb, f, 5, 5, p); + apr_brigade_insert_file(bb, f, 16, 1, p); + apr_brigade_insert_file(bb, f, 15, 1, p); + apr_brigade_insert_file(bb, f, 10, 5, p); + apr_brigade_insert_file(bb, f, 15, 1, p); + apr_brigade_insert_file(bb, f, 0, 5, p); + apr_brigade_insert_file(bb, f, 17, 1, p); + + /* can you tell what it is yet? */ + flatten_match(tc, "file seek test", bb, + "hello, brave world\n"); + + apr_file_close(f); + apr_brigade_destroy(bb); + apr_bucket_alloc_destroy(ba); +} + +/* Regression test for PR 34708, where a file bucket will keep + * duplicating itself on being read() when EOF is reached + * prematurely. */ +static void test_truncfile(abts_case *tc, void *data) +{ + apr_bucket_alloc_t *ba = apr_bucket_alloc_create(p); + apr_bucket_brigade *bb = apr_brigade_create(p, ba); + apr_file_t *f = make_test_file(tc, "testfile.txt", "hello"); + apr_bucket *e; + const char *buf; + apr_size_t len; + + apr_brigade_insert_file(bb, f, 0, 5, p); + + apr_file_trunc(f, 0); + + e = APR_BRIGADE_FIRST(bb); + + ABTS_ASSERT(tc, "single bucket in brigade", + APR_BUCKET_NEXT(e) == APR_BRIGADE_SENTINEL(bb)); + + apr_bucket_file_enable_mmap(e, 0); + + ABTS_ASSERT(tc, "read gave APR_EOF", + apr_bucket_read(e, &buf, &len, APR_BLOCK_READ) == APR_EOF); + + ABTS_ASSERT(tc, "read length 0", len == 0); + + ABTS_ASSERT(tc, "still a single bucket in brigade", + APR_BUCKET_NEXT(e) == APR_BRIGADE_SENTINEL(bb)); + + apr_file_close(f); + apr_brigade_destroy(bb); + apr_bucket_alloc_destroy(ba); +} + +static const char hello[] = "hello, world"; + +static void test_partition(abts_case *tc, void *data) +{ + apr_bucket_alloc_t *ba = apr_bucket_alloc_create(p); + apr_bucket_brigade *bb = apr_brigade_create(p, ba); + apr_bucket *e; + + e = apr_bucket_immortal_create(hello, strlen(hello), ba); + APR_BRIGADE_INSERT_HEAD(bb, e); + + APR_ASSERT_SUCCESS(tc, "partition brigade", + apr_brigade_partition(bb, 5, &e)); + + test_bucket_content(tc, APR_BRIGADE_FIRST(bb), + "hello", 5); + + test_bucket_content(tc, APR_BRIGADE_LAST(bb), + ", world", 7); + + ABTS_ASSERT(tc, "partition returns APR_INCOMPLETE", + apr_brigade_partition(bb, 8192, &e)); + + ABTS_ASSERT(tc, "APR_INCOMPLETE partition returned sentinel", + e == APR_BRIGADE_SENTINEL(bb)); + + apr_brigade_destroy(bb); + apr_bucket_alloc_destroy(ba); +} + +static void test_write_split(abts_case *tc, void *data) +{ + apr_bucket_alloc_t *ba = apr_bucket_alloc_create(p); + apr_bucket_brigade *bb1 = apr_brigade_create(p, ba); + apr_bucket_brigade *bb2; + apr_bucket *e; + + e = apr_bucket_heap_create(hello, strlen(hello), NULL, ba); + APR_BRIGADE_INSERT_HEAD(bb1, e); + apr_bucket_split(e, strlen("hello, ")); + bb2 = apr_brigade_split(bb1, APR_BRIGADE_LAST(bb1)); + apr_brigade_write(bb1, NULL, NULL, "foo", strlen("foo")); + test_bucket_content(tc, APR_BRIGADE_FIRST(bb2), "world", 5); + + apr_brigade_destroy(bb1); + apr_brigade_destroy(bb2); + apr_bucket_alloc_destroy(ba); +} + +static void test_write_putstrs(abts_case *tc, void *data) +{ + apr_bucket_alloc_t *ba = apr_bucket_alloc_create(p); + apr_bucket_brigade *bb = apr_brigade_create(p, ba); + apr_bucket *e; + char buf[30]; + apr_size_t len = sizeof(buf); + const char *expect = "123456789abcdefghij"; + + e = apr_bucket_heap_create("1", 1, NULL, ba); + APR_BRIGADE_INSERT_HEAD(bb, e); + + apr_brigade_putstrs(bb, NULL, NULL, "2", "34", "567", "8", "9a", "bcd", + "e", "f", "gh", "i", NULL); + apr_brigade_putstrs(bb, NULL, NULL, "j", NULL); + APR_ASSERT_SUCCESS(tc, "apr_brigade_flatten", + apr_brigade_flatten(bb, buf, &len)); + ABTS_STR_NEQUAL(tc, expect, buf, strlen(expect)); + + apr_brigade_destroy(bb); + apr_bucket_alloc_destroy(ba); +} + +abts_suite *testbuckets(abts_suite *suite) +{ + suite = ADD_SUITE(suite); + + abts_run_test(suite, test_create, NULL); + abts_run_test(suite, test_simple, NULL); + abts_run_test(suite, test_flatten, NULL); + abts_run_test(suite, test_split, NULL); + abts_run_test(suite, test_bwrite, NULL); + abts_run_test(suite, test_splitline, NULL); + abts_run_test(suite, test_splits, NULL); + abts_run_test(suite, test_insertfile, NULL); + abts_run_test(suite, test_manyfile, NULL); + abts_run_test(suite, test_truncfile, NULL); + abts_run_test(suite, test_partition, NULL); + abts_run_test(suite, test_write_split, NULL); + abts_run_test(suite, test_write_putstrs, NULL); + + return suite; +} + + diff --git a/test/testcond.c b/test/testcond.c new file mode 100644 index 00000000000..b5a20bc46dc --- /dev/null +++ b/test/testcond.c @@ -0,0 +1,670 @@ +/* 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_file_io.h" +#include "apr_thread_proc.h" +#include "apr_thread_mutex.h" +#include "apr_thread_cond.h" +#include "apr_errno.h" +#include "apr_general.h" +#include "apr_atomic.h" +#include "testutil.h" + +#define NTHREADS 10 + +#define ABTS_SUCCESS(rv) ABTS_INT_EQUAL(tc, APR_SUCCESS, rv) + +#if APR_HAS_THREADS + +typedef struct toolbox_t toolbox_t; + +struct toolbox_t { + void *data; + abts_case *tc; + apr_thread_mutex_t *mutex; + apr_thread_cond_t *cond; + void (*func)(toolbox_t *box); +}; + +typedef struct toolbox_fnptr_t toolbox_fnptr_t; + +struct toolbox_fnptr_t { + void (*func)(toolbox_t *box); +}; + +static void lost_signal(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_thread_cond_t *cond = NULL; + apr_thread_mutex_t *mutex = NULL; + + rv = apr_thread_mutex_create(&mutex, APR_THREAD_MUTEX_DEFAULT, p); + ABTS_SUCCESS(rv); + ABTS_PTR_NOTNULL(tc, mutex); + + rv = apr_thread_cond_create(&cond, p); + ABTS_SUCCESS(rv); + ABTS_PTR_NOTNULL(tc, cond); + + rv = apr_thread_cond_signal(cond); + ABTS_SUCCESS(rv); + + rv = apr_thread_mutex_lock(mutex); + ABTS_SUCCESS(rv); + + rv = apr_thread_cond_timedwait(cond, mutex, 10000); + ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_TIMEUP(rv)); + + rv = apr_thread_mutex_unlock(mutex); + ABTS_SUCCESS(rv); + + rv = apr_thread_cond_broadcast(cond); + ABTS_SUCCESS(rv); + + rv = apr_thread_mutex_lock(mutex); + ABTS_SUCCESS(rv); + + rv = apr_thread_cond_timedwait(cond, mutex, 10000); + ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_TIMEUP(rv)); + + rv = apr_thread_mutex_unlock(mutex); + ABTS_SUCCESS(rv); + + rv = apr_thread_cond_destroy(cond); + ABTS_SUCCESS(rv); + + rv = apr_thread_mutex_destroy(mutex); + ABTS_SUCCESS(rv); +} + +static void *APR_THREAD_FUNC thread_routine(apr_thread_t *thd, void *data) +{ + toolbox_t *box = data; + + box->func(box); + + apr_thread_exit(thd, 0); + + return NULL; +} + +static void lock_and_signal(toolbox_t *box) +{ + apr_status_t rv; + abts_case *tc = box->tc; + + rv = apr_thread_mutex_lock(box->mutex); + ABTS_SUCCESS(rv); + + rv = apr_thread_cond_signal(box->cond); + ABTS_SUCCESS(rv); + + rv = apr_thread_mutex_unlock(box->mutex); + ABTS_SUCCESS(rv); +} + +static void dynamic_binding(abts_case *tc, void *data) +{ + unsigned int i; + apr_status_t rv; + toolbox_t box[NTHREADS]; + apr_thread_t *thread[NTHREADS]; + apr_thread_mutex_t *mutex[NTHREADS]; + apr_thread_cond_t *cond = NULL; + + rv = apr_thread_cond_create(&cond, p); + ABTS_SUCCESS(rv); + ABTS_PTR_NOTNULL(tc, cond); + + for (i = 0; i < NTHREADS; i++) { + rv = apr_thread_mutex_create(&mutex[i], APR_THREAD_MUTEX_DEFAULT, p); + ABTS_SUCCESS(rv); + + rv = apr_thread_mutex_lock(mutex[i]); + ABTS_SUCCESS(rv); + + box[i].tc = tc; + box[i].cond = cond; + box[i].mutex = mutex[i]; + box[i].func = lock_and_signal; + + rv = apr_thread_create(&thread[i], NULL, thread_routine, &box[i], p); + ABTS_SUCCESS(rv); + } + + /* + * The dynamic binding should be preserved because we use only one waiter + */ + + for (i = 0; i < NTHREADS; i++) { + rv = apr_thread_cond_wait(cond, mutex[i]); + ABTS_SUCCESS(rv); + } + + for (i = 0; i < NTHREADS; i++) { + rv = apr_thread_cond_timedwait(cond, mutex[i], 10000); + ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_TIMEUP(rv)); + + rv = apr_thread_mutex_unlock(mutex[i]); + ABTS_SUCCESS(rv); + } + + for (i = 0; i < NTHREADS; i++) { + apr_status_t retval; + rv = apr_thread_join(&retval, thread[i]); + ABTS_SUCCESS(rv); + } + + rv = apr_thread_cond_destroy(cond); + ABTS_SUCCESS(rv); + + for (i = 0; i < NTHREADS; i++) { + rv = apr_thread_mutex_destroy(mutex[i]); + ABTS_SUCCESS(rv); + } +} + +static void lock_and_wait(toolbox_t *box) +{ + apr_status_t rv; + abts_case *tc = box->tc; + apr_uint32_t *count = box->data; + + rv = apr_thread_mutex_lock(box->mutex); + ABTS_SUCCESS(rv); + + apr_atomic_inc32(count); + + rv = apr_thread_cond_wait(box->cond, box->mutex); + ABTS_SUCCESS(rv); + + apr_atomic_dec32(count); + + rv = apr_thread_mutex_unlock(box->mutex); + ABTS_SUCCESS(rv); +} + +static void broadcast_threads(abts_case *tc, void *data) +{ + toolbox_t box; + unsigned int i; + apr_status_t rv; + apr_uint32_t count = 0; + apr_thread_cond_t *cond = NULL; + apr_thread_mutex_t *mutex = NULL; + apr_thread_t *thread[NTHREADS]; + + rv = apr_thread_cond_create(&cond, p); + ABTS_SUCCESS(rv); + ABTS_PTR_NOTNULL(tc, cond); + + rv = apr_thread_mutex_create(&mutex, APR_THREAD_MUTEX_DEFAULT, p); + ABTS_SUCCESS(rv); + ABTS_PTR_NOTNULL(tc, mutex); + + rv = apr_thread_mutex_lock(mutex); + ABTS_SUCCESS(rv); + + box.tc = tc; + box.data = &count; + box.mutex = mutex; + box.cond = cond; + box.func = lock_and_wait; + + for (i = 0; i < NTHREADS; i++) { + rv = apr_thread_create(&thread[i], NULL, thread_routine, &box, p); + ABTS_SUCCESS(rv); + } + + do { + rv = apr_thread_mutex_unlock(mutex); + ABTS_SUCCESS(rv); + apr_sleep(100000); + rv = apr_thread_mutex_lock(mutex); + ABTS_SUCCESS(rv); + } while (apr_atomic_read32(&count) != NTHREADS); + + rv = apr_thread_cond_broadcast(cond); + ABTS_SUCCESS(rv); + + rv = apr_thread_mutex_unlock(mutex); + ABTS_SUCCESS(rv); + + for (i = 0; i < NTHREADS; i++) { + apr_status_t retval; + rv = apr_thread_join(&retval, thread[i]); + ABTS_SUCCESS(rv); + } + + ABTS_INT_EQUAL(tc, 0, count); + + rv = apr_thread_cond_destroy(cond); + ABTS_SUCCESS(rv); + + rv = apr_thread_mutex_destroy(mutex); + ABTS_SUCCESS(rv); +} + +static void nested_lock_and_wait(toolbox_t *box) +{ + apr_status_t rv; + abts_case *tc = box->tc; + + rv = apr_thread_mutex_lock(box->mutex); + ABTS_SUCCESS(rv); + + rv = apr_thread_mutex_lock(box->mutex); + ABTS_SUCCESS(rv); + + rv = apr_thread_mutex_lock(box->mutex); + ABTS_SUCCESS(rv); + + rv = apr_thread_cond_wait(box->cond, box->mutex); + ABTS_SUCCESS(rv); +} + +static void nested_lock_and_unlock(toolbox_t *box) +{ + apr_status_t rv; + abts_case *tc = box->tc; + + rv = apr_thread_mutex_lock(box->mutex); + ABTS_SUCCESS(rv); + + rv = apr_thread_mutex_lock(box->mutex); + ABTS_SUCCESS(rv); + + rv = apr_thread_mutex_lock(box->mutex); + ABTS_SUCCESS(rv); + + rv = apr_thread_cond_timedwait(box->cond, box->mutex, 2000000); + ABTS_SUCCESS(rv); + + rv = apr_thread_mutex_unlock(box->mutex); + ABTS_SUCCESS(rv); + + rv = apr_thread_mutex_unlock(box->mutex); + ABTS_SUCCESS(rv); +} + +static void nested_wait(abts_case *tc, void *data) +{ + toolbox_fnptr_t *fnptr = data; + toolbox_t box; + apr_status_t rv, retval; + apr_thread_cond_t *cond = NULL; + apr_thread_t *thread = NULL; + apr_thread_mutex_t *mutex = NULL; + + rv = apr_thread_mutex_create(&mutex, APR_THREAD_MUTEX_NESTED, p); + ABTS_SUCCESS(rv); + ABTS_PTR_NOTNULL(tc, mutex); + + rv = apr_thread_cond_create(&cond, p); + ABTS_SUCCESS(rv); + ABTS_PTR_NOTNULL(tc, cond); + + rv = apr_thread_mutex_lock(mutex); + ABTS_SUCCESS(rv); + + box.tc = tc; + box.cond = cond; + box.mutex = mutex; + box.func = fnptr->func; + + rv = apr_thread_create(&thread, NULL, thread_routine, &box, p); + ABTS_SUCCESS(rv); + + rv = apr_thread_mutex_unlock(mutex); + ABTS_SUCCESS(rv); + + /* yield the processor */ + apr_sleep(500000); + + rv = apr_thread_cond_signal(cond); + ABTS_SUCCESS(rv); + + rv = apr_thread_join(&retval, thread); + ABTS_SUCCESS(rv); + + rv = apr_thread_mutex_trylock(mutex); + ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_EBUSY(rv)); + + rv = apr_thread_mutex_trylock(mutex); + ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_EBUSY(rv)); +} + +static volatile apr_uint64_t pipe_count; +static volatile apr_uint32_t exiting; + +static void pipe_consumer(toolbox_t *box) +{ + char ch; + apr_status_t rv; + apr_size_t nbytes; + abts_case *tc = box->tc; + apr_file_t *out = box->data; + apr_uint32_t consumed = 0; + + do { + rv = apr_thread_mutex_lock(box->mutex); + ABTS_SUCCESS(rv); + + while (!pipe_count && !exiting) { + rv = apr_thread_cond_wait(box->cond, box->mutex); + ABTS_SUCCESS(rv); + } + + if (!pipe_count && exiting) { + rv = apr_thread_mutex_unlock(box->mutex); + ABTS_SUCCESS(rv); + break; + } + + pipe_count--; + consumed++; + + rv = apr_thread_mutex_unlock(box->mutex); + ABTS_SUCCESS(rv); + + rv = apr_file_read_full(out, &ch, 1, &nbytes); + ABTS_SUCCESS(rv); + ABTS_SIZE_EQUAL(tc, 1, nbytes); + ABTS_TRUE(tc, ch == '.'); + } while (1); + + /* naive fairness test - it would be good to introduce or solidify + * a solid test to ensure one thread is not starved. + * ABTS_INT_EQUAL(tc, 1, !!consumed); + */ +} + +static void pipe_write(toolbox_t *box, char ch) +{ + apr_status_t rv; + apr_size_t nbytes; + abts_case *tc = box->tc; + apr_file_t *in = box->data; + + rv = apr_file_write_full(in, &ch, 1, &nbytes); + ABTS_SUCCESS(rv); + ABTS_SIZE_EQUAL(tc, 1, nbytes); + + rv = apr_thread_mutex_lock(box->mutex); + ABTS_SUCCESS(rv); + + if (!pipe_count) { + rv = apr_thread_cond_signal(box->cond); + ABTS_SUCCESS(rv); + } + + pipe_count++; + + rv = apr_thread_mutex_unlock(box->mutex); + ABTS_SUCCESS(rv); +} + +static void pipe_producer(toolbox_t *box) +{ + apr_uint32_t loop = 500; + + do { + pipe_write(box, '.'); + } while (loop--); +} + +static void pipe_producer_consumer(abts_case *tc, void *data) +{ + apr_status_t rv; + toolbox_t boxcons, boxprod; + apr_thread_t *thread[NTHREADS]; + apr_thread_cond_t *cond = NULL; + apr_thread_mutex_t *mutex = NULL; + apr_file_t *in = NULL, *out = NULL; + apr_uint32_t i, ncons = (apr_uint32_t)(NTHREADS * 0.70); + + rv = apr_file_pipe_create(&in, &out, p); + ABTS_SUCCESS(rv); + + rv = apr_thread_mutex_create(&mutex, APR_THREAD_MUTEX_DEFAULT, p); + ABTS_SUCCESS(rv); + ABTS_PTR_NOTNULL(tc, mutex); + + rv = apr_thread_cond_create(&cond, p); + ABTS_SUCCESS(rv); + ABTS_PTR_NOTNULL(tc, cond); + + boxcons.tc = tc; + boxcons.data = in; + boxcons.mutex = mutex; + boxcons.cond = cond; + boxcons.func = pipe_consumer; + + for (i = 0; i < ncons; i++) { + rv = apr_thread_create(&thread[i], NULL, thread_routine, &boxcons, p); + ABTS_SUCCESS(rv); + } + + boxprod.tc = tc; + boxprod.data = out; + boxprod.mutex = mutex; + boxprod.cond = cond; + boxprod.func = pipe_producer; + + for (; i < NTHREADS; i++) { + rv = apr_thread_create(&thread[i], NULL, thread_routine, &boxprod, p); + ABTS_SUCCESS(rv); + } + + for (i = ncons; i < NTHREADS; i++) { + apr_status_t retval; + rv = apr_thread_join(&retval, thread[i]); + ABTS_SUCCESS(rv); + } + + rv = apr_thread_mutex_lock(mutex); + ABTS_SUCCESS(rv); + + exiting = 1; + + rv = apr_thread_cond_broadcast(cond); + ABTS_SUCCESS(rv); + + rv = apr_thread_mutex_unlock(mutex); + ABTS_SUCCESS(rv); + + for (i = 0; i < ncons; i++) { + apr_status_t retval; + rv = apr_thread_join(&retval, thread[i]); + ABTS_SUCCESS(rv); + } + + rv = apr_thread_cond_destroy(cond); + ABTS_SUCCESS(rv); + + rv = apr_thread_mutex_destroy(mutex); + ABTS_SUCCESS(rv); + + rv = apr_file_close(in); + ABTS_SUCCESS(rv); + + rv = apr_file_close(out); + ABTS_SUCCESS(rv); +} + +volatile enum { + TOSS, + PING, + PONG, + OVER +} state; + +static void ping(toolbox_t *box) +{ + apr_status_t rv; + abts_case *tc = box->tc; + + rv = apr_thread_mutex_lock(box->mutex); + ABTS_SUCCESS(rv); + + if (state == TOSS) + state = PING; + + do { + rv = apr_thread_cond_signal(box->cond); + ABTS_SUCCESS(rv); + + state = PONG; + + rv = apr_thread_cond_wait(box->cond, box->mutex); + ABTS_SUCCESS(rv); + + ABTS_TRUE(tc, state == PING || state == OVER); + } while (state != OVER); + + rv = apr_thread_mutex_unlock(box->mutex); + ABTS_SUCCESS(rv); + + rv = apr_thread_cond_broadcast(box->cond); + ABTS_SUCCESS(rv); +} + +static void pong(toolbox_t *box) +{ + apr_status_t rv; + abts_case *tc = box->tc; + + rv = apr_thread_mutex_lock(box->mutex); + ABTS_SUCCESS(rv); + + if (state == TOSS) + state = PONG; + + do { + rv = apr_thread_cond_signal(box->cond); + ABTS_SUCCESS(rv); + + state = PING; + + rv = apr_thread_cond_wait(box->cond, box->mutex); + ABTS_SUCCESS(rv); + + ABTS_TRUE(tc, state == PONG || state == OVER); + } while (state != OVER); + + rv = apr_thread_mutex_unlock(box->mutex); + ABTS_SUCCESS(rv); + + rv = apr_thread_cond_broadcast(box->cond); + ABTS_SUCCESS(rv); +} + +static void ping_pong(abts_case *tc, void *data) +{ + apr_status_t rv, retval; + toolbox_t box_ping, box_pong; + apr_thread_cond_t *cond = NULL; + apr_thread_mutex_t *mutex = NULL; + apr_thread_t *thr_ping = NULL, *thr_pong = NULL; + + rv = apr_thread_mutex_create(&mutex, APR_THREAD_MUTEX_DEFAULT, p); + ABTS_SUCCESS(rv); + ABTS_PTR_NOTNULL(tc, mutex); + + rv = apr_thread_cond_create(&cond, p); + ABTS_SUCCESS(rv); + ABTS_PTR_NOTNULL(tc, cond); + + rv = apr_thread_mutex_lock(mutex); + ABTS_SUCCESS(rv); + + box_ping.tc = tc; + box_ping.data = NULL; + box_ping.mutex = mutex; + box_ping.cond = cond; + box_ping.func = ping; + + rv = apr_thread_create(&thr_ping, NULL, thread_routine, &box_ping, p); + ABTS_SUCCESS(rv); + + box_pong.tc = tc; + box_pong.data = NULL; + box_pong.mutex = mutex; + box_pong.cond = cond; + box_pong.func = pong; + + rv = apr_thread_create(&thr_pong, NULL, thread_routine, &box_pong, p); + ABTS_SUCCESS(rv); + + state = TOSS; + + rv = apr_thread_mutex_unlock(mutex); + ABTS_SUCCESS(rv); + + apr_sleep(3000000); + + rv = apr_thread_mutex_lock(mutex); + ABTS_SUCCESS(rv); + + state = OVER; + + rv = apr_thread_mutex_unlock(mutex); + ABTS_SUCCESS(rv); + + rv = apr_thread_join(&retval, thr_ping); + ABTS_SUCCESS(rv); + + rv = apr_thread_join(&retval, thr_pong); + ABTS_SUCCESS(rv); + + rv = apr_thread_cond_destroy(cond); + ABTS_SUCCESS(rv); + + rv = apr_thread_mutex_destroy(mutex); + ABTS_SUCCESS(rv); +} +#endif /* !APR_HAS_THREADS */ + +#if !APR_HAS_THREADS +static void threads_not_impl(abts_case *tc, void *data) +{ + ABTS_NOT_IMPL(tc, "Threads not implemented on this platform"); +} +#endif + +abts_suite *testcond(abts_suite *suite) +{ +#if APR_HAS_THREADS + toolbox_fnptr_t fnptr; +#endif + suite = ADD_SUITE(suite) + +#if !APR_HAS_THREADS + abts_run_test(suite, threads_not_impl, NULL); +#else + abts_run_test(suite, lost_signal, NULL); + abts_run_test(suite, dynamic_binding, NULL); + abts_run_test(suite, broadcast_threads, NULL); + fnptr.func = nested_lock_and_wait; + abts_run_test(suite, nested_wait, &fnptr); + fnptr.func = nested_lock_and_unlock; + abts_run_test(suite, nested_wait, &fnptr); + abts_run_test(suite, pipe_producer_consumer, NULL); + abts_run_test(suite, ping_pong, NULL); +#endif + + return suite; +} diff --git a/test/testcontext.c b/test/testcontext.c deleted file mode 100644 index 0c91d508002..00000000000 --- a/test/testcontext.c +++ /dev/null @@ -1,101 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#include <stdio.h> -#include <stdlib.h> -#include "apr_file_io.h" -#include "apr_errno.h" -#include "apr_general.h" -#include "apr_lib.h" -#ifdef BEOS -#include <unistd.h> -#endif - -ap_status_t string_cleanup(void *data) -{ - return APR_SUCCESS; -} - -int main() -{ - ap_pool_t *context; - char *testdata; - char *retdata; - - if (ap_initialize() != APR_SUCCESS) { - fprintf(stderr, "Couldn't initialize."); - exit(-1); - } - atexit(ap_terminate); - - if (ap_create_pool(&context, NULL) != APR_SUCCESS) { - fprintf(stderr, "Couldn't allocate context."); - exit(-1); - } - - testdata = ap_pstrdup(context, "This is a test\n"); - - ap_set_userdata(testdata, "TEST", string_cleanup, context); - - ap_get_userdata((void **)&retdata, "TEST", context); - - if (!strcmp(testdata, retdata)) { - fprintf(stdout, "User data is working ok\n"); - } - else { - fprintf(stdout, "User data is not working\n"); - } - - return 1; -} diff --git a/test/testcrypto.c b/test/testcrypto.c new file mode 100644 index 00000000000..865cffc6d5e --- /dev/null +++ b/test/testcrypto.c @@ -0,0 +1,1545 @@ +/* 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 "testutil.h" +#include "apr.h" +#include "apu.h" +#include "apu_errno.h" +#include "apr_pools.h" +#include "apr_dso.h" +#include "apr_crypto.h" +#include "apr_strings.h" + +#if APU_HAVE_CRYPTO + +#define TEST_STRING "12345" +#define ALIGNED_STRING "123456789012345" + +static const apr_crypto_driver_t *get_driver(abts_case *tc, apr_pool_t *pool, + const char *name, const char *params) +{ + + const apr_crypto_driver_t *driver = NULL; + const apu_err_t *result = NULL; + apr_status_t rv; + + rv = apr_crypto_init(pool); + ABTS_ASSERT(tc, "failed to init apr_crypto", rv == APR_SUCCESS); + + rv = apr_crypto_get_driver(&driver, name, params, &result, pool); + if (APR_ENOTIMPL == rv) { + ABTS_NOT_IMPL(tc, + apr_psprintf(pool, "Crypto driver '%s' not implemented", (char *)name)); + return NULL; + } + if (APR_EDSOOPEN == rv) { + ABTS_NOT_IMPL(tc, + apr_psprintf(pool, "Crypto driver '%s' DSO could not be opened", (char *)name)); + return NULL; + } + if (APR_SUCCESS != rv && result) { + char err[1024]; + apr_strerror(rv, err, sizeof(err) - 1); + fprintf(stderr, "get_driver error %d: %s: '%s' native error %d: %s (%s),", + rv, err, name, result->rc, result->reason ? result->reason : "", + result->msg ? result->msg : ""); + } + ABTS_ASSERT(tc, apr_psprintf(pool, "failed to apr_crypto_get_driver for '%s' with %d", + name, rv), rv == APR_SUCCESS); + ABTS_ASSERT(tc, "apr_crypto_get_driver returned NULL", driver != NULL); + if (!driver || rv) { + return NULL; + } + + return driver; + +} + +static const apr_crypto_driver_t *get_nss_driver(abts_case *tc, + apr_pool_t *pool) +{ + + /* initialise NSS */ + return get_driver(tc, pool, "nss", ""); + +} + +static const apr_crypto_driver_t *get_openssl_driver(abts_case *tc, + apr_pool_t *pool) +{ + + return get_driver(tc, pool, "openssl", NULL); + +} + +static const apr_crypto_driver_t *get_commoncrypto_driver(abts_case *tc, + apr_pool_t *pool) +{ + + return get_driver(tc, pool, "commoncrypto", NULL); + +} + +static apr_crypto_t *make(abts_case *tc, apr_pool_t *pool, + const apr_crypto_driver_t *driver) +{ + + apr_crypto_t *f = NULL; + + if (!driver) { + return NULL; + } + + /* get the context */ + apr_crypto_make(&f, driver, "engine=openssl", pool); + ABTS_ASSERT(tc, "apr_crypto_make returned NULL", f != NULL); + + return f; + +} + +static const apr_crypto_key_t *keysecret(abts_case *tc, apr_pool_t *pool, + const apr_crypto_driver_t *driver, const apr_crypto_t *f, + apr_crypto_block_key_type_e type, apr_crypto_block_key_mode_e mode, + int doPad, apr_size_t secretLen, const char *description) +{ + apr_crypto_key_t *key = NULL; + const apu_err_t *result = NULL; + apr_crypto_key_rec_t *rec = apr_pcalloc(pool, sizeof(apr_crypto_key_rec_t)); + apr_status_t rv; + + if (!f) { + return NULL; + } + + rec->ktype = APR_CRYPTO_KTYPE_SECRET; + rec->type = type; + rec->mode = mode; + rec->pad = doPad; + rec->k.secret.secret = apr_pcalloc(pool, secretLen); + rec->k.secret.secretLen = secretLen; + + /* init the passphrase */ + rv = apr_crypto_key(&key, rec, f, pool); + if (APR_ENOCIPHER == rv) { + apr_crypto_error(&result, f); + ABTS_NOT_IMPL(tc, + apr_psprintf(pool, "skipped: %s %s key return APR_ENOCIPHER: error %d: %s (%s)\n", description, apr_crypto_driver_name(driver), result->rc, result->reason ? result->reason : "", result->msg ? result->msg : "")); + return NULL; + } + else { + if (APR_SUCCESS != rv) { + apr_crypto_error(&result, f); + fprintf(stderr, "key: %s %s apr error %d / native error %d: %s (%s)\n", + description, apr_crypto_driver_name(driver), rv, result->rc, + result->reason ? result->reason : "", + result->msg ? result->msg : ""); + } + ABTS_ASSERT(tc, "apr_crypto_key returned APR_EKEYLENGTH", rv != APR_EKEYLENGTH); + ABTS_ASSERT(tc, "apr_crypto_key returned APR_ENOKEY", rv != APR_ENOKEY); + ABTS_ASSERT(tc, "apr_crypto_key returned APR_EPADDING", + rv != APR_EPADDING); + ABTS_ASSERT(tc, "apr_crypto_key returned APR_EKEYTYPE", + rv != APR_EKEYTYPE); + ABTS_ASSERT(tc, "failed to apr_crypto_key", rv == APR_SUCCESS); + ABTS_ASSERT(tc, "apr_crypto_key returned NULL context", key != NULL); + } + if (rv) { + return NULL; + } + return key; + +} + +static const apr_crypto_key_t *passphrase(abts_case *tc, apr_pool_t *pool, + const apr_crypto_driver_t *driver, const apr_crypto_t *f, + apr_crypto_block_key_type_e type, apr_crypto_block_key_mode_e mode, + int doPad, const char *description) +{ + + apr_crypto_key_t *key = NULL; + const apu_err_t *result = NULL; + const char *pass = "secret"; + const char *salt = "salt"; + apr_status_t rv; + + if (!f) { + return NULL; + } + + /* init the passphrase */ + rv = apr_crypto_passphrase(&key, NULL, pass, strlen(pass), + (unsigned char *) salt, strlen(salt), type, mode, doPad, 4096, f, + pool); + if (APR_ENOCIPHER == rv) { + apr_crypto_error(&result, f); + ABTS_NOT_IMPL(tc, apr_psprintf(pool, + "skipped: %s %s passphrase return APR_ENOCIPHER: error %d: %s (%s)\n", + description, apr_crypto_driver_name(driver), result->rc, + result->reason ? result->reason : "", result->msg ? result->msg : "")); + return NULL; + } + else { + if (APR_SUCCESS != rv) { + apr_crypto_error(&result, f); + fprintf(stderr, "passphrase: %s %s apr error %d / native error %d: %s (%s)\n", + description, apr_crypto_driver_name(driver), rv, result->rc, + result->reason ? result->reason : "", + result->msg ? result->msg : ""); + } + ABTS_ASSERT(tc, "apr_crypto_passphrase returned APR_ENOKEY", rv != APR_ENOKEY); + ABTS_ASSERT(tc, "apr_crypto_passphrase returned APR_EPADDING", rv != APR_EPADDING); + ABTS_ASSERT(tc, "apr_crypto_passphrase returned APR_EKEYTYPE", rv != APR_EKEYTYPE); + ABTS_ASSERT(tc, "failed to apr_crypto_passphrase", rv == APR_SUCCESS); + ABTS_ASSERT(tc, "apr_crypto_passphrase returned NULL context", key != NULL); + } + if (rv) { + return NULL; + } + return key; + +} + +static const apr_crypto_key_t *keypassphrase(abts_case *tc, apr_pool_t *pool, + const apr_crypto_driver_t *driver, const apr_crypto_t *f, + apr_crypto_block_key_type_e type, apr_crypto_block_key_mode_e mode, + int doPad, const char *description) +{ + + apr_crypto_key_t *key = NULL; + const apu_err_t *result = NULL; + const char *pass = "secret"; + const char *salt = "salt"; + apr_crypto_key_rec_t *rec = apr_pcalloc(pool, sizeof(apr_crypto_key_rec_t)); + apr_status_t rv; + + if (!f) { + return NULL; + } + + rec->ktype = APR_CRYPTO_KTYPE_PASSPHRASE; + rec->type = type; + rec->mode = mode; + rec->pad = doPad; + rec->k.passphrase.pass = pass; + rec->k.passphrase.passLen = strlen(pass); + rec->k.passphrase.salt = (unsigned char *)salt; + rec->k.passphrase.saltLen = strlen(salt); + rec->k.passphrase.iterations = 4096; + + /* init the passphrase */ + rv = apr_crypto_key(&key, rec, f, pool); + if (APR_ENOCIPHER == rv) { + apr_crypto_error(&result, f); + ABTS_NOT_IMPL(tc, apr_psprintf(pool, + "skipped: %s %s key passphrase return APR_ENOCIPHER: error %d: %s (%s)\n", + description, apr_crypto_driver_name(driver), result->rc, + result->reason ? result->reason : "", result->msg ? result->msg : "")); + return NULL; + } + else { + if (APR_SUCCESS != rv) { + apr_crypto_error(&result, f); + fprintf(stderr, "key passphrase: %s %s apr error %d / native error %d: %s (%s)\n", + description, apr_crypto_driver_name(driver), rv, result->rc, + result->reason ? result->reason : "", + result->msg ? result->msg : ""); + } + ABTS_ASSERT(tc, "apr_crypto_key returned APR_ENOKEY", rv != APR_ENOKEY); + ABTS_ASSERT(tc, "apr_crypto_key returned APR_EPADDING", rv != APR_EPADDING); + ABTS_ASSERT(tc, "apr_crypto_key returned APR_EKEYTYPE", rv != APR_EKEYTYPE); + ABTS_ASSERT(tc, "failed to apr_crypto_key", rv == APR_SUCCESS); + ABTS_ASSERT(tc, "apr_crypto_key returned NULL context", key != NULL); + } + if (rv) { + return NULL; + } + return key; + +} + +static unsigned char *encrypt_block(abts_case *tc, apr_pool_t *pool, + const apr_crypto_driver_t *driver, const apr_crypto_t *f, + const apr_crypto_key_t *key, const unsigned char *in, + const apr_size_t inlen, unsigned char **cipherText, + apr_size_t *cipherTextLen, const unsigned char **iv, + apr_size_t *blockSize, const char *description) +{ + + apr_crypto_block_t *block = NULL; + const apu_err_t *result = NULL; + apr_size_t len = 0; + apr_status_t rv; + + if (!driver || !f || !key || !in) { + return NULL; + } + + /* init the encryption */ + rv = apr_crypto_block_encrypt_init(&block, iv, key, blockSize, pool); + if (APR_ENOTIMPL == rv) { + ABTS_NOT_IMPL(tc, "apr_crypto_block_encrypt_init returned APR_ENOTIMPL"); + } + else { + if (APR_SUCCESS != rv) { + apr_crypto_error(&result, f); + fprintf(stderr, + "encrypt_init: %s %s (APR %d) native error %d: %s (%s)\n", + description, apr_crypto_driver_name(driver), rv, result->rc, + result->reason ? result->reason : "", + result->msg ? result->msg : ""); + } + ABTS_ASSERT(tc, "apr_crypto_block_encrypt_init returned APR_ENOKEY", + rv != APR_ENOKEY); + ABTS_ASSERT(tc, "apr_crypto_block_encrypt_init returned APR_ENOIV", + rv != APR_ENOIV); + ABTS_ASSERT(tc, "apr_crypto_block_encrypt_init returned APR_EKEYTYPE", + rv != APR_EKEYTYPE); + ABTS_ASSERT(tc, "apr_crypto_block_encrypt_init returned APR_EKEYLENGTH", + rv != APR_EKEYLENGTH); + ABTS_ASSERT(tc, + "apr_crypto_block_encrypt_init returned APR_ENOTENOUGHENTROPY", + rv != APR_ENOTENOUGHENTROPY); + ABTS_ASSERT(tc, "failed to apr_crypto_block_encrypt_init", + rv == APR_SUCCESS); + ABTS_ASSERT(tc, "apr_crypto_block_encrypt_init returned NULL context", + block != NULL); + } + if (!block || rv) { + return NULL; + } + + /* encrypt the block */ + rv = apr_crypto_block_encrypt(cipherText, cipherTextLen, in, inlen, block); + if (APR_SUCCESS != rv) { + apr_crypto_error(&result, f); + fprintf(stderr, "encrypt: %s %s (APR %d) native error %d: %s (%s)\n", + description, apr_crypto_driver_name(driver), rv, result->rc, + result->reason ? result->reason : "", + result->msg ? result->msg : ""); + } + ABTS_ASSERT(tc, "apr_crypto_block_encrypt returned APR_ECRYPT", rv != APR_ECRYPT); + ABTS_ASSERT(tc, "failed to apr_crypto_block_encrypt", rv == APR_SUCCESS); + ABTS_ASSERT(tc, "apr_crypto_block_encrypt failed to allocate buffer", *cipherText != NULL); + if (rv) { + return NULL; + } + + /* finalise the encryption */ + rv = apr_crypto_block_encrypt_finish(*cipherText + *cipherTextLen, &len, + block); + if (APR_SUCCESS != rv) { + apr_crypto_error(&result, f); + fprintf(stderr, + "encrypt_finish: %s %s (APR %d) native error %d: %s (%s)\n", + description, apr_crypto_driver_name(driver), rv, result->rc, + result->reason ? result->reason : "", + result->msg ? result->msg : ""); + } + ABTS_ASSERT(tc, "apr_crypto_block_encrypt_finish returned APR_ECRYPT", rv != APR_ECRYPT); + ABTS_ASSERT(tc, "apr_crypto_block_encrypt_finish returned APR_EPADDING", rv != APR_EPADDING); + ABTS_ASSERT(tc, "apr_crypto_block_encrypt_finish returned APR_ENOSPACE", rv != APR_ENOSPACE); + ABTS_ASSERT(tc, "failed to apr_crypto_block_encrypt_finish", rv == APR_SUCCESS); + *cipherTextLen += len; + apr_crypto_block_cleanup(block); + if (rv) { + return NULL; + } + + return *cipherText; + +} + +static unsigned char *decrypt_block(abts_case *tc, apr_pool_t *pool, + const apr_crypto_driver_t *driver, const apr_crypto_t *f, + const apr_crypto_key_t *key, unsigned char *cipherText, + apr_size_t cipherTextLen, unsigned char **plainText, + apr_size_t *plainTextLen, const unsigned char *iv, + apr_size_t *blockSize, const char *description) +{ + + apr_crypto_block_t *block = NULL; + const apu_err_t *result = NULL; + apr_size_t len = 0; + apr_status_t rv; + + if (!driver || !f || !key || !cipherText) { + return NULL; + } + + /* init the decryption */ + rv = apr_crypto_block_decrypt_init(&block, blockSize, iv, key, pool); + if (APR_ENOTIMPL == rv) { + ABTS_NOT_IMPL(tc, "apr_crypto_block_decrypt_init returned APR_ENOTIMPL"); + } + else { + if (APR_SUCCESS != rv) { + apr_crypto_error(&result, f); + fprintf(stderr, + "decrypt_init: %s %s (APR %d) native error %d: %s (%s)\n", + description, apr_crypto_driver_name(driver), rv, result->rc, + result->reason ? result->reason : "", + result->msg ? result->msg : ""); + } + ABTS_ASSERT(tc, "apr_crypto_block_decrypt_init returned APR_ENOKEY", rv != APR_ENOKEY); + ABTS_ASSERT(tc, "apr_crypto_block_decrypt_init returned APR_ENOIV", rv != APR_ENOIV); + ABTS_ASSERT(tc, "apr_crypto_block_decrypt_init returned APR_EKEYTYPE", rv != APR_EKEYTYPE); + ABTS_ASSERT(tc, "apr_crypto_block_decrypt_init returned APR_EKEYLENGTH", rv != APR_EKEYLENGTH); + ABTS_ASSERT(tc, "failed to apr_crypto_block_decrypt_init", rv == APR_SUCCESS); + ABTS_ASSERT(tc, "apr_crypto_block_decrypt_init returned NULL context", block != NULL); + } + if (!block || rv) { + return NULL; + } + + /* decrypt the block */ + rv = apr_crypto_block_decrypt(plainText, plainTextLen, cipherText, + cipherTextLen, block); + if (APR_SUCCESS != rv) { + apr_crypto_error(&result, f); + fprintf(stderr, "decrypt: %s %s (APR %d) native error %d: %s (%s)\n", + description, apr_crypto_driver_name(driver), rv, result->rc, + result->reason ? result->reason : "", + result->msg ? result->msg : ""); + } + ABTS_ASSERT(tc, "apr_crypto_block_decrypt returned APR_ECRYPT", rv != APR_ECRYPT); + ABTS_ASSERT(tc, "failed to apr_crypto_block_decrypt", rv == APR_SUCCESS); + ABTS_ASSERT(tc, "apr_crypto_block_decrypt failed to allocate buffer", *plainText != NULL); + if (rv) { + return NULL; + } + + /* finalise the decryption */ + rv = apr_crypto_block_decrypt_finish(*plainText + *plainTextLen, &len, + block); + if (APR_SUCCESS != rv) { + apr_crypto_error(&result, f); + fprintf(stderr, + "decrypt_finish: %s %s (APR %d) native error %d: %s (%s)\n", + description, apr_crypto_driver_name(driver), rv, result->rc, + result->reason ? result->reason : "", + result->msg ? result->msg : ""); + } + ABTS_ASSERT(tc, "apr_crypto_block_decrypt_finish returned APR_ECRYPT", rv != APR_ECRYPT); + ABTS_ASSERT(tc, "apr_crypto_block_decrypt_finish returned APR_EPADDING", rv != APR_EPADDING); + ABTS_ASSERT(tc, "apr_crypto_block_decrypt_finish returned APR_ENOSPACE", rv != APR_ENOSPACE); + ABTS_ASSERT(tc, "failed to apr_crypto_block_decrypt_finish", rv == APR_SUCCESS); + if (rv) { + return NULL; + } + + *plainTextLen += len; + apr_crypto_block_cleanup(block); + + return *plainText; + +} + +/** + * Interoperability test. + * + * data must point at an array of two driver structures. Data will be encrypted + * with the first driver, and decrypted with the second. + * + * If the two drivers interoperate, the test passes. + */ +static void crypto_block_cross(abts_case *tc, apr_pool_t *pool, + const apr_crypto_driver_t **drivers, + const apr_crypto_block_key_type_e type, + const apr_crypto_block_key_mode_e mode, int doPad, + const unsigned char *in, apr_size_t inlen, apr_size_t secretLen, + const char *description) +{ + const apr_crypto_driver_t *driver1 = drivers[0]; + const apr_crypto_driver_t *driver2 = drivers[1]; + apr_crypto_t *f1 = NULL; + apr_crypto_t *f2 = NULL; + const apr_crypto_key_t *key1 = NULL; + const apr_crypto_key_t *key2 = NULL; + const apr_crypto_key_t *key3 = NULL; + const apr_crypto_key_t *key4 = NULL; + const apr_crypto_key_t *key5 = NULL; + const apr_crypto_key_t *key6 = NULL; + + unsigned char *cipherText = NULL; + apr_size_t cipherTextLen = 0; + unsigned char *plainText = NULL; + apr_size_t plainTextLen = 0; + const unsigned char *iv = NULL; + apr_size_t blockSize = 0; + + f1 = make(tc, pool, driver1); + f2 = make(tc, pool, driver2); + key1 = passphrase(tc, pool, driver1, f1, type, mode, doPad, description); + key2 = passphrase(tc, pool, driver2, f2, type, mode, doPad, description); + + cipherText = encrypt_block(tc, pool, driver1, f1, key1, in, inlen, + &cipherText, &cipherTextLen, &iv, &blockSize, description); + plainText = decrypt_block(tc, pool, driver2, f2, key2, cipherText, + cipherTextLen, &plainText, &plainTextLen, iv, &blockSize, + description); + + if (cipherText && plainText) { + if (memcmp(in, plainText, inlen)) { + fprintf(stderr, "passphrase cross mismatch: %s %s/%s\n", description, + apr_crypto_driver_name(driver1), apr_crypto_driver_name( + driver2)); + } + ABTS_STR_EQUAL(tc, (char *)in, (char *)plainText); + } + + key3 = keysecret(tc, pool, driver1, f1, type, mode, doPad, secretLen, description); + key4 = keysecret(tc, pool, driver2, f2, type, mode, doPad, secretLen, description); + + iv = NULL; + blockSize = 0; + cipherText = NULL; + plainText = NULL; + cipherText = encrypt_block(tc, pool, driver1, f1, key3, in, inlen, + &cipherText, &cipherTextLen, &iv, &blockSize, description); + plainText = decrypt_block(tc, pool, driver2, f2, key4, cipherText, + cipherTextLen, &plainText, &plainTextLen, iv, &blockSize, + description); + + if (cipherText && plainText) { + if (memcmp(in, plainText, inlen)) { + fprintf(stderr, "key secret cross mismatch: %s %s/%s\n", description, + apr_crypto_driver_name(driver1), apr_crypto_driver_name( + driver2)); + } + ABTS_STR_EQUAL(tc, (char *)in, (char *)plainText); + } + + key5 = keypassphrase(tc, pool, driver1, f1, type, mode, doPad, description); + key6 = keypassphrase(tc, pool, driver2, f2, type, mode, doPad, description); + + iv = NULL; + blockSize = 0; + cipherText = NULL; + plainText = NULL; + cipherText = encrypt_block(tc, pool, driver1, f1, key5, in, inlen, + &cipherText, &cipherTextLen, &iv, &blockSize, description); + plainText = decrypt_block(tc, pool, driver2, f2, key6, cipherText, + cipherTextLen, &plainText, &plainTextLen, iv, &blockSize, + description); + + if (cipherText && plainText) { + if (memcmp(in, plainText, inlen)) { + fprintf(stderr, "key passphrase cross mismatch: %s %s/%s\n", description, + apr_crypto_driver_name(driver1), apr_crypto_driver_name( + driver2)); + } + ABTS_STR_EQUAL(tc, (char *)in, (char *)plainText); + } + +} + +/** + * Test initialisation. + */ +static void test_crypto_init(abts_case *tc, void *data) +{ + apr_pool_t *pool = NULL; + apr_status_t rv; + + apr_pool_create(&pool, NULL); + + rv = apr_crypto_init(pool); + ABTS_ASSERT(tc, "failed to init apr_crypto", rv == APR_SUCCESS); + + apr_pool_destroy(pool); + +} + +/** + * Simple test of OpenSSL key. + */ +static void test_crypto_key_openssl(abts_case *tc, void *data) +{ + apr_pool_t *pool = NULL; + const apr_crypto_driver_t *driver; + apr_crypto_t *f = NULL; + + apr_pool_create(&pool, NULL); + driver = get_openssl_driver(tc, pool); + + f = make(tc, pool, driver); + keysecret(tc, pool, driver, f, APR_KEY_AES_256, APR_MODE_CBC, 1, 32, + "KEY_AES_256/MODE_CBC"); + apr_pool_destroy(pool); + +} + +/** + * Simple test of NSS key. + */ +static void test_crypto_key_nss(abts_case *tc, void *data) +{ + apr_pool_t *pool = NULL; + const apr_crypto_driver_t *driver; + apr_crypto_t *f = NULL; + + apr_pool_create(&pool, NULL); + driver = get_nss_driver(tc, pool); + + f = make(tc, pool, driver); + keysecret(tc, pool, driver, f, APR_KEY_AES_256, APR_MODE_CBC, 1, 32, + "KEY_AES_256/MODE_CBC"); + apr_pool_destroy(pool); + +} + +/** + * Simple test of CommonCrypto key. + */ +static void test_crypto_key_commoncrypto(abts_case *tc, void *data) +{ + apr_pool_t *pool = NULL; + const apr_crypto_driver_t *driver; + apr_crypto_t *f = NULL; + + apr_pool_create(&pool, NULL); + driver = get_commoncrypto_driver(tc, pool); + + f = make(tc, pool, driver); + keysecret(tc, pool, driver, f, APR_KEY_AES_256, APR_MODE_CBC, 1, 32, + "KEY_AES_256/MODE_CBC"); + apr_pool_destroy(pool); + +} + +/** + * Simple test of OpenSSL block crypt. + */ +static void test_crypto_block_openssl(abts_case *tc, void *data) +{ + apr_pool_t *pool = NULL; + const apr_crypto_driver_t *drivers[] = { NULL, NULL }; + + const unsigned char *in = (const unsigned char *) ALIGNED_STRING; + apr_size_t inlen = sizeof(ALIGNED_STRING); + + apr_pool_create(&pool, NULL); + drivers[0] = get_openssl_driver(tc, pool); + drivers[1] = get_openssl_driver(tc, pool); + crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_CBC, 0, + in, inlen, 24, "KEY_3DES_192/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_ECB, 0, + in, inlen, 24, "KEY_3DES_192/MODE_ECB"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_CBC, 0, in, + inlen, 32, "KEY_AES_256/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_ECB, 0, in, + inlen, 32, "KEY_AES_256/MODE_ECB"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_CBC, 0, in, + inlen, 24, "KEY_AES_192/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_ECB, 0, in, + inlen, 24, "KEY_AES_192/MODE_ECB"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_CBC, 0, in, + inlen, 16, "KEY_AES_128/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_ECB, 0, in, + inlen, 16, "KEY_AES_128/MODE_ECB"); + apr_pool_destroy(pool); + +} + +/** + * Simple test of NSS block crypt. + */ +static void test_crypto_block_nss(abts_case *tc, void *data) +{ + apr_pool_t *pool = NULL; + const apr_crypto_driver_t *drivers[] = { NULL, NULL }; + + const unsigned char *in = (const unsigned char *) ALIGNED_STRING; + apr_size_t inlen = sizeof(ALIGNED_STRING); + + apr_pool_create(&pool, NULL); + drivers[0] = get_nss_driver(tc, pool); + drivers[1] = get_nss_driver(tc, pool); + crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_CBC, 0, + in, inlen, 24, "KEY_3DES_192/MODE_CBC"); + /* KEY_3DES_192 / MODE_ECB doesn't work on NSS */ + /* crypto_block_cross(tc, pool, drivers, KEY_3DES_192, MODE_ECB, 0, in, inlen, "KEY_3DES_192/MODE_ECB"); */ + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_CBC, 0, in, + inlen, 32, "KEY_AES_256/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_ECB, 0, in, + inlen, 32, "KEY_AES_256/MODE_ECB"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_CBC, 0, in, + inlen, 24, "KEY_AES_192/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_ECB, 0, in, + inlen, 24, "KEY_AES_192/MODE_ECB"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_CBC, 0, in, + inlen, 16, "KEY_AES_128/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_ECB, 0, in, + inlen, 16, "KEY_AES_128/MODE_ECB"); + apr_pool_destroy(pool); + +} + +/** + * Simple test of Common Crypto block crypt. + */ +static void test_crypto_block_commoncrypto(abts_case *tc, void *data) +{ + apr_pool_t *pool = NULL; + const apr_crypto_driver_t *drivers[] = { NULL, NULL }; + + const unsigned char *in = (const unsigned char *) ALIGNED_STRING; + apr_size_t inlen = sizeof(ALIGNED_STRING); + + apr_pool_create(&pool, NULL); + drivers[0] = get_commoncrypto_driver(tc, pool); + drivers[1] = get_commoncrypto_driver(tc, pool); + crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_CBC, 0, + in, inlen, 24, "KEY_3DES_192/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_ECB, 0, + in, inlen, 24, "KEY_3DES_192/MODE_ECB"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_CBC, 0, in, + inlen, 32, "KEY_AES_256/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_ECB, 0, in, + inlen, 32, "KEY_AES_256/MODE_ECB"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_CBC, 0, in, + inlen, 24, "KEY_AES_192/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_ECB, 0, in, + inlen, 24, "KEY_AES_192/MODE_ECB"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_CBC, 0, in, + inlen, 16, "KEY_AES_128/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_ECB, 0, in, + inlen, 16, "KEY_AES_128/MODE_ECB"); + apr_pool_destroy(pool); + +} + +/** + * Encrypt NSS, decrypt OpenSSL. + */ +static void test_crypto_block_nss_openssl(abts_case *tc, void *data) +{ + apr_pool_t *pool = NULL; + const apr_crypto_driver_t *drivers[] = { NULL, NULL }; + + const unsigned char *in = (const unsigned char *) ALIGNED_STRING; + apr_size_t inlen = sizeof(ALIGNED_STRING); + + apr_pool_create(&pool, NULL); + drivers[0] = get_nss_driver(tc, pool); + drivers[1] = get_openssl_driver(tc, pool); + + crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_CBC, 0, + in, inlen, 24, "KEY_3DES_192/MODE_CBC"); + + /* KEY_3DES_192 / MODE_ECB doesn't work on NSS */ + /* crypto_block_cross(tc, pool, drivers, KEY_3DES_192, MODE_ECB, 0, in, inlen, 24, "KEY_3DES_192/MODE_ECB"); */ + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_CBC, 0, in, + inlen, 32, "KEY_AES_256/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_ECB, 0, in, + inlen, 32, "KEY_AES_256/MODE_ECB"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_CBC, 0, in, + inlen, 24, "KEY_AES_192/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_ECB, 0, in, + inlen, 24, "KEY_AES_192/MODE_ECB"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_CBC, 0, in, + inlen, 16, "KEY_AES_128/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_ECB, 0, in, + inlen, 16, "KEY_AES_128/MODE_ECB"); + apr_pool_destroy(pool); + +} + +/** + * Encrypt OpenSSL, decrypt NSS. + */ +static void test_crypto_block_openssl_nss(abts_case *tc, void *data) +{ + apr_pool_t *pool = NULL; + const apr_crypto_driver_t *drivers[] = { NULL, NULL }; + + const unsigned char *in = (const unsigned char *) ALIGNED_STRING; + apr_size_t inlen = sizeof(ALIGNED_STRING); + + apr_pool_create(&pool, NULL); + drivers[0] = get_openssl_driver(tc, pool); + drivers[1] = get_nss_driver(tc, pool); + crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_CBC, 0, + in, inlen, 24, "KEY_3DES_192/MODE_CBC"); + + /* KEY_3DES_192 / MODE_ECB doesn't work on NSS */ + /* crypto_block_cross(tc, pool, drivers, KEY_3DES_192, MODE_ECB, 0, in, inlen, 24, "KEY_3DES_192/MODE_ECB"); */ + + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_CBC, 0, in, + inlen, 32, "KEY_AES_256/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_ECB, 0, in, + inlen, 32, "KEY_AES_256/MODE_ECB"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_CBC, 0, in, + inlen, 24, "KEY_AES_192/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_ECB, 0, in, + inlen, 24, "KEY_AES_192/MODE_ECB"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_CBC, 0, in, + inlen, 16, "KEY_AES_128/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_ECB, 0, in, + inlen, 16, "KEY_AES_128/MODE_ECB"); + apr_pool_destroy(pool); + +} + +/** + * Encrypt OpenSSL, decrypt CommonCrypto. + */ +static void test_crypto_block_openssl_commoncrypto(abts_case *tc, void *data) +{ + apr_pool_t *pool = NULL; + const apr_crypto_driver_t *drivers[] = + { NULL, NULL }; + + const unsigned char *in = (const unsigned char *) ALIGNED_STRING; + apr_size_t inlen = sizeof(ALIGNED_STRING); + + apr_pool_create(&pool, NULL); + drivers[0] = get_openssl_driver(tc, pool); + drivers[1] = get_commoncrypto_driver(tc, pool); + + crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_CBC, 0, in, + inlen, 24, "KEY_3DES_192/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_ECB, 0, in, + inlen, 24, "KEY_3DES_192/MODE_ECB"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_CBC, 0, in, + inlen, 32, "KEY_AES_256/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_ECB, 0, in, + inlen, 32, "KEY_AES_256/MODE_ECB"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_CBC, 0, in, + inlen, 24, "KEY_AES_192/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_ECB, 0, in, + inlen, 24, "KEY_AES_192/MODE_ECB"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_CBC, 0, in, + inlen, 16, "KEY_AES_128/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_ECB, 0, in, + inlen, 16, "KEY_AES_128/MODE_ECB"); + apr_pool_destroy(pool); + +} + +/** + * Encrypt OpenSSL, decrypt CommonCrypto. + */ +static void test_crypto_block_commoncrypto_openssl(abts_case *tc, void *data) +{ + apr_pool_t *pool = NULL; + const apr_crypto_driver_t *drivers[] = + { NULL, NULL }; + + const unsigned char *in = (const unsigned char *) ALIGNED_STRING; + apr_size_t inlen = sizeof(ALIGNED_STRING); + + apr_pool_create(&pool, NULL); + drivers[0] = get_commoncrypto_driver(tc, pool); + drivers[1] = get_openssl_driver(tc, pool); + + crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_CBC, 0, in, + inlen, 24, "KEY_3DES_192/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_ECB, 0, in, + inlen, 24, "KEY_3DES_192/MODE_ECB"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_CBC, 0, in, + inlen, 32, "KEY_AES_256/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_ECB, 0, in, + inlen, 32, "KEY_AES_256/MODE_ECB"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_CBC, 0, in, + inlen, 24, "KEY_AES_192/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_ECB, 0, in, + inlen, 24, "KEY_AES_192/MODE_ECB"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_CBC, 0, in, + inlen, 16, "KEY_AES_128/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_ECB, 0, in, + inlen, 16, "KEY_AES_128/MODE_ECB"); + apr_pool_destroy(pool); + +} + +/** + * Simple test of OpenSSL block crypt. + */ +static void test_crypto_block_openssl_pad(abts_case *tc, void *data) +{ + apr_pool_t *pool = NULL; + const apr_crypto_driver_t *drivers[] = { NULL, NULL }; + + const unsigned char *in = (const unsigned char *) TEST_STRING; + apr_size_t inlen = sizeof(TEST_STRING); + + apr_pool_create(&pool, NULL); + drivers[0] = get_openssl_driver(tc, pool); + drivers[1] = get_openssl_driver(tc, pool); + + crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_CBC, 1, + in, inlen, 24, "KEY_3DES_192/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_ECB, 1, + in, inlen, 24, "KEY_3DES_192/MODE_ECB"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_CBC, 1, in, + inlen, 32, "KEY_AES_256/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_ECB, 1, in, + inlen, 32, "KEY_AES_256/MODE_ECB"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_CBC, 1, in, + inlen, 24, "KEY_AES_192/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_ECB, 1, in, + inlen, 24, "KEY_AES_192/MODE_ECB"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_CBC, 1, in, + inlen, 16, "KEY_AES_128/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_ECB, 1, in, + inlen, 16, "KEY_AES_128/MODE_ECB"); + + apr_pool_destroy(pool); + +} + +/** + * Simple test of NSS block crypt. + */ +static void test_crypto_block_nss_pad(abts_case *tc, void *data) +{ + apr_pool_t *pool = NULL; + const apr_crypto_driver_t *drivers[] = + { NULL, NULL }; + + const unsigned char *in = (const unsigned char *) TEST_STRING; + apr_size_t inlen = sizeof(TEST_STRING); + + apr_pool_create(&pool, NULL); + drivers[0] = get_nss_driver(tc, pool); + drivers[1] = get_nss_driver(tc, pool); + + crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_CBC, 1, + in, inlen, 24, "KEY_3DES_192/MODE_CBC"); + /* KEY_3DES_192 / MODE_ECB doesn't work on NSS */ + /* crypto_block_cross(tc, pool, drivers, KEY_3DES_192, MODE_ECB, 1, in, inlen, 24, "KEY_3DES_192/MODE_ECB"); */ + + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_CBC, 1, in, + inlen, 32, "KEY_AES_256/MODE_CBC"); + + /* KEY_AES_256 / MODE_ECB doesn't support padding on NSS */ + /*crypto_block_cross(tc, pool, drivers, KEY_AES_256, MODE_ECB, 1, in, inlen, 32, "KEY_AES_256/MODE_ECB");*/ + + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_CBC, 1, in, + inlen, 24, "KEY_AES_192/MODE_CBC"); + + /* KEY_AES_256 / MODE_ECB doesn't support padding on NSS */ + /*crypto_block_cross(tc, pool, drivers, KEY_AES_192, MODE_ECB, 1, in, inlen, 24, "KEY_AES_192/MODE_ECB");*/ + + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_CBC, 1, in, + inlen, 16, "KEY_AES_128/MODE_CBC"); + + /* KEY_AES_256 / MODE_ECB doesn't support padding on NSS */ + /*crypto_block_cross(tc, pool, drivers, KEY_AES_128, MODE_ECB, 1, in, inlen, 16, "KEY_AES_128/MODE_ECB");*/ + + apr_pool_destroy(pool); + +} + +/** + * Simple test of Common Crypto block crypt. + */ +static void test_crypto_block_commoncrypto_pad(abts_case *tc, void *data) +{ + apr_pool_t *pool = NULL; + const apr_crypto_driver_t *drivers[] = { NULL, NULL }; + + const unsigned char *in = (const unsigned char *) TEST_STRING; + apr_size_t inlen = sizeof(TEST_STRING); + + apr_pool_create(&pool, NULL); + drivers[0] = get_commoncrypto_driver(tc, pool); + drivers[1] = get_commoncrypto_driver(tc, pool); + + crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_CBC, 1, + in, inlen, 24, "KEY_3DES_192/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_ECB, 1, + in, inlen, 24, "KEY_3DES_192/MODE_ECB"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_CBC, 1, in, + inlen, 32, "KEY_AES_256/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_ECB, 1, in, + inlen, 32, "KEY_AES_256/MODE_ECB"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_CBC, 1, in, + inlen, 24, "KEY_AES_192/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_ECB, 1, in, + inlen, 24, "KEY_AES_192/MODE_ECB"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_CBC, 1, in, + inlen, 16, "KEY_AES_128/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_ECB, 1, in, + inlen, 16, "KEY_AES_128/MODE_ECB"); + + apr_pool_destroy(pool); + +} + +/** + * Encrypt NSS, decrypt OpenSSL. + */ +static void test_crypto_block_nss_openssl_pad(abts_case *tc, void *data) +{ + apr_pool_t *pool = NULL; + const apr_crypto_driver_t *drivers[] = { NULL, NULL }; + + const unsigned char *in = (const unsigned char *) TEST_STRING; + apr_size_t inlen = sizeof(TEST_STRING); + + apr_pool_create(&pool, NULL); + drivers[0] = get_nss_driver(tc, pool); + drivers[1] = get_openssl_driver(tc, pool); + + crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_CBC, 1, + in, inlen, 24, "KEY_3DES_192/MODE_CBC"); + + /* KEY_3DES_192 / MODE_ECB doesn't work on NSS */ + /* crypto_block_cross(tc, pool, drivers, KEY_3DES_192, MODE_ECB, 1, in, inlen, 24, "KEY_3DES_192/MODE_ECB"); */ + + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_CBC, 1, in, + inlen, 32, "KEY_AES_256/MODE_CBC"); + + /* KEY_AES_256 / MODE_ECB doesn't support padding on NSS */ + /*crypto_block_cross(tc, pool, drivers, KEY_AES_256, MODE_ECB, 1, in, inlen, 32, "KEY_AES_256/MODE_ECB");*/ + + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_CBC, 1, in, + inlen, 24, "KEY_AES_192/MODE_CBC"); + + /* KEY_AES_192 / MODE_ECB doesn't support padding on NSS */ + /*crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_ECB, 1, in, + inlen, 24, "KEY_AES_192/MODE_ECB");*/ + + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_CBC, 1, in, + inlen, 16, "KEY_AES_128/MODE_CBC"); + + /* KEY_AES_192 / MODE_ECB doesn't support padding on NSS */ + /*crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_ECB, 1, in, + inlen, 16, "KEY_AES_128/MODE_ECB");*/ + + apr_pool_destroy(pool); + +} + +/** + * Encrypt OpenSSL, decrypt NSS. + */ +static void test_crypto_block_openssl_nss_pad(abts_case *tc, void *data) +{ + apr_pool_t *pool = NULL; + const apr_crypto_driver_t *drivers[] = { NULL, NULL }; + + const unsigned char *in = (const unsigned char *) TEST_STRING; + apr_size_t inlen = sizeof(TEST_STRING); + + apr_pool_create(&pool, NULL); + drivers[0] = get_openssl_driver(tc, pool); + drivers[1] = get_nss_driver(tc, pool); + crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_CBC, 1, + in, inlen, 24, "KEY_3DES_192/MODE_CBC"); + + /* KEY_3DES_192 / MODE_ECB doesn't work on NSS */ + /* crypto_block_cross(tc, pool, drivers, KEY_3DES_192, MODE_ECB, 1, in, inlen, 24, "KEY_3DES_192/MODE_ECB"); */ + + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_CBC, 1, in, + inlen, 32, "KEY_AES_256/MODE_CBC"); + + /* KEY_AES_256 / MODE_ECB doesn't support padding on NSS */ + /*crypto_block_cross(tc, pool, drivers, KEY_AES_256, MODE_ECB, 1, in, inlen, 32, "KEY_AES_256/MODE_ECB");*/ + + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_CBC, 1, in, inlen, + 24, "KEY_AES_192/MODE_CBC"); + + /* KEY_AES_192 / MODE_ECB doesn't support padding on NSS */ + /*crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_ECB, 1, in, inlen, + 24, "KEY_AES_192/MODE_ECB");*/ + + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_CBC, 1, in, inlen, + 16, "KEY_AES_128/MODE_CBC"); + + /* KEY_AES_128 / MODE_ECB doesn't support padding on NSS */ + /*crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_ECB, 1, in, inlen, + 16, "KEY_AES_128/MODE_ECB");*/ + + apr_pool_destroy(pool); + +} + +/** + * Encrypt CommonCrypto, decrypt OpenSSL. + */ +static void test_crypto_block_commoncrypto_openssl_pad(abts_case *tc, + void *data) +{ + apr_pool_t *pool = NULL; + const apr_crypto_driver_t *drivers[] = + { NULL, NULL }; + + const unsigned char *in = (const unsigned char *) TEST_STRING; + apr_size_t inlen = sizeof(TEST_STRING); + + apr_pool_create(&pool, NULL); + drivers[0] = get_commoncrypto_driver(tc, pool); + drivers[1] = get_openssl_driver(tc, pool); + + crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_CBC, 1, in, + inlen, 24, "KEY_3DES_192/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_ECB, 1, in, + inlen, 24, "KEY_3DES_192/MODE_ECB"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_CBC, 1, in, + inlen, 32, "KEY_AES_256/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_ECB, 1, in, + inlen, 32, "KEY_AES_256/MODE_ECB"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_CBC, 1, in, + inlen, 24, "KEY_AES_192/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_ECB, 1, in, + inlen, 24, "KEY_AES_192/MODE_ECB"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_CBC, 1, in, + inlen, 16, "KEY_AES_128/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_ECB, 1, in, + inlen, 16, "KEY_AES_128/MODE_ECB"); + + apr_pool_destroy(pool); + +} + +/** + * Encrypt OpenSSL, decrypt CommonCrypto. + */ +static void test_crypto_block_openssl_commoncrypto_pad(abts_case *tc, + void *data) +{ + apr_pool_t *pool = NULL; + const apr_crypto_driver_t *drivers[] = + { NULL, NULL }; + + const unsigned char *in = (const unsigned char *) TEST_STRING; + apr_size_t inlen = sizeof(TEST_STRING); + + apr_pool_create(&pool, NULL); + drivers[0] = get_openssl_driver(tc, pool); + drivers[1] = get_commoncrypto_driver(tc, pool); + + crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_CBC, 1, in, + inlen, 24, "KEY_3DES_192/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_ECB, 1, in, + inlen, 24, "KEY_3DES_192/MODE_ECB"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_CBC, 1, in, + inlen, 32, "KEY_AES_256/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_ECB, 1, in, + inlen, 32, "KEY_AES_256/MODE_ECB"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_CBC, 1, in, + inlen, 24, "KEY_AES_192/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_ECB, 1, in, + inlen, 24, "KEY_AES_192/MODE_ECB"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_CBC, 1, in, + inlen, 16, "KEY_AES_128/MODE_CBC"); + crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_ECB, 1, in, + inlen, 16, "KEY_AES_128/MODE_ECB"); + + apr_pool_destroy(pool); + +} + +/** + * Get Types, OpenSSL. + */ +static void test_crypto_get_block_key_types_openssl(abts_case *tc, void *data) +{ + apr_pool_t *pool = NULL; + const apr_crypto_driver_t *driver; + apr_crypto_t *f; + apr_hash_t *types; + int *key_3des_192; + int *key_aes_128; + int *key_aes_192; + int *key_aes_256; + + apr_pool_create(&pool, NULL); + driver = get_openssl_driver(tc, pool); + if (driver) { + + f = make(tc, pool, driver); + apr_crypto_get_block_key_types(&types, f); + + key_3des_192 = apr_hash_get(types, "3des192", APR_HASH_KEY_STRING); + ABTS_PTR_NOTNULL(tc, key_3des_192); + ABTS_INT_EQUAL(tc, *key_3des_192, APR_KEY_3DES_192); + + key_aes_128 = apr_hash_get(types, "aes128", APR_HASH_KEY_STRING); + ABTS_PTR_NOTNULL(tc, key_aes_128); + ABTS_INT_EQUAL(tc, *key_aes_128, APR_KEY_AES_128); + + key_aes_192 = apr_hash_get(types, "aes192", APR_HASH_KEY_STRING); + ABTS_PTR_NOTNULL(tc, key_aes_192); + ABTS_INT_EQUAL(tc, *key_aes_192, APR_KEY_AES_192); + + key_aes_256 = apr_hash_get(types, "aes256", APR_HASH_KEY_STRING); + ABTS_PTR_NOTNULL(tc, key_aes_256); + ABTS_INT_EQUAL(tc, *key_aes_256, APR_KEY_AES_256); + + } + + apr_pool_destroy(pool); + +} + +/** + * Get Types, NSS. + */ +static void test_crypto_get_block_key_types_nss(abts_case *tc, void *data) +{ + apr_pool_t *pool = NULL; + const apr_crypto_driver_t *driver; + apr_crypto_t *f; + apr_hash_t *types; + int *key_3des_192; + int *key_aes_128; + int *key_aes_192; + int *key_aes_256; + + apr_pool_create(&pool, NULL); + driver = get_nss_driver(tc, pool); + if (driver) { + + f = make(tc, pool, driver); + apr_crypto_get_block_key_types(&types, f); + + key_3des_192 = apr_hash_get(types, "3des192", APR_HASH_KEY_STRING); + ABTS_PTR_NOTNULL(tc, key_3des_192); + ABTS_INT_EQUAL(tc, *key_3des_192, APR_KEY_3DES_192); + + key_aes_128 = apr_hash_get(types, "aes128", APR_HASH_KEY_STRING); + ABTS_PTR_NOTNULL(tc, key_aes_128); + ABTS_INT_EQUAL(tc, *key_aes_128, APR_KEY_AES_128); + + key_aes_192 = apr_hash_get(types, "aes192", APR_HASH_KEY_STRING); + ABTS_PTR_NOTNULL(tc, key_aes_192); + ABTS_INT_EQUAL(tc, *key_aes_192, APR_KEY_AES_192); + + key_aes_256 = apr_hash_get(types, "aes256", APR_HASH_KEY_STRING); + ABTS_PTR_NOTNULL(tc, key_aes_256); + ABTS_INT_EQUAL(tc, *key_aes_256, APR_KEY_AES_256); + + } + + apr_pool_destroy(pool); + +} + +/** + * Get Types, Common Crypto. + */ +static void test_crypto_get_block_key_types_commoncrypto(abts_case *tc, void *data) +{ + apr_pool_t *pool = NULL; + const apr_crypto_driver_t *driver; + apr_crypto_t *f; + apr_hash_t *types; + int *key_3des_192; + int *key_aes_128; + int *key_aes_192; + int *key_aes_256; + + apr_pool_create(&pool, NULL); + driver = get_commoncrypto_driver(tc, pool); + if (driver) { + + f = make(tc, pool, driver); + apr_crypto_get_block_key_types(&types, f); + + key_3des_192 = apr_hash_get(types, "3des192", APR_HASH_KEY_STRING); + ABTS_PTR_NOTNULL(tc, key_3des_192); + ABTS_INT_EQUAL(tc, *key_3des_192, APR_KEY_3DES_192); + + key_aes_128 = apr_hash_get(types, "aes128", APR_HASH_KEY_STRING); + ABTS_PTR_NOTNULL(tc, key_aes_128); + ABTS_INT_EQUAL(tc, *key_aes_128, APR_KEY_AES_128); + + key_aes_192 = apr_hash_get(types, "aes192", APR_HASH_KEY_STRING); + ABTS_PTR_NOTNULL(tc, key_aes_192); + ABTS_INT_EQUAL(tc, *key_aes_192, APR_KEY_AES_192); + + key_aes_256 = apr_hash_get(types, "aes256", APR_HASH_KEY_STRING); + ABTS_PTR_NOTNULL(tc, key_aes_256); + ABTS_INT_EQUAL(tc, *key_aes_256, APR_KEY_AES_256); + + } + + apr_pool_destroy(pool); + +} + +/** + * Get Modes, OpenSSL. + */ +static void test_crypto_get_block_key_modes_openssl(abts_case *tc, void *data) +{ + apr_pool_t *pool = NULL; + const apr_crypto_driver_t *driver; + apr_crypto_t *f; + apr_hash_t *modes; + int *mode_ecb; + int *mode_cbc; + + apr_pool_create(&pool, NULL); + driver = get_openssl_driver(tc, pool); + if (driver) { + + f = make(tc, pool, driver); + apr_crypto_get_block_key_modes(&modes, f); + + mode_ecb = apr_hash_get(modes, "ecb", APR_HASH_KEY_STRING); + ABTS_PTR_NOTNULL(tc, mode_ecb); + ABTS_INT_EQUAL(tc, *mode_ecb, APR_MODE_ECB); + + mode_cbc = apr_hash_get(modes, "cbc", APR_HASH_KEY_STRING); + ABTS_PTR_NOTNULL(tc, mode_cbc); + ABTS_INT_EQUAL(tc, *mode_cbc, APR_MODE_CBC); + + } + + apr_pool_destroy(pool); + +} + +/** + * Get Modes, NSS. + */ +static void test_crypto_get_block_key_modes_nss(abts_case *tc, void *data) +{ + apr_pool_t *pool = NULL; + const apr_crypto_driver_t *driver; + apr_crypto_t *f; + apr_hash_t *modes; + int *mode_ecb; + int *mode_cbc; + + apr_pool_create(&pool, NULL); + driver = get_nss_driver(tc, pool); + if (driver) { + + f = make(tc, pool, driver); + apr_crypto_get_block_key_modes(&modes, f); + + mode_ecb = apr_hash_get(modes, "ecb", APR_HASH_KEY_STRING); + ABTS_PTR_NOTNULL(tc, mode_ecb); + ABTS_INT_EQUAL(tc, *mode_ecb, APR_MODE_ECB); + + mode_cbc = apr_hash_get(modes, "cbc", APR_HASH_KEY_STRING); + ABTS_PTR_NOTNULL(tc, mode_cbc); + ABTS_INT_EQUAL(tc, *mode_cbc, APR_MODE_CBC); + + } + + apr_pool_destroy(pool); + +} + +/** + * Get Modes, Common Crypto. + */ +static void test_crypto_get_block_key_modes_commoncrypto(abts_case *tc, void *data) +{ + apr_pool_t *pool = NULL; + const apr_crypto_driver_t *driver; + apr_crypto_t *f; + apr_hash_t *modes; + int *mode_ecb; + int *mode_cbc; + + apr_pool_create(&pool, NULL); + driver = get_commoncrypto_driver(tc, pool); + if (driver) { + + f = make(tc, pool, driver); + apr_crypto_get_block_key_modes(&modes, f); + + mode_ecb = apr_hash_get(modes, "ecb", APR_HASH_KEY_STRING); + ABTS_PTR_NOTNULL(tc, mode_ecb); + ABTS_INT_EQUAL(tc, *mode_ecb, APR_MODE_ECB); + + mode_cbc = apr_hash_get(modes, "cbc", APR_HASH_KEY_STRING); + ABTS_PTR_NOTNULL(tc, mode_cbc); + ABTS_INT_EQUAL(tc, *mode_cbc, APR_MODE_CBC); + + } + + apr_pool_destroy(pool); + +} + +static void test_crypto_memzero(abts_case *tc, void *data) +{ + /* Aligned message */ + struct { + char buf[7 * sizeof(int)]; + int untouched; + } msg; + /* A bit of type punning such that 'msg' might look unused + * after the call to apr_crypto_memzero(). + */ + int *ptr = (int *)&msg; + int i; + + /* Fill buf with non-zeros (odds) */ + for (i = 1; i < 2 * sizeof(msg.buf); i += 2) { + msg.buf[i / 2] = (char)i; + ABTS_ASSERT(tc, "test_crypto_memzero() barrier", msg.buf[i / 2] != 0); + } + + /* Zero out the whole, and check it */ + apr_crypto_memzero(&msg, sizeof msg); + for (i = 0; i < sizeof(msg) / sizeof(*ptr); ++i) { + ABTS_ASSERT(tc, "test_crypto_memzero() optimized out", ptr[i] == 0); + } +} + +static void test_crypto_equals(abts_case *tc, void *data) +{ + /* Buffers of each type of scalar */ + union { + char c; + short s; + int i; + long l; + float f; + double d; + void *p; + } buf0[7], buf1[7], buf[7]; + char *ptr = (char *)buf; + int i; + +#define TEST_SCALAR_MATCH(i, x, r) \ + ABTS_ASSERT(tc, "test_crypto_equals(" APR_STRINGIFY(x) ")" \ + " != " APR_STRINGIFY(r), \ + apr_crypto_equals(&buf##r[i].x, &buf[i].x, \ + sizeof(buf[i].x)) == r) + + /* Fill buf with non-zeros (odds) */ + for (i = 1; i < 2 * sizeof(buf); i += 2) { + ptr[i / 2] = (char)i; + } + /* Set buf1 = buf */ + memcpy(buf1, buf, sizeof buf); + /* Set buf0 = {0} */ + memset(buf0, 0, sizeof buf0); + + /* Check that buf1 == buf for each scalar */ + TEST_SCALAR_MATCH(0, c, 1); + TEST_SCALAR_MATCH(1, s, 1); + TEST_SCALAR_MATCH(2, i, 1); + TEST_SCALAR_MATCH(3, l, 1); + TEST_SCALAR_MATCH(4, f, 1); + TEST_SCALAR_MATCH(5, d, 1); + TEST_SCALAR_MATCH(6, p, 1); + + /* Check that buf0 != buf for each scalar */ + TEST_SCALAR_MATCH(0, c, 0); + TEST_SCALAR_MATCH(1, s, 0); + TEST_SCALAR_MATCH(2, i, 0); + TEST_SCALAR_MATCH(3, l, 0); + TEST_SCALAR_MATCH(4, f, 0); + TEST_SCALAR_MATCH(5, d, 0); + TEST_SCALAR_MATCH(6, p, 0); +} + +abts_suite *testcrypto(abts_suite *suite) +{ + suite = ADD_SUITE(suite); + + /* test simple init and shutdown */ + abts_run_test(suite, test_crypto_init, NULL); + + /* test key parsing - openssl */ + abts_run_test(suite, test_crypto_key_openssl, NULL); + + /* test key parsing - nss */ + abts_run_test(suite, test_crypto_key_nss, NULL); + + /* test key parsing - commoncrypto */ + abts_run_test(suite, test_crypto_key_commoncrypto, NULL); + + /* test a simple encrypt / decrypt operation - openssl */ + abts_run_test(suite, test_crypto_block_openssl, NULL); + + /* test a padded encrypt / decrypt operation - openssl */ + abts_run_test(suite, test_crypto_block_openssl_pad, NULL); + + /* test a simple encrypt / decrypt operation - nss */ + abts_run_test(suite, test_crypto_block_nss, NULL); + + /* test a padded encrypt / decrypt operation - nss */ + abts_run_test(suite, test_crypto_block_nss_pad, NULL); + + /* test a simple encrypt / decrypt operation - commoncrypto */ + abts_run_test(suite, test_crypto_block_commoncrypto, NULL); + + /* test a padded encrypt / decrypt operation - commoncrypto */ + abts_run_test(suite, test_crypto_block_commoncrypto_pad, NULL); + + /* test encrypt nss / decrypt openssl */ + abts_run_test(suite, test_crypto_block_nss_openssl, NULL); + + /* test padded encrypt nss / decrypt openssl */ + abts_run_test(suite, test_crypto_block_nss_openssl_pad, NULL); + + /* test encrypt openssl / decrypt nss */ + abts_run_test(suite, test_crypto_block_openssl_nss, NULL); + + /* test padded encrypt openssl / decrypt nss */ + abts_run_test(suite, test_crypto_block_openssl_nss_pad, NULL); + + /* test encrypt openssl / decrypt commoncrypto */ + abts_run_test(suite, test_crypto_block_openssl_commoncrypto, NULL); + + /* test padded encrypt openssl / decrypt commoncrypto */ + abts_run_test(suite, test_crypto_block_openssl_commoncrypto_pad, NULL); + + /* test encrypt commoncrypto / decrypt openssl */ + abts_run_test(suite, test_crypto_block_commoncrypto_openssl, NULL); + + /* test padded encrypt commoncrypto / decrypt openssl */ + abts_run_test(suite, test_crypto_block_commoncrypto_openssl_pad, NULL); + + /* test block key types openssl */ + abts_run_test(suite, test_crypto_get_block_key_types_openssl, NULL); + + /* test block key types nss */ + abts_run_test(suite, test_crypto_get_block_key_types_nss, NULL); + + /* test block key types commoncrypto */ + abts_run_test(suite, test_crypto_get_block_key_types_commoncrypto, NULL); + + /* test block key modes openssl */ + abts_run_test(suite, test_crypto_get_block_key_modes_openssl, NULL); + + /* test block key modes nss */ + abts_run_test(suite, test_crypto_get_block_key_modes_nss, NULL); + + /* test block key modes commoncrypto */ + abts_run_test(suite, test_crypto_get_block_key_modes_commoncrypto, NULL); + + abts_run_test(suite, test_crypto_memzero, NULL); + abts_run_test(suite, test_crypto_equals, NULL); + + return suite; +} + +#else + +/** + * Dummy test suite when crypto is turned off. + */ +abts_suite *testcrypto(abts_suite *suite) +{ + return ADD_SUITE(suite); +} + +#endif /* APU_HAVE_CRYPTO */ diff --git a/test/testdate.c b/test/testdate.c new file mode 100644 index 00000000000..b4e2edf263e --- /dev/null +++ b/test/testdate.c @@ -0,0 +1,202 @@ +/* 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 "abts.h" +#include "testutil.h" +#include "apr_date.h" +#include "apr_general.h" + +#if APR_HAVE_TIME_H +#include <time.h> +#endif /* APR_HAVE_TIME_H */ + +static struct datetest { + const char *input; + const char *output; +} tests[] = { + { "Mon, 27 Feb 1995 20:49:44 -0800", "Tue, 28 Feb 1995 04:49:44 GMT" }, + { "Fri, 1 Jul 2005 11:34:25 -0400", "Fri, 01 Jul 2005 15:34:25 GMT" }, + { "Monday, 27-Feb-95 20:49:44 -0800", "Tue, 28 Feb 1995 04:49:44 GMT" }, + { "Tue, 4 Mar 1997 12:43:52 +0200", "Tue, 04 Mar 1997 10:43:52 GMT" }, + { "Mon, 27 Feb 95 20:49:44 -0800", "Tue, 28 Feb 1995 04:49:44 GMT" }, + { "Tue, 4 Mar 97 12:43:52 +0200", "Tue, 04 Mar 1997 10:43:52 GMT" }, + { "Tue, 4 Mar 97 12:43:52 +0200", "Tue, 04 Mar 1997 10:43:52 GMT" }, + { "Mon, 27 Feb 95 20:49 GMT", "Mon, 27 Feb 1995 20:49:00 GMT" }, + { "Tue, 4 Mar 97 12:43 GMT", "Tue, 04 Mar 1997 12:43:00 GMT" }, + { NULL, NULL } +}; + +static const apr_time_t year2secs[] = { + APR_INT64_C(0), /* 1970 */ + APR_INT64_C(31536000), /* 1971 */ + APR_INT64_C(63072000), /* 1972 */ + APR_INT64_C(94694400), /* 1973 */ + APR_INT64_C(126230400), /* 1974 */ + APR_INT64_C(157766400), /* 1975 */ + APR_INT64_C(189302400), /* 1976 */ + APR_INT64_C(220924800), /* 1977 */ + APR_INT64_C(252460800), /* 1978 */ + APR_INT64_C(283996800), /* 1979 */ + APR_INT64_C(315532800), /* 1980 */ + APR_INT64_C(347155200), /* 1981 */ + APR_INT64_C(378691200), /* 1982 */ + APR_INT64_C(410227200), /* 1983 */ + APR_INT64_C(441763200), /* 1984 */ + APR_INT64_C(473385600), /* 1985 */ + APR_INT64_C(504921600), /* 1986 */ + APR_INT64_C(536457600), /* 1987 */ + APR_INT64_C(567993600), /* 1988 */ + APR_INT64_C(599616000), /* 1989 */ + APR_INT64_C(631152000), /* 1990 */ + APR_INT64_C(662688000), /* 1991 */ + APR_INT64_C(694224000), /* 1992 */ + APR_INT64_C(725846400), /* 1993 */ + APR_INT64_C(757382400), /* 1994 */ + APR_INT64_C(788918400), /* 1995 */ + APR_INT64_C(820454400), /* 1996 */ + APR_INT64_C(852076800), /* 1997 */ + APR_INT64_C(883612800), /* 1998 */ + APR_INT64_C(915148800), /* 1999 */ + APR_INT64_C(946684800), /* 2000 */ + APR_INT64_C(978307200), /* 2001 */ + APR_INT64_C(1009843200), /* 2002 */ + APR_INT64_C(1041379200), /* 2003 */ + APR_INT64_C(1072915200), /* 2004 */ + APR_INT64_C(1104537600), /* 2005 */ + APR_INT64_C(1136073600), /* 2006 */ + APR_INT64_C(1167609600), /* 2007 */ + APR_INT64_C(1199145600), /* 2008 */ + APR_INT64_C(1230768000), /* 2009 */ + APR_INT64_C(1262304000), /* 2010 */ + APR_INT64_C(1293840000), /* 2011 */ + APR_INT64_C(1325376000), /* 2012 */ + APR_INT64_C(1356998400), /* 2013 */ + APR_INT64_C(1388534400), /* 2014 */ + APR_INT64_C(1420070400), /* 2015 */ + APR_INT64_C(1451606400), /* 2016 */ + APR_INT64_C(1483228800), /* 2017 */ + APR_INT64_C(1514764800), /* 2018 */ + APR_INT64_C(1546300800), /* 2019 */ + APR_INT64_C(1577836800), /* 2020 */ + APR_INT64_C(1609459200), /* 2021 */ + APR_INT64_C(1640995200), /* 2022 */ + APR_INT64_C(1672531200), /* 2023 */ + APR_INT64_C(1704067200), /* 2024 */ + APR_INT64_C(1735689600), /* 2025 */ + APR_INT64_C(1767225600), /* 2026 */ + APR_INT64_C(1798761600), /* 2027 */ + APR_INT64_C(1830297600), /* 2028 */ + APR_INT64_C(1861920000), /* 2029 */ + APR_INT64_C(1893456000), /* 2030 */ + APR_INT64_C(1924992000), /* 2031 */ + APR_INT64_C(1956528000), /* 2032 */ + APR_INT64_C(1988150400), /* 2033 */ + APR_INT64_C(2019686400), /* 2034 */ + APR_INT64_C(2051222400), /* 2035 */ + APR_INT64_C(2082758400), /* 2036 */ + APR_INT64_C(2114380800), /* 2037 */ + APR_INT64_C(2145916800) /* 2038 */ +}; + +const char month_snames[12][4] = { + "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec" +}; + +/* XXX: non-portable */ +static void gm_timestr_822(char *ts, apr_time_t sec) +{ + static const char *const days[7]= + {"Sun","Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; + struct tm *tms; + time_t ls = (time_t)sec; + + tms = gmtime(&ls); + + sprintf(ts, "%s, %.2d %s %d %.2d:%.2d:%.2d GMT", days[tms->tm_wday], + tms->tm_mday, month_snames[tms->tm_mon], tms->tm_year + 1900, + tms->tm_hour, tms->tm_min, tms->tm_sec); +} + +/* Linear congruential generator */ +static apr_uint32_t lgc(apr_uint32_t a) +{ + apr_uint64_t z = a; + z *= 279470273; + z %= APR_UINT64_C(4294967291); + return (apr_uint32_t)z; +} + +static void test_date_parse_http(abts_case *tc, void *data) +{ + int year, i; + apr_time_t guess; + apr_time_t offset = 0; + apr_time_t secstodate, newsecs; + char datestr[50]; + + for (year = 1970; year < 2038; ++year) { + secstodate = year2secs[year - 1970] + offset; + gm_timestr_822(datestr, secstodate); + secstodate *= APR_USEC_PER_SEC; + newsecs = apr_date_parse_http(datestr); + ABTS_TRUE(tc, secstodate == newsecs); + } + +#if APR_HAS_RANDOM + apr_generate_random_bytes((unsigned char *)&guess, sizeof(guess)); +#else + guess = apr_time_now() % APR_TIME_C(4294967291); +#endif + + for (i = 0; i < 10000; ++i) { + guess = (time_t)lgc((apr_uint32_t)guess); + if (guess < 0) + guess *= -1; + secstodate = guess + offset; + gm_timestr_822(datestr, secstodate); + secstodate *= APR_USEC_PER_SEC; + newsecs = apr_date_parse_http(datestr); + ABTS_TRUE(tc, secstodate == newsecs); + } +} + +static void test_date_rfc(abts_case *tc, void *data) +{ + apr_time_t date; + int i = 0; + + while (tests[i].input) { + char str_date[APR_RFC822_DATE_LEN] = { 0 }; + + date = apr_date_parse_rfc(tests[i].input); + + apr_rfc822_date(str_date, date); + + ABTS_STR_EQUAL(tc, str_date, tests[i].output); + + i++; + } +} + +abts_suite *testdate(abts_suite *suite) +{ + suite = ADD_SUITE(suite); + + abts_run_test(suite, test_date_parse_http, NULL); + abts_run_test(suite, test_date_rfc, NULL); + + return suite; +} diff --git a/test/testdbd.c b/test/testdbd.c new file mode 100644 index 00000000000..b94c491b932 --- /dev/null +++ b/test/testdbd.c @@ -0,0 +1,245 @@ +/* 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 "testutil.h" +#include "apr.h" +#include "apu.h" +#include "apr_pools.h" +#include "apr_dbd.h" +#include "apr_strings.h" + +static void test_dbd_init(abts_case *tc, void *data) +{ + apr_pool_t *pool = p; + apr_status_t rv; + + rv = apr_dbd_init(pool); + ABTS_ASSERT(tc, "failed to init apr_dbd", rv == APR_SUCCESS); +} + +#if APU_HAVE_SQLITE2 || APU_HAVE_SQLITE3 +static void test_statement(abts_case *tc, apr_dbd_t* handle, + const apr_dbd_driver_t* driver, const char* sql) +{ + int nrows; + apr_status_t rv; + + rv = apr_dbd_query(driver, handle, &nrows, sql); + + ABTS_ASSERT(tc, sql, rv == APR_SUCCESS); +} + +static void create_table(abts_case *tc, apr_dbd_t* handle, + const apr_dbd_driver_t* driver) +{ + const char *sql = "CREATE TABLE apr_dbd_test (" + "col1 varchar(40) not null," + "col2 varchar(40)," + "col3 integer)"; + + test_statement(tc, handle, driver, sql); +} + +static void drop_table(abts_case *tc, apr_dbd_t* handle, + const apr_dbd_driver_t* driver) +{ + const char *sql = "DROP TABLE apr_dbd_test"; + test_statement(tc, handle, driver, sql); +} + +static void delete_rows(abts_case *tc, apr_dbd_t* handle, + const apr_dbd_driver_t* driver) +{ + const char *sql = "DELETE FROM apr_dbd_test"; + test_statement(tc, handle, driver, sql); +} + + +static void insert_data(abts_case *tc, apr_dbd_t* handle, + const apr_dbd_driver_t* driver, int count) +{ + apr_pool_t* pool = p; + const char* sql = "INSERT INTO apr_dbd_test VALUES('%d', '%d', %d)"; + char* sqf = NULL; + int i; + int nrows; + apr_status_t rv; + + for (i=0; i<count; i++) { + sqf = apr_psprintf(pool, sql, i, i, i); + rv = apr_dbd_query(driver, handle, &nrows, sqf); + ABTS_ASSERT(tc, sqf, rv == APR_SUCCESS); + ABTS_ASSERT(tc, sqf, 1 == nrows); + } +} + +static void select_rows(abts_case *tc, apr_dbd_t* handle, + const apr_dbd_driver_t* driver, int count) +{ + apr_status_t rv; + apr_pool_t* pool = p; + apr_pool_t* tpool; + const char* sql = "SELECT * FROM apr_dbd_test ORDER BY col1"; + apr_dbd_results_t *res = NULL; + apr_dbd_row_t *row = NULL; + int i; + + rv = apr_dbd_select(driver, pool, handle, &res, sql, 0); + ABTS_ASSERT(tc, sql, rv == APR_SUCCESS); + ABTS_PTR_NOTNULL(tc, res); + + apr_pool_create(&tpool, pool); + i = count; + while (i > 0) { + row = NULL; + rv = apr_dbd_get_row(driver, pool, res, &row, -1); + ABTS_ASSERT(tc, sql, rv == APR_SUCCESS); + ABTS_PTR_NOTNULL(tc, row); + apr_pool_clear(tpool); + i--; + } + ABTS_ASSERT(tc, "Missing Rows!", i == 0); + + res = NULL; + i = count; + + rv = apr_dbd_select(driver, pool, handle, &res, sql, 1); + ABTS_ASSERT(tc, sql, rv == APR_SUCCESS); + ABTS_PTR_NOTNULL(tc, res); + + rv = apr_dbd_num_tuples(driver, res); + ABTS_ASSERT(tc, "invalid row count", rv == count); + + while (i > 0) { + row = NULL; + rv = apr_dbd_get_row(driver, pool, res, &row, i); + ABTS_ASSERT(tc, sql, rv == APR_SUCCESS); + ABTS_PTR_NOTNULL(tc, row); + apr_pool_clear(tpool); + i--; + } + ABTS_ASSERT(tc, "Missing Rows!", i == 0); + rv = apr_dbd_get_row(driver, pool, res, &row, count+100); + ABTS_ASSERT(tc, "If we overseek, get_row should return -1", rv == -1); +} + +static void test_escape(abts_case *tc, apr_dbd_t *handle, + const apr_dbd_driver_t *driver) +{ + const char *escaped = apr_dbd_escape(driver, p, "foo'bar", handle); + + ABTS_STR_EQUAL(tc, "foo''bar", escaped); +} + +static void test_dbd_generic(abts_case *tc, apr_dbd_t* handle, + const apr_dbd_driver_t* driver) +{ + void* native; + apr_pool_t *pool = p; + apr_status_t rv; + + native = apr_dbd_native_handle(driver, handle); + ABTS_PTR_NOTNULL(tc, native); + + rv = apr_dbd_check_conn(driver, pool, handle); + + create_table(tc, handle, driver); + select_rows(tc, handle, driver, 0); + insert_data(tc, handle, driver, 5); + select_rows(tc, handle, driver, 5); + delete_rows(tc, handle, driver); + select_rows(tc, handle, driver, 0); + drop_table(tc, handle, driver); + + test_escape(tc, handle, driver); + + rv = apr_dbd_close(driver, handle); + ABTS_ASSERT(tc, "failed to close database", rv == APR_SUCCESS); +} +#endif + +#if APU_HAVE_SQLITE2 +static void test_dbd_sqlite2(abts_case *tc, void *data) +{ + apr_pool_t *pool = p; + apr_status_t rv; + const apr_dbd_driver_t* driver = NULL; + apr_dbd_t* handle = NULL; + + rv = apr_dbd_get_driver(pool, "sqlite2", &driver); + ABTS_ASSERT(tc, "failed to fetch sqlite2 driver", rv == APR_SUCCESS); + ABTS_PTR_NOTNULL(tc, driver); + if (!driver) { + return; + } + + ABTS_STR_EQUAL(tc, "sqlite2", apr_dbd_name(driver)); + + rv = apr_dbd_open(driver, pool, "data/sqlite2.db:600", &handle); + ABTS_ASSERT(tc, "failed to open sqlite2 atabase", rv == APR_SUCCESS); + ABTS_PTR_NOTNULL(tc, handle); + if (!handle) { + return; + } + + test_dbd_generic(tc, handle, driver); +} +#endif + +#if APU_HAVE_SQLITE3 +static void test_dbd_sqlite3(abts_case *tc, void *data) +{ + apr_pool_t *pool = p; + apr_status_t rv; + const apr_dbd_driver_t* driver = NULL; + apr_dbd_t* handle = NULL; + + rv = apr_dbd_get_driver(pool, "sqlite3", &driver); + ABTS_ASSERT(tc, "failed to fetch sqlite3 driver", rv == APR_SUCCESS); + ABTS_PTR_NOTNULL(tc, driver); + if (!driver) { + return; + } + + ABTS_STR_EQUAL(tc, "sqlite3", apr_dbd_name(driver)); + + rv = apr_dbd_open(driver, pool, "data/sqlite3.db", &handle); + ABTS_ASSERT(tc, "failed to open sqlite3 database", rv == APR_SUCCESS); + ABTS_PTR_NOTNULL(tc, handle); + if (!handle) { + return; + } + + test_dbd_generic(tc, handle, driver); +} +#endif + +abts_suite *testdbd(abts_suite *suite) +{ + suite = ADD_SUITE(suite); + + + abts_run_test(suite, test_dbd_init, NULL); + +#if APU_HAVE_SQLITE2 + abts_run_test(suite, test_dbd_sqlite2, NULL); +#endif + +#if APU_HAVE_SQLITE3 + abts_run_test(suite, test_dbd_sqlite3, NULL); +#endif + return suite; +} diff --git a/test/testdbm.c b/test/testdbm.c new file mode 100644 index 00000000000..aaea4116bc2 --- /dev/null +++ b/test/testdbm.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_general.h" +#include "apr_pools.h" +#include "apr_errno.h" +#include "apr_dbm.h" +#include "apr_uuid.h" +#include "apr_strings.h" +#include "abts.h" +#include "testutil.h" + +#define NUM_TABLE_ROWS 1024 + +typedef struct { + apr_datum_t key; + apr_datum_t val; + int deleted; + int visited; +} dbm_table_t; + +static dbm_table_t *generate_table(void) +{ + unsigned int i; + apr_uuid_t uuid; + dbm_table_t *table = apr_pcalloc(p, sizeof(*table) * NUM_TABLE_ROWS); + + for (i = 0; i < NUM_TABLE_ROWS/2; i++) { + apr_uuid_get(&uuid); + table[i].key.dptr = apr_pmemdup(p, uuid.data, sizeof(uuid.data)); + table[i].key.dsize = sizeof(uuid.data); + table[i].val.dptr = apr_palloc(p, APR_UUID_FORMATTED_LENGTH + 1); + table[i].val.dsize = APR_UUID_FORMATTED_LENGTH + 1; + apr_uuid_format(table[i].val.dptr, &uuid); + } + + for (; i < NUM_TABLE_ROWS; i++) { + apr_uuid_get(&uuid); + table[i].val.dptr = apr_pmemdup(p, uuid.data, sizeof(uuid.data)); + table[i].val.dsize = sizeof(uuid.data); + table[i].key.dptr = apr_palloc(p, APR_UUID_FORMATTED_LENGTH + 1); + table[i].key.dsize = APR_UUID_FORMATTED_LENGTH + 1; + apr_uuid_format(table[i].key.dptr, &uuid); + } + + return table; +} + +static void test_dbm_store(abts_case *tc, apr_dbm_t *db, dbm_table_t *table) +{ + apr_status_t rv; + unsigned int i = NUM_TABLE_ROWS - 1; + + for (; i >= NUM_TABLE_ROWS/2; i--) { + rv = apr_dbm_store(db, table[i].key, table[i].val); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + table[i].deleted = FALSE; + } + + for (i = 0; i < NUM_TABLE_ROWS/2; i++) { + rv = apr_dbm_store(db, table[i].key, table[i].val); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + table[i].deleted = FALSE; + } +} + +static void test_dbm_fetch(abts_case *tc, apr_dbm_t *db, dbm_table_t *table) +{ + apr_status_t rv; + unsigned int i; + apr_datum_t val; + + for (i = 0; i < NUM_TABLE_ROWS; i++) { + memset(&val, 0, sizeof(val)); + rv = apr_dbm_fetch(db, table[i].key, &val); + if (!table[i].deleted) { + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_INT_EQUAL(tc, table[i].val.dsize, val.dsize); + ABTS_INT_EQUAL(tc, 0, memcmp(table[i].val.dptr, val.dptr, val.dsize)); + apr_dbm_freedatum(db, val); + } else { + ABTS_INT_EQUAL(tc, 0, val.dsize); + } + } +} + +static void test_dbm_delete(abts_case *tc, apr_dbm_t *db, dbm_table_t *table) +{ + apr_status_t rv; + unsigned int i; + + for (i = 0; i < NUM_TABLE_ROWS; i++) { + /* XXX: random */ + if (i & 1) + continue; + rv = apr_dbm_delete(db, table[i].key); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + table[i].deleted = TRUE; + } +} + +static void test_dbm_exists(abts_case *tc, apr_dbm_t *db, dbm_table_t *table) +{ + unsigned int i; + int cond; + + for (i = 0; i < NUM_TABLE_ROWS; i++) { + cond = apr_dbm_exists(db, table[i].key); + if (table[i].deleted) { + ABTS_TRUE(tc, cond == 0); + } else { + ABTS_TRUE(tc, cond != 0); + } + } +} + +static void test_dbm_traversal(abts_case *tc, apr_dbm_t *db, dbm_table_t *table) +{ + apr_status_t rv; + unsigned int i; + apr_datum_t key; + + rv = apr_dbm_firstkey(db, &key); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + do { + if (key.dptr == NULL || key.dsize == 0) + break; + + for (i = 0; i < NUM_TABLE_ROWS; i++) { + if (table[i].key.dsize != key.dsize) + continue; + if (memcmp(table[i].key.dptr, key.dptr, key.dsize)) + continue; + ABTS_INT_EQUAL(tc, 0, table[i].deleted); + ABTS_INT_EQUAL(tc, 0, table[i].visited); + table[i].visited++; + } + + rv = apr_dbm_nextkey(db, &key); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + } while (1); + + for (i = 0; i < NUM_TABLE_ROWS; i++) { + if (table[i].deleted) + continue; + ABTS_INT_EQUAL(tc, 1, table[i].visited); + table[i].visited = 0; + } +} + +static void test_dbm(abts_case *tc, void *data) +{ + apr_dbm_t *db; + apr_status_t rv; + dbm_table_t *table; + const char *type = data; + const char *file = apr_pstrcat(p, "data/test-", type, NULL); + + rv = apr_dbm_open_ex(&db, type, file, APR_DBM_RWCREATE, APR_FPROT_OS_DEFAULT, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + if (rv != APR_SUCCESS) + return; + + table = generate_table(); + + test_dbm_store(tc, db, table); + test_dbm_fetch(tc, db, table); + test_dbm_delete(tc, db, table); + test_dbm_exists(tc, db, table); + test_dbm_traversal(tc, db, table); + + apr_dbm_close(db); + + rv = apr_dbm_open_ex(&db, type, file, APR_DBM_READONLY, APR_FPROT_OS_DEFAULT, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + if (rv != APR_SUCCESS) + return; + + test_dbm_exists(tc, db, table); + test_dbm_traversal(tc, db, table); + test_dbm_fetch(tc, db, table); + + apr_dbm_close(db); +} + +abts_suite *testdbm(abts_suite *suite) +{ + suite = ADD_SUITE(suite); + +#if APU_HAVE_GDBM + abts_run_test(suite, test_dbm, "gdbm"); +#endif +#if APU_HAVE_NDBM + abts_run_test(suite, test_dbm, "ndbm"); +#endif +#if APU_HAVE_SDBM + abts_run_test(suite, test_dbm, "sdbm"); +#endif +#if APU_HAVE_DB + abts_run_test(suite, test_dbm, "db"); +#endif + + return suite; +} diff --git a/test/testdir.c b/test/testdir.c new file mode 100644 index 00000000000..87085bd0a0f --- /dev/null +++ b/test/testdir.c @@ -0,0 +1,405 @@ +/* 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 <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "apr_file_io.h" +#include "apr_file_info.h" +#include "apr_errno.h" +#include "apr_general.h" +#include "apr_lib.h" +#include "apr_thread_proc.h" +#include "testutil.h" + +static void test_mkdir(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_finfo_t finfo; + + rv = apr_dir_make("data/testdir", + APR_FPROT_UREAD | APR_FPROT_UWRITE | APR_FPROT_UEXECUTE, + p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + rv = apr_stat(&finfo, "data/testdir", APR_FINFO_TYPE, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_INT_EQUAL(tc, APR_DIR, finfo.filetype); +} + +static void test_mkdir_recurs(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_finfo_t finfo; + + rv = apr_dir_make_recursive("data/one/two/three", + APR_FPROT_UREAD | APR_FPROT_UWRITE | APR_FPROT_UEXECUTE, + p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + rv = apr_stat(&finfo, "data/one", APR_FINFO_TYPE, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_INT_EQUAL(tc, APR_DIR, finfo.filetype); + + rv = apr_stat(&finfo, "data/one/two", APR_FINFO_TYPE, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_INT_EQUAL(tc, APR_DIR, finfo.filetype); + + rv = apr_stat(&finfo, "data/one/two/three", APR_FINFO_TYPE, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_INT_EQUAL(tc, APR_DIR, finfo.filetype); +} + +struct thread_data +{ + abts_case *tc; + apr_pool_t *pool; +}; + +static void *APR_THREAD_FUNC thread_mkdir_func(apr_thread_t *thd, void *data) +{ + struct thread_data *td = data; + apr_status_t s1, s2, s3, s4, s5; + + s1 = apr_dir_make_recursive("data/prll/one/thwo/three", + APR_FPROT_UREAD | APR_FPROT_UWRITE | APR_FPROT_UEXECUTE, + td->pool); + s2 = apr_dir_make_recursive("data/prll/four/five/six/seven/eight", + APR_FPROT_UREAD | APR_FPROT_UWRITE | APR_FPROT_UEXECUTE, + td->pool); + s3 = apr_dir_make_recursive("data/prll/nine/ten", + APR_FPROT_UREAD | APR_FPROT_UWRITE | APR_FPROT_UEXECUTE, + td->pool); + s4 = apr_dir_make_recursive("data/prll/11/12/13/14/15/16/17/18/19/20", + APR_FPROT_UREAD | APR_FPROT_UWRITE | APR_FPROT_UEXECUTE, + td->pool); + s5 = apr_dir_make_recursive("data/fortytwo", + APR_FPROT_UREAD | APR_FPROT_UWRITE | APR_FPROT_UEXECUTE, + td->pool); + + ABTS_INT_EQUAL(td->tc, APR_SUCCESS, s1); + ABTS_INT_EQUAL(td->tc, APR_SUCCESS, s2); + ABTS_INT_EQUAL(td->tc, APR_SUCCESS, s3); + ABTS_INT_EQUAL(td->tc, APR_SUCCESS, s4); + ABTS_INT_EQUAL(td->tc, APR_SUCCESS, s5); + return NULL; +} + +static void test_mkdir_recurs_parallel(abts_case *tc, void *data) +{ + struct thread_data td1, td2, td3, td4; + apr_thread_t *t1, *t2, *t3, *t4; + apr_status_t s1, s2, s3, s4; + + td1.tc = td2.tc = td3.tc = td4.tc = tc; + apr_pool_create(&td1.pool, p); + apr_pool_create(&td2.pool, p); + apr_pool_create(&td3.pool, p); + apr_pool_create(&td4.pool, p); + + s1 = apr_thread_create(&t1, NULL, thread_mkdir_func, &td1, td1.pool); + ABTS_INT_EQUAL(tc, APR_SUCCESS, s1); + s2 = apr_thread_create(&t2, NULL, thread_mkdir_func, &td2, td2.pool); + ABTS_INT_EQUAL(tc, APR_SUCCESS, s2); + s3 = apr_thread_create(&t3, NULL, thread_mkdir_func, &td3, td3.pool); + ABTS_INT_EQUAL(tc, APR_SUCCESS, s3); + s4 = apr_thread_create(&t4, NULL, thread_mkdir_func, &td4, td4.pool); + ABTS_INT_EQUAL(tc, APR_SUCCESS, s4); + + apr_thread_join(&s1, t1); + apr_thread_join(&s2, t2); + apr_thread_join(&s3, t3); + apr_thread_join(&s4, t4); + + ABTS_INT_EQUAL(tc, APR_SUCCESS, s1); + ABTS_INT_EQUAL(tc, APR_SUCCESS, s2); + ABTS_INT_EQUAL(tc, APR_SUCCESS, s3); + ABTS_INT_EQUAL(tc, APR_SUCCESS, s4); +} + +static void test_remove(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_finfo_t finfo; + + rv = apr_dir_remove("data/testdir", p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + rv = apr_stat(&finfo, "data/testdir", APR_FINFO_TYPE, p); + ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_ENOENT(rv)); +} + +static void test_removeall_fail(abts_case *tc, void *data) +{ + apr_status_t rv; + + rv = apr_dir_remove("data/one", p); + ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_ENOTEMPTY(rv)); +} + +static void test_removeall(abts_case *tc, void *data) +{ + apr_status_t rv; + + rv = apr_dir_remove("data/one/two/three", p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + rv = apr_dir_remove("data/one/two", p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + rv = apr_dir_remove("data/one", p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + rv = apr_dir_remove("data/prll/one/thwo/three", p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + rv = apr_dir_remove("data/prll/one/thwo", p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + rv = apr_dir_remove("data/prll/one", p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + rv = apr_dir_remove("data/prll/four/five/six/seven/eight", p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + rv = apr_dir_remove("data/prll/four/five/six/seven", p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + rv = apr_dir_remove("data/prll/four/five/six", p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + rv = apr_dir_remove("data/prll/four/five", p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + rv = apr_dir_remove("data/prll/four", p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + rv = apr_dir_remove("data/prll/nine/ten", p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + rv = apr_dir_remove("data/prll/nine", p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + rv = apr_dir_remove("data/prll/11/12/13/14/15/16/17/18/19/20", p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + rv = apr_dir_remove("data/prll/11/12/13/14/15/16/17/18/19", p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + rv = apr_dir_remove("data/prll/11/12/13/14/15/16/17/18", p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + rv = apr_dir_remove("data/prll/11/12/13/14/15/16/17", p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + rv = apr_dir_remove("data/prll/11/12/13/14/15/16", p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + rv = apr_dir_remove("data/prll/11/12/13/14/15", p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + rv = apr_dir_remove("data/prll/11/12/13/14", p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + rv = apr_dir_remove("data/prll/11/12/13", p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + rv = apr_dir_remove("data/prll/11/12", p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + rv = apr_dir_remove("data/prll/11", p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + rv = apr_dir_remove("data/prll", p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + rv = apr_dir_remove("data/fortytwo", p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); +} + +static void test_remove_notthere(abts_case *tc, void *data) +{ + apr_status_t rv; + + rv = apr_dir_remove("data/notthere", p); + ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_ENOENT(rv)); +} + +static void test_mkdir_twice(abts_case *tc, void *data) +{ + apr_status_t rv; + + rv = apr_dir_make("data/testdir", APR_FPROT_UREAD | APR_FPROT_UWRITE | APR_FPROT_UEXECUTE, + p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + rv = apr_dir_make("data/testdir", APR_FPROT_UREAD | APR_FPROT_UWRITE | APR_FPROT_UEXECUTE, + p); + ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_EEXIST(rv)); + + rv = apr_dir_remove("data/testdir", p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); +} + +static void test_opendir(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_dir_t *dir; + + rv = apr_dir_open(&dir, "data", p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + apr_dir_close(dir); +} + +static void test_opendir_notthere(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_dir_t *dir; + + rv = apr_dir_open(&dir, "notthere", p); + ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_ENOENT(rv)); +} + +static void test_closedir(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_dir_t *dir; + + rv = apr_dir_open(&dir, "data", p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + rv = apr_dir_close(dir); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); +} + +static void test_rewind(abts_case *tc, void *data) +{ + apr_dir_t *dir; + apr_finfo_t first, second; + + APR_ASSERT_SUCCESS(tc, "apr_dir_open failed", apr_dir_open(&dir, "data", p)); + + APR_ASSERT_SUCCESS(tc, "apr_dir_read failed", + apr_dir_read(&first, APR_FINFO_DIRENT, dir)); + + APR_ASSERT_SUCCESS(tc, "apr_dir_rewind failed", apr_dir_rewind(dir)); + + APR_ASSERT_SUCCESS(tc, "second apr_dir_read failed", + apr_dir_read(&second, APR_FINFO_DIRENT, dir)); + + APR_ASSERT_SUCCESS(tc, "apr_dir_close failed", apr_dir_close(dir)); + + ABTS_STR_EQUAL(tc, first.name, second.name); +} + +/* Test for a (fixed) bug in apr_dir_read(). This bug only happened + in threadless cases. */ +static void test_uncleared_errno(abts_case *tc, void *data) +{ + apr_file_t *thefile = NULL; + apr_finfo_t finfo; + apr_int32_t finfo_flags = APR_FINFO_TYPE | APR_FINFO_NAME; + apr_dir_t *this_dir; + apr_status_t rv; + + rv = apr_dir_make("dir1", APR_FPROT_OS_DEFAULT, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + rv = apr_dir_make("dir2", APR_FPROT_OS_DEFAULT, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + rv = apr_file_open(&thefile, "dir1/file1", + APR_FOPEN_READ | APR_FOPEN_WRITE | APR_FOPEN_CREATE, + APR_FPROT_OS_DEFAULT, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + rv = apr_file_close(thefile); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + /* Try to remove dir1. This should fail because it's not empty. + However, on a platform with threads disabled (such as FreeBSD), + `errno' will be set as a result. */ + rv = apr_dir_remove("dir1", p); + ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_ENOTEMPTY(rv)); + + /* Read `.' and `..' out of dir2. */ + rv = apr_dir_open(&this_dir, "dir2", p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + rv = apr_dir_read(&finfo, finfo_flags, this_dir); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + rv = apr_dir_read(&finfo, finfo_flags, this_dir); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + /* Now, when we attempt to do a third read of empty dir2, and the + underlying system readdir() returns NULL, the old value of + errno shouldn't cause a false alarm. We should get an ENOENT + back from apr_dir_read, and *not* the old errno. */ + rv = apr_dir_read(&finfo, finfo_flags, this_dir); + ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_ENOENT(rv)); + + rv = apr_dir_close(this_dir); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + /* Cleanup */ + rv = apr_file_remove("dir1/file1", p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + rv = apr_dir_remove("dir1", p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + rv = apr_dir_remove("dir2", p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + +} + +static void test_rmkdir_nocwd(abts_case *tc, void *data) +{ + char *cwd, *path; + + APR_ASSERT_SUCCESS(tc, "make temp dir", + apr_dir_make("dir3", APR_FPROT_OS_DEFAULT, p)); + + APR_ASSERT_SUCCESS(tc, "obtain cwd", apr_filepath_get(&cwd, 0, p)); + + APR_ASSERT_SUCCESS(tc, "determine path to temp dir", + apr_filepath_merge(&path, cwd, "dir3", 0, p)); + + APR_ASSERT_SUCCESS(tc, "change to temp dir", apr_filepath_set(path, p)); + + APR_ASSERT_SUCCESS(tc, "restore cwd", apr_filepath_set(cwd, p)); + + APR_ASSERT_SUCCESS(tc, "remove cwd", apr_dir_remove(path, p)); +} + + +abts_suite *testdir(abts_suite *suite) +{ + suite = ADD_SUITE(suite) + + abts_run_test(suite, test_mkdir, NULL); + abts_run_test(suite, test_mkdir_recurs, NULL); + abts_run_test(suite, test_mkdir_recurs_parallel, NULL); + abts_run_test(suite, test_remove, NULL); + abts_run_test(suite, test_removeall_fail, NULL); + abts_run_test(suite, test_removeall, NULL); + abts_run_test(suite, test_remove_notthere, NULL); + abts_run_test(suite, test_mkdir_twice, NULL); + abts_run_test(suite, test_rmkdir_nocwd, NULL); + + abts_run_test(suite, test_rewind, NULL); + + abts_run_test(suite, test_opendir, NULL); + abts_run_test(suite, test_opendir_notthere, NULL); + abts_run_test(suite, test_closedir, NULL); + abts_run_test(suite, test_uncleared_errno, NULL); + + return suite; +} + diff --git a/test/testdll.dsp b/test/testdll.dsp new file mode 100644 index 00000000000..e19285d457a --- /dev/null +++ b/test/testdll.dsp @@ -0,0 +1,462 @@ +# Microsoft Developer Studio Project File - Name="testdll" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) External Target" 0x0106 + +CFG=testdll - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "testdll.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "testdll.mak" CFG="testdll - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "testdll - Win32 Release" (based on "Win32 (x86) External Target") +!MESSAGE "testdll - Win32 Debug" (based on "Win32 (x86) External Target") +!MESSAGE "testdll - Win32 Release9x" (based on "Win32 (x86) External Target") +!MESSAGE "testdll - Win32 Debug9x" (based on "Win32 (x86) External Target") +!MESSAGE "testdll - x64 Release" (based on "Win32 (x86) External Target") +!MESSAGE "testdll - x64 Debug" (based on "Win32 (x86) External Target") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" + +!IF "$(CFG)" == "testdll - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "" +# PROP BASE Intermediate_Dir "" +# PROP BASE Cmd_Line "NMAKE /f Makefile.win INTDIR=Release OUTDIR=Release MODEL=dynamic all check" +# PROP BASE Rebuild_Opt "/a" +# PROP BASE Target_File "Release\testall.exe" +# PROP BASE Bsc_Name "" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "" +# PROP Intermediate_Dir "" +# PROP Cmd_Line "NMAKE /f Makefile.win INTDIR=Release OUTDIR=Release MODEL=dynamic all check" +# PROP Rebuild_Opt "/a" +# PROP Target_File "Release\testall.exe" +# PROP Bsc_Name "" +# PROP Target_Dir "" + +!ELSEIF "$(CFG)" == "testdll - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "" +# PROP BASE Intermediate_Dir "" +# PROP BASE Cmd_Line "NMAKE /f Makefile.win INTDIR=Debug OUTDIR=Debug MODEL=dynamic _DEBUG=1 all check" +# PROP BASE Rebuild_Opt "/a" +# PROP BASE Target_File "Debug\testall.exe" +# PROP BASE Bsc_Name "" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "" +# PROP Intermediate_Dir "" +# PROP Cmd_Line "NMAKE /f Makefile.win INTDIR=Debug OUTDIR=Debug MODEL=dynamic _DEBUG=1 all check" +# PROP Rebuild_Opt "/a" +# PROP Target_File "Debug\testall.exe" +# PROP Bsc_Name "" +# PROP Target_Dir "" + +!ELSEIF "$(CFG)" == "testdll - Win32 Release9x" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "" +# PROP BASE Intermediate_Dir "" +# PROP BASE Cmd_Line "NMAKE /f Makefile.win INTDIR=9x\Release OUTDIR=9x\Release MODEL=dynamic all check" +# PROP BASE Rebuild_Opt "/a" +# PROP BASE Target_File "9x\Release\testall.exe" +# PROP BASE Bsc_Name "" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "" +# PROP Intermediate_Dir "" +# PROP Cmd_Line "NMAKE /f Makefile.win INTDIR=9x\Release OUTDIR=9x\Release MODEL=dynamic all check" +# PROP Rebuild_Opt "/a" +# PROP Target_File "9x\Release\testall.exe" +# PROP Bsc_Name "" +# PROP Target_Dir "" + +!ELSEIF "$(CFG)" == "testdll - Win32 Debug9x" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "" +# PROP BASE Intermediate_Dir "" +# PROP BASE Cmd_Line "NMAKE /f Makefile.win INTDIR=9x\Debug OUTDIR=9x\Debug MODEL=dynamic _DEBUG=1 all check" +# PROP BASE Rebuild_Opt "/a" +# PROP BASE Target_File "9x\Debug\testall.exe" +# PROP BASE Bsc_Name "" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "" +# PROP Intermediate_Dir "" +# PROP Cmd_Line "NMAKE /f Makefile.win INTDIR=9x\Debug OUTDIR=9x\Debug MODEL=dynamic _DEBUG=1 all check" +# PROP Rebuild_Opt "/a" +# PROP Target_File "9x\Debug\testall.exe" +# PROP Bsc_Name "" +# PROP Target_Dir "" + +!ELSEIF "$(CFG)" == "testdll - x64 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "" +# PROP BASE Intermediate_Dir "" +# PROP BASE Cmd_Line "NMAKE /f Makefile.win INTDIR=x64\Release OUTDIR=x64\Release MODEL=dynamic all check" +# PROP BASE Rebuild_Opt "/a" +# PROP BASE Target_File "x64\Release\testall.exe" +# PROP BASE Bsc_Name "" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "" +# PROP Intermediate_Dir "" +# PROP Cmd_Line "NMAKE /f Makefile.win INTDIR=x64\Release OUTDIR=x64\Release MODEL=dynamic all check" +# PROP Rebuild_Opt "/a" +# PROP Target_File "x64\Release\testall.exe" +# PROP Bsc_Name "" +# PROP Target_Dir "" + +!ELSEIF "$(CFG)" == "testdll - x64 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "" +# PROP BASE Intermediate_Dir "" +# PROP BASE Cmd_Line "NMAKE /f Makefile.win INTDIR=x64\Debug OUTDIR=x64\Debug MODEL=dynamic _DEBUG=1 all check" +# PROP BASE Rebuild_Opt "/a" +# PROP BASE Target_File "x64\Debug\testall.exe" +# PROP BASE Bsc_Name "" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "" +# PROP Intermediate_Dir "" +# PROP Cmd_Line "NMAKE /f Makefile.win INTDIR=x64\Debug OUTDIR=x64\Debug MODEL=dynamic _DEBUG=1 all check" +# PROP Rebuild_Opt "/a" +# PROP Target_File "x64\Debug\testall.exe" +# PROP Bsc_Name "" +# PROP Target_Dir "" + +!ENDIF + +# Begin Target + +# Name "testdll - Win32 Release" +# Name "testdll - Win32 Debug" +# Name "testdll - Win32 Release9x" +# Name "testdll - Win32 Debug9x" +# Name "testdll - x64 Release" +# Name "testdll - x64 Debug" +# Begin Group "testall Source Files" + +# PROP Default_Filter ".c" +# Begin Source File + +SOURCE=.\abts.c +# End Source File +# Begin Source File + +SOURCE=.\abts.h +# End Source File +# Begin Source File + +SOURCE=.\abts_tests.h +# End Source File +# Begin Source File + +SOURCE=.\testapp.c +# End Source File +# Begin Source File + +SOURCE=.\testargs.c +# End Source File +# Begin Source File + +SOURCE=.\testatomic.c +# End Source File +# Begin Source File + +SOURCE=.\testcond.c +# End Source File +# Begin Source File + +SOURCE=.\testdir.c +# End Source File +# Begin Source File + +SOURCE=.\testdso.c +# End Source File +# Begin Source File + +SOURCE=.\testdup.c +# End Source File +# Begin Source File + +SOURCE=.\testenv.c +# End Source File +# Begin Source File + +SOURCE=.\testfile.c +# End Source File +# Begin Source File + +SOURCE=.\testfilecopy.c +# End Source File +# Begin Source File + +SOURCE=.\testfileinfo.c +# End Source File +# Begin Source File + +SOURCE=.\testflock.c +# End Source File +# Begin Source File + +SOURCE=.\testflock.h +# End Source File +# Begin Source File + +SOURCE=.\testfmt.c +# End Source File +# Begin Source File + +SOURCE=.\testfnmatch.c +# End Source File +# Begin Source File + +SOURCE=.\testglobalmutex.c +# End Source File +# Begin Source File + +SOURCE=.\testglobalmutex.h +# End Source File +# Begin Source File + +SOURCE=.\testhash.c +# End Source File +# Begin Source File + +SOURCE=.\testipsub.c +# End Source File +# Begin Source File + +SOURCE=.\testlfs.c +# End Source File +# Begin Source File + +SOURCE=.\testlfsabi.c +# End Source File +# Begin Source File + +SOURCE=.\testlfsabi.h +# End Source File +# Begin Source File + +SOURCE=.\testlfsabi_include.c +# End Source File +# Begin Source File + +SOURCE=.\testlfsabi32.c +# End Source File +# Begin Source File + +SOURCE=.\testlfsabi64.c +# End Source File +# Begin Source File + +SOURCE=.\testlock.c +# End Source File +# Begin Source File + +SOURCE=.\testmmap.c +# End Source File +# Begin Source File + +SOURCE=.\testnames.c +# End Source File +# Begin Source File + +SOURCE=.\testoc.c +# End Source File +# Begin Source File + +SOURCE=.\testpath.c +# End Source File +# Begin Source File + +SOURCE=.\testpipe.c +# End Source File +# Begin Source File + +SOURCE=.\testpoll.c +# End Source File +# Begin Source File + +SOURCE=.\testpools.c +# End Source File +# Begin Source File + +SOURCE=.\testproc.c +# End Source File +# Begin Source File + +SOURCE=.\testrand.c +# End Source File +# Begin Source File + +SOURCE=.\testshm.c +# End Source File +# Begin Source File + +SOURCE=.\testshm.h +# End Source File +# Begin Source File + +SOURCE=.\testsleep.c +# End Source File +# Begin Source File + +SOURCE=.\testsock.c +# End Source File +# Begin Source File + +SOURCE=.\testsock.h +# End Source File +# Begin Source File + +SOURCE=.\testsockets.c +# End Source File +# Begin Source File + +SOURCE=.\testsockopt.c +# End Source File +# Begin Source File + +SOURCE=.\teststr.c +# End Source File +# Begin Source File + +SOURCE=.\teststrnatcmp.c +# End Source File +# Begin Source File + +SOURCE=.\testtable.c +# End Source File +# Begin Source File + +SOURCE=.\testtemp.c +# End Source File +# Begin Source File + +SOURCE=.\testthread.c +# End Source File +# Begin Source File + +SOURCE=.\testtime.c +# End Source File +# Begin Source File + +SOURCE=.\testud.c +# End Source File +# Begin Source File + +SOURCE=.\testuser.c +# End Source File +# Begin Source File + +SOURCE=.\testutil.c +# End Source File +# Begin Source File + +SOURCE=.\testutil.h +# End Source File +# Begin Source File + +SOURCE=.\testvsn.c +# End Source File +# End Group +# Begin Group "Other Source Files" + +# PROP Default_Filter ".c" +# Begin Source File + +SOURCE=.\globalmutexchild.c +# End Source File +# Begin Source File + +SOURCE=.\mod_test.c +# End Source File +# Begin Source File + +SOURCE=.\nw_misc.c +# End Source File +# Begin Source File + +SOURCE=.\occhild.c +# End Source File +# Begin Source File + +SOURCE=.\proc_child.c +# End Source File +# Begin Source File + +SOURCE=.\readchild.c +# End Source File +# Begin Source File + +SOURCE=.\sendfile.c +# End Source File +# Begin Source File + +SOURCE=.\sockchild.c +# End Source File +# Begin Source File + +SOURCE=.\testlockperf.c +# End Source File +# Begin Source File + +SOURCE=.\testmutexscope.c +# End Source File +# Begin Source File + +SOURCE=.\testprocmutex.c +# End Source File +# Begin Source File + +SOURCE=.\testshmconsumer.c +# End Source File +# Begin Source File + +SOURCE=.\testshmproducer.c +# End Source File +# Begin Source File + +SOURCE=.\tryread.c +# End Source File +# End Group +# Begin Source File + +SOURCE=.\Makefile.win +# End Source File +# End Target +# End Project diff --git a/test/testdso.c b/test/testdso.c index ecc6eeaa119..0d9f27bb2ee 100644 --- a/test/testdso.c +++ b/test/testdso.c @@ -1,100 +1,263 @@ +/* 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 "testutil.h" #include "apr_general.h" #include "apr_pools.h" #include "apr_errno.h" #include "apr_dso.h" -#include <string.h> -#include <stdlib.h> +#include "apr_strings.h" +#include "apr_file_info.h" +#if APR_HAVE_UNISTD_H +#include <unistd.h> +#endif + +#if APR_HAS_DSO -#define LIB_NAME "mod_test.so" +#ifdef NETWARE +# define MOD_NAME "mod_test.nlm" +#elif defined(BEOS) || defined(__MVS__) +# define MOD_NAME "mod_test.so" +#elif defined(WIN32) +# define MOD_NAME TESTBINPATH "mod_test.dll" +#elif defined(DARWIN) +# define MOD_NAME ".libs/mod_test.so" +# define LIB_NAME ".libs/libmod_test.dylib" +#elif (defined(__hpux__) || defined(__hpux)) && !defined(__ia64) +# define MOD_NAME ".libs/mod_test.sl" +# define LIB_NAME ".libs/libmod_test.sl" +#elif defined(_AIX) || defined(__bsdi__) +# define MOD_NAME ".libs/libmod_test.so" +# define LIB_NAME ".libs/libmod_test.so" +#else /* Every other Unix */ +# define MOD_NAME ".libs/mod_test.so" +# define LIB_NAME ".libs/libmod_test.so" +#endif -int main (int argc, char ** argv) +static char *modname; + +static void test_load_module(abts_case *tc, void *data) { - ap_dso_handle_t *h = NULL; - ap_dso_handle_sym_t func1 = NULL; - ap_dso_handle_sym_t func2 = NULL; - ap_pool_t *cont; - void (*function)(void); - void (*function1)(int); - int *retval; - char filename[256]; - - getcwd(filename, 256); - strcat(filename, "/"); - strcat(filename, LIB_NAME); - - ap_initialize(); - atexit(ap_terminate); - - if (ap_create_pool(&cont, NULL) != APR_SUCCESS) { - fprintf(stderr, "Couldn't allocate context."); - exit(-1); - } + apr_dso_handle_t *h = NULL; + apr_status_t status; + char errstr[256]; - fprintf(stdout,"Initializing DSO's........................."); - if (ap_dso_init() != APR_SUCCESS) { - fprintf(stderr, "Couldn't initialize DSO's !"); - exit (-1); - } - fprintf(stdout,"OK\n"); - fprintf(stdout,"Trying to load DSO now....................."); - fflush(stdout); - if (ap_dso_load(&h, filename, cont) != APR_SUCCESS){ - fprintf(stderr, "Failed to load %s!\n", filename); - exit (-1); + status = apr_dso_load(&h, modname, p); + ABTS_ASSERT(tc, apr_dso_error(h, errstr, 256), APR_SUCCESS == status); + ABTS_PTR_NOTNULL(tc, h); + + apr_dso_unload(h); +} + +static void test_dso_sym(abts_case *tc, void *data) +{ + apr_dso_handle_t *h = NULL; + apr_dso_handle_sym_t func1 = NULL; + apr_status_t status; + void (*function)(char str[256]); + char teststr[256]; + char errstr[256]; + + status = apr_dso_load(&h, modname, p); + ABTS_ASSERT(tc, apr_dso_error(h, errstr, 256), APR_SUCCESS == status); + ABTS_PTR_NOTNULL(tc, h); + + status = apr_dso_sym(&func1, h, "print_hello"); + ABTS_ASSERT(tc, apr_dso_error(h, errstr, 256), APR_SUCCESS == status); + ABTS_PTR_NOTNULL(tc, func1); + + if (!tc->failed) { + function = (void (*)(char *))func1; + (*function)(teststr); + ABTS_STR_EQUAL(tc, "Hello - I'm a DSO!\n", teststr); } - fprintf(stdout,"OK\n"); - - fprintf(stdout,"Trying to get the DSO's attention.........."); - fflush(stdout); - if (ap_dso_sym(&func1, h, "print_hello") != APR_SUCCESS) { - fprintf(stderr, "Failed!\n"); - exit (-1); - } - fprintf(stdout,"OK\n"); - - function = (void *)func1; - (*function)(); - - fprintf(stdout,"Saying farewell 5 times...................."); - fflush(stdout); - if (ap_dso_sym(&func2, h, "print_goodbye") != APR_SUCCESS) { - fprintf(stderr, "Failed!\n"); - exit (-1); - } - fprintf(stdout,"OK\n"); - - function1 = (void *)(int)func2; - (*function1)(5); - - fprintf(stdout,"Checking how many times I said goodbye.."); - fflush(stdout); - if (ap_dso_sym(&func1, h, "goodbyes") != APR_SUCCESS) { - fprintf(stderr, "Failed!\n"); - exit (-1); + + apr_dso_unload(h); +} + +static void test_dso_sym_return_value(abts_case *tc, void *data) +{ + apr_dso_handle_t *h = NULL; + apr_dso_handle_sym_t func1 = NULL; + apr_status_t status; + int (*function)(int); + char errstr[256]; + + status = apr_dso_load(&h, modname, p); + ABTS_ASSERT(tc, apr_dso_error(h, errstr, 256), APR_SUCCESS == status); + ABTS_PTR_NOTNULL(tc, h); + + status = apr_dso_sym(&func1, h, "count_reps"); + ABTS_ASSERT(tc, apr_dso_error(h, errstr, 256), APR_SUCCESS == status); + ABTS_PTR_NOTNULL(tc, func1); + + if (!tc->failed) { + function = (int (*)(int))func1; + status = (*function)(5); + ABTS_INT_EQUAL(tc, 5, status); } - retval = (int *)func1; - fprintf(stdout,"%d..", (*retval)); - fflush(stdout); - if ((*retval) == 5){ - fprintf(stderr,"OK\n"); - } else { - fprintf(stderr,"Failed!\n"); + + apr_dso_unload(h); +} + +static void test_unload_module(abts_case *tc, void *data) +{ + apr_dso_handle_t *h = NULL; + apr_status_t status; + char errstr[256]; + apr_dso_handle_sym_t func1 = NULL; + + status = apr_dso_load(&h, modname, p); + ABTS_ASSERT(tc, apr_dso_error(h, errstr, 256), APR_SUCCESS == status); + ABTS_PTR_NOTNULL(tc, h); + + status = apr_dso_unload(h); + ABTS_ASSERT(tc, apr_dso_error(h, errstr, 256), APR_SUCCESS == status); + + status = apr_dso_sym(&func1, h, "print_hello"); + ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_ESYMNOTFOUND(status)); +} + + +#ifdef LIB_NAME +static char *libname; + +static void test_load_library(abts_case *tc, void *data) +{ + apr_dso_handle_t *h = NULL; + apr_status_t status; + char errstr[256]; + + status = apr_dso_load(&h, libname, p); + ABTS_ASSERT(tc, apr_dso_error(h, errstr, 256), APR_SUCCESS == status); + ABTS_PTR_NOTNULL(tc, h); + + apr_dso_unload(h); +} + +static void test_dso_sym_library(abts_case *tc, void *data) +{ + apr_dso_handle_t *h = NULL; + apr_dso_handle_sym_t func1 = NULL; + apr_status_t status; + void (*function)(char str[256]); + char teststr[256]; + char errstr[256]; + + status = apr_dso_load(&h, libname, p); + ABTS_ASSERT(tc, apr_dso_error(h, errstr, 256), APR_SUCCESS == status); + ABTS_PTR_NOTNULL(tc, h); + + status = apr_dso_sym(&func1, h, "print_hello"); + ABTS_ASSERT(tc, apr_dso_error(h, errstr, 256), APR_SUCCESS == status); + ABTS_PTR_NOTNULL(tc, func1); + + if (!tc->failed) { + function = (void (*)(char *))func1; + (*function)(teststr); + ABTS_STR_EQUAL(tc, "Hello - I'm a DSO!\n", teststr); } - - fprintf(stdout,"Trying to unload DSO now..................."); - if (ap_dso_unload(h) != APR_SUCCESS) { - fprintf(stderr, "Failed!\n"); - exit (-1); + + apr_dso_unload(h); +} + +static void test_dso_sym_return_value_library(abts_case *tc, void *data) +{ + apr_dso_handle_t *h = NULL; + apr_dso_handle_sym_t func1 = NULL; + apr_status_t status; + int (*function)(int); + char errstr[256]; + + status = apr_dso_load(&h, libname, p); + ABTS_ASSERT(tc, apr_dso_error(h, errstr, 256), APR_SUCCESS == status); + ABTS_PTR_NOTNULL(tc, h); + + status = apr_dso_sym(&func1, h, "count_reps"); + ABTS_ASSERT(tc, apr_dso_error(h, errstr, 256), APR_SUCCESS == status); + ABTS_PTR_NOTNULL(tc, func1); + + if (!tc->failed) { + function = (int (*)(int))func1; + status = (*function)(5); + ABTS_INT_EQUAL(tc, 5, status); } - fprintf(stdout,"OK\n"); - - fprintf(stdout,"Checking it's been unloaded................"); - fflush(stdout); - if (ap_dso_sym(&func1, h, "print_hello") == APR_SUCCESS) { - fprintf(stderr, "Failed!\n"); - exit (-1); - } - fprintf(stdout,"OK\n"); + + apr_dso_unload(h); +} + +static void test_unload_library(abts_case *tc, void *data) +{ + apr_dso_handle_t *h = NULL; + apr_status_t status; + char errstr[256]; + apr_dso_handle_sym_t func1 = NULL; + + status = apr_dso_load(&h, libname, p); + ABTS_ASSERT(tc, apr_dso_error(h, errstr, 256), APR_SUCCESS == status); + ABTS_PTR_NOTNULL(tc, h); + + status = apr_dso_unload(h); + ABTS_ASSERT(tc, apr_dso_error(h, errstr, 256), APR_SUCCESS == status); + + status = apr_dso_sym(&func1, h, "print_hello"); + ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_ESYMNOTFOUND(status)); +} + +#endif /* def(LIB_NAME) */ + +static void test_load_notthere(abts_case *tc, void *data) +{ + apr_dso_handle_t *h = NULL; + apr_status_t status; + + status = apr_dso_load(&h, "No_File.so", p); + + ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_EDSOOPEN(status)); + ABTS_PTR_NOTNULL(tc, h); +} + +#endif /* APR_HAS_DSO */ + +abts_suite *testdso(abts_suite *suite) +{ + suite = ADD_SUITE(suite) + +#if APR_HAS_DSO + apr_filepath_merge(&modname, NULL, MOD_NAME, 0, p); + + abts_run_test(suite, test_load_module, NULL); + abts_run_test(suite, test_dso_sym, NULL); + abts_run_test(suite, test_dso_sym_return_value, NULL); + abts_run_test(suite, test_unload_module, NULL); + +#ifdef LIB_NAME + apr_filepath_merge(&libname, NULL, LIB_NAME, 0, p); - return 0; + abts_run_test(suite, test_load_library, NULL); + abts_run_test(suite, test_dso_sym_library, NULL); + abts_run_test(suite, test_dso_sym_return_value_library, NULL); + abts_run_test(suite, test_unload_library, NULL); +#endif + + abts_run_test(suite, test_load_notthere, NULL); +#endif /* APR_HAS_DSO */ + + return suite; } + diff --git a/test/testdup.c b/test/testdup.c new file mode 100644 index 00000000000..2a261f2d798 --- /dev/null +++ b/test/testdup.c @@ -0,0 +1,198 @@ +/* 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_general.h" +#include "apr_pools.h" +#include "apr_errno.h" +#include "apr_file_io.h" +#include "testutil.h" + +#define TEST "Testing\n" +#define TEST2 "Testing again\n" +#define FILEPATH "data/" + +static void test_file_dup(abts_case *tc, void *data) +{ + apr_file_t *file1 = NULL; + apr_file_t *file3 = NULL; + apr_status_t rv; + apr_finfo_t finfo; + + /* First, create a new file, empty... */ + rv = apr_file_open(&file1, FILEPATH "testdup.file", + APR_FOPEN_READ | APR_FOPEN_WRITE | APR_FOPEN_CREATE | + APR_FOPEN_DELONCLOSE, APR_FPROT_OS_DEFAULT, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_PTR_NOTNULL(tc, file1); + + rv = apr_file_dup(&file3, file1, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_PTR_NOTNULL(tc, file3); + + rv = apr_file_close(file1); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + /* cleanup after ourselves */ + rv = apr_file_close(file3); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + rv = apr_stat(&finfo, FILEPATH "testdup.file", APR_FINFO_NORM, p); + ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_ENOENT(rv)); +} + +static void test_file_readwrite(abts_case *tc, void *data) +{ + apr_file_t *file1 = NULL; + apr_file_t *file3 = NULL; + apr_status_t rv; + apr_finfo_t finfo; + apr_size_t txtlen = sizeof(TEST); + char buff[50]; + apr_off_t fpos; + + /* First, create a new file, empty... */ + rv = apr_file_open(&file1, FILEPATH "testdup.readwrite.file", + APR_FOPEN_READ | APR_FOPEN_WRITE | APR_FOPEN_CREATE | + APR_FOPEN_DELONCLOSE, APR_FPROT_OS_DEFAULT, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_PTR_NOTNULL(tc, file1); + + rv = apr_file_dup(&file3, file1, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_PTR_NOTNULL(tc, file3); + + rv = apr_file_write(file3, TEST, &txtlen); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_SIZE_EQUAL(tc, sizeof(TEST), txtlen); + + fpos = 0; + rv = apr_file_seek(file1, APR_SET, &fpos); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_ASSERT(tc, "File position mismatch, expected 0", fpos == 0); + + txtlen = 50; + rv = apr_file_read(file1, buff, &txtlen); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_STR_EQUAL(tc, TEST, buff); + + /* cleanup after ourselves */ + rv = apr_file_close(file1); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + rv = apr_file_close(file3); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + rv = apr_stat(&finfo, FILEPATH "testdup.readwrite.file", APR_FINFO_NORM, p); + ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_ENOENT(rv)); +} + +static void test_dup2(abts_case *tc, void *data) +{ + apr_file_t *testfile = NULL; + apr_file_t *errfile = NULL; + apr_file_t *saveerr = NULL; + apr_status_t rv; + + rv = apr_file_open(&testfile, FILEPATH "testdup2.file", + APR_FOPEN_READ | APR_FOPEN_WRITE | APR_FOPEN_CREATE | + APR_FOPEN_DELONCLOSE, APR_FPROT_OS_DEFAULT, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_PTR_NOTNULL(tc, testfile); + + rv = apr_file_open_stderr(&errfile, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + /* Set aside the real errfile */ + rv = apr_file_dup(&saveerr, errfile, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_PTR_NOTNULL(tc, saveerr); + + rv = apr_file_dup2(errfile, testfile, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_PTR_NOTNULL(tc, errfile); + + apr_file_close(testfile); + + rv = apr_file_dup2(errfile, saveerr, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_PTR_NOTNULL(tc, errfile); + + apr_file_close(saveerr); +} + +static void test_dup2_readwrite(abts_case *tc, void *data) +{ + apr_file_t *errfile = NULL; + apr_file_t *testfile = NULL; + apr_file_t *saveerr = NULL; + apr_status_t rv; + apr_size_t txtlen = sizeof(TEST); + char buff[50]; + apr_off_t fpos; + + rv = apr_file_open(&testfile, FILEPATH "testdup2.readwrite.file", + APR_FOPEN_READ | APR_FOPEN_WRITE | APR_FOPEN_CREATE | + APR_FOPEN_DELONCLOSE, APR_FPROT_OS_DEFAULT, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_PTR_NOTNULL(tc, testfile); + + rv = apr_file_open_stderr(&errfile, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + /* Set aside the real errfile */ + rv = apr_file_dup(&saveerr, errfile, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_PTR_NOTNULL(tc, saveerr); + + rv = apr_file_dup2(errfile, testfile, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_PTR_NOTNULL(tc, errfile); + + txtlen = sizeof(TEST2); + rv = apr_file_write(errfile, TEST2, &txtlen); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_SIZE_EQUAL(tc, sizeof(TEST2), txtlen); + + fpos = 0; + rv = apr_file_seek(testfile, APR_SET, &fpos); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_ASSERT(tc, "File position mismatch, expected 0", fpos == 0); + + txtlen = 50; + rv = apr_file_read(testfile, buff, &txtlen); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_STR_EQUAL(tc, TEST2, buff); + + apr_file_close(testfile); + + rv = apr_file_dup2(errfile, saveerr, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_PTR_NOTNULL(tc, errfile); + + apr_file_close(saveerr); +} + +abts_suite *testdup(abts_suite *suite) +{ + suite = ADD_SUITE(suite) + + abts_run_test(suite, test_file_dup, NULL); + abts_run_test(suite, test_file_readwrite, NULL); + abts_run_test(suite, test_dup2, NULL); + abts_run_test(suite, test_dup2_readwrite, NULL); + + return suite; +} + diff --git a/test/testenv.c b/test/testenv.c new file mode 100644 index 00000000000..f5a74c38d91 --- /dev/null +++ b/test/testenv.c @@ -0,0 +1,144 @@ +/* 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_env.h" +#include "apr_errno.h" +#include "testutil.h" + +#define TEST_ENVVAR_NAME "apr_test_envvar" +#define TEST_ENVVAR2_NAME "apr_test_envvar2" +#define TEST_ENVVAR_VALUE "Just a value that we'll check" + +static int have_env_set; +static int have_env_get; +static int have_env_del; + +static void test_setenv(abts_case *tc, void *data) +{ + apr_status_t rv; + + rv = apr_env_set(TEST_ENVVAR_NAME, TEST_ENVVAR_VALUE, p); + have_env_set = (rv != APR_ENOTIMPL); + if (!have_env_set) { + ABTS_NOT_IMPL(tc, "apr_env_set"); + } else { + APR_ASSERT_SUCCESS(tc, "set environment variable", rv); + } +} + +static void test_getenv(abts_case *tc, void *data) +{ + char *value; + apr_status_t rv; + + if (!have_env_set) { + ABTS_NOT_IMPL(tc, "apr_env_set (skip test for apr_env_get)"); + return; + } + + rv = apr_env_get(&value, TEST_ENVVAR_NAME, p); + have_env_get = (rv != APR_ENOTIMPL); + if (!have_env_get) { + ABTS_NOT_IMPL(tc, "apr_env_get"); + return; + } + APR_ASSERT_SUCCESS(tc, "get environment variable", rv); + ABTS_STR_EQUAL(tc, TEST_ENVVAR_VALUE, value); +} + +static void test_delenv(abts_case *tc, void *data) +{ + char *value; + apr_status_t rv; + + if (!have_env_set) { + ABTS_NOT_IMPL(tc, "apr_env_set (skip test for apr_env_delete)"); + return; + } + + rv = apr_env_delete(TEST_ENVVAR_NAME, p); + have_env_del = (rv != APR_ENOTIMPL); + if (!have_env_del) { + ABTS_NOT_IMPL(tc, "apr_env_delete"); + return; + } + APR_ASSERT_SUCCESS(tc, "delete environment variable", rv); + + if (!have_env_get) { + ABTS_NOT_IMPL(tc, "apr_env_get (skip sanity check for apr_env_delete)"); + return; + } + rv = apr_env_get(&value, TEST_ENVVAR_NAME, p); + ABTS_INT_EQUAL(tc, APR_ENOENT, rv); +} + +/** http://issues.apache.org/bugzilla/show_bug.cgi?id=40764 */ +static void test_emptyenv(abts_case *tc, void *data) +{ + char *value; + apr_status_t rv; + + if (!(have_env_set && have_env_get)) { + ABTS_NOT_IMPL(tc, "apr_env_set (skip test_emptyenv)"); + return; + } + /** Set empty string and test that rv != ENOENT) */ + rv = apr_env_set(TEST_ENVVAR_NAME, "", p); + APR_ASSERT_SUCCESS(tc, "set environment variable", rv); + rv = apr_env_get(&value, TEST_ENVVAR_NAME, p); + APR_ASSERT_SUCCESS(tc, "get environment variable", rv); + ABTS_STR_EQUAL(tc, "", value); + + if (!have_env_del) { + ABTS_NOT_IMPL(tc, "apr_env (skip recycle test_emptyenv)"); + return; + } + /** Delete and retest */ + rv = apr_env_delete(TEST_ENVVAR_NAME, p); + APR_ASSERT_SUCCESS(tc, "delete environment variable", rv); + rv = apr_env_get(&value, TEST_ENVVAR_NAME, p); + ABTS_INT_EQUAL(tc, APR_ENOENT, rv); + + /** Set second variable + test*/ + rv = apr_env_set(TEST_ENVVAR2_NAME, TEST_ENVVAR_VALUE, p); + APR_ASSERT_SUCCESS(tc, "set second environment variable", rv); + rv = apr_env_get(&value, TEST_ENVVAR2_NAME, p); + APR_ASSERT_SUCCESS(tc, "get second environment variable", rv); + ABTS_STR_EQUAL(tc, TEST_ENVVAR_VALUE, value); + + /** Finally, test ENOENT (first variable) followed by second != ENOENT) */ + rv = apr_env_get(&value, TEST_ENVVAR_NAME, p); + ABTS_INT_EQUAL(tc, APR_ENOENT, rv); + rv = apr_env_get(&value, TEST_ENVVAR2_NAME, p); + APR_ASSERT_SUCCESS(tc, "verify second environment variable", rv); + ABTS_STR_EQUAL(tc, TEST_ENVVAR_VALUE, value); + + /** Cleanup */ + apr_env_delete(TEST_ENVVAR2_NAME, p); +} + +abts_suite *testenv(abts_suite *suite) +{ + suite = ADD_SUITE(suite) + + abts_run_test(suite, test_setenv, NULL); + abts_run_test(suite, test_getenv, NULL); + abts_run_test(suite, test_delenv, NULL); + abts_run_test(suite, test_emptyenv, NULL); + + return suite; +} + diff --git a/test/testescape.c b/test/testescape.c new file mode 100644 index 00000000000..66452274d5f --- /dev/null +++ b/test/testescape.c @@ -0,0 +1,311 @@ +/* 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 <assert.h> +#include <stdio.h> +#include <stdlib.h> + +#include "apr_escape.h" +#include "apr_strings.h" + +#include "abts.h" +#include "testutil.h" + +static void test_escape(abts_case *tc, void *data) +{ + apr_pool_t *pool; + const char *src, *target; + const char *dest; + const void *vdest; + apr_size_t len, vlen; + + apr_pool_create(&pool, NULL); + + src = "Hello World &;`'\"|*?~<>^()[]{}$\\"; + target = "Hello World \\&\\;\\`\\'\\\"\\|\\*\\?\\~\\<\\>\\^\\(\\)\\[\\]\\{\\}\\$\\\\"; + dest = apr_pescape_shell(pool, src); + ABTS_ASSERT(tc, + apr_psprintf(pool, "shell escaped (%s) does not match expected output (%s)", + dest, target), + (strcmp(dest, target) == 0)); + apr_escape_shell(NULL, src, APR_ESCAPE_STRING, &len); + ABTS_ASSERT(tc, + apr_psprintf(pool, "size mismatch (%" APR_SIZE_T_FMT "!=%" APR_SIZE_T_FMT ")", len, strlen(dest) + 1), + (len == strlen(dest) + 1)); + +#if !(defined(OS2) || defined(WIN32)) + /* Now try with newline, which is converted to a space on OS/2 and Windows. + */ + src = "Hello World &;`'\"|*?~<>^()[]{}$\\\n"; + target = "Hello World \\&\\;\\`\\'\\\"\\|\\*\\?\\~\\<\\>\\^\\(\\)\\[\\]\\{\\}\\$\\\\\\\n"; + dest = apr_pescape_shell(pool, src); + ABTS_ASSERT(tc, + apr_psprintf(pool, "shell escaped (%s) does not match expected output (%s)", + dest, target), + (strcmp(dest, target) == 0)); + apr_escape_shell(NULL, src, APR_ESCAPE_STRING, &len); + ABTS_ASSERT(tc, + apr_psprintf(pool, "size mismatch (%" APR_SIZE_T_FMT "!=%" APR_SIZE_T_FMT ")", len, strlen(dest) + 1), + (len == strlen(dest) + 1)); +#endif + + src = "Hello"; + dest = apr_punescape_url(pool, src, NULL, NULL, 0); + ABTS_PTR_EQUAL(tc, src, dest); + + src = "Hello"; + dest = apr_punescape_url(pool, src, NULL, NULL, 1); + ABTS_PTR_EQUAL(tc, src, dest); + + src = "Hello%20"; + dest = apr_punescape_url(pool, src, " ", NULL, 0); + ABTS_PTR_EQUAL(tc, NULL, dest); + + src = "Hello%20World"; + target = "Hello World"; + dest = apr_punescape_url(pool, src, NULL, NULL, 0); + ABTS_STR_EQUAL(tc, target, dest); + apr_unescape_url(NULL, src, APR_ESCAPE_STRING, NULL, NULL, 0, &len); + ABTS_ASSERT(tc, + apr_psprintf(pool, "size mismatch (%" APR_SIZE_T_FMT "!=%" APR_SIZE_T_FMT ")", len, strlen(dest) + 1), + (len == strlen(dest) + 1)); + + src = "Hello+World"; + target = "Hello World"; + dest = apr_punescape_url(pool, src, NULL, NULL, 1); + ABTS_STR_EQUAL(tc, target, dest); + apr_unescape_url(NULL, src, APR_ESCAPE_STRING, NULL, NULL, 1, &len); + ABTS_ASSERT(tc, + apr_psprintf(pool, "size mismatch (%" APR_SIZE_T_FMT "!=%" APR_SIZE_T_FMT ")", len, strlen(dest) + 1), + (len == strlen(dest) + 1)); + + src = "Hello%20World"; + target = "Hello%20World"; + dest = apr_punescape_url(pool, src, NULL, " ", 0); + ABTS_STR_EQUAL(tc, target, dest); + apr_unescape_url(NULL, src, APR_ESCAPE_STRING, NULL, " ", 0, &len); + ABTS_ASSERT(tc, + apr_psprintf(pool, "size mismatch (%" APR_SIZE_T_FMT "!=%" APR_SIZE_T_FMT ")", len, strlen(dest) + 1), + (len == strlen(dest) + 1)); + + src = "Hello"; + dest = apr_pescape_path_segment(pool, src); + ABTS_PTR_EQUAL(tc, src, dest); + + src = "$-_.+!*'(),:@&=/~Hello World"; + target = "$-_.+!*'(),:@&=%2f~Hello%20World"; + dest = apr_pescape_path_segment(pool, src); + ABTS_STR_EQUAL(tc, target, dest); + apr_escape_path_segment(NULL, src, APR_ESCAPE_STRING, &len); + ABTS_ASSERT(tc, + apr_psprintf(pool, "size mismatch (%" APR_SIZE_T_FMT "!=%" APR_SIZE_T_FMT ")", len, strlen(dest) + 1), + (len == strlen(dest) + 1)); + + src = "Hello"; + dest = apr_pescape_path(pool, src, 0); + ABTS_PTR_EQUAL(tc, src, dest); + + src = "$-_.+!*'(),:@&=/~Hello World"; + target = "./$-_.+!*'(),:@&=/~Hello%20World"; + dest = apr_pescape_path(pool, src, 0); + ABTS_STR_EQUAL(tc, target, dest); + apr_escape_path(NULL, src, APR_ESCAPE_STRING, 0, &len); + ABTS_ASSERT(tc, + apr_psprintf(pool, "size mismatch (%" APR_SIZE_T_FMT "!=%" APR_SIZE_T_FMT ")", len, strlen(dest) + 1), + (len == strlen(dest) + 1)); + + src = "Hello"; + dest = apr_pescape_path(pool, src, 1); + ABTS_PTR_EQUAL(tc, src, dest); + + src = "$-_.+!*'(),:@&=/~Hello World"; + target = "$-_.+!*'(),:@&=/~Hello%20World"; + dest = apr_pescape_path(pool, src, 1); + ABTS_STR_EQUAL(tc, target, dest); + apr_escape_path(NULL, src, APR_ESCAPE_STRING, 1, &len); + ABTS_ASSERT(tc, + apr_psprintf(pool, "size mismatch (%" APR_SIZE_T_FMT "!=%" APR_SIZE_T_FMT ")", len, strlen(dest) + 1), + (len == strlen(dest) + 1)); + + src = "Hello"; + dest = apr_pescape_urlencoded(pool, src); + ABTS_PTR_EQUAL(tc, src, dest); + + src = "$-_.+!*'(),:@&=/~Hello World"; + target = "%24-_.%2b%21*%27%28%29%2c%3a%40%26%3d%2f%7eHello+World"; + dest = apr_pescape_urlencoded(pool, src); + ABTS_STR_EQUAL(tc, target, dest); + apr_escape_urlencoded(NULL, src, APR_ESCAPE_STRING, &len); + ABTS_ASSERT(tc, + apr_psprintf(pool, "size mismatch (%" APR_SIZE_T_FMT "!=%" APR_SIZE_T_FMT ")", len, strlen(dest) + 1), + (len == strlen(dest) + 1)); + + src = "Hello"; + dest = apr_pescape_entity(pool, src, 0); + ABTS_PTR_EQUAL(tc, src, dest); + + src = "\xFF<>&\'\"Hello World"; + target = "\xFF<>&'"Hello World"; + dest = apr_pescape_entity(pool, src, 0); + ABTS_STR_EQUAL(tc, target, dest); + apr_escape_entity(NULL, src, APR_ESCAPE_STRING, 0, &len); + ABTS_ASSERT(tc, + apr_psprintf(pool, "size mismatch (%" APR_SIZE_T_FMT "!=%" APR_SIZE_T_FMT ")", len, strlen(dest) + 1), + (len == strlen(dest) + 1)); + +#if !APR_CHARSET_EBCDIC + src = "Hello"; + dest = apr_pescape_entity(pool, src, 1); + ABTS_PTR_EQUAL(tc, src, dest); + + src = "\xFF<>&\'\"Hello World"; + target = "ÿ<>&'"Hello World"; + dest = apr_pescape_entity(pool, src, 1); + ABTS_STR_EQUAL(tc, target, dest); + apr_escape_entity(NULL, src, APR_ESCAPE_STRING, 1, &len); + ABTS_ASSERT(tc, + apr_psprintf(pool, "size mismatch (%" APR_SIZE_T_FMT "!=%" APR_SIZE_T_FMT ")", len, strlen(dest) + 1), + (len == strlen(dest) + 1)); + + src = "Hello"; + dest = apr_punescape_entity(pool, src); + ABTS_PTR_EQUAL(tc, src, dest); + + src = "\xFF<>&'"Hello World"; + target = "\xFF<>&\'\"Hello World"; + dest = apr_punescape_entity(pool, src); + ABTS_STR_EQUAL(tc, target, dest); + apr_unescape_entity(NULL, src, APR_ESCAPE_STRING, &len); + ABTS_ASSERT(tc, + apr_psprintf(pool, "size mismatch (%" APR_SIZE_T_FMT "!=%" APR_SIZE_T_FMT ")", len, strlen(dest) + 1), + (len == strlen(dest) + 1)); + + src = "ÿ<>&'"Hello World"; + target = "\xFF<>&\'\"Hello World"; + dest = apr_punescape_entity(pool, src); + ABTS_STR_EQUAL(tc, target, dest); + apr_unescape_entity(NULL, src, APR_ESCAPE_STRING, &len); + ABTS_ASSERT(tc, + apr_psprintf(pool, "size mismatch (%" APR_SIZE_T_FMT "!=%" APR_SIZE_T_FMT ")", len, strlen(dest) + 1), + (len == strlen(dest) + 1)); + + src = " <>&'"Hello World"; + target = " <>&\'\"Hello World"; + dest = apr_punescape_entity(pool, src); + ABTS_STR_EQUAL(tc, target, dest); + apr_unescape_entity(NULL, src, APR_ESCAPE_STRING, &len); + ABTS_ASSERT(tc, + apr_psprintf(pool, "size mismatch (%" APR_SIZE_T_FMT "!=%" APR_SIZE_T_FMT ")", len, strlen(dest) + 1), + (len == strlen(dest) + 1)); +#endif + + src = "Hello"; + dest = apr_pescape_echo(pool, src, 0); + ABTS_PTR_EQUAL(tc, src, dest); + + src = "\a\b\f\\n\r\t\v\"Hello World\""; + target = "\\a\\b\\f\\\\n\\r\\t\\v\"Hello World\""; + dest = apr_pescape_echo(pool, src, 0); + ABTS_STR_EQUAL(tc, target, dest); + apr_escape_echo(NULL, src, APR_ESCAPE_STRING, 0, &len); + ABTS_ASSERT(tc, + apr_psprintf(pool, "size mismatch (%" APR_SIZE_T_FMT "!=%" APR_SIZE_T_FMT ")", len, strlen(dest) + 1), + (len == strlen(dest) + 1)); + + src = "\a\b\f\\n\r\t\v\"Hello World\""; + target = "\\a\\b\\f\\\\n\\r\\t\\v\\\"Hello World\\\""; + dest = apr_pescape_echo(pool, src, 1); + ABTS_STR_EQUAL(tc, target, dest); + apr_escape_echo(NULL, src, APR_ESCAPE_STRING, 1, &len); + ABTS_ASSERT(tc, + apr_psprintf(pool, "size mismatch (%" APR_SIZE_T_FMT "!=%" APR_SIZE_T_FMT ")", len, strlen(dest) + 1), + (len == strlen(dest) + 1)); + + src = "\xFF\x00\xFF\x00"; + target = "ff00ff00"; + dest = apr_pescape_hex(pool, src, 4, 0); + ABTS_STR_EQUAL(tc, target, dest); + apr_escape_hex(NULL, src, 4, 0, &len); + ABTS_ASSERT(tc, + apr_psprintf(pool, "size mismatch (%" APR_SIZE_T_FMT "!=%" APR_SIZE_T_FMT ")", len, strlen(dest) + 1), + (len == strlen(dest) + 1)); + + src = "\xFF\x00\xFF\x00"; + target = "ff:00:ff:00"; + dest = apr_pescape_hex(pool, src, 4, 1); + ABTS_STR_EQUAL(tc, target, dest); + apr_escape_hex(NULL, src, 4, 1, &len); + ABTS_ASSERT(tc, + apr_psprintf(pool, "size mismatch (%" APR_SIZE_T_FMT "!=%" APR_SIZE_T_FMT ")", len, strlen(dest) + 1), + (len == strlen(dest) + 1)); + + src = "ff:00:ff:00"; + target = "\xFF\x00\xFF\x00"; + vdest = apr_punescape_hex(pool, src, 1, &vlen); + ABTS_ASSERT(tc, "apr_punescape_hex target!=dest", memcmp(target, vdest, 4) == 0); + ABTS_INT_EQUAL(tc, (int)vlen, 4); + apr_unescape_hex(NULL, src, APR_ESCAPE_STRING, 1, &len); + ABTS_ASSERT(tc, + apr_psprintf(pool, "size mismatch (%" APR_SIZE_T_FMT "!=%" APR_SIZE_T_FMT ")", len, (apr_size_t)4), + (len == 4)); + + src = "Parens R Us (for all your parenthetical needs) plus asterisk* \"+,;<>\\"; + target = "Parens R Us (for all your parenthetical needs) plus asterisk* \\22\\2b\\2c\\3b\\3c\\3e\\5c"; + dest = apr_pescape_ldap(pool, src, APR_ESCAPE_STRING, APR_ESCAPE_LDAP_DN); + ABTS_ASSERT(tc, + apr_psprintf(pool, "ldap escaped (%s) does not match expected output (%s)", + dest, target), + (strcmp(dest, target) == 0)); + apr_escape_ldap(NULL, src, APR_ESCAPE_STRING, APR_ESCAPE_LDAP_DN, &len); + ABTS_ASSERT(tc, + apr_psprintf(pool, "size mismatch (%" APR_SIZE_T_FMT "!=%" APR_SIZE_T_FMT ")", len, strlen(dest) + 1), + (len == strlen(dest) + 1)); + + src = "Parens R Us (for all your parenthetical needs) plus asterisk* \"+,;<>\\"; + target = "Parens R Us \\28for all your parenthetical needs\\29 plus asterisk\\2a \"+,;<>\\5c"; + dest = apr_pescape_ldap(pool, src, APR_ESCAPE_STRING, APR_ESCAPE_LDAP_FILTER); + ABTS_ASSERT(tc, + apr_psprintf(pool, "ldap escaped (%s) does not match expected output (%s)", + dest, target), + (strcmp(dest, target) == 0)); + apr_escape_ldap(NULL, src, APR_ESCAPE_STRING, APR_ESCAPE_LDAP_FILTER, &len); + ABTS_ASSERT(tc, + apr_psprintf(pool, "size mismatch (%" APR_SIZE_T_FMT "!=%" APR_SIZE_T_FMT ")", len, strlen(dest) + 1), + (len == strlen(dest) + 1)); + + src = "Parens R Us (for all your parenthetical needs) plus asterisk* \"+,;<>\\"; + target = "Parens R Us \\28for all your parenthetical needs\\29 plus asterisk\\2a \\22\\2b\\2c\\3b\\3c\\3e\\5c"; + dest = apr_pescape_ldap(pool, src, APR_ESCAPE_STRING, APR_ESCAPE_LDAP_ALL); + ABTS_ASSERT(tc, + apr_psprintf(pool, "ldap escaped (%s) does not match expected output (%s)", + dest, target), + (strcmp(dest, target) == 0)); + apr_escape_ldap(NULL, src, APR_ESCAPE_STRING, APR_ESCAPE_LDAP_ALL, &len); + ABTS_ASSERT(tc, + apr_psprintf(pool, "size mismatch (%" APR_SIZE_T_FMT "!=%" APR_SIZE_T_FMT ")", len, strlen(dest) + 1), + (len == strlen(dest) + 1)); + + apr_pool_destroy(pool); +} + +abts_suite *testescape(abts_suite *suite) +{ + suite = ADD_SUITE(suite); + + abts_run_test(suite, test_escape, NULL); + + return suite; +} diff --git a/test/testfile.c b/test/testfile.c index 1b164515e6f..73b13c4bf14 100644 --- a/test/testfile.c +++ b/test/testfile.c @@ -1,356 +1,1905 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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 <stdio.h> -#include <stdlib.h> #include "apr_file_io.h" +#include "apr_file_info.h" +#include "apr_network_io.h" #include "apr_errno.h" #include "apr_general.h" +#include "apr_poll.h" #include "apr_lib.h" -#ifdef BEOS -#include <unistd.h> -#endif - -int test_filedel(ap_pool_t *); -int testdirs(ap_pool_t *); - -int main() -{ - ap_pool_t *context; - ap_pool_t *cont2; - ap_file_t *thefile = NULL; - ap_status_t status = 0; - ap_int32_t flag = APR_READ | APR_WRITE | APR_CREATE; - ap_ssize_t nbytes = 0; - ap_off_t zer = 0; - char *buf; - char *str; - char *filename = "test.fil"; +#include "apr_strings.h" +#include "apr_thread_proc.h" +#include "testutil.h" + +#define DIRNAME "data" +#define FILENAME DIRNAME "/file_datafile.txt" +#define TESTSTR "This is the file data file." + +#define TESTREAD_BLKSIZE 1024 +#define APR_BUFFERSIZE 4096 /* This should match APR's buffer size. */ + + + +static void test_open_noreadwrite(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_file_t *thefile = NULL; + + rv = apr_file_open(&thefile, FILENAME, + APR_FOPEN_CREATE | APR_FOPEN_EXCL, + APR_FPROT_UREAD | APR_FPROT_UWRITE | APR_FPROT_GREAD, p); + ABTS_TRUE(tc, rv != APR_SUCCESS); + ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_EACCES(rv)); + ABTS_PTR_EQUAL(tc, NULL, thefile); +} + +static void test_open_excl(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_file_t *thefile = NULL; + + rv = apr_file_open(&thefile, FILENAME, + APR_FOPEN_CREATE | APR_FOPEN_EXCL | APR_FOPEN_WRITE, + APR_FPROT_UREAD | APR_FPROT_UWRITE | APR_FPROT_GREAD, p); + ABTS_TRUE(tc, rv != APR_SUCCESS); + ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_EEXIST(rv)); + ABTS_PTR_EQUAL(tc, NULL, thefile); +} + +static void test_open_read(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_file_t *filetest = NULL; + + rv = apr_file_open(&filetest, FILENAME, + APR_FOPEN_READ, + APR_FPROT_UREAD | APR_FPROT_UWRITE | APR_FPROT_GREAD, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_PTR_NOTNULL(tc, filetest); + apr_file_close(filetest); +} + +static void link_existing(abts_case *tc, void *data) +{ + apr_status_t rv; + + rv = apr_file_link("data/file_datafile.txt", "data/file_datafile2.txt"); + apr_file_remove("data/file_datafile2.txt", p); + ABTS_ASSERT(tc, "Couldn't create hardlink to file", rv == APR_SUCCESS); +} + +static void link_nonexisting(abts_case *tc, void *data) +{ + apr_status_t rv; + + rv = apr_file_link("data/does_not_exist.txt", "data/fake.txt"); + ABTS_ASSERT(tc, "", rv != APR_SUCCESS); +} + +static void test_read(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_size_t nbytes = 256; + char *str = apr_pcalloc(p, nbytes + 1); + apr_file_t *filetest = NULL; + + rv = apr_file_open(&filetest, FILENAME, + APR_FOPEN_READ, + APR_FPROT_UREAD | APR_FPROT_UWRITE | APR_FPROT_GREAD, p); + + APR_ASSERT_SUCCESS(tc, "Opening test file " FILENAME, rv); + rv = apr_file_read(filetest, str, &nbytes); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_SIZE_EQUAL(tc, strlen(TESTSTR), nbytes); + ABTS_STR_EQUAL(tc, TESTSTR, str); + + apr_file_close(filetest); +} + +static void test_readzero(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_size_t nbytes = 0; + char *str = NULL; + apr_file_t *filetest; + + rv = apr_file_open(&filetest, FILENAME, APR_FOPEN_READ, APR_FPROT_OS_DEFAULT, p); + APR_ASSERT_SUCCESS(tc, "Opening test file " FILENAME, rv); + + rv = apr_file_read(filetest, str, &nbytes); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_SIZE_EQUAL(tc, 0, nbytes); + + apr_file_close(filetest); +} + +static void test_filename(abts_case *tc, void *data) +{ + const char *str; + apr_status_t rv; + apr_file_t *filetest = NULL; + + rv = apr_file_open(&filetest, FILENAME, + APR_FOPEN_READ, + APR_FPROT_UREAD | APR_FPROT_UWRITE | APR_FPROT_GREAD, p); + APR_ASSERT_SUCCESS(tc, "Opening test file " FILENAME, rv); + + rv = apr_file_name_get(&str, filetest); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_STR_EQUAL(tc, FILENAME, str); + + apr_file_close(filetest); +} + +static void test_fileclose(abts_case *tc, void *data) +{ + char str; + apr_status_t rv; + apr_size_t one = 1; + apr_file_t *filetest = NULL; + + rv = apr_file_open(&filetest, FILENAME, + APR_FOPEN_READ, + APR_FPROT_UREAD | APR_FPROT_UWRITE | APR_FPROT_GREAD, p); + APR_ASSERT_SUCCESS(tc, "Opening test file " FILENAME, rv); + + rv = apr_file_close(filetest); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + /* We just closed the file, so this should fail */ + rv = apr_file_read(filetest, &str, &one); + ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_EBADF(rv)); +} + +static void test_file_remove(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_file_t *filetest = NULL; + + rv = apr_file_remove(FILENAME, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + rv = apr_file_open(&filetest, FILENAME, APR_FOPEN_READ, + APR_FPROT_UREAD | APR_FPROT_UWRITE | APR_FPROT_GREAD, p); + ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_ENOENT(rv)); +} + +static void test_open_write(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_file_t *filetest = NULL; + + filetest = NULL; + rv = apr_file_open(&filetest, FILENAME, + APR_FOPEN_WRITE, + APR_FPROT_UREAD | APR_FPROT_UWRITE | APR_FPROT_GREAD, p); + ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_ENOENT(rv)); + ABTS_PTR_EQUAL(tc, NULL, filetest); +} + +static void test_open_writecreate(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_file_t *filetest = NULL; + + filetest = NULL; + rv = apr_file_open(&filetest, FILENAME, + APR_FOPEN_WRITE | APR_FOPEN_CREATE, + APR_FPROT_UREAD | APR_FPROT_UWRITE | APR_FPROT_GREAD, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + apr_file_close(filetest); +} + +static void test_write(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_size_t bytes = strlen(TESTSTR); + apr_file_t *filetest = NULL; + + rv = apr_file_open(&filetest, FILENAME, + APR_FOPEN_WRITE | APR_FOPEN_CREATE, + APR_FPROT_UREAD | APR_FPROT_UWRITE | APR_FPROT_GREAD, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + rv = apr_file_write(filetest, TESTSTR, &bytes); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + apr_file_close(filetest); +} + +static void test_open_readwrite(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_file_t *filetest = NULL; + + filetest = NULL; + rv = apr_file_open(&filetest, FILENAME, + APR_FOPEN_READ | APR_FOPEN_WRITE, + APR_FPROT_UREAD | APR_FPROT_UWRITE | APR_FPROT_GREAD, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_PTR_NOTNULL(tc, filetest); + + apr_file_close(filetest); +} + +static void test_seek(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_off_t offset = 5; + apr_size_t nbytes = 256; + char *str = apr_pcalloc(p, nbytes + 1); + apr_file_t *filetest = NULL; + + rv = apr_file_open(&filetest, FILENAME, + APR_FOPEN_READ, + APR_FPROT_UREAD | APR_FPROT_UWRITE | APR_FPROT_GREAD, p); + APR_ASSERT_SUCCESS(tc, "Open test file " FILENAME, rv); + + rv = apr_file_read(filetest, str, &nbytes); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_SIZE_EQUAL(tc, strlen(TESTSTR), nbytes); + ABTS_STR_EQUAL(tc, TESTSTR, str); + + memset(str, 0, nbytes + 1); + + rv = apr_file_seek(filetest, SEEK_SET, &offset); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + rv = apr_file_read(filetest, str, &nbytes); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_SIZE_EQUAL(tc, strlen(TESTSTR) - 5, nbytes); + ABTS_STR_EQUAL(tc, TESTSTR + 5, str); + + apr_file_close(filetest); + + /* Test for regression of sign error bug with SEEK_END and + buffered files. */ + rv = apr_file_open(&filetest, FILENAME, + APR_FOPEN_READ | APR_FOPEN_BUFFERED, + APR_FPROT_UREAD | APR_FPROT_UWRITE | APR_FPROT_GREAD, p); + APR_ASSERT_SUCCESS(tc, "Open test file " FILENAME, rv); + + offset = -5; + rv = apr_file_seek(filetest, SEEK_END, &offset); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_SIZE_EQUAL(tc, strlen(TESTSTR) - 5, nbytes); + + memset(str, 0, nbytes + 1); + nbytes = 256; + rv = apr_file_read(filetest, str, &nbytes); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_SIZE_EQUAL(tc, 5, nbytes); + ABTS_STR_EQUAL(tc, TESTSTR + strlen(TESTSTR) - 5, str); + + apr_file_close(filetest); +} + +static void test_userdata_set(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_file_t *filetest = NULL; + + rv = apr_file_open(&filetest, FILENAME, + APR_FOPEN_WRITE, + APR_FPROT_UREAD | APR_FPROT_UWRITE | APR_FPROT_GREAD, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + rv = apr_file_data_set(filetest, "This is a test", + "test", apr_pool_cleanup_null); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + apr_file_close(filetest); +} + +static void test_userdata_get(abts_case *tc, void *data) +{ + apr_status_t rv; + void *udata; char *teststr; + apr_file_t *filetest = NULL; - if (ap_initialize() != APR_SUCCESS) { - fprintf(stderr, "Couldn't initialize."); - exit(-1); - } - atexit(ap_terminate); - if (ap_create_pool(&context, NULL) != APR_SUCCESS) { - fprintf(stderr, "Couldn't allocate context."); - exit(-1); - } - if (ap_create_pool(&cont2, context) != APR_SUCCESS) { - fprintf(stderr, "Couldn't allocate context."); - exit(-1); - } + rv = apr_file_open(&filetest, FILENAME, + APR_FOPEN_WRITE, + APR_FPROT_UREAD | APR_FPROT_UWRITE | APR_FPROT_GREAD, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); - fprintf(stdout, "Testing file functions.\n"); + rv = apr_file_data_set(filetest, "This is a test", + "test", apr_pool_cleanup_null); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); - fprintf(stdout, "\tOpening file......."); - if (ap_open(&thefile, filename, flag, APR_UREAD | APR_UWRITE | APR_GREAD, context) != APR_SUCCESS) { - perror("Didn't open file"); - exit(-1); - } - else { - fprintf(stdout, "OK\n"); - } + rv = apr_file_data_get(&udata, "test", filetest); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + teststr = udata; + ABTS_STR_EQUAL(tc, "This is a test", teststr); + + apr_file_close(filetest); +} + +static void test_userdata_getnokey(abts_case *tc, void *data) +{ + apr_status_t rv; + void *teststr; + apr_file_t *filetest = NULL; + + rv = apr_file_open(&filetest, FILENAME, + APR_FOPEN_WRITE, + APR_FPROT_UREAD | APR_FPROT_UWRITE | APR_FPROT_GREAD, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + rv = apr_file_data_get(&teststr, "nokey", filetest); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_PTR_EQUAL(tc, NULL, teststr); + apr_file_close(filetest); +} + +static void test_buffer_set_get(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_size_t bufsize; + apr_file_t *filetest = NULL; + char * buffer; + + rv = apr_file_open(&filetest, FILENAME, + APR_FOPEN_WRITE | APR_FOPEN_BUFFERED, + APR_FPROT_UREAD | APR_FPROT_UWRITE | APR_FPROT_GREAD, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + bufsize = apr_file_buffer_size_get(filetest); + ABTS_SIZE_EQUAL(tc, APR_BUFFERSIZE, bufsize); + + buffer = apr_pcalloc(p, 10240); + rv = apr_file_buffer_set(filetest, buffer, 10240); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); - fprintf(stdout, "\tChecking file......."); - if (thefile == NULL) { - fprintf(stderr, "Bad file des\n"); - exit(-1); - } - ap_get_filename(&str, thefile); - if (strcmp(str, filename) != 0) { - fprintf(stderr, "wrong filename\n"); - exit(-1); - } - else { - fprintf(stdout, "OK\n"); - } + bufsize = apr_file_buffer_size_get(filetest); + ABTS_SIZE_EQUAL(tc, 10240, bufsize); + + rv = apr_file_buffer_set(filetest, buffer, 12); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + bufsize = apr_file_buffer_size_get(filetest); + ABTS_SIZE_EQUAL(tc, 12, bufsize); + + apr_file_close(filetest); +} +static void test_getc(abts_case *tc, void *data) +{ + apr_file_t *f = NULL; + apr_status_t rv; + char ch; + + rv = apr_file_open(&f, FILENAME, APR_FOPEN_READ, 0, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + apr_file_getc(&ch, f); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_INT_EQUAL(tc, (int)TESTSTR[0], (int)ch); + apr_file_close(f); +} + +static void test_ungetc(abts_case *tc, void *data) +{ + apr_file_t *f = NULL; + apr_status_t rv; + char ch; + + rv = apr_file_open(&f, FILENAME, APR_FOPEN_READ, 0, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + apr_file_getc(&ch, f); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_INT_EQUAL(tc, (int)TESTSTR[0], (int)ch); + + apr_file_ungetc('X', f); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + apr_file_getc(&ch, f); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_INT_EQUAL(tc, 'X', (int)ch); + + apr_file_close(f); +} + +static void test_gets(abts_case *tc, void *data) +{ + apr_file_t *f = NULL; + apr_status_t rv; + char *str = apr_palloc(p, 256); + + rv = apr_file_open(&f, FILENAME, APR_FOPEN_READ, 0, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + rv = apr_file_gets(str, 256, f); + /* Only one line in the test file, so APR will encounter EOF on the first + * call to gets, but we should get APR_SUCCESS on this call and + * APR_EOF on the next. + */ + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_STR_EQUAL(tc, TESTSTR, str); + rv = apr_file_gets(str, 256, f); + ABTS_INT_EQUAL(tc, APR_EOF, rv); + ABTS_STR_EQUAL(tc, "", str); + /* Calling gets after EOF should return EOF. */ + rv = apr_file_gets(str, 256, f); + ABTS_INT_EQUAL(tc, APR_EOF, rv); + ABTS_STR_EQUAL(tc, "", str); + apr_file_close(f); +} + +static void test_gets_buffered(abts_case *tc, void *data) +{ + apr_file_t *f = NULL; + apr_status_t rv; + char *str = apr_palloc(p, 256); + + /* This will deadlock gets before the r524355 fix. */ + rv = apr_file_open(&f, FILENAME, APR_FOPEN_READ|APR_FOPEN_BUFFERED|APR_FOPEN_XTHREAD, 0, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + rv = apr_file_gets(str, 256, f); + /* Only one line in the test file, so APR will encounter EOF on the first + * call to gets, but we should get APR_SUCCESS on this call and + * APR_EOF on the next. + */ + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_STR_EQUAL(tc, TESTSTR, str); + rv = apr_file_gets(str, 256, f); + ABTS_INT_EQUAL(tc, APR_EOF, rv); + ABTS_STR_EQUAL(tc, "", str); + /* Calling gets after EOF should return EOF. */ + rv = apr_file_gets(str, 256, f); + ABTS_INT_EQUAL(tc, APR_EOF, rv); + ABTS_STR_EQUAL(tc, "", str); + apr_file_close(f); +} + +static void test_gets_empty(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_file_t *f; + const char *fname = "data/testgets_empty.txt"; + char buf[256]; + + apr_file_remove(fname, p); + + rv = apr_file_open(&f, fname, APR_FOPEN_CREATE | APR_FOPEN_WRITE, + APR_FPROT_OS_DEFAULT, p); + APR_ASSERT_SUCCESS(tc, "open test file", rv); + apr_file_close(f); + + rv = apr_file_open(&f, fname, APR_FOPEN_READ, APR_FPROT_OS_DEFAULT, p); + APR_ASSERT_SUCCESS(tc, "re-open test file", rv); + + rv = apr_file_gets(buf, sizeof(buf), f); + ABTS_INT_EQUAL(tc, APR_EOF, rv); + ABTS_STR_EQUAL(tc, "", buf); + /* Calling gets after EOF should return EOF. */ + rv = apr_file_gets(buf, sizeof(buf), f); + ABTS_INT_EQUAL(tc, APR_EOF, rv); + ABTS_STR_EQUAL(tc, "", buf); + apr_file_close(f); +} + +static void test_gets_multiline(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_file_t *f; + const char *fname = "data/testgets_multiline.txt"; + char buf[256]; + + apr_file_remove(fname, p); + + rv = apr_file_open(&f, fname, APR_FOPEN_CREATE | APR_FOPEN_WRITE, + APR_FPROT_OS_DEFAULT, p); + APR_ASSERT_SUCCESS(tc, "open test file", rv); + rv = apr_file_puts("a\nb\n", f); + APR_ASSERT_SUCCESS(tc, "write test data", rv); + apr_file_close(f); + + rv = apr_file_open(&f, fname, APR_FOPEN_READ, APR_FPROT_OS_DEFAULT, p); + APR_ASSERT_SUCCESS(tc, "re-open test file", rv); + + memset(buf, 0, sizeof(buf)); + rv = apr_file_gets(buf, sizeof(buf), f); + APR_ASSERT_SUCCESS(tc, "read first line", rv); + ABTS_STR_EQUAL(tc, "a\n", buf); + + memset(buf, 0, sizeof(buf)); + rv = apr_file_gets(buf, sizeof(buf), f); + APR_ASSERT_SUCCESS(tc, "read second line", rv); + ABTS_STR_EQUAL(tc, "b\n", buf); + + rv = apr_file_gets(buf, sizeof(buf), f); + ABTS_INT_EQUAL(tc, APR_EOF, rv); + ABTS_STR_EQUAL(tc, "", buf); + /* Calling gets after EOF should return EOF. */ + rv = apr_file_gets(buf, sizeof(buf), f); + ABTS_INT_EQUAL(tc, APR_EOF, rv); + ABTS_STR_EQUAL(tc, "", buf); + apr_file_close(f); +} + +static void test_gets_small_buf(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_file_t *f; + const char *fname = "data/testgets_small_buf.txt"; + char buf[2]; + + apr_file_remove(fname, p); + + rv = apr_file_open(&f, fname, APR_FOPEN_CREATE | APR_FOPEN_WRITE, + APR_FPROT_OS_DEFAULT, p); + APR_ASSERT_SUCCESS(tc, "open test file", rv); + rv = apr_file_puts("ab\n", f); + apr_file_close(f); + + rv = apr_file_open(&f, fname, APR_FOPEN_READ, APR_FPROT_OS_DEFAULT, p); + APR_ASSERT_SUCCESS(tc, "re-open test file", rv); + /* Buffer is too small to hold the full line, test that gets properly + * returns the line content character by character. + */ + memset(buf, 0, sizeof(buf)); + rv = apr_file_gets(buf, sizeof(buf), f); + APR_ASSERT_SUCCESS(tc, "read first chunk", rv); + ABTS_STR_EQUAL(tc, "a", buf); + + memset(buf, 0, sizeof(buf)); + rv = apr_file_gets(buf, sizeof(buf), f); + APR_ASSERT_SUCCESS(tc, "read second chunk", rv); + ABTS_STR_EQUAL(tc, "b", buf); + + memset(buf, 0, sizeof(buf)); + rv = apr_file_gets(buf, sizeof(buf), f); + APR_ASSERT_SUCCESS(tc, "read third chunk", rv); + ABTS_STR_EQUAL(tc, "\n", buf); + + rv = apr_file_gets(buf, sizeof(buf), f); + ABTS_INT_EQUAL(tc, APR_EOF, rv); + ABTS_STR_EQUAL(tc, "", buf); + /* Calling gets after EOF should return EOF. */ + rv = apr_file_gets(buf, sizeof(buf), f); + ABTS_INT_EQUAL(tc, APR_EOF, rv); + ABTS_STR_EQUAL(tc, "", buf); + apr_file_close(f); +} + +static void test_gets_ungetc(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_file_t *f; + const char *fname = "data/testgets_ungetc.txt"; + char buf[256]; + + apr_file_remove(fname, p); + + rv = apr_file_open(&f, fname, APR_FOPEN_CREATE | APR_FOPEN_WRITE, + APR_FPROT_OS_DEFAULT, p); + APR_ASSERT_SUCCESS(tc, "open test file", rv); + rv = apr_file_puts("a\n", f); + APR_ASSERT_SUCCESS(tc, "write test data", rv); + apr_file_close(f); + + rv = apr_file_open(&f, fname, APR_FOPEN_READ, APR_FPROT_OS_DEFAULT, p); + APR_ASSERT_SUCCESS(tc, "re-open test file", rv); + + rv = apr_file_ungetc('b', f); + APR_ASSERT_SUCCESS(tc, "call ungetc", rv); + memset(buf, 0, sizeof(buf)); + rv = apr_file_gets(buf, sizeof(buf), f); + APR_ASSERT_SUCCESS(tc, "read line", rv); + ABTS_STR_EQUAL(tc, "ba\n", buf); + + rv = apr_file_ungetc('\n', f); + APR_ASSERT_SUCCESS(tc, "call ungetc with EOL", rv); + memset(buf, 0, sizeof(buf)); + rv = apr_file_gets(buf, sizeof(buf), f); + APR_ASSERT_SUCCESS(tc, "read line", rv); + ABTS_STR_EQUAL(tc, "\n", buf); + + rv = apr_file_gets(buf, sizeof(buf), f); + ABTS_INT_EQUAL(tc, APR_EOF, rv); + ABTS_STR_EQUAL(tc, "", buf); + /* Calling gets after EOF should return EOF. */ + rv = apr_file_gets(buf, sizeof(buf), f); + ABTS_INT_EQUAL(tc, APR_EOF, rv); + ABTS_STR_EQUAL(tc, "", buf); + apr_file_close(f); +} + +static void test_gets_buffered_big(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_file_t *f; + const char *fname = "data/testgets_buffered_big.txt"; + char hugestr[APR_BUFFERSIZE + 2]; + char buf[APR_BUFFERSIZE + 2]; + + apr_file_remove(fname, p); + + rv = apr_file_open(&f, fname, APR_FOPEN_CREATE | APR_FOPEN_WRITE, + APR_FPROT_OS_DEFAULT, p); + APR_ASSERT_SUCCESS(tc, "open test file", rv); + /* Test an edge case with a buffered file and the line that exceeds + * the default buffer size by 1 (the line itself fits into the buffer, + * but the line + EOL does not). + */ + memset(hugestr, 'a', sizeof(hugestr)); + hugestr[sizeof(hugestr) - 2] = '\n'; + hugestr[sizeof(hugestr) - 1] = '\0'; + rv = apr_file_puts(hugestr, f); + APR_ASSERT_SUCCESS(tc, "write first line", rv); + rv = apr_file_puts("b\n", f); + APR_ASSERT_SUCCESS(tc, "write second line", rv); + apr_file_close(f); - fprintf(stdout, "\tWriting to file......."); + rv = apr_file_open(&f, fname, APR_FOPEN_READ | APR_FOPEN_BUFFERED, + APR_FPROT_OS_DEFAULT, p); + APR_ASSERT_SUCCESS(tc, "re-open test file", rv); + + memset(buf, 0, sizeof(buf)); + rv = apr_file_gets(buf, sizeof(buf), f); + APR_ASSERT_SUCCESS(tc, "read first line", rv); + ABTS_STR_EQUAL(tc, hugestr, buf); + + memset(buf, 0, sizeof(buf)); + rv = apr_file_gets(buf, sizeof(buf), f); + APR_ASSERT_SUCCESS(tc, "read second line", rv); + ABTS_STR_EQUAL(tc, "b\n", buf); + + rv = apr_file_gets(buf, sizeof(buf), f); + ABTS_INT_EQUAL(tc, APR_EOF, rv); + ABTS_STR_EQUAL(tc, "", buf); + /* Calling gets after EOF should return EOF. */ + rv = apr_file_gets(buf, sizeof(buf), f); + ABTS_INT_EQUAL(tc, APR_EOF, rv); + ABTS_STR_EQUAL(tc, "", buf); + apr_file_close(f); +} + +static void test_bigread(abts_case *tc, void *data) +{ + apr_file_t *f = NULL; + apr_status_t rv; + char buf[APR_BUFFERSIZE * 2]; + apr_size_t nbytes; + + /* Create a test file with known content. + */ + rv = apr_file_open(&f, "data/created_file", + APR_FOPEN_CREATE | APR_FOPEN_WRITE | APR_FOPEN_TRUNCATE, + APR_FPROT_UREAD | APR_FPROT_UWRITE, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + nbytes = APR_BUFFERSIZE; + memset(buf, 0xFE, nbytes); + + rv = apr_file_write(f, buf, &nbytes); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_SIZE_EQUAL(tc, APR_BUFFERSIZE, nbytes); + + rv = apr_file_close(f); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + f = NULL; + rv = apr_file_open(&f, "data/created_file", APR_FOPEN_READ, 0, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + nbytes = sizeof buf; + rv = apr_file_read(f, buf, &nbytes); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_SIZE_EQUAL(tc, APR_BUFFERSIZE, nbytes); + + rv = apr_file_close(f); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + rv = apr_file_remove("data/created_file", p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); +} + +/* This is a horrible name for this function. We are testing APR, not how + * Apache uses APR. And, this function tests _way_ too much stuff. + */ +static void test_mod_neg(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_file_t *f; + const char *s; + int i; + apr_size_t nbytes; + char buf[8192]; + apr_off_t cur; + const char *fname = "data/modneg.dat"; + + rv = apr_file_open(&f, fname, + APR_FOPEN_CREATE | APR_FOPEN_WRITE, + APR_FPROT_UREAD | APR_FPROT_UWRITE, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + s = "body56789\n"; + nbytes = strlen(s); + rv = apr_file_write(f, s, &nbytes); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_SIZE_EQUAL(tc, strlen(s), nbytes); - nbytes = (ap_ssize_t)strlen("this is a test"); - if (ap_write(thefile, "this is a test", &nbytes) != APR_SUCCESS) { - perror("something's wrong"); - exit(-1); - } - if (nbytes != (ap_ssize_t)strlen("this is a test")) { - fprintf(stderr, "didn't write properly.\n"); - exit(-1); - } - else { - fprintf(stdout, "OK\n"); + for (i = 0; i < 7980; i++) { + s = "0"; + nbytes = strlen(s); + rv = apr_file_write(f, s, &nbytes); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_SIZE_EQUAL(tc, strlen(s), nbytes); } + + s = "end456789\n"; + nbytes = strlen(s); + rv = apr_file_write(f, s, &nbytes); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_SIZE_EQUAL(tc, strlen(s), nbytes); - fprintf(stdout, "\tMoving to start of file......."); - zer = 0; - if (ap_seek(thefile, SEEK_SET, &zer) != 0) { - perror("couldn't seek to beginning of file."); - exit(-1); - } - else { - fprintf(stdout, "OK\n"); + for (i = 0; i < 10000; i++) { + s = "1"; + nbytes = strlen(s); + rv = apr_file_write(f, s, &nbytes); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_SIZE_EQUAL(tc, strlen(s), nbytes); } + + rv = apr_file_close(f); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); - fprintf(stdout, "\tReading from the file......."); - nbytes = (ap_ssize_t)strlen("this is a test"); - buf = (char *)ap_palloc(context, nbytes + 1); - if (ap_read(thefile, buf, &nbytes) != APR_SUCCESS) { - perror("something's wrong"); - exit(-1); - } - if (nbytes != (ap_ssize_t)strlen("this is a test")) { - fprintf(stderr, "didn't read properly.\n"); - exit(-1); - } - else { - fprintf(stdout, "OK\n"); - } + rv = apr_file_open(&f, fname, APR_FOPEN_READ, 0, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); - fprintf(stdout, "\tAdding user data to the file......."); - status = ap_set_filedata(thefile, "This is a test", "test", ap_null_cleanup); - if (status != APR_SUCCESS) { - fprintf(stderr, "Couldn't add the data\n"); - exit(-1); - } - else { - fprintf(stdout, "OK\n"); - } + rv = apr_file_gets(buf, 11, f); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_STR_EQUAL(tc, "body56789\n", buf); - fprintf(stdout, "\tGetting user data from the file......."); - status = ap_get_filedata((void **)&teststr, "test", thefile); - if (status != APR_SUCCESS || strcmp(teststr, "This is a test")) { - fprintf(stderr, "Couldn't get the data\n"); - exit(-1); - } - else { - fprintf(stdout, "OK\n"); - } + cur = 0; + rv = apr_file_seek(f, APR_CUR, &cur); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_ASSERT(tc, "File Pointer Mismatch, expected 10", cur == 10); - fprintf(stdout, "\tClosing File......."); - status = ap_close(thefile); - if (status != APR_SUCCESS) { - fprintf(stderr, "Couldn't close the file\n"); - exit(-1); - } - else { - fprintf(stdout, "OK\n"); - } + nbytes = sizeof(buf); + rv = apr_file_read(f, buf, &nbytes); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_SIZE_EQUAL(tc, nbytes, sizeof(buf)); + + cur = -((apr_off_t)nbytes - 7980); + rv = apr_file_seek(f, APR_CUR, &cur); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_ASSERT(tc, "File Pointer Mismatch, expected 7990", cur == 7990); + + rv = apr_file_gets(buf, 11, f); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_STR_EQUAL(tc, "end456789\n", buf); + + rv = apr_file_close(f); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + rv = apr_file_remove(fname, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); +} + +/* Test that the contents of file FNAME are equal to data EXPECT of + * length EXPECTLEN. */ +static void file_contents_equal(abts_case *tc, + const char *fname, + const void *expect, + apr_size_t expectlen) +{ + void *actual = apr_palloc(p, expectlen); + apr_file_t *f; + + APR_ASSERT_SUCCESS(tc, "open file", + apr_file_open(&f, fname, APR_FOPEN_READ|APR_FOPEN_BUFFERED, + 0, p)); + APR_ASSERT_SUCCESS(tc, "read from file", + apr_file_read_full(f, actual, expectlen, NULL)); - fprintf(stdout, "\tDeleting file......."); - status = ap_remove_file(filename, context); - if (status != APR_SUCCESS) { - fprintf(stderr, "Couldn't delete the file\n"); - exit(-1); - } - else { - fprintf(stdout, "OK\n"); - } + ABTS_ASSERT(tc, "matched expected file contents", + memcmp(expect, actual, expectlen) == 0); + + APR_ASSERT_SUCCESS(tc, "close file", apr_file_close(f)); +} + +#define LINE1 "this is a line of text\n" +#define LINE2 "this is a second line of text\n" + +static void test_puts(abts_case *tc, void *data) +{ + apr_file_t *f; + const char *fname = "data/testputs.txt"; + + APR_ASSERT_SUCCESS(tc, "open file for writing", + apr_file_open(&f, fname, + APR_FOPEN_WRITE|APR_FOPEN_CREATE|APR_FOPEN_TRUNCATE, + APR_FPROT_OS_DEFAULT, p)); - fprintf(stdout, "\tMaking sure it's gone......."); - status = ap_open(&thefile, filename, APR_READ, APR_UREAD | APR_UWRITE | APR_GREAD, context); - if (status == APR_SUCCESS) { - fprintf(stderr, "I could open the file for some reason?\n"); - exit(-1); - } - else { - fprintf(stdout, "OK\n"); - } + APR_ASSERT_SUCCESS(tc, "write line to file", + apr_file_puts(LINE1, f)); + APR_ASSERT_SUCCESS(tc, "write second line to file", + apr_file_puts(LINE2, f)); + + APR_ASSERT_SUCCESS(tc, "close for writing", + apr_file_close(f)); - testdirs(context); - test_filedel(context); + file_contents_equal(tc, fname, LINE1 LINE2, strlen(LINE1 LINE2)); +} + +static void test_writev(abts_case *tc, void *data) +{ + apr_file_t *f; + apr_size_t nbytes; + struct iovec vec[5]; + const char *fname = "data/testwritev.txt"; + + APR_ASSERT_SUCCESS(tc, "open file for writing", + apr_file_open(&f, fname, + APR_FOPEN_WRITE|APR_FOPEN_CREATE|APR_FOPEN_TRUNCATE, + APR_FPROT_OS_DEFAULT, p)); + + vec[0].iov_base = LINE1; + vec[0].iov_len = strlen(LINE1); + + APR_ASSERT_SUCCESS(tc, "writev of size 1 to file", + apr_file_writev(f, vec, 1, &nbytes)); + + file_contents_equal(tc, fname, LINE1, strlen(LINE1)); + + vec[0].iov_base = LINE1; + vec[0].iov_len = strlen(LINE1); + vec[1].iov_base = LINE2; + vec[1].iov_len = strlen(LINE2); + vec[2].iov_base = LINE1; + vec[2].iov_len = strlen(LINE1); + vec[3].iov_base = LINE1; + vec[3].iov_len = strlen(LINE1); + vec[4].iov_base = LINE2; + vec[4].iov_len = strlen(LINE2); + + APR_ASSERT_SUCCESS(tc, "writev of size 5 to file", + apr_file_writev(f, vec, 5, &nbytes)); + + APR_ASSERT_SUCCESS(tc, "close for writing", + apr_file_close(f)); + + file_contents_equal(tc, fname, LINE1 LINE1 LINE2 LINE1 LINE1 LINE2, + strlen(LINE1)*4 + strlen(LINE2)*2); - return 1; } -int test_filedel(ap_pool_t *context) +static void test_writev_full(abts_case *tc, void *data) { - ap_file_t *thefile = NULL; - ap_int32_t flag = APR_READ | APR_WRITE | APR_CREATE; - ap_status_t stat; - - stat = ap_open(&thefile, "testdel", flag, APR_UREAD | APR_UWRITE | APR_GREAD, context); - if (stat != APR_SUCCESS) { - return stat; - } + apr_file_t *f; + apr_size_t nbytes; + struct iovec vec[5]; + const char *fname = "data/testwritev_full.txt"; - if ((stat = ap_close(thefile)) != APR_SUCCESS) { - return stat; - } + APR_ASSERT_SUCCESS(tc, "open file for writing", + apr_file_open(&f, fname, + APR_FOPEN_WRITE|APR_FOPEN_CREATE|APR_FOPEN_TRUNCATE, + APR_FPROT_OS_DEFAULT, p)); + + vec[0].iov_base = LINE1; + vec[0].iov_len = strlen(LINE1); + vec[1].iov_base = LINE2; + vec[1].iov_len = strlen(LINE2); + vec[2].iov_base = LINE1; + vec[2].iov_len = strlen(LINE1); + vec[3].iov_base = LINE1; + vec[3].iov_len = strlen(LINE1); + vec[4].iov_base = LINE2; + vec[4].iov_len = strlen(LINE2); - if ((stat = ap_remove_file("testdel", context)) != APR_SUCCESS) { - return stat; - } + APR_ASSERT_SUCCESS(tc, "writev_full of size 5 to file", + apr_file_writev_full(f, vec, 5, &nbytes)); + + ABTS_SIZE_EQUAL(tc, strlen(LINE1)*3 + strlen(LINE2)*2, nbytes); + + APR_ASSERT_SUCCESS(tc, "close for writing", + apr_file_close(f)); + + file_contents_equal(tc, fname, LINE1 LINE2 LINE1 LINE1 LINE2, + strlen(LINE1)*3 + strlen(LINE2)*2); - stat = ap_open(&thefile, "testdel", APR_READ, APR_UREAD | APR_UWRITE | APR_GREAD, context); - if (stat == APR_SUCCESS) { - return stat; - } - - return APR_SUCCESS; } -int testdirs(ap_pool_t *context) +static void test_writev_buffered(abts_case *tc, void *data) { - ap_dir_t *temp; - ap_file_t *file = NULL; - ap_ssize_t bytes; - ap_filetype_e type; - char *fname; + apr_file_t *f; + apr_size_t nbytes; + struct iovec vec[2]; + const char *fname = "data/testwritev_buffered.dat"; - fprintf(stdout, "Testing Directory functions.\n"); + APR_ASSERT_SUCCESS(tc, "open file for writing", + apr_file_open(&f, fname, + APR_FOPEN_WRITE | APR_FOPEN_CREATE | APR_FOPEN_TRUNCATE | + APR_FOPEN_BUFFERED, APR_FPROT_OS_DEFAULT, p)); - fprintf(stdout, "\tMakeing Directory......."); - if (ap_make_dir("testdir", APR_UREAD | APR_UWRITE | APR_UEXECUTE | APR_GREAD | APR_GWRITE | APR_GEXECUTE | APR_WREAD | APR_WWRITE | APR_WEXECUTE, context) != APR_SUCCESS) { - fprintf(stderr, "Could not create directory\n"); - return -1; - } - else { - fprintf(stdout, "OK\n"); - } + nbytes = strlen(TESTSTR); + APR_ASSERT_SUCCESS(tc, "buffered write", + apr_file_write(f, TESTSTR, &nbytes)); - if (ap_open(&file, "testdir/testfile", APR_READ | APR_WRITE | APR_CREATE, APR_UREAD | APR_UWRITE | APR_UEXECUTE, context) != APR_SUCCESS) {; - return -1; - } + vec[0].iov_base = LINE1; + vec[0].iov_len = strlen(LINE1); + vec[1].iov_base = LINE2; + vec[1].iov_len = strlen(LINE2); - bytes = strlen("Another test!!!"); - ap_write(file, "Another test!!", &bytes); - ap_close(file); + APR_ASSERT_SUCCESS(tc, "writev of size 2 to file", + apr_file_writev(f, vec, 2, &nbytes)); - fprintf(stdout, "\tOpening Directory......."); - if (ap_opendir(&temp, "testdir", context) != APR_SUCCESS) { - fprintf(stderr, "Could not open directory\n"); - return -1; - } - else { - fprintf(stdout, "OK\n"); - } + APR_ASSERT_SUCCESS(tc, "close for writing", + apr_file_close(f)); - fprintf(stdout, "\tReading Directory......."); - if ((ap_readdir(temp)) != APR_SUCCESS) { - fprintf(stderr, "Could not read directory\n"); - return -1; - } - else { - fprintf(stdout, "OK\n"); - } - - fprintf(stdout, "\tGetting Information about the file.......\n"); - fprintf(stdout, "\t\tFile name......."); - do { - /* Because I want the file I created, I am skipping the "." and ".." - * files that are here. - */ - if (ap_readdir(temp) != APR_SUCCESS) { - fprintf(stderr, "Error reading directory testdir"); - return -1; - } - ap_get_dir_filename(&fname, temp); - } while (fname[0] == '.'); - if (strcmp(fname, "testfile")) { - fprintf(stderr, "Got wrong file name %s\n", fname); - return -1; - } - fprintf(stdout, "OK\n"); + file_contents_equal(tc, fname, TESTSTR LINE1 LINE2, + strlen(TESTSTR) + strlen(LINE1) + strlen(LINE2)); +} + +static void test_writev_buffered_seek(abts_case *tc, void *data) +{ + apr_file_t *f; + apr_status_t rv; + apr_off_t off = 0; + struct iovec vec[3]; + apr_size_t nbytes = strlen(TESTSTR); + char *str = apr_pcalloc(p, nbytes+1); + const char *fname = "data/testwritev_buffered.dat"; + + APR_ASSERT_SUCCESS(tc, "open file for writing", + apr_file_open(&f, fname, + APR_FOPEN_WRITE | APR_FOPEN_READ | APR_FOPEN_BUFFERED, + APR_FPROT_OS_DEFAULT, p)); + + rv = apr_file_read(f, str, &nbytes); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_STR_EQUAL(tc, TESTSTR, str); + APR_ASSERT_SUCCESS(tc, "buffered seek", apr_file_seek(f, APR_SET, &off)); + + vec[0].iov_base = LINE1; + vec[0].iov_len = strlen(LINE1); + vec[1].iov_base = LINE2; + vec[1].iov_len = strlen(LINE2); + vec[2].iov_base = TESTSTR; + vec[2].iov_len = strlen(TESTSTR); + + APR_ASSERT_SUCCESS(tc, "writev of size 2 to file", + apr_file_writev(f, vec, 3, &nbytes)); + + APR_ASSERT_SUCCESS(tc, "close for writing", + apr_file_close(f)); + + file_contents_equal(tc, fname, LINE1 LINE2 TESTSTR, + strlen(LINE1) + strlen(LINE2) + strlen(TESTSTR)); + + APR_ASSERT_SUCCESS(tc, "remove file", apr_file_remove(fname, p)); +} + +static void test_truncate(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_file_t *f; + const char *fname = "data/testtruncate.dat"; + const char *s; + apr_size_t nbytes; + apr_finfo_t finfo; + + apr_file_remove(fname, p); + + rv = apr_file_open(&f, fname, + APR_FOPEN_CREATE | APR_FOPEN_WRITE, + APR_FPROT_UREAD | APR_FPROT_UWRITE, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + s = "some data"; + nbytes = strlen(s); + rv = apr_file_write(f, s, &nbytes); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_SIZE_EQUAL(tc, strlen(s), nbytes); + + rv = apr_file_close(f); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + rv = apr_file_open(&f, fname, + APR_FOPEN_TRUNCATE | APR_FOPEN_WRITE, + APR_FPROT_UREAD | APR_FPROT_UWRITE, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + rv = apr_file_close(f); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + rv = apr_stat(&finfo, fname, APR_FINFO_SIZE, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_ASSERT(tc, "File size mismatch, expected 0 (empty)", finfo.size == 0); + + rv = apr_file_remove(fname, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); +} + +static void test_file_trunc(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_file_t *f; + const char *fname = "data/testtruncate.dat"; + const char *s; + apr_size_t nbytes; + apr_finfo_t finfo; + char c; + + apr_file_remove(fname, p); + + rv = apr_file_open(&f, fname, + APR_FOPEN_CREATE | APR_FOPEN_READ | + APR_FOPEN_WRITE, + APR_FPROT_UREAD | APR_FPROT_UWRITE, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + s = "some data"; + nbytes = strlen(s); + rv = apr_file_write(f, s, &nbytes); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_SIZE_EQUAL(tc, strlen(s), nbytes); + rv = apr_file_trunc(f, 4); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + /* Test apr_file_info_get(). */ + rv = apr_file_info_get(&finfo, APR_FINFO_SIZE, f); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_INT_EQUAL(tc, 4, (int)finfo.size); + /* EOF is not reported until the next read. */ + rv = apr_file_eof(f); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + rv = apr_file_getc(&c, f); + ABTS_INT_EQUAL(tc, APR_EOF, rv); + rv = apr_file_eof(f); + ABTS_INT_EQUAL(tc, APR_EOF, rv); + + rv = apr_file_close(f); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + rv = apr_stat(&finfo, fname, APR_FINFO_SIZE, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_INT_EQUAL(tc, 4, (int)finfo.size); + + rv = apr_file_remove(fname, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); +} + +static void test_file_trunc_buffered_write(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_file_t *f; + const char *fname = "data/testtruncate_buffered_write.dat"; + const char *s; + apr_size_t nbytes; + apr_finfo_t finfo; + char c; + + apr_file_remove(fname, p); + + rv = apr_file_open(&f, fname, + APR_FOPEN_CREATE | APR_FOPEN_READ | + APR_FOPEN_WRITE | APR_FOPEN_BUFFERED, + APR_FPROT_UREAD | APR_FPROT_UWRITE, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + s = "some data"; + nbytes = strlen(s); + rv = apr_file_write(f, s, &nbytes); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_SIZE_EQUAL(tc, strlen(s), nbytes); + rv = apr_file_trunc(f, 4); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + /* Test apr_file_info_get(). */ + rv = apr_file_info_get(&finfo, APR_FINFO_SIZE, f); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_INT_EQUAL(tc, 4, (int)finfo.size); + /* EOF is not reported until the next read. */ + rv = apr_file_eof(f); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + rv = apr_file_getc(&c, f); + ABTS_INT_EQUAL(tc, APR_EOF, rv); + rv = apr_file_eof(f); + ABTS_INT_EQUAL(tc, APR_EOF, rv); + + rv = apr_file_close(f); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + rv = apr_stat(&finfo, fname, APR_FINFO_SIZE, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_INT_EQUAL(tc, 4, (int)finfo.size); + + rv = apr_file_remove(fname, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); +} + +static void test_file_trunc_buffered_write2(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_file_t *f; + const char *fname = "data/testtruncate_buffered_write2.dat"; + apr_finfo_t finfo; + char c; - fprintf(stdout, "\t\tFile type......."); - ap_dir_entry_ftype(&type, temp); - if (type != APR_REG) { - fprintf(stderr, "Got wrong file type\n"); - return -1; + apr_file_remove(fname, p); + + rv = apr_file_open(&f, fname, + APR_FOPEN_CREATE | APR_FOPEN_READ | + APR_FOPEN_WRITE | APR_FOPEN_BUFFERED, + APR_FPROT_OS_DEFAULT, p); + APR_ASSERT_SUCCESS(tc, "open test file", rv); + + rv = apr_file_puts("abc", f); + APR_ASSERT_SUCCESS(tc, "write first string", rv); + rv = apr_file_flush(f); + APR_ASSERT_SUCCESS(tc, "flush", rv); + rv = apr_file_puts("def", f); + APR_ASSERT_SUCCESS(tc, "write second string", rv); + /* Truncate behind the write buffer. */ + rv = apr_file_trunc(f, 2); + APR_ASSERT_SUCCESS(tc, "truncate the file", rv); + /* Test apr_file_info_get(). */ + rv = apr_file_info_get(&finfo, APR_FINFO_SIZE, f); + APR_ASSERT_SUCCESS(tc, "get file info", rv); + ABTS_INT_EQUAL(tc, 2, (int)finfo.size); + /* EOF is not reported until the next read. */ + rv = apr_file_eof(f); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + rv = apr_file_getc(&c, f); + ABTS_INT_EQUAL(tc, APR_EOF, rv); + rv = apr_file_eof(f); + ABTS_INT_EQUAL(tc, APR_EOF, rv); + + apr_file_close(f); + + rv = apr_stat(&finfo, fname, APR_FINFO_SIZE, p); + APR_ASSERT_SUCCESS(tc, "stat file", rv); + ABTS_INT_EQUAL(tc, 2, (int)finfo.size); + + apr_file_remove(fname, p); +} + +static void test_file_trunc_buffered_read(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_file_t *f; + const char *fname = "data/testtruncate_buffered_read.dat"; + apr_finfo_t finfo; + char c; + + apr_file_remove(fname, p); + + rv = apr_file_open(&f, fname, + APR_FOPEN_CREATE | APR_FOPEN_READ | + APR_FOPEN_WRITE, APR_FPROT_OS_DEFAULT, p); + APR_ASSERT_SUCCESS(tc, "open test file", rv); + + rv = apr_file_puts("abc", f); + APR_ASSERT_SUCCESS(tc, "write test data", rv); + apr_file_close(f); + + rv = apr_file_open(&f, fname, + APR_FOPEN_READ | APR_FOPEN_WRITE | + APR_FOPEN_BUFFERED, APR_FPROT_OS_DEFAULT, p); + APR_ASSERT_SUCCESS(tc, "re-open test file", rv); + + /* Read to fill in the buffer. */ + rv = apr_file_getc(&c, f); + APR_ASSERT_SUCCESS(tc, "read char", rv); + /* Truncate the file. */ + rv = apr_file_trunc(f, 1); + APR_ASSERT_SUCCESS(tc, "truncate the file", rv); + /* Test apr_file_info_get(). */ + rv = apr_file_info_get(&finfo, APR_FINFO_SIZE, f); + APR_ASSERT_SUCCESS(tc, "get file info", rv); + ABTS_INT_EQUAL(tc, 1, (int)finfo.size); + /* EOF is not reported until the next read. */ + rv = apr_file_eof(f); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + rv = apr_file_getc(&c, f); + ABTS_INT_EQUAL(tc, APR_EOF, rv); + rv = apr_file_eof(f); + ABTS_INT_EQUAL(tc, APR_EOF, rv); + + apr_file_close(f); + + rv = apr_stat(&finfo, fname, APR_FINFO_SIZE, p); + APR_ASSERT_SUCCESS(tc, "stat file", rv); + ABTS_INT_EQUAL(tc, 1, (int)finfo.size); + + apr_file_remove(fname, p); +} + +static void test_bigfprintf(abts_case *tc, void *data) +{ + apr_file_t *f; + const char *fname = "data/testbigfprintf.dat"; + char *to_write; + int i; + + apr_file_remove(fname, p); + + APR_ASSERT_SUCCESS(tc, "open test file", + apr_file_open(&f, fname, + APR_FOPEN_CREATE|APR_FOPEN_WRITE, + APR_FPROT_UREAD|APR_FPROT_UWRITE, p)); + + + to_write = malloc(HUGE_STRING_LEN + 3); + + for (i = 0; i < HUGE_STRING_LEN + 1; ++i) + to_write[i] = 'A' + i%26; + + strcpy(to_write + HUGE_STRING_LEN, "42"); + + i = apr_file_printf(f, "%s", to_write); + ABTS_INT_EQUAL(tc, HUGE_STRING_LEN + 2, i); + + apr_file_close(f); + + file_contents_equal(tc, fname, to_write, HUGE_STRING_LEN + 2); + + free(to_write); +} + +static void test_fail_write_flush(abts_case *tc, void *data) +{ + apr_file_t *f; + const char *fname = "data/testflush.dat"; + apr_status_t rv; + char buf[APR_BUFFERSIZE]; + int n; + + apr_file_remove(fname, p); + + APR_ASSERT_SUCCESS(tc, "open test file", + apr_file_open(&f, fname, + APR_FOPEN_CREATE|APR_FOPEN_READ|APR_FOPEN_BUFFERED, + APR_FPROT_UREAD|APR_FPROT_UWRITE, p)); + + memset(buf, 'A', sizeof buf); + + /* Try three writes. One of these should fail when it exceeds the + * internal buffer and actually tries to write to the file, which + * was opened read-only and hence should be unwritable. */ + for (n = 0, rv = APR_SUCCESS; n < 4 && rv == APR_SUCCESS; n++) { + apr_size_t bytes = sizeof buf; + rv = apr_file_write(f, buf, &bytes); } - fprintf(stdout, "OK\n"); - fprintf(stdout, "\t\tFile size......."); - ap_dir_entry_size(&bytes, temp); - if (bytes != (ap_ssize_t)strlen("Another test!!!")) { - fprintf(stderr, "Got wrong file size %d\n", bytes); - return -1; + ABTS_ASSERT(tc, "failed to write to read-only buffered fd", + rv != APR_SUCCESS); + + apr_file_close(f); +} + +static void test_fail_read_flush(abts_case *tc, void *data) +{ + apr_file_t *f; + const char *fname = "data/testflush.dat"; + apr_status_t rv; + char buf[2]; + + apr_file_remove(fname, p); + + APR_ASSERT_SUCCESS(tc, "open test file", + apr_file_open(&f, fname, + APR_FOPEN_CREATE|APR_FOPEN_READ|APR_FOPEN_BUFFERED, + APR_FPROT_UREAD|APR_FPROT_UWRITE, p)); + + /* this write should be buffered. */ + APR_ASSERT_SUCCESS(tc, "buffered write should succeed", + apr_file_puts("hello", f)); + + /* Now, trying a read should fail since the write must be flushed, + * and should fail with something other than EOF since the file is + * opened read-only. */ + rv = apr_file_read_full(f, buf, 2, NULL); + + ABTS_ASSERT(tc, "read should flush buffered write and fail", + rv != APR_SUCCESS && rv != APR_EOF); + + /* Likewise for gets */ + rv = apr_file_gets(buf, 2, f); + + ABTS_ASSERT(tc, "gets should flush buffered write and fail", + rv != APR_SUCCESS && rv != APR_EOF); + + /* Likewise for seek. */ + { + apr_off_t offset = 0; + + rv = apr_file_seek(f, APR_SET, &offset); } - fprintf(stdout, "OK\n"); - - fprintf(stdout, "\tRewinding directory......."); - ap_rewinddir(temp); - fprintf(stdout, "OK\n"); + + ABTS_ASSERT(tc, "seek should flush buffered write and fail", + rv != APR_SUCCESS && rv != APR_EOF); + + apr_file_close(f); +} + +static void test_xthread(abts_case *tc, void *data) +{ + apr_file_t *f; + const char *fname = "data/testxthread.dat"; + apr_status_t rv; + apr_int32_t flags = APR_FOPEN_CREATE|APR_FOPEN_READ|APR_FOPEN_WRITE|APR_FOPEN_APPEND|APR_FOPEN_XTHREAD; + char buf[128] = { 0 }; + + /* Test for bug 38438, opening file with append + xthread and seeking to + the end of the file resulted in writes going to the beginning not the + end. */ + + apr_file_remove(fname, p); + + APR_ASSERT_SUCCESS(tc, "open test file", + apr_file_open(&f, fname, flags, + APR_FPROT_UREAD|APR_FPROT_UWRITE, p)); + + APR_ASSERT_SUCCESS(tc, "write should succeed", + apr_file_puts("hello", f)); + + apr_file_close(f); - fprintf(stdout, "\tClosing Directory......."); - if (ap_closedir(temp) != APR_SUCCESS) { - fprintf(stderr, "Could not close directory\n"); - return -1; + APR_ASSERT_SUCCESS(tc, "open test file", + apr_file_open(&f, fname, flags, + APR_FPROT_UREAD|APR_FPROT_UWRITE, p)); + + /* Seek to the end. */ + { + apr_off_t offset = 0; + + rv = apr_file_seek(f, APR_END, &offset); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); } - else { - fprintf(stdout, "OK\n"); + + APR_ASSERT_SUCCESS(tc, "more writes should succeed", + apr_file_puts("world", f)); + + /* Back to the beginning. */ + { + apr_off_t offset = 0; + + rv = apr_file_seek(f, APR_SET, &offset); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); } + + apr_file_read_full(f, buf, sizeof(buf), NULL); + + ABTS_STR_EQUAL(tc, "helloworld", buf); + + apr_file_close(f); +} + +static void test_append(abts_case *tc, void *data) +{ + apr_file_t *f1; + apr_file_t *f2; + const char *fname = "data/testappend.dat"; + apr_int32_t flags = APR_FOPEN_CREATE | APR_FOPEN_READ | APR_FOPEN_WRITE | APR_FOPEN_APPEND; + char buf[128]; + apr_off_t offset; + + apr_file_remove(fname, p); + + /* Open test file with APR_FOPEN_APPEND, but without APR_FOPEN_XTHREAD. */ + APR_ASSERT_SUCCESS(tc, "open test file", + apr_file_open(&f1, fname, flags, APR_FPROT_OS_DEFAULT, p)); + + /* Open test file with APR_FOPEN_APPEND and APR_FOPEN_XTHREAD. */ + APR_ASSERT_SUCCESS(tc, "open test file", + apr_file_open(&f2, fname, flags | APR_FOPEN_XTHREAD, APR_FPROT_OS_DEFAULT, p)); + + APR_ASSERT_SUCCESS(tc, "write should succeed", + apr_file_puts("w1", f1)); + offset = 0; + APR_ASSERT_SUCCESS(tc, "seek should succeed", + apr_file_seek(f1, APR_CUR, &offset)); + ABTS_INT_EQUAL(tc, 2, (int) offset); + + APR_ASSERT_SUCCESS(tc, "write should succeed", + apr_file_puts("w2", f2)); + offset = 0; + APR_ASSERT_SUCCESS(tc, "seek should succeed", + apr_file_seek(f2, APR_CUR, &offset)); + ABTS_INT_EQUAL(tc, 4, (int) offset); + + APR_ASSERT_SUCCESS(tc, "write should succeed", + apr_file_puts("w3", f1)); + offset = 0; + APR_ASSERT_SUCCESS(tc, "seek should succeed", + apr_file_seek(f1, APR_CUR, &offset)); + ABTS_INT_EQUAL(tc, 6, (int) offset); + + APR_ASSERT_SUCCESS(tc, "write should succeed", + apr_file_puts("w4", f2)); + + offset = 0; + APR_ASSERT_SUCCESS(tc, "seek should succeed", + apr_file_seek(f2, APR_CUR, &offset)); + ABTS_INT_EQUAL(tc, 8, (int) offset); + + /* Check file content file using F1. */ + offset = 0; + APR_ASSERT_SUCCESS(tc, "seek should succeed", + apr_file_seek(f1, APR_SET, &offset)); + memset(buf, 0, sizeof(buf)); + apr_file_read_full(f1, buf, sizeof(buf), NULL); + ABTS_STR_EQUAL(tc, "w1w2w3w4", buf); + + /* Check file content file using F2. */ + offset = 0; + APR_ASSERT_SUCCESS(tc, "seek should succeed", + apr_file_seek(f2, APR_SET, &offset)); + memset(buf, 0, sizeof(buf)); + apr_file_read_full(f2, buf, sizeof(buf), NULL); + ABTS_STR_EQUAL(tc, "w1w2w3w4", buf); + + apr_file_close(f1); + apr_file_close(f2); +} + +static void test_large_write_buffered(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_file_t *f; + const char *fname = "data/testlarge_write_buffered.dat"; + apr_size_t len; + apr_size_t bytes_written; + apr_size_t bytes_read; + char *buf; + char *buf2; + + apr_file_remove(fname, p); + + rv = apr_file_open(&f, fname, + APR_FOPEN_CREATE | APR_FOPEN_WRITE | APR_FOPEN_BUFFERED, + APR_FPROT_OS_DEFAULT, p); + APR_ASSERT_SUCCESS(tc, "open test file for writing", rv); + + /* Test a single large write. */ + len = 80000; + buf = apr_palloc(p, len); + memset(buf, 'a', len); + rv = apr_file_write_full(f, buf, len, &bytes_written); + APR_ASSERT_SUCCESS(tc, "write to file", rv); + ABTS_INT_EQUAL(tc, (int)len, (int)bytes_written); + apr_file_close(f); + + rv = apr_file_open(&f, fname, APR_FOPEN_READ, + APR_FPROT_OS_DEFAULT, p); + APR_ASSERT_SUCCESS(tc, "open test file for reading", rv); + + buf2 = apr_palloc(p, len + 1); + rv = apr_file_read_full(f, buf2, len + 1, &bytes_read); + ABTS_INT_EQUAL(tc, APR_EOF, rv); + ABTS_INT_EQUAL(tc, (int)len, (int)bytes_read); + ABTS_TRUE(tc, memcmp(buf, buf2, len) == 0); + apr_file_close(f); + + apr_file_remove(fname, p); +} + +static void test_two_large_writes_buffered(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_file_t *f; + const char *fname = "data/testtwo_large_writes_buffered.dat"; + apr_size_t len; + apr_size_t bytes_written; + apr_size_t bytes_read; + char *buf; + char *buf2; + + apr_file_remove(fname, p); + + rv = apr_file_open(&f, fname, + APR_FOPEN_CREATE | APR_FOPEN_WRITE | APR_FOPEN_BUFFERED, + APR_FPROT_OS_DEFAULT, p); + APR_ASSERT_SUCCESS(tc, "open test file for writing", rv); + + /* Test two consecutive large writes. */ + len = 80000; + buf = apr_palloc(p, len); + memset(buf, 'a', len); + + rv = apr_file_write_full(f, buf, len / 2, &bytes_written); + APR_ASSERT_SUCCESS(tc, "write to file", rv); + ABTS_INT_EQUAL(tc, (int)(len / 2), (int)bytes_written); + + rv = apr_file_write_full(f, buf, len / 2, &bytes_written); + APR_ASSERT_SUCCESS(tc, "write to file", rv); + ABTS_INT_EQUAL(tc, (int)(len / 2), (int)bytes_written); + + apr_file_close(f); + + rv = apr_file_open(&f, fname, APR_FOPEN_READ, + APR_FPROT_OS_DEFAULT, p); + APR_ASSERT_SUCCESS(tc, "open test file for reading", rv); + + buf2 = apr_palloc(p, len + 1); + rv = apr_file_read_full(f, buf2, len + 1, &bytes_read); + ABTS_INT_EQUAL(tc, APR_EOF, rv); + ABTS_INT_EQUAL(tc, (int) len, (int)bytes_read); + ABTS_TRUE(tc, memcmp(buf, buf2, len) == 0); + apr_file_close(f); + + apr_file_remove(fname, p); +} + +static void test_small_and_large_writes_buffered(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_file_t *f; + const char *fname = "data/testtwo_large_writes_buffered.dat"; + apr_size_t len; + apr_size_t bytes_written; + apr_size_t bytes_read; + char *buf; + char *buf2; + + apr_file_remove(fname, p); + + rv = apr_file_open(&f, fname, + APR_FOPEN_CREATE | APR_FOPEN_WRITE | APR_FOPEN_BUFFERED, + APR_FPROT_OS_DEFAULT, p); + APR_ASSERT_SUCCESS(tc, "open test file for writing", rv); + + /* Test small write followed by a large write. */ + len = 80000; + buf = apr_palloc(p, len); + memset(buf, 'a', len); + + rv = apr_file_write_full(f, buf, 5, &bytes_written); + APR_ASSERT_SUCCESS(tc, "write to file", rv); + ABTS_INT_EQUAL(tc, 5, (int)bytes_written); + + rv = apr_file_write_full(f, buf, len - 5, &bytes_written); + APR_ASSERT_SUCCESS(tc, "write to file", rv); + ABTS_INT_EQUAL(tc, (int)(len - 5), (int)bytes_written); + + apr_file_close(f); + + rv = apr_file_open(&f, fname, APR_FOPEN_READ, + APR_FPROT_OS_DEFAULT, p); + APR_ASSERT_SUCCESS(tc, "open test file for reading", rv); + + buf2 = apr_palloc(p, len + 1); + rv = apr_file_read_full(f, buf2, len + 1, &bytes_read); + ABTS_INT_EQUAL(tc, APR_EOF, rv); + ABTS_INT_EQUAL(tc, (int) len, (int)bytes_read); + ABTS_TRUE(tc, memcmp(buf, buf2, len) == 0); + apr_file_close(f); + + apr_file_remove(fname, p); +} + +static void test_write_buffered_spanning_over_bufsize(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_file_t *f; + const char *fname = "data/testwrite_buffered_spanning_over_bufsize.dat"; + apr_size_t len; + apr_size_t bytes_written; + apr_size_t bytes_read; + char *buf; + char *buf2; - fprintf(stdout, "\tRemoving file from directory......."); - if (ap_remove_file("testdir/testfile", context) != APR_SUCCESS) { - fprintf(stderr, "Could not remove file\n"); - return -1; + apr_file_remove(fname, p); + + rv = apr_file_open(&f, fname, + APR_FOPEN_CREATE | APR_FOPEN_WRITE | APR_FOPEN_BUFFERED, + APR_FPROT_OS_DEFAULT, p); + APR_ASSERT_SUCCESS(tc, "open test file for writing", rv); + + /* Test three writes than span over the default buffer size. */ + len = APR_BUFFERSIZE + 1; + buf = apr_palloc(p, len); + memset(buf, 'a', len); + + rv = apr_file_write_full(f, buf, APR_BUFFERSIZE - 1, &bytes_written); + APR_ASSERT_SUCCESS(tc, "write to file", rv); + ABTS_INT_EQUAL(tc, APR_BUFFERSIZE - 1, (int)bytes_written); + + rv = apr_file_write_full(f, buf, 2, &bytes_written); + APR_ASSERT_SUCCESS(tc, "write to file", rv); + ABTS_INT_EQUAL(tc, 2, (int)bytes_written); + + apr_file_close(f); + + rv = apr_file_open(&f, fname, APR_FOPEN_READ, + APR_FPROT_OS_DEFAULT, p); + APR_ASSERT_SUCCESS(tc, "open test file for reading", rv); + + buf2 = apr_palloc(p, len + 1); + rv = apr_file_read_full(f, buf2, len + 1, &bytes_read); + ABTS_INT_EQUAL(tc, APR_EOF, rv); + ABTS_INT_EQUAL(tc, (int)len, (int)bytes_read); + ABTS_TRUE(tc, memcmp(buf, buf2, len) == 0); + apr_file_close(f); + + apr_file_remove(fname, p); +} + +typedef struct thread_file_append_ctx_t { + apr_pool_t *pool; + const char *fname; + apr_size_t chunksize; + char val; + int num_writes; + char *errmsg; +} thread_file_append_ctx_t; + +static void * APR_THREAD_FUNC thread_file_append_func(apr_thread_t *thd, void *data) +{ + thread_file_append_ctx_t *ctx = data; + apr_status_t rv; + apr_file_t *f; + int i; + char *writebuf; + char *readbuf; + + rv = apr_file_open(&f, ctx->fname, + APR_FOPEN_READ | APR_FOPEN_WRITE | APR_FOPEN_APPEND, + APR_FPROT_OS_DEFAULT, ctx->pool); + if (rv) { + apr_thread_exit(thd, rv); + return NULL; } - else { - fprintf(stdout, "OK\n"); + + writebuf = apr_palloc(ctx->pool, ctx->chunksize); + memset(writebuf, ctx->val, ctx->chunksize); + readbuf = apr_palloc(ctx->pool, ctx->chunksize); + + for (i = 0; i < ctx->num_writes; i++) { + apr_size_t bytes_written; + apr_size_t bytes_read; + apr_off_t offset; + + rv = apr_file_write_full(f, writebuf, ctx->chunksize, &bytes_written); + if (rv) { + apr_thread_exit(thd, rv); + return NULL; + } + /* After writing the data, seek back from the current offset and + * verify what we just wrote. */ + offset = -((apr_off_t)ctx->chunksize); + rv = apr_file_seek(f, APR_CUR, &offset); + if (rv) { + apr_thread_exit(thd, rv); + return NULL; + } + rv = apr_file_read_full(f, readbuf, ctx->chunksize, &bytes_read); + if (rv) { + apr_thread_exit(thd, rv); + return NULL; + } + if (memcmp(readbuf, writebuf, ctx->chunksize) != 0) { + ctx->errmsg = apr_psprintf( + ctx->pool, + "Unexpected data at file offset %" APR_OFF_T_FMT, + offset); + apr_thread_exit(thd, APR_SUCCESS); + return NULL; + } } - fprintf(stdout, "\tRemoving Directory......."); - if (ap_remove_dir("testdir", context) != APR_SUCCESS) { - fprintf(stderr, "Could not remove directory\n"); - return -1; + apr_file_close(f); + apr_thread_exit(thd, APR_SUCCESS); + + return NULL; +} + +static void test_atomic_append(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_status_t thread_rv; + apr_file_t *f; + const char *fname = "data/testatomic_append.dat"; + unsigned int seed; + thread_file_append_ctx_t ctx1 = {0}; + thread_file_append_ctx_t ctx2 = {0}; + apr_thread_t *t1; + apr_thread_t *t2; + + apr_file_remove(fname, p); + + rv = apr_file_open(&f, fname, APR_FOPEN_WRITE | APR_FOPEN_CREATE, + APR_FPROT_OS_DEFAULT, p); + APR_ASSERT_SUCCESS(tc, "create file", rv); + apr_file_close(f); + + seed = (unsigned int)apr_time_now(); + abts_log_message("Random seed for test_atomic_append() is %u", seed); + srand(seed); + + /* Create two threads appending data to the same file. */ + apr_pool_create(&ctx1.pool, p); + ctx1.fname = fname; + ctx1.chunksize = 1 + rand() % 8192; + ctx1.val = 'A'; + ctx1.num_writes = 1000; + rv = apr_thread_create(&t1, NULL, thread_file_append_func, &ctx1, p); + APR_ASSERT_SUCCESS(tc, "create thread", rv); + + apr_pool_create(&ctx2.pool, p); + ctx2.fname = fname; + ctx2.chunksize = 1 + rand() % 8192; + ctx2.val = 'B'; + ctx2.num_writes = 1000; + rv = apr_thread_create(&t2, NULL, thread_file_append_func, &ctx2, p); + APR_ASSERT_SUCCESS(tc, "create thread", rv); + + rv = apr_thread_join(&thread_rv, t1); + APR_ASSERT_SUCCESS(tc, "join thread", rv); + APR_ASSERT_SUCCESS(tc, "no thread errors", thread_rv); + if (ctx1.errmsg) { + ABTS_FAIL(tc, ctx1.errmsg); } - else { - fprintf(stdout, "OK\n"); + rv = apr_thread_join(&thread_rv, t2); + APR_ASSERT_SUCCESS(tc, "join thread", rv); + APR_ASSERT_SUCCESS(tc, "no thread errors", thread_rv); + if (ctx2.errmsg) { + ABTS_FAIL(tc, ctx2.errmsg); } - - return 1; -} + + apr_file_remove(fname, p); +} + +static void test_append_locked(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_file_t *f; + const char *fname = "data/testappend_locked.dat"; + apr_size_t bytes_written; + apr_size_t bytes_read; + char buf[64] = {0}; + + apr_file_remove(fname, p); + + rv = apr_file_open(&f, fname, + APR_FOPEN_WRITE | APR_FOPEN_CREATE | APR_FOPEN_APPEND, + APR_FPROT_OS_DEFAULT, p); + APR_ASSERT_SUCCESS(tc, "create file", rv); + + rv = apr_file_lock(f, APR_FLOCK_EXCLUSIVE); + APR_ASSERT_SUCCESS(tc, "lock file", rv); + + /* PR50058: Appending to a locked file should not deadlock. */ + rv = apr_file_write_full(f, "abc", 3, &bytes_written); + APR_ASSERT_SUCCESS(tc, "write to file", rv); + + apr_file_unlock(f); + apr_file_close(f); + + rv = apr_file_open(&f, fname, APR_FOPEN_READ, APR_FPROT_OS_DEFAULT, p); + APR_ASSERT_SUCCESS(tc, "open file", rv); + + rv = apr_file_read_full(f, buf, sizeof(buf), &bytes_read); + ABTS_INT_EQUAL(tc, APR_EOF, rv); + ABTS_INT_EQUAL(tc, 3, (int)bytes_read); + ABTS_STR_EQUAL(tc, "abc", buf); + + apr_file_close(f); + apr_file_remove(fname, p); +} + +static void test_append_read(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_file_t *f; + const char *fname = "data/testappend_read.dat"; + apr_off_t offset; + char buf[64]; + + apr_file_remove(fname, p); + + /* Create file with contents. */ + rv = apr_file_open(&f, fname, APR_FOPEN_WRITE | APR_FOPEN_CREATE, + APR_FPROT_OS_DEFAULT, p); + APR_ASSERT_SUCCESS(tc, "create file", rv); + + rv = apr_file_puts("abc", f); + APR_ASSERT_SUCCESS(tc, "write to file", rv); + apr_file_close(f); + + /* Re-open it with APR_FOPEN_APPEND. */ + rv = apr_file_open(&f, fname, + APR_FOPEN_READ | APR_FOPEN_WRITE | APR_FOPEN_APPEND, + APR_FPROT_OS_DEFAULT, p); + APR_ASSERT_SUCCESS(tc, "open file", rv); + + /* Test the initial file offset. Even though we used APR_FOPEN_APPEND, + * the offset should be kept in the beginning of the file until the + * first append. (Previously, the Windows implementation performed + * an erroneous seek to the file's end right after opening it.) + */ + offset = 0; + rv = apr_file_seek(f, APR_CUR, &offset); + APR_ASSERT_SUCCESS(tc, "get file offset", rv); + ABTS_INT_EQUAL(tc, 0, (int)offset); + + /* Test reading from the file. */ + rv = apr_file_gets(buf, sizeof(buf), f); + APR_ASSERT_SUCCESS(tc, "read from file", rv); + ABTS_STR_EQUAL(tc, "abc", buf); + + /* Test the file offset after reading. */ + offset = 0; + rv = apr_file_seek(f, APR_CUR, &offset); + APR_ASSERT_SUCCESS(tc, "get file offset", rv); + ABTS_INT_EQUAL(tc, 3, (int)offset); + + apr_file_close(f); + apr_file_remove(fname, p); +} + +abts_suite *testfile(abts_suite *suite) +{ + suite = ADD_SUITE(suite) + + abts_run_test(suite, test_open_noreadwrite, NULL); + abts_run_test(suite, test_open_excl, NULL); + abts_run_test(suite, test_open_read, NULL); + abts_run_test(suite, test_open_readwrite, NULL); + abts_run_test(suite, link_existing, NULL); + abts_run_test(suite, link_nonexisting, NULL); + abts_run_test(suite, test_read, NULL); + abts_run_test(suite, test_readzero, NULL); + abts_run_test(suite, test_seek, NULL); + abts_run_test(suite, test_filename, NULL); + abts_run_test(suite, test_fileclose, NULL); + abts_run_test(suite, test_file_remove, NULL); + abts_run_test(suite, test_open_write, NULL); + abts_run_test(suite, test_open_writecreate, NULL); + abts_run_test(suite, test_write, NULL); + abts_run_test(suite, test_userdata_set, NULL); + abts_run_test(suite, test_userdata_get, NULL); + abts_run_test(suite, test_userdata_getnokey, NULL); + abts_run_test(suite, test_getc, NULL); + abts_run_test(suite, test_ungetc, NULL); + abts_run_test(suite, test_gets, NULL); + abts_run_test(suite, test_gets_buffered, NULL); + abts_run_test(suite, test_gets_empty, NULL); + abts_run_test(suite, test_gets_multiline, NULL); + abts_run_test(suite, test_gets_small_buf, NULL); + abts_run_test(suite, test_gets_ungetc, NULL); + abts_run_test(suite, test_gets_buffered_big, NULL); + abts_run_test(suite, test_puts, NULL); + abts_run_test(suite, test_writev, NULL); + abts_run_test(suite, test_writev_full, NULL); + abts_run_test(suite, test_writev_buffered, NULL); + abts_run_test(suite, test_writev_buffered_seek, NULL); + abts_run_test(suite, test_bigread, NULL); + abts_run_test(suite, test_mod_neg, NULL); + abts_run_test(suite, test_truncate, NULL); + abts_run_test(suite, test_file_trunc, NULL); + abts_run_test(suite, test_file_trunc_buffered_write, NULL); + abts_run_test(suite, test_file_trunc_buffered_write2, NULL); + abts_run_test(suite, test_file_trunc_buffered_read, NULL); + abts_run_test(suite, test_bigfprintf, NULL); + abts_run_test(suite, test_fail_write_flush, NULL); + abts_run_test(suite, test_fail_read_flush, NULL); + abts_run_test(suite, test_buffer_set_get, NULL); + abts_run_test(suite, test_xthread, NULL); + abts_run_test(suite, test_append, NULL); + abts_run_test(suite, test_large_write_buffered, NULL); + abts_run_test(suite, test_two_large_writes_buffered, NULL); + abts_run_test(suite, test_small_and_large_writes_buffered, NULL); + abts_run_test(suite, test_write_buffered_spanning_over_bufsize, NULL); + abts_run_test(suite, test_atomic_append, NULL); + abts_run_test(suite, test_append_locked, NULL); + abts_run_test(suite, test_append_read, NULL); + + return suite; +} diff --git a/test/testfile.dsp b/test/testfile.dsp deleted file mode 100644 index 25671fdf927..00000000000 --- a/test/testfile.dsp +++ /dev/null @@ -1,92 +0,0 @@ -# Microsoft Developer Studio Project File - Name="testfile" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 5.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Console Application" 0x0103 - -CFG=testfile - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "testfile.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "testfile.mak" CFG="testfile - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "testfile - Win32 Release" (based on\ - "Win32 (x86) Console Application") -!MESSAGE "testfile - Win32 Debug" (based on "Win32 (x86) Console Application") -!MESSAGE - -# Begin Project -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -RSC=rc.exe - -!IF "$(CFG)" == "testfile - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /W3 /GX /O2 /I "..\include" /I "..\..\include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD BASE RSC /l 0x409 /d "NDEBUG" -# ADD RSC /l 0x409 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 -# ADD LINK32 ..\Release\aprlib.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"..\Release\testfile.exe" -# SUBTRACT LINK32 /debug - -!ELSEIF "$(CFG)" == "testfile - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /I "..\include" /I "..\..\include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /FD /c -# SUBTRACT CPP /YX /Yc /Yu -# ADD BASE RSC /l 0x409 /d "_DEBUG" -# ADD RSC /l 0x409 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept -# ADD LINK32 ..\Debug\aprlib.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"..\Debug\testfile.exe" /pdbtype:sept - -!ENDIF - -# Begin Target - -# Name "testfile - Win32 Release" -# Name "testfile - Win32 Debug" -# Begin Source File - -SOURCE=.\testfile.c -# End Source File -# End Target -# End Project diff --git a/test/testfilecopy.c b/test/testfilecopy.c new file mode 100644 index 00000000000..fc2dea48b06 --- /dev/null +++ b/test/testfilecopy.c @@ -0,0 +1,138 @@ +/* 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 "testutil.h" +#include "apr_file_io.h" +#include "apr_file_info.h" +#include "apr_errno.h" +#include "apr_pools.h" + +static void copy_helper(abts_case *tc, const char *from, const char * to, + apr_fileperms_t perms, int append, apr_pool_t *p) +{ + apr_status_t rv; + apr_status_t dest_rv; + apr_finfo_t copy; + apr_finfo_t orig; + apr_finfo_t dest; + + dest_rv = apr_stat(&dest, to, APR_FINFO_SIZE, p); + + if (!append) { + rv = apr_file_copy(from, to, perms, p); + } + else { + rv = apr_file_append(from, to, perms, p); + } + APR_ASSERT_SUCCESS(tc, "Error copying file", rv); + + rv = apr_stat(&orig, from, APR_FINFO_SIZE, p); + APR_ASSERT_SUCCESS(tc, "Couldn't stat original file", rv); + + rv = apr_stat(©, to, APR_FINFO_SIZE, p); + APR_ASSERT_SUCCESS(tc, "Couldn't stat copy file", rv); + + if (!append) { + ABTS_ASSERT(tc, "File size differs", orig.size == copy.size); + } + else { + ABTS_ASSERT(tc, "File size differs", + ((dest_rv == APR_SUCCESS) + ? dest.size : 0) + orig.size == copy.size); + } +} + +static void copy_short_file(abts_case *tc, void *data) +{ + apr_status_t rv; + + /* make absolutely sure that the dest file doesn't exist. */ + apr_file_remove("data/file_copy.txt", p); + + copy_helper(tc, "data/file_datafile.txt", "data/file_copy.txt", + APR_FPROT_FILE_SOURCE_PERMS, 0, p); + rv = apr_file_remove("data/file_copy.txt", p); + APR_ASSERT_SUCCESS(tc, "Couldn't remove copy file", rv); +} + +static void copy_over_existing(abts_case *tc, void *data) +{ + apr_status_t rv; + + /* make absolutely sure that the dest file doesn't exist. */ + apr_file_remove("data/file_copy.txt", p); + + /* This is a cheat. I don't want to create a new file, so I just copy + * one file, then I copy another. If the second copy succeeds, then + * this works. + */ + copy_helper(tc, "data/file_datafile.txt", "data/file_copy.txt", + APR_FPROT_FILE_SOURCE_PERMS, 0, p); + + copy_helper(tc, "data/mmap_datafile.txt", "data/file_copy.txt", + APR_FPROT_FILE_SOURCE_PERMS, 0, p); + + rv = apr_file_remove("data/file_copy.txt", p); + APR_ASSERT_SUCCESS(tc, "Couldn't remove copy file", rv); +} + +static void append_nonexist(abts_case *tc, void *data) +{ + apr_status_t rv; + + /* make absolutely sure that the dest file doesn't exist. */ + apr_file_remove("data/file_copy.txt", p); + + copy_helper(tc, "data/file_datafile.txt", "data/file_copy.txt", + APR_FPROT_FILE_SOURCE_PERMS, 0, p); + rv = apr_file_remove("data/file_copy.txt", p); + APR_ASSERT_SUCCESS(tc, "Couldn't remove copy file", rv); +} + +static void append_exist(abts_case *tc, void *data) +{ + apr_status_t rv; + + /* make absolutely sure that the dest file doesn't exist. */ + apr_file_remove("data/file_copy.txt", p); + + /* This is a cheat. I don't want to create a new file, so I just copy + * one file, then I copy another. If the second copy succeeds, then + * this works. + */ + copy_helper(tc, "data/file_datafile.txt", "data/file_copy.txt", + APR_FPROT_FILE_SOURCE_PERMS, 0, p); + + copy_helper(tc, "data/mmap_datafile.txt", "data/file_copy.txt", + APR_FPROT_FILE_SOURCE_PERMS, 1, p); + + rv = apr_file_remove("data/file_copy.txt", p); + APR_ASSERT_SUCCESS(tc, "Couldn't remove copy file", rv); +} + +abts_suite *testfilecopy(abts_suite *suite) +{ + suite = ADD_SUITE(suite) + + abts_run_test(suite, copy_short_file, NULL); + abts_run_test(suite, copy_over_existing, NULL); + + abts_run_test(suite, append_nonexist, NULL); + abts_run_test(suite, append_exist, NULL); + + return suite; +} + diff --git a/test/testfileinfo.c b/test/testfileinfo.c new file mode 100644 index 00000000000..ce3f461fc48 --- /dev/null +++ b/test/testfileinfo.c @@ -0,0 +1,263 @@ +/* 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_file_io.h" +#include "apr_file_info.h" +#include "apr_strings.h" +#include "apr_errno.h" +#include "apr_general.h" +#include "apr_poll.h" +#include "apr_lib.h" +#include "testutil.h" + +#define FILENAME "data/file_datafile.txt" +#define NEWFILENAME "data/new_datafile.txt" +#define NEWFILEDATA "This is new text in a new file." + +static const struct view_fileinfo +{ + apr_int32_t bits; + char *description; +} vfi[] = { + {APR_FINFO_MTIME, "MTIME"}, + {APR_FINFO_CTIME, "CTIME"}, + {APR_FINFO_ATIME, "ATIME"}, + {APR_FINFO_SIZE, "SIZE"}, + {APR_FINFO_DEV, "DEV"}, + {APR_FINFO_INODE, "INODE"}, + {APR_FINFO_NLINK, "NLINK"}, + {APR_FINFO_TYPE, "TYPE"}, + {APR_FINFO_USER, "USER"}, + {APR_FINFO_GROUP, "GROUP"}, + {APR_FINFO_UPROT, "UPROT"}, + {APR_FINFO_GPROT, "GPROT"}, + {APR_FINFO_WPROT, "WPROT"}, + {0, NULL} +}; + +static void finfo_equal(abts_case *tc, apr_finfo_t *f1, apr_finfo_t *f2) +{ + /* Minimum supported flags across all platforms (APR_FINFO_MIN) */ + ABTS_ASSERT(tc, "apr_stat and apr_getfileinfo must return APR_FINFO_TYPE", + (f1->valid & f2->valid & APR_FINFO_TYPE)); + ABTS_ASSERT(tc, "apr_stat and apr_getfileinfo differ in filetype", + f1->filetype == f2->filetype); + ABTS_ASSERT(tc, "apr_stat and apr_getfileinfo must return APR_FINFO_SIZE", + (f1->valid & f2->valid & APR_FINFO_SIZE)); + ABTS_ASSERT(tc, "apr_stat and apr_getfileinfo differ in size", + f1->size == f2->size); + ABTS_ASSERT(tc, "apr_stat and apr_getfileinfo must return APR_FINFO_ATIME", + (f1->valid & f2->valid & APR_FINFO_ATIME)); + ABTS_ASSERT(tc, "apr_stat and apr_getfileinfo differ in atime", + f1->atime == f2->atime); + ABTS_ASSERT(tc, "apr_stat and apr_getfileinfo must return APR_FINFO_MTIME", + (f1->valid & f2->valid & APR_FINFO_MTIME)); + ABTS_ASSERT(tc, "apr_stat and apr_getfileinfo differ in mtime", + f1->mtime == f2->mtime); + ABTS_ASSERT(tc, "apr_stat and apr_getfileinfo must return APR_FINFO_CTIME", + (f1->valid & f2->valid & APR_FINFO_CTIME)); + ABTS_ASSERT(tc, "apr_stat and apr_getfileinfo differ in ctime", + f1->ctime == f2->ctime); + + if (f1->valid & f2->valid & APR_FINFO_NAME) + ABTS_ASSERT(tc, "apr_stat and apr_getfileinfo differ in name", + !strcmp(f1->name, f2->name)); + if (f1->fname && f2->fname) + ABTS_ASSERT(tc, "apr_stat and apr_getfileinfo differ in fname", + !strcmp(f1->fname, f2->fname)); + + /* Additional supported flags not supported on all platforms */ + if (f1->valid & f2->valid & APR_FINFO_USER) + ABTS_ASSERT(tc, "apr_stat and apr_getfileinfo differ in user", + !apr_uid_compare(f1->user, f2->user)); + if (f1->valid & f2->valid & APR_FINFO_GROUP) + ABTS_ASSERT(tc, "apr_stat and apr_getfileinfo differ in group", + !apr_gid_compare(f1->group, f2->group)); + if (f1->valid & f2->valid & APR_FINFO_INODE) + ABTS_ASSERT(tc, "apr_stat and apr_getfileinfo differ in inode", + f1->inode == f2->inode); + if (f1->valid & f2->valid & APR_FINFO_DEV) + ABTS_ASSERT(tc, "apr_stat and apr_getfileinfo differ in device", + f1->device == f2->device); + if (f1->valid & f2->valid & APR_FINFO_NLINK) + ABTS_ASSERT(tc, "apr_stat and apr_getfileinfo differ in nlink", + f1->nlink == f2->nlink); + if (f1->valid & f2->valid & APR_FINFO_CSIZE) + ABTS_ASSERT(tc, "apr_stat and apr_getfileinfo differ in csize", + f1->csize == f2->csize); + if (f1->valid & f2->valid & APR_FINFO_PROT) + ABTS_ASSERT(tc, "apr_stat and apr_getfileinfo differ in protection", + f1->protection == f2->protection); +} + +static void test_info_get(abts_case *tc, void *data) +{ + apr_file_t *thefile; + apr_finfo_t finfo; + apr_status_t rv; + + rv = apr_file_open(&thefile, FILENAME, APR_FOPEN_READ, APR_FPROT_OS_DEFAULT, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + rv = apr_file_info_get(&finfo, APR_FINFO_NORM, thefile); + if (APR_STATUS_IS_INCOMPLETE(rv)) { + char *str; + int i; + str = apr_pstrdup(p, "APR_INCOMPLETE: Missing "); + for (i = 0; vfi[i].bits; ++i) { + if (vfi[i].bits & ~finfo.valid) { + str = apr_pstrcat(p, str, vfi[i].description, " ", NULL); + } + } + ABTS_FAIL(tc, str); + } + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + apr_file_close(thefile); +} + +static void test_stat(abts_case *tc, void *data) +{ + apr_finfo_t finfo; + apr_status_t rv; + + rv = apr_stat(&finfo, FILENAME, APR_FINFO_NORM, p); + if (APR_STATUS_IS_INCOMPLETE(rv)) { + char *str; + int i; + str = apr_pstrdup(p, "APR_INCOMPLETE: Missing "); + for (i = 0; vfi[i].bits; ++i) { + if (vfi[i].bits & ~finfo.valid) { + str = apr_pstrcat(p, str, vfi[i].description, " ", NULL); + } + } + ABTS_FAIL(tc, str); + } + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); +} + +static void test_stat_eq_finfo(abts_case *tc, void *data) +{ + apr_file_t *thefile; + apr_finfo_t finfo; + apr_finfo_t stat_finfo; + apr_status_t rv; + + rv = apr_file_open(&thefile, FILENAME, APR_FOPEN_READ, APR_FPROT_OS_DEFAULT, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + rv = apr_file_info_get(&finfo, APR_FINFO_NORM, thefile); + + /* Opening the file may have toggled the atime member (time last + * accessed), so fetch our apr_stat() after getting the fileinfo + * of the open file... + */ + rv = apr_stat(&stat_finfo, FILENAME, APR_FINFO_NORM, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + apr_file_close(thefile); + + finfo_equal(tc, &stat_finfo, &finfo); +} + +static void test_buffered_write_size(abts_case *tc, void *data) +{ + const apr_size_t data_len = strlen(NEWFILEDATA); + apr_file_t *thefile; + apr_finfo_t finfo; + apr_status_t rv; + apr_size_t bytes; + + rv = apr_file_open(&thefile, NEWFILENAME, + APR_FOPEN_READ | APR_FOPEN_WRITE | APR_FOPEN_CREATE | APR_FOPEN_TRUNCATE + | APR_FOPEN_BUFFERED | APR_FOPEN_DELONCLOSE, + APR_FPROT_OS_DEFAULT, p); + APR_ASSERT_SUCCESS(tc, "open file", rv); + + /* A funny thing happened to me the other day: I wrote something + * into a buffered file, then asked for its size using + * apr_file_info_get; and guess what? The size was 0! That's not a + * nice way to behave. + */ + bytes = data_len; + rv = apr_file_write(thefile, NEWFILEDATA, &bytes); + APR_ASSERT_SUCCESS(tc, "write file contents", rv); + ABTS_TRUE(tc, data_len == bytes); + + rv = apr_file_info_get(&finfo, APR_FINFO_SIZE, thefile); + APR_ASSERT_SUCCESS(tc, "get file size", rv); + ABTS_TRUE(tc, bytes == (apr_size_t) finfo.size); + apr_file_close(thefile); +} + +static void test_mtime_set(abts_case *tc, void *data) +{ + apr_file_t *thefile; + apr_finfo_t finfo; + apr_time_t epoch = 0; + apr_status_t rv; + + /* This test sort of depends on the system clock being at least + * marginally ccorrect; We'll be setting the modification time to + * the epoch. + */ + rv = apr_file_open(&thefile, NEWFILENAME, + APR_FOPEN_READ | APR_FOPEN_WRITE | APR_FOPEN_CREATE | APR_FOPEN_TRUNCATE + | APR_FOPEN_BUFFERED | APR_FOPEN_DELONCLOSE, + APR_FPROT_OS_DEFAULT, p); + APR_ASSERT_SUCCESS(tc, "open file", rv); + + /* Check that the current mtime is not the epoch */ + rv = apr_stat(&finfo, NEWFILENAME, APR_FINFO_MTIME, p); + if (APR_STATUS_IS_INCOMPLETE(rv)) { + char *str; + int i; + str = apr_pstrdup(p, "APR_INCOMPLETE: Missing "); + for (i = 0; vfi[i].bits; ++i) { + if (vfi[i].bits & ~finfo.valid) { + str = apr_pstrcat(p, str, vfi[i].description, " ", NULL); + } + } + ABTS_FAIL(tc, str); + } + APR_ASSERT_SUCCESS(tc, "get initial mtime", rv); + ABTS_TRUE(tc, finfo.mtime != epoch); + + /* Reset the mtime to the epoch and verify the result. + * Note: we blindly assume that if the first apr_stat succeeded, + * the second one will, too. + */ + rv = apr_file_mtime_set(NEWFILENAME, epoch, p); + APR_ASSERT_SUCCESS(tc, "set mtime", rv); + + rv = apr_stat(&finfo, NEWFILENAME, APR_FINFO_MTIME, p); + APR_ASSERT_SUCCESS(tc, "get modified mtime", rv); + ABTS_TRUE(tc, finfo.mtime == epoch); + + apr_file_close(thefile); +} + +abts_suite *testfileinfo(abts_suite *suite) +{ + suite = ADD_SUITE(suite) + + abts_run_test(suite, test_info_get, NULL); + abts_run_test(suite, test_stat, NULL); + abts_run_test(suite, test_stat_eq_finfo, NULL); + abts_run_test(suite, test_buffered_write_size, NULL); + abts_run_test(suite, test_mtime_set, NULL); + + return suite; +} + diff --git a/test/testflock.c b/test/testflock.c new file mode 100644 index 00000000000..2cf9f358ea1 --- /dev/null +++ b/test/testflock.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. + */ + +#include "testflock.h" +#include "testutil.h" +#include "apr_pools.h" +#include "apr_thread_proc.h" +#include "apr_file_io.h" +#include "apr_file_info.h" +#include "apr_general.h" +#include "apr_strings.h" + +static int launch_reader(abts_case *tc) +{ + apr_proc_t proc = {0}; + apr_procattr_t *procattr; + const char *args[2]; + apr_status_t rv; + apr_exit_why_e why; + int exitcode; + + rv = apr_procattr_create(&procattr, p); + APR_ASSERT_SUCCESS(tc, "Couldn't create procattr", rv); + + rv = apr_procattr_io_set(procattr, APR_NO_PIPE, APR_NO_PIPE, + APR_NO_PIPE); + APR_ASSERT_SUCCESS(tc, "Couldn't set io in procattr", rv); + + rv = apr_procattr_cmdtype_set(procattr, APR_PROGRAM_ENV); + APR_ASSERT_SUCCESS(tc, "Couldn't set copy environment", rv); + + rv = apr_procattr_error_check_set(procattr, 1); + APR_ASSERT_SUCCESS(tc, "Couldn't set error check in procattr", rv); + + args[0] = "tryread" EXTENSION; + args[1] = NULL; + rv = apr_proc_create(&proc, TESTBINPATH "tryread" EXTENSION, args, NULL, procattr, p); + APR_ASSERT_SUCCESS(tc, "Couldn't launch program", rv); + + ABTS_ASSERT(tc, "wait for child process", + apr_proc_wait(&proc, &exitcode, &why, APR_WAIT) == APR_CHILD_DONE); + + ABTS_ASSERT(tc, "child terminated normally", why == APR_PROC_EXIT); + return exitcode; +} + +static void test_withlock(abts_case *tc, void *data) +{ + apr_file_t *file; + apr_status_t rv; + int code; + + rv = apr_file_open(&file, TESTFILE, APR_FOPEN_WRITE|APR_FOPEN_CREATE, + APR_FPROT_OS_DEFAULT, p); + APR_ASSERT_SUCCESS(tc, "Could not create file.", rv); + ABTS_PTR_NOTNULL(tc, file); + + rv = apr_file_lock(file, APR_FLOCK_EXCLUSIVE); + APR_ASSERT_SUCCESS(tc, "Could not lock the file.", rv); + ABTS_PTR_NOTNULL(tc, file); + + code = launch_reader(tc); + ABTS_INT_EQUAL(tc, FAILED_READ, code); + + (void) apr_file_close(file); +} + +static void test_withoutlock(abts_case *tc, void *data) +{ + int code; + + code = launch_reader(tc); + ABTS_INT_EQUAL(tc, SUCCESSFUL_READ, code); +} + +static void remove_lockfile(abts_case *tc, void *data) +{ + APR_ASSERT_SUCCESS(tc, "Couldn't remove lock file.", + apr_file_remove(TESTFILE, p)); +} + +abts_suite *testflock(abts_suite *suite) +{ + suite = ADD_SUITE(suite) + + abts_run_test(suite, test_withlock, NULL); + abts_run_test(suite, test_withoutlock, NULL); + abts_run_test(suite, remove_lockfile, NULL); + + return suite; +} diff --git a/test/testflock.h b/test/testflock.h new file mode 100644 index 00000000000..554a0ce5649 --- /dev/null +++ b/test/testflock.h @@ -0,0 +1,27 @@ +/* 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. + */ + +#ifndef TESTFLOCK +#define TESTFLOCK + +#define TESTFILE "data/testfile.lock" + +#define FAILED_READ 0 +#define SUCCESSFUL_READ 1 +#define UNEXPECTED_ERROR 2 + +#endif + diff --git a/test/testfmt.c b/test/testfmt.c new file mode 100644 index 00000000000..5b066ddb439 --- /dev/null +++ b/test/testfmt.c @@ -0,0 +1,166 @@ +/* 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 "testutil.h" +#include "apr.h" +#include "apr_portable.h" +#include "apr_strings.h" + +static void ssize_t_fmt(abts_case *tc, void *data) +{ + char buf[100]; + apr_ssize_t var = 0; + + sprintf(buf, "%" APR_SSIZE_T_FMT, var); + ABTS_STR_EQUAL(tc, "0", buf); + apr_snprintf(buf, sizeof(buf), "%" APR_SSIZE_T_FMT, var); + ABTS_STR_EQUAL(tc, "0", buf); +} + +static void size_t_fmt(abts_case *tc, void *data) +{ + char buf[100]; + apr_size_t var = 0; + + sprintf(buf, "%" APR_SIZE_T_FMT, var); + ABTS_STR_EQUAL(tc, "0", buf); + apr_snprintf(buf, sizeof(buf), "%" APR_SIZE_T_FMT, var); + ABTS_STR_EQUAL(tc, "0", buf); +} + +static void time_t_fmt(abts_case *tc, void *data) +{ + char buf[100]; + apr_time_t var = 1; + + sprintf(buf, "%" APR_TIME_T_FMT, var); + ABTS_STR_EQUAL(tc, "1", buf); + apr_snprintf(buf, sizeof(buf), "%" APR_TIME_T_FMT, var); + ABTS_STR_EQUAL(tc, "1", buf); +} + +static void off_t_fmt(abts_case *tc, void *data) +{ + char buf[100]; + apr_off_t var = 0; + + sprintf(buf, "%" APR_OFF_T_FMT, var); + ABTS_STR_EQUAL(tc, "0", buf); + apr_snprintf(buf, sizeof(buf), "%" APR_OFF_T_FMT, var); + ABTS_STR_EQUAL(tc, "0", buf); +} + +static void pid_t_fmt(abts_case *tc, void *data) +{ + char buf[100]; + pid_t var = 0; + + sprintf(buf, "%" APR_PID_T_FMT, var); + ABTS_STR_EQUAL(tc, "0", buf); + apr_snprintf(buf, sizeof(buf), "%" APR_PID_T_FMT, var); + ABTS_STR_EQUAL(tc, "0", buf); +} + +static void int64_t_fmt(abts_case *tc, void *data) +{ + char buf[100]; + apr_int64_t var = 0; + + sprintf(buf, "%" APR_INT64_T_FMT, var); + ABTS_STR_EQUAL(tc, "0", buf); + apr_snprintf(buf, sizeof(buf), "%" APR_INT64_T_FMT, var); + ABTS_STR_EQUAL(tc, "0", buf); +} + +static void uint64_t_fmt(abts_case *tc, void *data) +{ + char buf[100]; + apr_uint64_t var = APR_UINT64_C(14000000); + + sprintf(buf, "%" APR_UINT64_T_FMT, var); + ABTS_STR_EQUAL(tc, "14000000", buf); + apr_snprintf(buf, sizeof(buf), "%" APR_UINT64_T_FMT, var); + ABTS_STR_EQUAL(tc, "14000000", buf); +} + +static void uint64_t_hex_fmt(abts_case *tc, void *data) +{ + char buf[100]; + apr_uint64_t var = APR_UINT64_C(14000000); + + sprintf(buf, "%" APR_UINT64_T_HEX_FMT, var); + ABTS_STR_EQUAL(tc, "d59f80", buf); + apr_snprintf(buf, sizeof(buf), "%" APR_UINT64_T_HEX_FMT, var); + ABTS_STR_EQUAL(tc, "d59f80", buf); +} + +static void more_int64_fmts(abts_case *tc, void *data) +{ + char buf[100]; + apr_int64_t i = APR_INT64_C(-42); + apr_int64_t ibig = APR_INT64_C(-314159265358979323); + apr_uint64_t ui = APR_UINT64_C(42); + apr_uint64_t big = APR_UINT64_C(10267677267010969076); + + apr_snprintf(buf, sizeof buf, "%" APR_INT64_T_FMT, i); + ABTS_STR_EQUAL(tc, "-42", buf); + + apr_snprintf(buf, sizeof buf, "%" APR_UINT64_T_FMT, ui); + ABTS_STR_EQUAL(tc, "42", buf); + + apr_snprintf(buf, sizeof buf, "%" APR_UINT64_T_FMT, big); + ABTS_STR_EQUAL(tc, "10267677267010969076", buf); + + apr_snprintf(buf, sizeof buf, "%" APR_INT64_T_FMT, ibig); + ABTS_STR_EQUAL(tc, "-314159265358979323", buf); +} + +static void error_fmt(abts_case *tc, void *data) +{ + char ebuf[150], sbuf[150], *s; + apr_status_t rv; + + rv = APR_SUCCESS; + apr_strerror(rv, ebuf, sizeof ebuf); + apr_snprintf(sbuf, sizeof sbuf, "%pm", &rv); + ABTS_STR_EQUAL(tc, sbuf, ebuf); + + rv = APR_ENOTIMPL; + s = apr_pstrcat(p, "foo-", + apr_strerror(rv, ebuf, sizeof ebuf), + "-bar", NULL); + apr_snprintf(sbuf, sizeof sbuf, "foo-%pm-bar", &rv); + ABTS_STR_EQUAL(tc, sbuf, s); +} + +abts_suite *testfmt(abts_suite *suite) +{ + suite = ADD_SUITE(suite) + + abts_run_test(suite, ssize_t_fmt, NULL); + abts_run_test(suite, size_t_fmt, NULL); + abts_run_test(suite, time_t_fmt, NULL); + abts_run_test(suite, off_t_fmt, NULL); + abts_run_test(suite, pid_t_fmt, NULL); + abts_run_test(suite, int64_t_fmt, NULL); + abts_run_test(suite, uint64_t_fmt, NULL); + abts_run_test(suite, uint64_t_hex_fmt, NULL); + abts_run_test(suite, more_int64_fmts, NULL); + abts_run_test(suite, error_fmt, NULL); + + return suite; +} + diff --git a/test/testfnmatch.c b/test/testfnmatch.c new file mode 100644 index 00000000000..1d1c0315dbd --- /dev/null +++ b/test/testfnmatch.c @@ -0,0 +1,256 @@ +/* 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 "testutil.h" +#include "apr_file_info.h" +#include "apr_fnmatch.h" +#include "apr_tables.h" + +/* XXX NUM_FILES must be equal to the nummber of expected files with a + * .txt extension in the data directory at the time testfnmatch + * happens to be run (!?!). */ + +#define NUM_FILES (10) + +#define APR_FNM_BITS 15 +#define APR_FNM_FAILBIT 256 + +#define FAILS_IF(X) 0, X +#define SUCCEEDS_IF(X) X, 256 +#define SUCCEEDS 0, 256 +#define FAILS 256, 0 + +static struct pattern_s { + const char *pattern; + const char *string; + int require_flags; + int fail_flags; +} patterns[] = { + +/* Pattern, String to Test, Flags to Match */ + {"", "test", FAILS}, + {"", "*", FAILS}, + {"test", "*", FAILS}, + {"test", "test", SUCCEEDS}, + + /* Remember C '\\' is a single backslash in pattern */ + {"te\\st", "test", FAILS_IF(APR_FNM_NOESCAPE)}, + {"te\\\\st", "te\\st", FAILS_IF(APR_FNM_NOESCAPE)}, + {"te\\*t", "te*t", FAILS_IF(APR_FNM_NOESCAPE)}, + {"te\\*t", "test", FAILS}, + {"te\\?t", "te?t", FAILS_IF(APR_FNM_NOESCAPE)}, + {"te\\?t", "test", FAILS}, + + {"tesT", "test", SUCCEEDS_IF(APR_FNM_CASE_BLIND)}, + {"test", "Test", SUCCEEDS_IF(APR_FNM_CASE_BLIND)}, + {"tEst", "teSt", SUCCEEDS_IF(APR_FNM_CASE_BLIND)}, + + {"?est", "test", SUCCEEDS}, + {"te?t", "test", SUCCEEDS}, + {"tes?", "test", SUCCEEDS}, + {"test?", "test", FAILS}, + + {"*", "", SUCCEEDS}, + {"*", "test", SUCCEEDS}, + {"*test", "test", SUCCEEDS}, + {"*est", "test", SUCCEEDS}, + {"*st", "test", SUCCEEDS}, + {"t*t", "test", SUCCEEDS}, + {"te*t", "test", SUCCEEDS}, + {"te*st", "test", SUCCEEDS}, + {"te*", "test", SUCCEEDS}, + {"tes*", "test", SUCCEEDS}, + {"test*", "test", SUCCEEDS}, + + {".[\\-\\t]", ".t", SUCCEEDS}, + {"test*?*[a-z]*", "testgoop", SUCCEEDS}, + {"te[^x]t", "test", SUCCEEDS}, + {"te[^abc]t", "test", SUCCEEDS}, + {"te[^x]t", "test", SUCCEEDS}, + {"te[!x]t", "test", SUCCEEDS}, + {"te[^x]t", "text", FAILS}, + {"te[^\\x]t", "text", FAILS}, + {"te[^x\\", "text", FAILS}, + {"te[/]t", "text", FAILS}, + {"te[S]t", "test", SUCCEEDS_IF(APR_FNM_CASE_BLIND)}, + {"te[r-t]t", "test", SUCCEEDS}, + {"te[r-t]t", "teSt", SUCCEEDS_IF(APR_FNM_CASE_BLIND)}, + {"te[r-T]t", "test", SUCCEEDS_IF(APR_FNM_CASE_BLIND)}, + {"te[R-T]t", "test", SUCCEEDS_IF(APR_FNM_CASE_BLIND)}, + {"te[r-Tz]t", "tezt", SUCCEEDS}, + {"te[R-T]t", "tent", FAILS}, + {"tes[]t]", "test", SUCCEEDS}, + {"tes[t-]", "test", SUCCEEDS}, + {"tes[t-]]", "test]", SUCCEEDS}, + {"tes[t-]]", "test", FAILS}, + {"tes[u-]", "test", FAILS}, + {"tes[t-]", "tes[t-]", FAILS}, + {"test[/-/]", "test[/-/]", SUCCEEDS_IF(APR_FNM_PATHNAME)}, + {"test[\\/-/]", "test[/-/]", APR_FNM_PATHNAME, APR_FNM_NOESCAPE}, + {"test[/-\\/]", "test[/-/]", APR_FNM_PATHNAME, APR_FNM_NOESCAPE}, + {"test[/-/]", "test/", FAILS_IF(APR_FNM_PATHNAME)}, + {"test[\\/-/]", "test/", FAILS_IF(APR_FNM_PATHNAME)}, + {"test[/-\\/]", "test/", FAILS_IF(APR_FNM_PATHNAME)}, + + {"/", "", FAILS}, + {"", "/", FAILS}, + {"/test", "test", FAILS}, + {"test", "/test", FAILS}, + {"test/", "test", FAILS}, + {"test", "test/", FAILS}, + {"\\/test", "/test", FAILS_IF(APR_FNM_NOESCAPE)}, + {"*test", "/test", FAILS_IF(APR_FNM_PATHNAME)}, + {"/*/test/", "/test", FAILS}, + {"/*/test/", "/test/test/", SUCCEEDS}, + {"test/this", "test/", FAILS}, + {"test/", "test/this", FAILS}, + {"test*/this", "test/this", SUCCEEDS}, + {"test*/this", "test/that", FAILS}, + {"test/*this", "test/this", SUCCEEDS}, + + {".*", ".this", SUCCEEDS}, + {"*", ".this", FAILS_IF(APR_FNM_PERIOD)}, + {"?this", ".this", FAILS_IF(APR_FNM_PERIOD)}, + {"[.]this", ".this", FAILS_IF(APR_FNM_PERIOD)}, + + {"test/this", "test/this", SUCCEEDS}, + {"test?this", "test/this", FAILS_IF(APR_FNM_PATHNAME)}, + {"test*this", "test/this", FAILS_IF(APR_FNM_PATHNAME)}, + {"test[/]this", "test/this", FAILS_IF(APR_FNM_PATHNAME)}, + + {"test/.*", "test/.this", SUCCEEDS}, + {"test/*", "test/.this", FAILS_IF(APR_FNM_PERIOD | APR_FNM_PATHNAME)}, + {"test/?this", "test/.this", FAILS_IF(APR_FNM_PERIOD | APR_FNM_PATHNAME)}, + {"test/[.]this", "test/.this", FAILS_IF(APR_FNM_PERIOD | APR_FNM_PATHNAME)}, + + {NULL, NULL, 0} +}; + + + +static void test_fnmatch(abts_case *tc, void *data) +{ + struct pattern_s *test = patterns; + char buf[80]; + int i = APR_FNM_BITS + 1; + int res; + + for (test = patterns; test->pattern; ++test) + { + for (i = 0; i <= APR_FNM_BITS; ++i) + { + res = apr_fnmatch(test->pattern, test->string, i); + if (((i & test->require_flags) != test->require_flags) + || ((i & test->fail_flags) == test->fail_flags)) { + if (res != APR_FNM_NOMATCH) + break; + } + else { + if (res != 0) + break; + } + } + if (i <= APR_FNM_BITS) + break; + } + + if (i <= APR_FNM_BITS) { + sprintf(buf, "apr_fnmatch(\"%s\", \"%s\", %d) returns %d\n", + test->pattern, test->string, i, res); + abts_fail(tc, buf, __LINE__); + } +} + +static void test_fnmatch_test(abts_case *tc, void *data) +{ + static const struct test { + const char *pattern; + int result; + } ft_tests[] = { + { "a*b", 1 }, + { "a?", 1 }, + { "a\\b?", 1 }, + { "a[b-c]", 1 }, + { "a", 0 }, + { "a\\", 0 }, + { NULL, 0 } + }; + const struct test *t; + + for (t = ft_tests; t->pattern != NULL; t++) { + int res = apr_fnmatch_test(t->pattern); + + if (res != t->result) { + char buf[128]; + + sprintf(buf, "apr_fnmatch_test(\"%s\") = %d, expected %d\n", + t->pattern, res, t->result); + abts_fail(tc, buf, __LINE__); + } + } +} + +static void test_glob(abts_case *tc, void *data) +{ + int i; + char **list; + apr_array_header_t *result; + + APR_ASSERT_SUCCESS(tc, "glob match against data/*.txt", + apr_match_glob("data\\*.txt", &result, p)); + + ABTS_INT_EQUAL(tc, NUM_FILES, result->nelts); + + list = (char **)result->elts; + for (i = 0; i < result->nelts; i++) { + char *dot = strrchr(list[i], '.'); + ABTS_STR_EQUAL(tc, ".txt", dot); + } +} + +static void test_glob_currdir(abts_case *tc, void *data) +{ + int i; + char **list; + apr_array_header_t *result; + apr_filepath_set("data", p); + + APR_ASSERT_SUCCESS(tc, "glob match against *.txt with data as current", + apr_match_glob("*.txt", &result, p)); + + + ABTS_INT_EQUAL(tc, NUM_FILES, result->nelts); + + list = (char **)result->elts; + for (i = 0; i < result->nelts; i++) { + char *dot = strrchr(list[i], '.'); + ABTS_STR_EQUAL(tc, ".txt", dot); + } + apr_filepath_set("..", p); +} + +abts_suite *testfnmatch(abts_suite *suite) +{ + suite = ADD_SUITE(suite) + + abts_run_test(suite, test_fnmatch, NULL); + abts_run_test(suite, test_fnmatch_test, NULL); + abts_run_test(suite, test_glob, NULL); + abts_run_test(suite, test_glob_currdir, NULL); + + return suite; +} + diff --git a/test/testglobalmutex.c b/test/testglobalmutex.c new file mode 100644 index 00000000000..c79884cfcf5 --- /dev/null +++ b/test/testglobalmutex.c @@ -0,0 +1,143 @@ +/* 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 "testglobalmutex.h" +#include "apr_thread_proc.h" +#include "apr_global_mutex.h" +#include "apr_strings.h" +#include "apr_errno.h" +#include "testutil.h" + +static void launch_child(abts_case *tc, apr_lockmech_e mech, + apr_proc_t *proc, apr_pool_t *p) +{ + apr_procattr_t *procattr; + const char *args[3]; + apr_status_t rv; + + rv = apr_procattr_create(&procattr, p); + APR_ASSERT_SUCCESS(tc, "Couldn't create procattr", rv); + + rv = apr_procattr_io_set(procattr, APR_NO_PIPE, APR_NO_PIPE, + APR_NO_PIPE); + APR_ASSERT_SUCCESS(tc, "Couldn't set io in procattr", rv); + + rv = apr_procattr_error_check_set(procattr, 1); + APR_ASSERT_SUCCESS(tc, "Couldn't set error check in procattr", rv); + + args[0] = "globalmutexchild" EXTENSION; + args[1] = (const char*)apr_itoa(p, (int)mech); + args[2] = NULL; + rv = apr_proc_create(proc, TESTBINPATH "globalmutexchild" EXTENSION, args, NULL, + procattr, p); + APR_ASSERT_SUCCESS(tc, "Couldn't launch program", rv); +} + +static int wait_child(abts_case *tc, apr_proc_t *proc) +{ + int exitcode; + apr_exit_why_e why; + + ABTS_ASSERT(tc, "Error waiting for child process", + apr_proc_wait(proc, &exitcode, &why, APR_WAIT) == APR_CHILD_DONE); + + ABTS_ASSERT(tc, "child didn't terminate normally", why == APR_PROC_EXIT); + return exitcode; +} + +/* return symbolic name for a locking meechanism */ +static const char *mutexname(apr_lockmech_e mech) +{ + switch (mech) { + case APR_LOCK_FCNTL: return "fcntl"; + case APR_LOCK_FLOCK: return "flock"; + case APR_LOCK_SYSVSEM: return "sysvsem"; + case APR_LOCK_PROC_PTHREAD: return "proc_pthread"; + case APR_LOCK_POSIXSEM: return "posixsem"; + case APR_LOCK_DEFAULT: return "default"; + case APR_LOCK_DEFAULT_TIMED: return "default_timed"; + default: return "unknown"; + } +} + +static void test_exclusive(abts_case *tc, void *data) +{ + apr_lockmech_e mech = *(apr_lockmech_e *)data; + apr_proc_t p1, p2, p3, p4; + apr_status_t rv; + apr_global_mutex_t *global_lock; + int x = 0; + abts_log_message("lock mechanism is: "); + abts_log_message(mutexname(mech)); + + rv = apr_global_mutex_create(&global_lock, LOCKNAME, mech, p); + if (rv == APR_ENOTIMPL) { + /* MacOS lacks TIMED implementation, so don't fail for ENOTIMPL */ + ABTS_NOT_IMPL(tc, "global mutex TIMED not implemented"); + return; + } + APR_ASSERT_SUCCESS(tc, "Error creating mutex", rv); + + launch_child(tc, mech, &p1, p); + launch_child(tc, mech, &p2, p); + launch_child(tc, mech, &p3, p); + launch_child(tc, mech, &p4, p); + + x += wait_child(tc, &p1); + x += wait_child(tc, &p2); + x += wait_child(tc, &p3); + x += wait_child(tc, &p4); + + if (x != MAX_COUNTER) { + char buf[200]; + sprintf(buf, "global mutex '%s' failed: %d not %d", + mutexname(mech), x, MAX_COUNTER); + abts_fail(tc, buf, __LINE__); + } +} + +abts_suite *testglobalmutex(abts_suite *suite) +{ + apr_lockmech_e mech = APR_LOCK_DEFAULT; + + suite = ADD_SUITE(suite) + abts_run_test(suite, test_exclusive, &mech); +#if APR_HAS_POSIXSEM_SERIALIZE + mech = APR_LOCK_POSIXSEM; + abts_run_test(suite, test_exclusive, &mech); +#endif +#if APR_HAS_SYSVSEM_SERIALIZE + mech = APR_LOCK_SYSVSEM; + abts_run_test(suite, test_exclusive, &mech); +#endif +#if APR_HAS_PROC_PTHREAD_SERIALIZE + mech = APR_LOCK_PROC_PTHREAD; + abts_run_test(suite, test_exclusive, &mech); +#endif +#if APR_HAS_FCNTL_SERIALIZE + mech = APR_LOCK_FCNTL; + abts_run_test(suite, test_exclusive, &mech); +#endif +#if APR_HAS_FLOCK_SERIALIZE + mech = APR_LOCK_FLOCK; + abts_run_test(suite, test_exclusive, &mech); +#endif + mech = APR_LOCK_DEFAULT_TIMED; + abts_run_test(suite, test_exclusive, &mech); + + return suite; +} + diff --git a/test/testglobalmutex.h b/test/testglobalmutex.h new file mode 100644 index 00000000000..027062843dc --- /dev/null +++ b/test/testglobalmutex.h @@ -0,0 +1,27 @@ +/* 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. + */ + +#ifndef TESTGLOBALMUTEX_H +#define TESTGLOBALMUTEX_H + +/* set this to 255 so that the child processes can return it successfully. */ +#define MAX_ITER 255 +#define MAX_COUNTER (MAX_ITER * 4) + +#define LOCKNAME "data/apr_globalmutex.lock" + +#endif + diff --git a/test/testhash.c b/test/testhash.c new file mode 100644 index 00000000000..9dd5804b818 --- /dev/null +++ b/test/testhash.c @@ -0,0 +1,570 @@ +/* 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 "testutil.h" +#include "apr.h" +#include "apr_strings.h" +#include "apr_general.h" +#include "apr_pools.h" +#include "apr_hash.h" + +#define MAX_LTH 256 +#define MAX_DEPTH 11 + +static int comp_string(const void *str1, const void *str2) +{ + return strcmp(str1,str2); +} + +static void dump_hash(apr_pool_t *p, apr_hash_t *h, char str[][MAX_LTH]) +{ + apr_hash_index_t *hi; + int i = 0; + + for (hi = apr_hash_first(p, h); hi; hi = apr_hash_next(hi)) { + const char *key = apr_hash_this_key(hi); + apr_ssize_t len = apr_hash_this_key_len(hi); + char *val = apr_hash_this_val(hi); + + str[i][0]='\0'; + apr_snprintf(str[i], MAX_LTH, "%sKey %s (%" APR_SSIZE_T_FMT ") Value %s\n", + str[i], key, len, val); + i++; + } + str[i][0]='\0'; + apr_snprintf(str[i], MAX_LTH, "%s#entries %d\n", str[i], i); + + /* Sort the result strings so that they can be checked for expected results easily, + * without having to worry about platform quirks + */ + qsort( + str, /* Pointer to elements */ + i, /* number of elements */ + MAX_LTH, /* size of one element */ + comp_string /* Pointer to comparison routine */ + ); +} + +static void sum_hash(apr_pool_t *p, apr_hash_t *h, int *pcount, int *keySum, int *valSum) +{ + apr_hash_index_t *hi; + void *val, *key; + int count = 0; + + *keySum = 0; + *valSum = 0; + *pcount = 0; + for (hi = apr_hash_first(p, h); hi; hi = apr_hash_next(hi)) { + apr_hash_this(hi, (void*)&key, NULL, &val); + *valSum += *(int *)val; + *keySum += *(int *)key; + count++; + } + *pcount=count; +} + +static void hash_make(abts_case *tc, void *data) +{ + apr_hash_t *h = NULL; + + h = apr_hash_make(p); + ABTS_PTR_NOTNULL(tc, h); +} + +static void hash_set(abts_case *tc, void *data) +{ + apr_hash_t *h = NULL; + char *result = NULL; + + h = apr_hash_make(p); + ABTS_PTR_NOTNULL(tc, h); + + apr_hash_set(h, "key", APR_HASH_KEY_STRING, "value"); + result = apr_hash_get(h, "key", APR_HASH_KEY_STRING); + ABTS_STR_EQUAL(tc, "value", result); +} + +static void hash_get_or_set(abts_case *tc, void *data) +{ + apr_hash_t *h = NULL; + char *result = NULL; + + h = apr_hash_make(p); + ABTS_PTR_NOTNULL(tc, h); + + result = apr_hash_get_or_set(h, "key", APR_HASH_KEY_STRING, "value"); + ABTS_STR_EQUAL(tc, "value", result); + + result = apr_hash_get_or_set(h, "key", APR_HASH_KEY_STRING, "other"); + ABTS_STR_EQUAL(tc, "value", result); + + result = apr_hash_get_or_set(h, "key", APR_HASH_KEY_STRING, NULL); + ABTS_STR_EQUAL(tc, "value", result); + + apr_hash_set(h, "key", APR_HASH_KEY_STRING, NULL); + result = apr_hash_get(h, "key", APR_HASH_KEY_STRING); + ABTS_PTR_EQUAL(tc, NULL, result); + + result = apr_hash_get_or_set(h, "key", APR_HASH_KEY_STRING, NULL); + ABTS_PTR_EQUAL(tc, NULL, result); + + result = apr_hash_get_or_set(h, "key", APR_HASH_KEY_STRING, "other"); + ABTS_STR_EQUAL(tc, "other", result); +} + +static void hash_reset(abts_case *tc, void *data) +{ + apr_hash_t *h = NULL; + char *result = NULL; + + h = apr_hash_make(p); + ABTS_PTR_NOTNULL(tc, h); + + apr_hash_set(h, "key", APR_HASH_KEY_STRING, "value"); + result = apr_hash_get(h, "key", APR_HASH_KEY_STRING); + ABTS_STR_EQUAL(tc, "value", result); + + apr_hash_set(h, "key", APR_HASH_KEY_STRING, "new"); + result = apr_hash_get(h, "key", APR_HASH_KEY_STRING); + ABTS_STR_EQUAL(tc, "new", result); +} + +static void same_value(abts_case *tc, void *data) +{ + apr_hash_t *h = NULL; + char *result = NULL; + + h = apr_hash_make(p); + ABTS_PTR_NOTNULL(tc, h); + + apr_hash_set(h, "same1", APR_HASH_KEY_STRING, "same"); + result = apr_hash_get(h, "same1", APR_HASH_KEY_STRING); + ABTS_STR_EQUAL(tc, "same", result); + + apr_hash_set(h, "same2", APR_HASH_KEY_STRING, "same"); + result = apr_hash_get(h, "same2", APR_HASH_KEY_STRING); + ABTS_STR_EQUAL(tc, "same", result); +} + +static unsigned int hash_custom( const char *key, apr_ssize_t *klen) +{ + unsigned int hash = 0; + while( *klen ) { + (*klen) --; + hash = hash * 33 + key[ *klen ]; + } + return hash; +} + +static void same_value_custom(abts_case *tc, void *data) +{ + apr_hash_t *h = NULL; + char *result = NULL; + + h = apr_hash_make_custom(p, hash_custom); + ABTS_PTR_NOTNULL(tc, h); + + apr_hash_set(h, "same1", 5, "same"); + result = apr_hash_get(h, "same1", 5); + ABTS_STR_EQUAL(tc, "same", result); + + apr_hash_set(h, "same2", 5, "same"); + result = apr_hash_get(h, "same2", 5); + ABTS_STR_EQUAL(tc, "same", result); +} + +static void key_space(abts_case *tc, void *data) +{ + apr_hash_t *h = NULL; + char *result = NULL; + + h = apr_hash_make(p); + ABTS_PTR_NOTNULL(tc, h); + + apr_hash_set(h, "key with space", APR_HASH_KEY_STRING, "value"); + result = apr_hash_get(h, "key with space", APR_HASH_KEY_STRING); + ABTS_STR_EQUAL(tc, "value", result); +} + +static void hash_clear(abts_case *tc, void *data) +{ + apr_hash_t *h; + int i, *e; + + h = apr_hash_make(p); + ABTS_PTR_NOTNULL(tc, h); + + for (i = 1; i <= 10; i++) { + e = apr_palloc(p, sizeof(int)); + *e = i; + apr_hash_set(h, e, sizeof(*e), e); + } + apr_hash_clear(h); + i = apr_hash_count(h); + ABTS_INT_EQUAL(tc, 0, i); +} + +/* This is kind of a hack, but I am just keeping an existing test. This is + * really testing apr_hash_first, apr_hash_next, and apr_hash_this which + * should be tested in three separate tests, but this will do for now. + */ +static void hash_traverse(abts_case *tc, void *data) +{ + apr_hash_t *h; + char StrArray[MAX_DEPTH][MAX_LTH]; + + h = apr_hash_make(p); + ABTS_PTR_NOTNULL(tc, h); + + apr_hash_set(h, "OVERWRITE", APR_HASH_KEY_STRING, "should not see this"); + apr_hash_set(h, "FOO3", APR_HASH_KEY_STRING, "bar3"); + apr_hash_set(h, "FOO3", APR_HASH_KEY_STRING, "bar3"); + apr_hash_set(h, "FOO1", APR_HASH_KEY_STRING, "bar1"); + apr_hash_set(h, "FOO2", APR_HASH_KEY_STRING, "bar2"); + apr_hash_set(h, "FOO4", APR_HASH_KEY_STRING, "bar4"); + apr_hash_set(h, "SAME1", APR_HASH_KEY_STRING, "same"); + apr_hash_set(h, "SAME2", APR_HASH_KEY_STRING, "same"); + apr_hash_set(h, "OVERWRITE", APR_HASH_KEY_STRING, "Overwrite key"); + + dump_hash(p, h, StrArray); + + ABTS_STR_EQUAL(tc, "Key FOO1 (4) Value bar1\n", StrArray[0]); + ABTS_STR_EQUAL(tc, "Key FOO2 (4) Value bar2\n", StrArray[1]); + ABTS_STR_EQUAL(tc, "Key FOO3 (4) Value bar3\n", StrArray[2]); + ABTS_STR_EQUAL(tc, "Key FOO4 (4) Value bar4\n", StrArray[3]); + ABTS_STR_EQUAL(tc, "Key OVERWRITE (9) Value Overwrite key\n", StrArray[4]); + ABTS_STR_EQUAL(tc, "Key SAME1 (5) Value same\n", StrArray[5]); + ABTS_STR_EQUAL(tc, "Key SAME2 (5) Value same\n", StrArray[6]); + ABTS_STR_EQUAL(tc, "#entries 7\n", StrArray[7]); +} + +/* This is kind of a hack, but I am just keeping an existing test. This is + * really testing apr_hash_first, apr_hash_next, and apr_hash_this which + * should be tested in three separate tests, but this will do for now. + */ +static void summation_test(abts_case *tc, void *data) +{ + apr_hash_t *h; + int sumKeys, sumVal, trySumKey, trySumVal; + int i, j, *val, *key; + + h =apr_hash_make(p); + ABTS_PTR_NOTNULL(tc, h); + + sumKeys = 0; + sumVal = 0; + trySumKey = 0; + trySumVal = 0; + + for (i = 0; i < 100; i++) { + j = i * 10 + 1; + sumKeys += j; + sumVal += i; + key = apr_palloc(p, sizeof(int)); + *key = j; + val = apr_palloc(p, sizeof(int)); + *val = i; + apr_hash_set(h, key, sizeof(int), val); + } + + sum_hash(p, h, &i, &trySumKey, &trySumVal); + ABTS_INT_EQUAL(tc, 100, i); + ABTS_INT_EQUAL(tc, sumVal, trySumVal); + ABTS_INT_EQUAL(tc, sumKeys, trySumKey); +} + +static void delete_key(abts_case *tc, void *data) +{ + apr_hash_t *h = NULL; + char *result = NULL; + + h = apr_hash_make(p); + ABTS_PTR_NOTNULL(tc, h); + + apr_hash_set(h, "key", APR_HASH_KEY_STRING, "value"); + apr_hash_set(h, "key2", APR_HASH_KEY_STRING, "value2"); + + result = apr_hash_get(h, "key", APR_HASH_KEY_STRING); + ABTS_STR_EQUAL(tc, "value", result); + + result = apr_hash_get(h, "key2", APR_HASH_KEY_STRING); + ABTS_STR_EQUAL(tc, "value2", result); + + apr_hash_set(h, "key", APR_HASH_KEY_STRING, NULL); + + result = apr_hash_get(h, "key", APR_HASH_KEY_STRING); + ABTS_PTR_EQUAL(tc, NULL, result); + + result = apr_hash_get(h, "key2", APR_HASH_KEY_STRING); + ABTS_STR_EQUAL(tc, "value2", result); +} + +static void hash_count_0(abts_case *tc, void *data) +{ + apr_hash_t *h = NULL; + int count; + + h = apr_hash_make(p); + ABTS_PTR_NOTNULL(tc, h); + + count = apr_hash_count(h); + ABTS_INT_EQUAL(tc, 0, count); +} + +static void hash_count_1(abts_case *tc, void *data) +{ + apr_hash_t *h = NULL; + int count; + + h = apr_hash_make(p); + ABTS_PTR_NOTNULL(tc, h); + + apr_hash_set(h, "key", APR_HASH_KEY_STRING, "value"); + + count = apr_hash_count(h); + ABTS_INT_EQUAL(tc, 1, count); +} + +static void hash_count_5(abts_case *tc, void *data) +{ + apr_hash_t *h = NULL; + int count; + + h = apr_hash_make(p); + ABTS_PTR_NOTNULL(tc, h); + + apr_hash_set(h, "key1", APR_HASH_KEY_STRING, "value1"); + apr_hash_set(h, "key2", APR_HASH_KEY_STRING, "value2"); + apr_hash_set(h, "key3", APR_HASH_KEY_STRING, "value3"); + apr_hash_set(h, "key4", APR_HASH_KEY_STRING, "value4"); + apr_hash_set(h, "key5", APR_HASH_KEY_STRING, "value5"); + + count = apr_hash_count(h); + ABTS_INT_EQUAL(tc, 5, count); +} + +static void overlay_empty(abts_case *tc, void *data) +{ + apr_hash_t *base = NULL; + apr_hash_t *overlay = NULL; + apr_hash_t *result = NULL; + int count; + char StrArray[MAX_DEPTH][MAX_LTH]; + + base = apr_hash_make(p); + overlay = apr_hash_make(p); + ABTS_PTR_NOTNULL(tc, base); + ABTS_PTR_NOTNULL(tc, overlay); + + apr_hash_set(base, "key1", APR_HASH_KEY_STRING, "value1"); + apr_hash_set(base, "key2", APR_HASH_KEY_STRING, "value2"); + apr_hash_set(base, "key3", APR_HASH_KEY_STRING, "value3"); + apr_hash_set(base, "key4", APR_HASH_KEY_STRING, "value4"); + apr_hash_set(base, "key5", APR_HASH_KEY_STRING, "value5"); + + result = apr_hash_overlay(p, overlay, base); + + count = apr_hash_count(result); + ABTS_INT_EQUAL(tc, 5, count); + + dump_hash(p, result, StrArray); + + ABTS_STR_EQUAL(tc, "Key key1 (4) Value value1\n", StrArray[0]); + ABTS_STR_EQUAL(tc, "Key key2 (4) Value value2\n", StrArray[1]); + ABTS_STR_EQUAL(tc, "Key key3 (4) Value value3\n", StrArray[2]); + ABTS_STR_EQUAL(tc, "Key key4 (4) Value value4\n", StrArray[3]); + ABTS_STR_EQUAL(tc, "Key key5 (4) Value value5\n", StrArray[4]); + ABTS_STR_EQUAL(tc, "#entries 5\n", StrArray[5]); +} + +static void overlay_2unique(abts_case *tc, void *data) +{ + apr_hash_t *base = NULL; + apr_hash_t *overlay = NULL; + apr_hash_t *result = NULL; + int count; + char StrArray[MAX_DEPTH][MAX_LTH]; + + base = apr_hash_make(p); + overlay = apr_hash_make(p); + ABTS_PTR_NOTNULL(tc, base); + ABTS_PTR_NOTNULL(tc, overlay); + + apr_hash_set(base, "base1", APR_HASH_KEY_STRING, "value1"); + apr_hash_set(base, "base2", APR_HASH_KEY_STRING, "value2"); + apr_hash_set(base, "base3", APR_HASH_KEY_STRING, "value3"); + apr_hash_set(base, "base4", APR_HASH_KEY_STRING, "value4"); + apr_hash_set(base, "base5", APR_HASH_KEY_STRING, "value5"); + + apr_hash_set(overlay, "overlay1", APR_HASH_KEY_STRING, "value1"); + apr_hash_set(overlay, "overlay2", APR_HASH_KEY_STRING, "value2"); + apr_hash_set(overlay, "overlay3", APR_HASH_KEY_STRING, "value3"); + apr_hash_set(overlay, "overlay4", APR_HASH_KEY_STRING, "value4"); + apr_hash_set(overlay, "overlay5", APR_HASH_KEY_STRING, "value5"); + + result = apr_hash_overlay(p, overlay, base); + + count = apr_hash_count(result); + ABTS_INT_EQUAL(tc, 10, count); + + dump_hash(p, result, StrArray); + + ABTS_STR_EQUAL(tc, "Key base1 (5) Value value1\n", StrArray[0]); + ABTS_STR_EQUAL(tc, "Key base2 (5) Value value2\n", StrArray[1]); + ABTS_STR_EQUAL(tc, "Key base3 (5) Value value3\n", StrArray[2]); + ABTS_STR_EQUAL(tc, "Key base4 (5) Value value4\n", StrArray[3]); + ABTS_STR_EQUAL(tc, "Key base5 (5) Value value5\n", StrArray[4]); + ABTS_STR_EQUAL(tc, "Key overlay1 (8) Value value1\n", StrArray[5]); + ABTS_STR_EQUAL(tc, "Key overlay2 (8) Value value2\n", StrArray[6]); + ABTS_STR_EQUAL(tc, "Key overlay3 (8) Value value3\n", StrArray[7]); + ABTS_STR_EQUAL(tc, "Key overlay4 (8) Value value4\n", StrArray[8]); + ABTS_STR_EQUAL(tc, "Key overlay5 (8) Value value5\n", StrArray[9]); + ABTS_STR_EQUAL(tc, "#entries 10\n", StrArray[10]); +} + +static void overlay_same(abts_case *tc, void *data) +{ + apr_hash_t *base = NULL; + apr_hash_t *result = NULL; + int count; + char StrArray[MAX_DEPTH][MAX_LTH]; + + base = apr_hash_make(p); + ABTS_PTR_NOTNULL(tc, base); + + apr_hash_set(base, "base1", APR_HASH_KEY_STRING, "value1"); + apr_hash_set(base, "base2", APR_HASH_KEY_STRING, "value2"); + apr_hash_set(base, "base3", APR_HASH_KEY_STRING, "value3"); + apr_hash_set(base, "base4", APR_HASH_KEY_STRING, "value4"); + apr_hash_set(base, "base5", APR_HASH_KEY_STRING, "value5"); + + result = apr_hash_overlay(p, base, base); + + count = apr_hash_count(result); + ABTS_INT_EQUAL(tc, 5, count); + + dump_hash(p, result, StrArray); + + ABTS_STR_EQUAL(tc, "Key base1 (5) Value value1\n", StrArray[0]); + ABTS_STR_EQUAL(tc, "Key base2 (5) Value value2\n", StrArray[1]); + ABTS_STR_EQUAL(tc, "Key base3 (5) Value value3\n", StrArray[2]); + ABTS_STR_EQUAL(tc, "Key base4 (5) Value value4\n", StrArray[3]); + ABTS_STR_EQUAL(tc, "Key base5 (5) Value value5\n", StrArray[4]); + ABTS_STR_EQUAL(tc, "#entries 5\n", StrArray[5]); +} + +static void overlay_fetch(abts_case *tc, void *data) +{ + apr_hash_t *base = NULL; + apr_hash_t *overlay = NULL; + apr_hash_t *result = NULL; + int count; + + base = apr_hash_make(p); + overlay = apr_hash_make(p); + ABTS_PTR_NOTNULL(tc, base); + ABTS_PTR_NOTNULL(tc, overlay); + + apr_hash_set(base, "base1", APR_HASH_KEY_STRING, "value1"); + apr_hash_set(base, "base2", APR_HASH_KEY_STRING, "value2"); + apr_hash_set(base, "base3", APR_HASH_KEY_STRING, "value3"); + apr_hash_set(base, "base4", APR_HASH_KEY_STRING, "value4"); + apr_hash_set(base, "base5", APR_HASH_KEY_STRING, "value5"); + + apr_hash_set(overlay, "overlay1", APR_HASH_KEY_STRING, "value1"); + apr_hash_set(overlay, "overlay2", APR_HASH_KEY_STRING, "value2"); + apr_hash_set(overlay, "overlay3", APR_HASH_KEY_STRING, "value3"); + apr_hash_set(overlay, "overlay4", APR_HASH_KEY_STRING, "value4"); + apr_hash_set(overlay, "overlay5", APR_HASH_KEY_STRING, "value5"); + + result = apr_hash_overlay(p, overlay, base); + + count = apr_hash_count(result); + ABTS_INT_EQUAL(tc, 10, count); + + ABTS_STR_EQUAL(tc, "value1", + apr_hash_get(result, "base1", APR_HASH_KEY_STRING)); + ABTS_STR_EQUAL(tc, "value2", + apr_hash_get(result, "base2", APR_HASH_KEY_STRING)); + ABTS_STR_EQUAL(tc, "value3", + apr_hash_get(result, "base3", APR_HASH_KEY_STRING)); + ABTS_STR_EQUAL(tc, "value4", + apr_hash_get(result, "base4", APR_HASH_KEY_STRING)); + ABTS_STR_EQUAL(tc, "value5", + apr_hash_get(result, "base5", APR_HASH_KEY_STRING)); + ABTS_STR_EQUAL(tc, "value1", + apr_hash_get(result, "overlay1", APR_HASH_KEY_STRING)); + ABTS_STR_EQUAL(tc, "value2", + apr_hash_get(result, "overlay2", APR_HASH_KEY_STRING)); + ABTS_STR_EQUAL(tc, "value3", + apr_hash_get(result, "overlay3", APR_HASH_KEY_STRING)); + ABTS_STR_EQUAL(tc, "value4", + apr_hash_get(result, "overlay4", APR_HASH_KEY_STRING)); + ABTS_STR_EQUAL(tc, "value5", + apr_hash_get(result, "overlay5", APR_HASH_KEY_STRING)); + + ABTS_STR_EQUAL(tc, "value1", + apr_hash_get(base, "base1", APR_HASH_KEY_STRING)); + ABTS_STR_EQUAL(tc, "value2", + apr_hash_get(base, "base2", APR_HASH_KEY_STRING)); + ABTS_STR_EQUAL(tc, "value3", + apr_hash_get(base, "base3", APR_HASH_KEY_STRING)); + ABTS_STR_EQUAL(tc, "value4", + apr_hash_get(base, "base4", APR_HASH_KEY_STRING)); + ABTS_STR_EQUAL(tc, "value5", + apr_hash_get(base, "base5", APR_HASH_KEY_STRING)); + + ABTS_STR_EQUAL(tc, "value1", + apr_hash_get(overlay, "overlay1", APR_HASH_KEY_STRING)); + ABTS_STR_EQUAL(tc, "value2", + apr_hash_get(overlay, "overlay2", APR_HASH_KEY_STRING)); + ABTS_STR_EQUAL(tc, "value3", + apr_hash_get(overlay, "overlay3", APR_HASH_KEY_STRING)); + ABTS_STR_EQUAL(tc, "value4", + apr_hash_get(overlay, "overlay4", APR_HASH_KEY_STRING)); + ABTS_STR_EQUAL(tc, "value5", + apr_hash_get(overlay, "overlay5", APR_HASH_KEY_STRING)); +} + +abts_suite *testhash(abts_suite *suite) +{ + suite = ADD_SUITE(suite) + + abts_run_test(suite, hash_make, NULL); + abts_run_test(suite, hash_set, NULL); + abts_run_test(suite, hash_get_or_set, NULL); + abts_run_test(suite, hash_reset, NULL); + abts_run_test(suite, same_value, NULL); + abts_run_test(suite, same_value_custom, NULL); + abts_run_test(suite, key_space, NULL); + abts_run_test(suite, delete_key, NULL); + + abts_run_test(suite, hash_count_0, NULL); + abts_run_test(suite, hash_count_1, NULL); + abts_run_test(suite, hash_count_5, NULL); + + abts_run_test(suite, hash_clear, NULL); + abts_run_test(suite, hash_traverse, NULL); + abts_run_test(suite, summation_test, NULL); + + abts_run_test(suite, overlay_empty, NULL); + abts_run_test(suite, overlay_2unique, NULL); + abts_run_test(suite, overlay_same, NULL); + abts_run_test(suite, overlay_fetch, NULL); + + return suite; +} + diff --git a/test/testhooks.c b/test/testhooks.c new file mode 100644 index 00000000000..b2b16d4c1eb --- /dev/null +++ b/test/testhooks.c @@ -0,0 +1,194 @@ +/* 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 "abts.h" +#include "testutil.h" + +#define APR_HOOK_PROBES_ENABLED + +#define APR_HOOK_PROBE_ENTRY(ud,ns,name,args) \ + ud = toy_hook_probe_entry(#name) + +#define APR_HOOK_PROBE_RETURN(ud,ns,name,rv,args) \ + toy_hook_probe_return(ud, #name, rv) + +#define APR_HOOK_PROBE_INVOKE(ud,ns,name,src,args) \ + toy_hook_probe_invoke(ud, #name, src) + +#define APR_HOOK_PROBE_COMPLETE(ud,ns,name,src,rv,args) \ + toy_hook_probe_complete(ud, #name, src, rv) + +#include "apr_hooks.h" + +#define TEST_DECLARE(type) type + +APR_DECLARE_EXTERNAL_HOOK(test,TEST,int, toyhook, (char *x, apr_size_t s)) + +APR_HOOK_STRUCT( + APR_HOOK_LINK(toyhook) +) + +static void *toy_hook_probe_entry(const char *name); +static void toy_hook_probe_return(void *ud, const char *name, int rv); +static void toy_hook_probe_invoke(void *ud, const char *name, const char *src); +static void toy_hook_probe_complete(void *ud, const char *name, + const char *src, int rv); + +APR_IMPLEMENT_EXTERNAL_HOOK_RUN_ALL(test,TEST,int, toyhook, + (char *x, apr_size_t s), (x, s), 0, -1) + +typedef struct { + char *buf; + apr_size_t buf_size; +} hook_probe_data_t; + +static apr_pool_t *probe_buf_pool; +static char *probe_buf; + +static void safe_concat(char *buf, apr_size_t buf_size, const char *append) +{ + if (strlen(buf) + strlen(append) + 1 <= buf_size) { + strcat(buf, append); + } +} + +static void *toy_hook_probe_entry(const char *name) +{ + hook_probe_data_t *ud = apr_palloc(probe_buf_pool, sizeof *ud); + ud->buf_size = 18; + ud->buf = (char *)apr_palloc(probe_buf_pool, ud->buf_size); + ud->buf[0] = '\0'; + safe_concat(ud->buf, ud->buf_size, "E"); + return (void *)ud; +} + +static void toy_hook_probe_return(void *vud, const char *name, int rv) +{ + hook_probe_data_t *ud = vud; + + safe_concat(ud->buf, ud->buf_size, "R"); + probe_buf = ud->buf; +} + +static void toy_hook_probe_invoke(void *vud, const char *name, + const char *src) +{ + hook_probe_data_t *ud = vud; + + safe_concat(ud->buf, ud->buf_size, "I"); + safe_concat(ud->buf, ud->buf_size, src); +} + +static void toy_hook_probe_complete(void *vud, const char *name, + const char *src, int rv) +{ + hook_probe_data_t *ud = vud; + + safe_concat(ud->buf, ud->buf_size, "C"); +} + +static int toyhook_1(char *x, apr_size_t buf_size) +{ + safe_concat(x, buf_size, "1"); + return 0; +} + +static int toyhook_2(char *x, apr_size_t buf_size) +{ + safe_concat(x, buf_size, "2"); + return 0; +} + +static int toyhook_3(char *x, apr_size_t buf_size) +{ + safe_concat(x, buf_size, "3"); + return 0; +} + +static int toyhook_4(char *x, apr_size_t buf_size) +{ + safe_concat(x, buf_size, "4"); + return 0; +} + +static int toyhook_5(char *x, apr_size_t buf_size) +{ + safe_concat(x, buf_size, "5"); + return 0; +} + +static void test_basic_ordering(abts_case *tc, void *data) +{ + char buf[6] = {0}; + + apr_hook_global_pool = p; + apr_hook_deregister_all(); + + apr_hook_debug_current = "5"; + test_hook_toyhook(toyhook_5, NULL, NULL, APR_HOOK_MIDDLE + 2); + apr_hook_debug_current = "1"; + test_hook_toyhook(toyhook_1, NULL, NULL, APR_HOOK_MIDDLE - 2); + apr_hook_debug_current = "3"; + test_hook_toyhook(toyhook_3, NULL, NULL, APR_HOOK_MIDDLE); + apr_hook_debug_current = "2"; + test_hook_toyhook(toyhook_2, NULL, NULL, APR_HOOK_MIDDLE - 1); + apr_hook_debug_current = "4"; + test_hook_toyhook(toyhook_4, NULL, NULL, APR_HOOK_MIDDLE + 1); + + apr_hook_sort_all(); + + probe_buf_pool = p; + test_run_toyhook(buf, sizeof buf); + + ABTS_STR_EQUAL(tc, "12345", buf); + ABTS_STR_EQUAL(tc, "EI1CI2CI3CI4CI5CR", probe_buf); +} + +static void test_pred_ordering(abts_case *tc, void *data) +{ + char buf[10] = {0}; + static const char *hook2_predecessors[] = {"1", NULL}; + static const char *hook3_predecessors[] = {"2", NULL}; + + apr_hook_global_pool = p; + apr_hook_deregister_all(); + + apr_hook_debug_current = "1"; + test_hook_toyhook(toyhook_1, NULL, NULL, APR_HOOK_MIDDLE); + apr_hook_debug_current = "3"; + test_hook_toyhook(toyhook_3, hook3_predecessors, NULL, APR_HOOK_MIDDLE); + apr_hook_debug_current = "2"; + test_hook_toyhook(toyhook_2, hook2_predecessors, NULL, APR_HOOK_MIDDLE); + apr_hook_debug_current = "2"; + test_hook_toyhook(toyhook_2, hook2_predecessors, NULL, APR_HOOK_MIDDLE); + + apr_hook_sort_all(); + + probe_buf_pool = p; + test_run_toyhook(buf, sizeof buf); + + /* FAILS ABTS_STR_EQUAL(tc, "1223", buf); */ +} + +abts_suite *testhooks(abts_suite *suite) +{ + suite = ADD_SUITE(suite); + + abts_run_test(suite, test_basic_ordering, NULL); + abts_run_test(suite, test_pred_ordering, NULL); + + return suite; +} diff --git a/test/testipsub.c b/test/testipsub.c new file mode 100644 index 00000000000..7bdb8ccb4e1 --- /dev/null +++ b/test/testipsub.c @@ -0,0 +1,233 @@ +/* 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 "testutil.h" +#include "apr_general.h" +#include "apr_network_io.h" +#include "apr_errno.h" + +static void test_bad_input(abts_case *tc, void *data) +{ + struct { + const char *ipstr; + const char *mask; + apr_status_t expected_rv; + } testcases[] = + { + /* so we have a few good inputs in here; sue me */ + {"my.host.name", NULL, APR_EINVAL} + ,{"127.0.0.256", NULL, APR_EBADIP} + ,{"127.0.0.1", NULL, APR_SUCCESS} + ,{"127.0.0.1", "32", APR_SUCCESS} + ,{"127.0.0.1", "1", APR_SUCCESS} + ,{"127.0.0.1", "15", APR_SUCCESS} + ,{"127.0.0.1", "-1", APR_EBADMASK} + ,{"127.0.0.1", "0", APR_EBADMASK} + ,{"127.0.0.1", "33", APR_EBADMASK} + ,{"127.0.0.1", "255.0.0.0", APR_SUCCESS} + ,{"127.0.0.1", "255.0", APR_EBADMASK} + ,{"127.0.0.1", "255.255.256.0", APR_EBADMASK} + ,{"127.0.0.1", "abc", APR_EBADMASK} + ,{"127", NULL, APR_SUCCESS} + ,{"127.0.0.1.2", NULL, APR_EBADIP} + ,{"127.0.0.1.2", "8", APR_EBADIP} + ,{"127", "255.0.0.0", APR_EBADIP} /* either EBADIP or EBADMASK seems fine */ + ,{"", NULL, APR_EINVAL} +#if APR_HAVE_IPV6 + ,{"::1", NULL, APR_SUCCESS} + ,{"::1", "20", APR_SUCCESS} + ,{"::ffff:9.67.113.15", NULL, APR_EBADIP} /* yes, this is goodness */ + ,{"fe80::", "16", APR_SUCCESS} + ,{"fe80::", "255.0.0.0", APR_EBADMASK} + ,{"fe80::1", "0", APR_EBADMASK} + ,{"fe80::1", "-1", APR_EBADMASK} + ,{"fe80::1", "1", APR_SUCCESS} + ,{"fe80::1", "33", APR_SUCCESS} + ,{"fe80::1", "128", APR_SUCCESS} + ,{"fe80::1", "129", APR_EBADMASK} +#else + /* do some IPv6 stuff and verify that it fails with APR_EBADIP */ + ,{"::ffff:9.67.113.15", NULL, APR_EBADIP} +#endif + }; + int i; + apr_ipsubnet_t *ipsub; + apr_status_t rv; + + for (i = 0; i < (sizeof testcases / sizeof testcases[0]); i++) { + rv = apr_ipsubnet_create(&ipsub, testcases[i].ipstr, testcases[i].mask, p); + ABTS_INT_EQUAL(tc, testcases[i].expected_rv, rv); + } +} + +static void test_singleton_subnets(abts_case *tc, void *data) +{ + const char *v4addrs[] = { + "127.0.0.1", "129.42.18.99", "63.161.155.20", "207.46.230.229", "64.208.42.36", + "198.144.203.195", "192.18.97.241", "198.137.240.91", "62.156.179.119", + "204.177.92.181" + }; + apr_ipsubnet_t *ipsub; + apr_sockaddr_t *sa; + apr_status_t rv; + int i, j, rc; + + for (i = 0; i < sizeof v4addrs / sizeof v4addrs[0]; i++) { + rv = apr_ipsubnet_create(&ipsub, v4addrs[i], NULL, p); + ABTS_TRUE(tc, rv == APR_SUCCESS); + for (j = 0; j < sizeof v4addrs / sizeof v4addrs[0]; j++) { + rv = apr_sockaddr_info_get(&sa, v4addrs[j], APR_INET, 0, 0, p); + ABTS_TRUE(tc, rv == APR_SUCCESS); + rc = apr_ipsubnet_test(ipsub, sa); + if (!strcmp(v4addrs[i], v4addrs[j])) { + ABTS_TRUE(tc, rc != 0); + } + else { + ABTS_TRUE(tc, rc == 0); + } + } + } + + /* same for v6? */ +} + +static void test_interesting_subnets(abts_case *tc, void *data) +{ + struct { + const char *ipstr, *mask; + int family; + char *in_subnet, *not_in_subnet; + } testcases[] = + { + {"9.67", NULL, APR_INET, "9.67.113.15", "10.1.2.3"} + ,{"9.67.0.0", "16", APR_INET, "9.67.113.15", "10.1.2.3"} + ,{"9.67.0.0", "255.255.0.0", APR_INET, "9.67.113.15", "10.1.2.3"} + ,{"9.67.113.99", "16", APR_INET, "9.67.113.15", "10.1.2.3"} + ,{"9.67.113.99", "255.255.255.0", APR_INET, "9.67.113.15", "10.1.2.3"} + ,{"127", NULL, APR_INET, "127.0.0.1", "10.1.2.3"} + ,{"127.0.0.1", "8", APR_INET, "127.0.0.1", "10.1.2.3"} +#if APR_HAVE_IPV6 + ,{"38.0.0.0", "8", APR_INET6, "::ffff:38.1.1.1", "2600::1"} /* PR 54047 */ + ,{"fe80::", "8", APR_INET6, "fe80::1", "ff01::1"} + ,{"ff01::", "8", APR_INET6, "ff01::1", "fe80::1"} + ,{"3FFE:8160::", "28", APR_INET6, "3ffE:816e:abcd:1234::1", "3ffe:8170::1"} + ,{"127.0.0.1", NULL, APR_INET6, "::ffff:127.0.0.1", "fe80::1"} + ,{"127.0.0.1", "8", APR_INET6, "::ffff:127.0.0.1", "fe80::1"} +#endif + }; + apr_ipsubnet_t *ipsub; + apr_sockaddr_t *sa; + apr_status_t rv; + int i, rc; + + for (i = 0; i < sizeof testcases / sizeof testcases[0]; i++) { + rv = apr_ipsubnet_create(&ipsub, testcases[i].ipstr, testcases[i].mask, p); + ABTS_TRUE(tc, rv == APR_SUCCESS); + rv = apr_sockaddr_info_get(&sa, testcases[i].in_subnet, testcases[i].family, 0, 0, p); + ABTS_TRUE(tc, rv == APR_SUCCESS); + ABTS_TRUE(tc, sa != NULL); + if (!sa) continue; + rc = apr_ipsubnet_test(ipsub, sa); + ABTS_TRUE(tc, rc != 0); + rv = apr_sockaddr_info_get(&sa, testcases[i].not_in_subnet, testcases[i].family, 0, 0, p); + ABTS_TRUE(tc, rv == APR_SUCCESS); + rc = apr_ipsubnet_test(ipsub, sa); + ABTS_TRUE(tc, rc == 0); + } +} + +static void test_badmask_str(abts_case *tc, void *data) +{ + char buf[128]; + + ABTS_STR_EQUAL(tc, apr_strerror(APR_EBADMASK, buf, sizeof buf), + "The specified network mask is invalid."); +} + +static void test_badip_str(abts_case *tc, void *data) +{ + char buf[128]; + + ABTS_STR_EQUAL(tc, apr_strerror(APR_EBADIP, buf, sizeof buf), + "The specified IP address is invalid."); +} + +static void test_parse_addr_port(abts_case *tc, void *data) +{ + const struct { + const char *input; + apr_status_t rv; + const char *addr, *scope_id; + apr_port_t port; + } *test, testcases[] = { + /* Success cases */ + { "localhost:80", APR_SUCCESS, "localhost", NULL, 80 } + ,{ "localhost", APR_SUCCESS, "localhost", NULL, 0 } + ,{ "www.example.com:8080", APR_SUCCESS, "www.example.com", NULL, 8080 } + ,{ "w:1", APR_SUCCESS, "w", NULL, 1 } + ,{ "127.0.0.1:80", APR_SUCCESS, "127.0.0.1", NULL, 80 } + ,{ "[::]:80", APR_SUCCESS, "::", NULL, 80 } + ,{ "[::%eth0]:80", APR_SUCCESS, "::", "eth0", 80 } + ,{ "[::%eth0]", APR_SUCCESS, "::", "eth0", 0 } + ,{ "8080", APR_SUCCESS, NULL, NULL, 8080 } /* API doc has this case */ + + /* Failure cases */ + ,{ "localhost:999999", APR_EINVAL, NULL, NULL, 0 } + ,{ "localhost:0", APR_EINVAL, NULL, NULL, 0 } + ,{ "[abc]", APR_EINVAL, NULL, NULL, 0 } + ,{ "[::]z:80", APR_EINVAL, NULL, NULL, 0 } + ,{ "[:::80", APR_EINVAL, NULL, NULL, 0 } + ,{ "[zzzz]:80", APR_EINVAL, NULL, NULL, 0 } + ,{ "[::%]:80", APR_EINVAL, NULL, NULL, 0 } +/* ,{ "127.0.0.1:80x", APR_EINVAL, NULL, NULL, 0 } <- should fail, doesn't */ +/* ,{ "127.0.0.1x:80", APR_EINVAL, NULL, NULL, 0 } <- maybe should fail?, doesn't */ +/* ,{ "localhost:-1", APR_EINVAL, NULL, NULL, 0 } <- should fail, doesn't */ + }; + unsigned i; + + for (i = 0; i < (sizeof testcases / sizeof testcases[0]); i++) { + char *addr, *scope_id; + apr_port_t port; + apr_status_t rv; + + test = &testcases[i]; + + rv = apr_parse_addr_port(&addr, &scope_id, &port, test->input, p); + ABTS_INT_EQUAL(tc, test->rv, rv); + + if (test->rv != APR_SUCCESS) continue; + + APR_ASSERT_SUCCESS(tc, "parse address", test->rv); + + ABTS_STR_EQUAL(tc, test->addr, addr); + ABTS_STR_EQUAL(tc, test->scope_id, scope_id); + ABTS_INT_EQUAL(tc, test->port, port); + } +} + +abts_suite *testipsub(abts_suite *suite) +{ + suite = ADD_SUITE(suite) + + abts_run_test(suite, test_bad_input, NULL); + abts_run_test(suite, test_singleton_subnets, NULL); + abts_run_test(suite, test_interesting_subnets, NULL); + abts_run_test(suite, test_badmask_str, NULL); + abts_run_test(suite, test_badip_str, NULL); + abts_run_test(suite, test_parse_addr_port, NULL); + return suite; +} + diff --git a/test/testlfs.c b/test/testlfs.c new file mode 100644 index 00000000000..aa5357389fc --- /dev/null +++ b/test/testlfs.c @@ -0,0 +1,373 @@ +/* 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_file_io.h" +#include "apr_file_info.h" +#include "apr_errno.h" +#include "apr_general.h" +#include "apr_poll.h" +#include "apr_strings.h" +#include "apr_lib.h" +#include "apr_mmap.h" +#include "testutil.h" + +/* TODO: in 1.3.0 this becomes APR_HAS_SPARSE_FILES, HOWEVER we will + * still need to test csize before proceeding, because having sparse + * file support in the OS/APR does not mean this volume supports it! + */ +#if APR_HAS_LARGE_FILES + +/* Tests which create an 8GB sparse file and then check it can be used + * as normal. */ + +static apr_off_t oneMB = APR_INT64_C(2) << 19; +static apr_off_t eightGB = APR_INT64_C(2) << 32; + +static int madefile = 0; + +#define PRECOND if (!madefile) { ABTS_NOT_IMPL(tc, "Large file tests not enabled"); return; } + +#define TESTDIR "lfstests" +#define TESTFILE "large.bin" +#define TESTFN "lfstests/large.bin" + +static void test_open(abts_case *tc, void *data) +{ + apr_file_t *f; + apr_finfo_t testsize; + apr_status_t rv; + + rv = apr_dir_make(TESTDIR, APR_FPROT_OS_DEFAULT, p); + if (rv && !APR_STATUS_IS_EEXIST(rv)) { + APR_ASSERT_SUCCESS(tc, "make test directory", rv); + } + + /* First attempt a 1MB sparse file so we don't tax the poor test box */ + rv = apr_file_open(&f, TESTFN, APR_FOPEN_CREATE | APR_FOPEN_WRITE + | APR_FOPEN_TRUNCATE | APR_FOPEN_SPARSE, + APR_FPROT_OS_DEFAULT, p); + + APR_ASSERT_SUCCESS(tc, "open file", rv); + + APR_ASSERT_SUCCESS(tc, "Truncate to 1MB", rv = apr_file_trunc(f, oneMB+1)); + + if (rv == APR_SUCCESS) { + rv = apr_file_info_get(&testsize, APR_FINFO_CSIZE, f); + } + + /* give up if we can't determine the allocation size of the file, + * or if it's not an obviously small allocation but the allocation + * unit doesn't appear insanely large - on most platforms, it's just + * zero physical bytes at this point. + */ + if (rv != APR_SUCCESS || (testsize.csize > oneMB + && testsize.csize < oneMB * 2)) { + ABTS_NOT_IMPL(tc, "Creation of large file (apparently not sparse)"); + + madefile = 0; + } + else { + /* Proceed with our 8GB sparse file now */ + rv = apr_file_trunc(f, eightGB); + + /* 8GB may pass rlimits or filesystem limits */ + + if (APR_STATUS_IS_EINVAL(rv) +#ifdef EFBIG + || rv == EFBIG +#endif + ) { + ABTS_NOT_IMPL(tc, "Creation of large file (rlimit, quota or fs)"); + } + else { + APR_ASSERT_SUCCESS(tc, "truncate file to 8gb", rv); + } + madefile = rv == APR_SUCCESS; + } + + APR_ASSERT_SUCCESS(tc, "close large file", apr_file_close(f)); + + if (!madefile) { + APR_ASSERT_SUCCESS(tc, "remove large file", apr_file_remove(TESTFN, p)); + } +} + +static void test_reopen(abts_case *tc, void *data) +{ + apr_file_t *fh; + apr_finfo_t finfo; + apr_status_t rv; + + PRECOND; + + rv = apr_file_open(&fh, TESTFN, APR_FOPEN_SPARSE | APR_FOPEN_READ, + APR_FPROT_OS_DEFAULT, p); + APR_ASSERT_SUCCESS(tc, "re-open 8GB file", rv); + + APR_ASSERT_SUCCESS(tc, "file_info_get failed", + apr_file_info_get(&finfo, APR_FINFO_NORM, fh)); + + ABTS_ASSERT(tc, "file_info_get gave incorrect size", + finfo.size == eightGB); + + APR_ASSERT_SUCCESS(tc, "re-close large file", apr_file_close(fh)); +} + +static void test_stat(abts_case *tc, void *data) +{ + apr_finfo_t finfo; + + PRECOND; + + APR_ASSERT_SUCCESS(tc, "stat large file", + apr_stat(&finfo, TESTFN, APR_FINFO_NORM, p)); + + ABTS_ASSERT(tc, "stat gave incorrect size", finfo.size == eightGB); +} + +static void test_readdir(abts_case *tc, void *data) +{ + apr_dir_t *dh; + apr_status_t rv; + + PRECOND; + + APR_ASSERT_SUCCESS(tc, "open test directory", + apr_dir_open(&dh, TESTDIR, p)); + + do { + apr_finfo_t finfo; + + rv = apr_dir_read(&finfo, APR_FINFO_MIN, dh); + + if (rv == APR_SUCCESS && strcmp(finfo.name, TESTFILE) == 0) { + ABTS_ASSERT(tc, "apr_dir_read gave incorrect size for large file", + finfo.size == eightGB); + } + + } while (rv == APR_SUCCESS); + + if (!APR_STATUS_IS_ENOENT(rv)) { + APR_ASSERT_SUCCESS(tc, "apr_dir_read failed", rv); + } + + APR_ASSERT_SUCCESS(tc, "close test directory", + apr_dir_close(dh)); +} + +#define TESTSTR "Hello, world." + +static void test_append(abts_case *tc, void *data) +{ + apr_file_t *fh; + apr_finfo_t finfo; + apr_status_t rv; + + PRECOND; + + rv = apr_file_open(&fh, TESTFN, APR_FOPEN_SPARSE | APR_FOPEN_WRITE + | APR_FOPEN_APPEND, + APR_FPROT_OS_DEFAULT, p); + APR_ASSERT_SUCCESS(tc, "open 8GB file for append", rv); + + APR_ASSERT_SUCCESS(tc, "append to 8GB file", + apr_file_write_full(fh, TESTSTR, strlen(TESTSTR), NULL)); + + APR_ASSERT_SUCCESS(tc, "file_info_get failed", + apr_file_info_get(&finfo, APR_FINFO_NORM, fh)); + + ABTS_ASSERT(tc, "file_info_get gave incorrect size", + finfo.size == eightGB + strlen(TESTSTR)); + + APR_ASSERT_SUCCESS(tc, "close 8GB file", apr_file_close(fh)); +} + +static void test_seek(abts_case *tc, void *data) +{ + apr_file_t *fh; + apr_off_t pos; + apr_status_t rv; + + PRECOND; + + rv = apr_file_open(&fh, TESTFN, APR_FOPEN_SPARSE | APR_FOPEN_WRITE, + APR_FPROT_OS_DEFAULT, p); + APR_ASSERT_SUCCESS(tc, "open 8GB file for writing", rv); + + pos = 0; + APR_ASSERT_SUCCESS(tc, "relative seek to end", + apr_file_seek(fh, APR_END, &pos)); + ABTS_ASSERT(tc, "seek to END gave 8GB", pos == eightGB); + + pos = eightGB; + APR_ASSERT_SUCCESS(tc, "seek to 8GB", apr_file_seek(fh, APR_SET, &pos)); + ABTS_ASSERT(tc, "seek gave 8GB offset", pos == eightGB); + + pos = 0; + APR_ASSERT_SUCCESS(tc, "relative seek to 0", apr_file_seek(fh, APR_CUR, &pos)); + ABTS_ASSERT(tc, "relative seek gave 8GB offset", pos == eightGB); + + apr_file_close(fh); +} + +static void test_write(abts_case *tc, void *data) +{ + apr_file_t *fh; + apr_off_t pos = eightGB - 4; + apr_status_t rv; + + PRECOND; + + rv = apr_file_open(&fh, TESTFN, APR_FOPEN_SPARSE | APR_FOPEN_WRITE, + APR_FPROT_OS_DEFAULT, p); + APR_ASSERT_SUCCESS(tc, "re-open 8GB file", rv); + + APR_ASSERT_SUCCESS(tc, "seek to 8GB - 4", + apr_file_seek(fh, APR_SET, &pos)); + ABTS_ASSERT(tc, "seek gave 8GB-4 offset", pos == eightGB - 4); + + APR_ASSERT_SUCCESS(tc, "write magic string to 8GB-4", + apr_file_write_full(fh, "FISH", 4, NULL)); + + APR_ASSERT_SUCCESS(tc, "close 8GB file", apr_file_close(fh)); +} + + +#if APR_HAS_MMAP +static void test_mmap(abts_case *tc, void *data) +{ + apr_mmap_t *map; + apr_file_t *fh; + apr_size_t len = 65536; /* hopefully a multiple of the page size */ + apr_off_t off = eightGB - len; + apr_status_t rv; + void *ptr; + + PRECOND; + + rv = apr_file_open(&fh, TESTFN, APR_FOPEN_SPARSE | APR_FOPEN_READ, + APR_FPROT_OS_DEFAULT, p); + APR_ASSERT_SUCCESS(tc, "open 8gb file for mmap", rv); + + APR_ASSERT_SUCCESS(tc, "mmap 8GB file", + apr_mmap_create(&map, fh, off, len, APR_MMAP_READ, p)); + + APR_ASSERT_SUCCESS(tc, "close file", apr_file_close(fh)); + + ABTS_ASSERT(tc, "mapped a 64K block", map->size == len); + + APR_ASSERT_SUCCESS(tc, "get pointer into mmaped region", + apr_mmap_offset(&ptr, map, len - 4)); + ABTS_ASSERT(tc, "pointer was not NULL", ptr != NULL); + + ABTS_ASSERT(tc, "found the magic string", memcmp(ptr, "FISH", 4) == 0); + + APR_ASSERT_SUCCESS(tc, "delete mmap handle", apr_mmap_delete(map)); +} +#endif /* APR_HAS_MMAP */ + +static void test_format(abts_case *tc, void *data) +{ + apr_off_t off; + + PRECOND; + + off = apr_atoi64(apr_off_t_toa(p, eightGB)); + + ABTS_ASSERT(tc, "apr_atoi64 parsed apr_off_t_toa result incorrectly", + off == eightGB); +} + +#define TESTBUFFN TESTDIR "/buffer.bin" + +static void test_buffered(abts_case *tc, void *data) +{ + apr_off_t off; + apr_file_t *f; + apr_status_t rv; + + PRECOND; + + rv = apr_file_open(&f, TESTBUFFN, APR_FOPEN_CREATE | APR_FOPEN_WRITE + | APR_FOPEN_TRUNCATE | APR_FOPEN_BUFFERED + | APR_FOPEN_SPARSE, + APR_FPROT_OS_DEFAULT, p); + APR_ASSERT_SUCCESS(tc, "open buffered file", rv); + + APR_ASSERT_SUCCESS(tc, "truncate to 8GB", + apr_file_trunc(f, eightGB)); + + off = eightGB; + APR_ASSERT_SUCCESS(tc, "seek to 8GB", + apr_file_seek(f, APR_SET, &off)); + ABTS_ASSERT(tc, "returned seek position still 8GB", + off == eightGB); + + off = 0; + APR_ASSERT_SUCCESS(tc, "relative seek", + apr_file_seek(f, APR_CUR, &off)); + ABTS_ASSERT(tc, "relative seek still at 8GB", + off == eightGB); + + off = 0; + APR_ASSERT_SUCCESS(tc, "end-relative seek", + apr_file_seek(f, APR_END, &off)); + ABTS_ASSERT(tc, "end-relative seek still at 8GB", + off == eightGB); + + off = -eightGB; + APR_ASSERT_SUCCESS(tc, "relative seek to beginning", + apr_file_seek(f, APR_CUR, &off)); + ABTS_ASSERT(tc, "seek to beginning got zero", + off == 0); + + APR_ASSERT_SUCCESS(tc, "close buffered file", + apr_file_close(f)); +} + +#else /* !APR_HAS_LARGE_FILES */ + +static void test_nolfs(abts_case *tc, void *data) +{ + ABTS_NOT_IMPL(tc, "Large Files not supported"); +} + +#endif + +abts_suite *testlfs(abts_suite *suite) +{ + suite = ADD_SUITE(suite) + +#if APR_HAS_LARGE_FILES + abts_run_test(suite, test_open, NULL); + abts_run_test(suite, test_reopen, NULL); + abts_run_test(suite, test_stat, NULL); + abts_run_test(suite, test_readdir, NULL); + abts_run_test(suite, test_seek, NULL); + abts_run_test(suite, test_append, NULL); + abts_run_test(suite, test_write, NULL); +#if APR_HAS_MMAP + abts_run_test(suite, test_mmap, NULL); +#endif + abts_run_test(suite, test_format, NULL); + abts_run_test(suite, test_buffered, NULL); +#else + abts_run_test(suite, test_nolfs, NULL); +#endif + + return suite; +} + diff --git a/test/testlfsabi.c b/test/testlfsabi.c new file mode 100644 index 00000000000..2c1e963b3e6 --- /dev/null +++ b/test/testlfsabi.c @@ -0,0 +1,60 @@ +/* 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 "testutil.h" +#include "testlfsabi.h" +#include "apr_file_info.h" + +/* + * Check that various types don't change size depending on + * -D_FILE_OFFSET_BITS=64 + */ + +extern void get_type_sizes32(int *res); +extern void get_type_sizes64(int *res); + +static void get_type_sizes(int *res) +{ +#include "testlfsabi_include.c" +} + +static void check_type_sizes(abts_case *tc, void *data) +{ + int normal[IDX_MAX], bits32[IDX_MAX], bits64[IDX_MAX]; + get_type_sizes(normal); + get_type_sizes32(bits32); + get_type_sizes64(bits64); + CHECKSIZE(tc, normal, bits32, apr_dev_t); + CHECKSIZE(tc, normal, bits64, apr_dev_t); + CHECKSIZE(tc, normal, bits32, apr_ino_t); + CHECKSIZE(tc, normal, bits64, apr_ino_t); + CHECKSIZE(tc, normal, bits32, apr_off_t); + CHECKSIZE(tc, normal, bits64, apr_off_t); + CHECKSIZE(tc, normal, bits32, apr_socklen_t); + CHECKSIZE(tc, normal, bits64, apr_socklen_t); + CHECKSIZE(tc, normal, bits32, apr_size_t); + CHECKSIZE(tc, normal, bits64, apr_size_t); +} + +abts_suite *testlfsabi(abts_suite *suite) +{ + suite = ADD_SUITE(suite) + + abts_run_test(suite, check_type_sizes, NULL); + + return suite; +} + diff --git a/test/testlfsabi.h b/test/testlfsabi.h new file mode 100644 index 00000000000..32c84e8e7fc --- /dev/null +++ b/test/testlfsabi.h @@ -0,0 +1,32 @@ +/* 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 "abts.h" + +#define IDX_apr_dev_t 0 +#define IDX_apr_ino_t 1 +#define IDX_apr_off_t 2 +#define IDX_apr_socklen_t 3 +#define IDX_apr_size_t 4 +#define IDX_MAX 5 + +#define GETSIZE(res, type) res[(IDX_##type)] = sizeof(type) +#define CHECKSIZE(tc, res1, res2, type) \ + ABTS_INT_EQUAL(tc, res1[(IDX_##type)], res2[(IDX_##type)]); + +extern void get_type_sizes32(int *res); +extern void get_type_sizes64(int *res); + diff --git a/test/testlfsabi32.c b/test/testlfsabi32.c new file mode 100644 index 00000000000..c65bffda259 --- /dev/null +++ b/test/testlfsabi32.c @@ -0,0 +1,29 @@ +/* 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. + */ + +#ifdef _FILE_OFFSET_BITS +#undef _FILE_OFFSET_BITS +#endif + +#define _FILE_OFFSET_BITS 32 + +#include "testlfsabi.h" +#include "apr_file_info.h" + +void get_type_sizes32(int *res) +{ +#include "testlfsabi_include.c" +} diff --git a/test/testlfsabi64.c b/test/testlfsabi64.c new file mode 100644 index 00000000000..ce66c5cf8a8 --- /dev/null +++ b/test/testlfsabi64.c @@ -0,0 +1,29 @@ +/* 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. + */ + +#ifdef _FILE_OFFSET_BITS +#undef _FILE_OFFSET_BITS +#endif + +#define _FILE_OFFSET_BITS 64 + +#include "testlfsabi.h" +#include "apr_file_info.h" + +void get_type_sizes64(int *res) +{ +#include "testlfsabi_include.c" +} diff --git a/test/testlfsabi_include.c b/test/testlfsabi_include.c new file mode 100644 index 00000000000..c634d83a917 --- /dev/null +++ b/test/testlfsabi_include.c @@ -0,0 +1,21 @@ +/* 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. + */ + + GETSIZE(res, apr_dev_t); + GETSIZE(res, apr_ino_t); + GETSIZE(res, apr_off_t); + GETSIZE(res, apr_socklen_t); + GETSIZE(res, apr_size_t); diff --git a/test/testlib.dsp b/test/testlib.dsp new file mode 100644 index 00000000000..93408ca9f2e --- /dev/null +++ b/test/testlib.dsp @@ -0,0 +1,462 @@ +# Microsoft Developer Studio Project File - Name="testlib" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) External Target" 0x0106 + +CFG=testlib - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "testlib.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "testlib.mak" CFG="testlib - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "testlib - Win32 Release" (based on "Win32 (x86) External Target") +!MESSAGE "testlib - Win32 Debug" (based on "Win32 (x86) External Target") +!MESSAGE "testlib - Win32 Release9x" (based on "Win32 (x86) External Target") +!MESSAGE "testlib - Win32 Debug9x" (based on "Win32 (x86) External Target") +!MESSAGE "testlib - x64 Release" (based on "Win32 (x86) External Target") +!MESSAGE "testlib - x64 Debug" (based on "Win32 (x86) External Target") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" + +!IF "$(CFG)" == "testlib - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "" +# PROP BASE Intermediate_Dir "" +# PROP BASE Cmd_Line "NMAKE /f Makefile.win INTDIR=LibR OUTDIR=LibR MODEL=static all check" +# PROP BASE Rebuild_Opt "/a" +# PROP BASE Target_File "LibR\testall.exe" +# PROP BASE Bsc_Name "" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "" +# PROP Intermediate_Dir "" +# PROP Cmd_Line "NMAKE /f Makefile.win INTDIR=LibR OUTDIR=LibR MODEL=static all check" +# PROP Rebuild_Opt "/a" +# PROP Target_File "LibR\testall.exe" +# PROP Bsc_Name "" +# PROP Target_Dir "" + +!ELSEIF "$(CFG)" == "testlib - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "" +# PROP BASE Intermediate_Dir "" +# PROP BASE Cmd_Line "NMAKE /f Makefile.win INTDIR=LibD OUTDIR=LibD MODEL=static _DEBUG=1 all check" +# PROP BASE Rebuild_Opt "/a" +# PROP BASE Target_File "LibD\testall.exe" +# PROP BASE Bsc_Name "" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "" +# PROP Intermediate_Dir "" +# PROP Cmd_Line "NMAKE /f Makefile.win INTDIR=LibD OUTDIR=LibD MODEL=static _DEBUG=1 all check" +# PROP Rebuild_Opt "/a" +# PROP Target_File "LibD\testall.exe" +# PROP Bsc_Name "" +# PROP Target_Dir "" + +!ELSEIF "$(CFG)" == "testlib - Win32 Release9x" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "" +# PROP BASE Intermediate_Dir "" +# PROP BASE Cmd_Line "NMAKE /f Makefile.win INTDIR=9x\LibR OUTDIR=9x\LibR MODEL=static all check" +# PROP BASE Rebuild_Opt "/a" +# PROP BASE Target_File "9x\LibR\testall.exe" +# PROP BASE Bsc_Name "" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "" +# PROP Intermediate_Dir "" +# PROP Cmd_Line "NMAKE /f Makefile.win INTDIR=9x\LibR OUTDIR=9x\LibR MODEL=static all check" +# PROP Rebuild_Opt "/a" +# PROP Target_File "9x\LibR\testall.exe" +# PROP Bsc_Name "" +# PROP Target_Dir "" + +!ELSEIF "$(CFG)" == "testlib - Win32 Debug9x" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "" +# PROP BASE Intermediate_Dir "" +# PROP BASE Cmd_Line "NMAKE /f Makefile.win INTDIR=9x\LibD OUTDIR=9x\LibD MODEL=static _DEBUG=1 all check" +# PROP BASE Rebuild_Opt "/a" +# PROP BASE Target_File "9x\LibD\testall.exe" +# PROP BASE Bsc_Name "" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "" +# PROP Intermediate_Dir "" +# PROP Cmd_Line "NMAKE /f Makefile.win INTDIR=9x\LibD OUTDIR=9x\LibD MODEL=static _DEBUG=1 all check" +# PROP Rebuild_Opt "/a" +# PROP Target_File "9x\LibD\testall.exe" +# PROP Bsc_Name "" +# PROP Target_Dir "" + +!ELSEIF "$(CFG)" == "testlib - x64 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "" +# PROP BASE Intermediate_Dir "" +# PROP BASE Cmd_Line "NMAKE /f Makefile.win INTDIR=x64\LibR OUTDIR=x64\LibR MODEL=static all check" +# PROP BASE Rebuild_Opt "/a" +# PROP BASE Target_File "x64\LibR\testall.exe" +# PROP BASE Bsc_Name "" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "" +# PROP Intermediate_Dir "" +# PROP Cmd_Line "NMAKE /f Makefile.win INTDIR=x64\LibR OUTDIR=x64\LibR MODEL=static all check" +# PROP Rebuild_Opt "/a" +# PROP Target_File "x64\LibR\testall.exe" +# PROP Bsc_Name "" +# PROP Target_Dir "" + +!ELSEIF "$(CFG)" == "testlib - x64 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "" +# PROP BASE Intermediate_Dir "" +# PROP BASE Cmd_Line "NMAKE /f Makefile.win INTDIR=x64\LibD OUTDIR=x64\LibD MODEL=static _DEBUG=1 all check" +# PROP BASE Rebuild_Opt "/a" +# PROP BASE Target_File "x64\LibD\testall.exe" +# PROP BASE Bsc_Name "" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "" +# PROP Intermediate_Dir "" +# PROP Cmd_Line "NMAKE /f Makefile.win INTDIR=x64\LibD OUTDIR=x64\LibD MODEL=static _DEBUG=1 all check" +# PROP Rebuild_Opt "/a" +# PROP Target_File "x64\LibD\testall.exe" +# PROP Bsc_Name "" +# PROP Target_Dir "" + +!ENDIF + +# Begin Target + +# Name "testlib - Win32 Release" +# Name "testlib - Win32 Debug" +# Name "testlib - Win32 Release9x" +# Name "testlib - Win32 Debug9x" +# Name "testlib - x64 Release" +# Name "testlib - x64 Debug" +# Begin Group "testall Source Files" + +# PROP Default_Filter ".c" +# Begin Source File + +SOURCE=.\abts.c +# End Source File +# Begin Source File + +SOURCE=.\abts.h +# End Source File +# Begin Source File + +SOURCE=.\abts_tests.h +# End Source File +# Begin Source File + +SOURCE=.\testapp.c +# End Source File +# Begin Source File + +SOURCE=.\testargs.c +# End Source File +# Begin Source File + +SOURCE=.\testatomic.c +# End Source File +# Begin Source File + +SOURCE=.\testcond.c +# End Source File +# Begin Source File + +SOURCE=.\testdir.c +# End Source File +# Begin Source File + +SOURCE=.\testdso.c +# End Source File +# Begin Source File + +SOURCE=.\testdup.c +# End Source File +# Begin Source File + +SOURCE=.\testenv.c +# End Source File +# Begin Source File + +SOURCE=.\testfile.c +# End Source File +# Begin Source File + +SOURCE=.\testfilecopy.c +# End Source File +# Begin Source File + +SOURCE=.\testfileinfo.c +# End Source File +# Begin Source File + +SOURCE=.\testflock.c +# End Source File +# Begin Source File + +SOURCE=.\testflock.h +# End Source File +# Begin Source File + +SOURCE=.\testfmt.c +# End Source File +# Begin Source File + +SOURCE=.\testfnmatch.c +# End Source File +# Begin Source File + +SOURCE=.\testglobalmutex.c +# End Source File +# Begin Source File + +SOURCE=.\testglobalmutex.h +# End Source File +# Begin Source File + +SOURCE=.\testhash.c +# End Source File +# Begin Source File + +SOURCE=.\testipsub.c +# End Source File +# Begin Source File + +SOURCE=.\testlfs.c +# End Source File +# Begin Source File + +SOURCE=.\testlfsabi.c +# End Source File +# Begin Source File + +SOURCE=.\testlfsabi.h +# End Source File +# Begin Source File + +SOURCE=.\testlfsabi_include.c +# End Source File +# Begin Source File + +SOURCE=.\testlfsabi32.c +# End Source File +# Begin Source File + +SOURCE=.\testlfsabi64.c +# End Source File +# Begin Source File + +SOURCE=.\testlock.c +# End Source File +# Begin Source File + +SOURCE=.\testmmap.c +# End Source File +# Begin Source File + +SOURCE=.\testnames.c +# End Source File +# Begin Source File + +SOURCE=.\testoc.c +# End Source File +# Begin Source File + +SOURCE=.\testpath.c +# End Source File +# Begin Source File + +SOURCE=.\testpipe.c +# End Source File +# Begin Source File + +SOURCE=.\testpoll.c +# End Source File +# Begin Source File + +SOURCE=.\testpools.c +# End Source File +# Begin Source File + +SOURCE=.\testproc.c +# End Source File +# Begin Source File + +SOURCE=.\testrand.c +# End Source File +# Begin Source File + +SOURCE=.\testshm.c +# End Source File +# Begin Source File + +SOURCE=.\testshm.h +# End Source File +# Begin Source File + +SOURCE=.\testsleep.c +# End Source File +# Begin Source File + +SOURCE=.\testsock.c +# End Source File +# Begin Source File + +SOURCE=.\testsock.h +# End Source File +# Begin Source File + +SOURCE=.\testsockets.c +# End Source File +# Begin Source File + +SOURCE=.\testsockopt.c +# End Source File +# Begin Source File + +SOURCE=.\teststr.c +# End Source File +# Begin Source File + +SOURCE=.\teststrnatcmp.c +# End Source File +# Begin Source File + +SOURCE=.\testtable.c +# End Source File +# Begin Source File + +SOURCE=.\testtemp.c +# End Source File +# Begin Source File + +SOURCE=.\testthread.c +# End Source File +# Begin Source File + +SOURCE=.\testtime.c +# End Source File +# Begin Source File + +SOURCE=.\testud.c +# End Source File +# Begin Source File + +SOURCE=.\testuser.c +# End Source File +# Begin Source File + +SOURCE=.\testutil.c +# End Source File +# Begin Source File + +SOURCE=.\testutil.h +# End Source File +# Begin Source File + +SOURCE=.\testvsn.c +# End Source File +# End Group +# Begin Group "Other Source Files" + +# PROP Default_Filter ".c" +# Begin Source File + +SOURCE=.\globalmutexchild.c +# End Source File +# Begin Source File + +SOURCE=.\mod_test.c +# End Source File +# Begin Source File + +SOURCE=.\nw_misc.c +# End Source File +# Begin Source File + +SOURCE=.\occhild.c +# End Source File +# Begin Source File + +SOURCE=.\proc_child.c +# End Source File +# Begin Source File + +SOURCE=.\readchild.c +# End Source File +# Begin Source File + +SOURCE=.\sendfile.c +# End Source File +# Begin Source File + +SOURCE=.\sockchild.c +# End Source File +# Begin Source File + +SOURCE=.\testlockperf.c +# End Source File +# Begin Source File + +SOURCE=.\testmutexscope.c +# End Source File +# Begin Source File + +SOURCE=.\testprocmutex.c +# End Source File +# Begin Source File + +SOURCE=.\testshmconsumer.c +# End Source File +# Begin Source File + +SOURCE=.\testshmproducer.c +# End Source File +# Begin Source File + +SOURCE=.\tryread.c +# End Source File +# End Group +# Begin Source File + +SOURCE=.\Makefile.win +# End Source File +# End Target +# End Project diff --git a/test/testlock.c b/test/testlock.c new file mode 100644 index 00000000000..cd48768ca67 --- /dev/null +++ b/test/testlock.c @@ -0,0 +1,404 @@ +/* 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_thread_proc.h" +#include "apr_file_io.h" +#include "apr_thread_mutex.h" +#include "apr_thread_rwlock.h" +#include "apr_thread_cond.h" +#include "apr_errno.h" +#include "apr_general.h" +#include "apr_getopt.h" +#include "testutil.h" + +#if APR_HAS_THREADS + +#define MAX_ITER 40000 +#define MAX_COUNTER 100000 +#define MAX_RETRY 5 + +static void *APR_THREAD_FUNC thread_rwlock_func(apr_thread_t *thd, void *data); +static void *APR_THREAD_FUNC thread_mutex_function(apr_thread_t *thd, void *data); +static void *APR_THREAD_FUNC thread_cond_producer(apr_thread_t *thd, void *data); +static void *APR_THREAD_FUNC thread_cond_consumer(apr_thread_t *thd, void *data); + +static apr_thread_mutex_t *thread_mutex; +static apr_thread_rwlock_t *rwlock; +static int i = 0, x = 0; + +static int buff[MAX_COUNTER]; + +struct { + apr_thread_mutex_t *mutex; + int nput; + int nval; +} put; + +struct { + apr_thread_mutex_t *mutex; + apr_thread_cond_t *cond; + int nready; +} nready; + +static apr_thread_mutex_t *timeout_mutex; +static apr_thread_cond_t *timeout_cond; + +static void *APR_THREAD_FUNC thread_rwlock_func(apr_thread_t *thd, void *data) +{ + int exitLoop = 1; + + while (1) + { + apr_thread_rwlock_rdlock(rwlock); + if (i == MAX_ITER) + exitLoop = 0; + apr_thread_rwlock_unlock(rwlock); + + if (!exitLoop) + break; + + apr_thread_rwlock_wrlock(rwlock); + if (i != MAX_ITER) + { + i++; + x++; + } + apr_thread_rwlock_unlock(rwlock); + } + return NULL; +} + +static void *APR_THREAD_FUNC thread_mutex_function(apr_thread_t *thd, void *data) +{ + int exitLoop = 1; + + /* slight delay to allow things to settle */ + apr_sleep (1); + + while (1) + { + if (data) { + apr_thread_mutex_timedlock(thread_mutex, *(apr_interval_time_t *)data); + } + else { + apr_thread_mutex_lock(thread_mutex); + } + if (i == MAX_ITER) + exitLoop = 0; + else + { + i++; + x++; + } + apr_thread_mutex_unlock(thread_mutex); + + if (!exitLoop) + break; + } + return NULL; +} + +static void *APR_THREAD_FUNC thread_cond_producer(apr_thread_t *thd, void *data) +{ + for (;;) { + apr_thread_mutex_lock(put.mutex); + if (put.nput >= MAX_COUNTER) { + apr_thread_mutex_unlock(put.mutex); + return NULL; + } + buff[put.nput] = put.nval; + put.nput++; + put.nval++; + apr_thread_mutex_unlock(put.mutex); + + apr_thread_mutex_lock(nready.mutex); + if (nready.nready == 0) + apr_thread_cond_signal(nready.cond); + nready.nready++; + apr_thread_mutex_unlock(nready.mutex); + + *((int *) data) += 1; + } + + return NULL; +} + +static void *APR_THREAD_FUNC thread_cond_consumer(apr_thread_t *thd, void *data) +{ + int i; + + for (i = 0; i < MAX_COUNTER; i++) { + apr_thread_mutex_lock(nready.mutex); + while (nready.nready == 0) + apr_thread_cond_wait(nready.cond, nready.mutex); + nready.nready--; + apr_thread_mutex_unlock(nready.mutex); + + if (buff[i] != i) + printf("buff[%d] = %d\n", i, buff[i]); + } + + return NULL; +} + +static void test_thread_mutex(abts_case *tc, void *data) +{ + apr_thread_t *t1, *t2, *t3, *t4; + apr_status_t s1, s2, s3, s4; + + s1 = apr_thread_mutex_create(&thread_mutex, APR_THREAD_MUTEX_DEFAULT, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, s1); + ABTS_PTR_NOTNULL(tc, thread_mutex); + + i = 0; + x = 0; + + s1 = apr_thread_create(&t1, NULL, thread_mutex_function, NULL, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, s1); + s2 = apr_thread_create(&t2, NULL, thread_mutex_function, NULL, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, s2); + s3 = apr_thread_create(&t3, NULL, thread_mutex_function, NULL, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, s3); + s4 = apr_thread_create(&t4, NULL, thread_mutex_function, NULL, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, s4); + + apr_thread_join(&s1, t1); + apr_thread_join(&s2, t2); + apr_thread_join(&s3, t3); + apr_thread_join(&s4, t4); + + ABTS_INT_EQUAL(tc, MAX_ITER, x); +} + +static void test_thread_timedmutex(abts_case *tc, void *data) +{ + apr_thread_t *t1, *t2, *t3, *t4; + apr_status_t s1, s2, s3, s4; + apr_interval_time_t timeout; + + s1 = apr_thread_mutex_create(&thread_mutex, APR_THREAD_MUTEX_TIMED, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, s1); + ABTS_PTR_NOTNULL(tc, thread_mutex); + + i = 0; + x = 0; + + timeout = apr_time_from_sec(5); + + s1 = apr_thread_create(&t1, NULL, thread_mutex_function, &timeout, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, s1); + s2 = apr_thread_create(&t2, NULL, thread_mutex_function, &timeout, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, s2); + s3 = apr_thread_create(&t3, NULL, thread_mutex_function, &timeout, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, s3); + s4 = apr_thread_create(&t4, NULL, thread_mutex_function, &timeout, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, s4); + + apr_thread_join(&s1, t1); + apr_thread_join(&s2, t2); + apr_thread_join(&s3, t3); + apr_thread_join(&s4, t4); + + ABTS_INT_EQUAL(tc, MAX_ITER, x); +} + +static void test_thread_rwlock(abts_case *tc, void *data) +{ + apr_thread_t *t1, *t2, *t3, *t4; + apr_status_t s1, s2, s3, s4; + + s1 = apr_thread_rwlock_create(&rwlock, p); + if (s1 == APR_ENOTIMPL) { + ABTS_NOT_IMPL(tc, "rwlocks not implemented"); + return; + } + APR_ASSERT_SUCCESS(tc, "rwlock_create", s1); + ABTS_PTR_NOTNULL(tc, rwlock); + + i = 0; + x = 0; + + s1 = apr_thread_create(&t1, NULL, thread_rwlock_func, NULL, p); + APR_ASSERT_SUCCESS(tc, "create thread 1", s1); + s2 = apr_thread_create(&t2, NULL, thread_rwlock_func, NULL, p); + APR_ASSERT_SUCCESS(tc, "create thread 2", s2); + s3 = apr_thread_create(&t3, NULL, thread_rwlock_func, NULL, p); + APR_ASSERT_SUCCESS(tc, "create thread 3", s3); + s4 = apr_thread_create(&t4, NULL, thread_rwlock_func, NULL, p); + APR_ASSERT_SUCCESS(tc, "create thread 4", s4); + + apr_thread_join(&s1, t1); + apr_thread_join(&s2, t2); + apr_thread_join(&s3, t3); + apr_thread_join(&s4, t4); + + ABTS_INT_EQUAL(tc, MAX_ITER, x); + + apr_thread_rwlock_destroy(rwlock); +} + +static void test_cond(abts_case *tc, void *data) +{ + apr_thread_t *p1, *p2, *p3, *p4, *c1; + apr_status_t s0, s1, s2, s3, s4; + int count1, count2, count3, count4; + int sum; + + APR_ASSERT_SUCCESS(tc, "create put mutex", + apr_thread_mutex_create(&put.mutex, + APR_THREAD_MUTEX_DEFAULT, p)); + ABTS_PTR_NOTNULL(tc, put.mutex); + + APR_ASSERT_SUCCESS(tc, "create nready mutex", + apr_thread_mutex_create(&nready.mutex, + APR_THREAD_MUTEX_DEFAULT, p)); + ABTS_PTR_NOTNULL(tc, nready.mutex); + + APR_ASSERT_SUCCESS(tc, "create condvar", + apr_thread_cond_create(&nready.cond, p)); + ABTS_PTR_NOTNULL(tc, nready.cond); + + count1 = count2 = count3 = count4 = 0; + put.nput = put.nval = 0; + nready.nready = 0; + i = 0; + x = 0; + + s0 = apr_thread_create(&p1, NULL, thread_cond_producer, &count1, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, s0); + s1 = apr_thread_create(&p2, NULL, thread_cond_producer, &count2, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, s1); + s2 = apr_thread_create(&p3, NULL, thread_cond_producer, &count3, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, s2); + s3 = apr_thread_create(&p4, NULL, thread_cond_producer, &count4, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, s3); + s4 = apr_thread_create(&c1, NULL, thread_cond_consumer, NULL, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, s4); + + apr_thread_join(&s0, p1); + apr_thread_join(&s1, p2); + apr_thread_join(&s2, p3); + apr_thread_join(&s3, p4); + apr_thread_join(&s4, c1); + + APR_ASSERT_SUCCESS(tc, "destroy condvar", + apr_thread_cond_destroy(nready.cond)); + + sum = count1 + count2 + count3 + count4; + /* + printf("count1 = %d count2 = %d count3 = %d count4 = %d\n", + count1, count2, count3, count4); + */ + ABTS_INT_EQUAL(tc, MAX_COUNTER, sum); +} + +static void test_timeoutcond(abts_case *tc, void *data) +{ + apr_status_t s; + apr_interval_time_t timeout; + apr_time_t begin, end; + int i; + + s = apr_thread_mutex_create(&timeout_mutex, APR_THREAD_MUTEX_DEFAULT, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, s); + ABTS_PTR_NOTNULL(tc, timeout_mutex); + + s = apr_thread_cond_create(&timeout_cond, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, s); + ABTS_PTR_NOTNULL(tc, timeout_cond); + + timeout = apr_time_from_sec(5); + + for (i = 0; i < MAX_RETRY; i++) { + apr_thread_mutex_lock(timeout_mutex); + + begin = apr_time_now(); + s = apr_thread_cond_timedwait(timeout_cond, timeout_mutex, timeout); + end = apr_time_now(); + apr_thread_mutex_unlock(timeout_mutex); + + if (s != APR_SUCCESS && !APR_STATUS_IS_TIMEUP(s)) { + continue; + } + ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_TIMEUP(s)); + ABTS_ASSERT(tc, "Timer returned too late", end - begin - timeout < 500000); + break; + } + ABTS_ASSERT(tc, "Too many retries", i < MAX_RETRY); + APR_ASSERT_SUCCESS(tc, "Unable to destroy the conditional", + apr_thread_cond_destroy(timeout_cond)); +} + +static void test_timeoutmutex(abts_case *tc, void *data) +{ + apr_status_t s; + apr_interval_time_t timeout; + apr_time_t begin, end; + int i; + + s = apr_thread_mutex_create(&timeout_mutex, APR_THREAD_MUTEX_TIMED, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, s); + ABTS_PTR_NOTNULL(tc, timeout_mutex); + + timeout = apr_time_from_sec(5); + + ABTS_INT_EQUAL(tc, 0, apr_thread_mutex_lock(timeout_mutex)); + for (i = 0; i < MAX_RETRY; i++) { + begin = apr_time_now(); + s = apr_thread_mutex_timedlock(timeout_mutex, timeout); + end = apr_time_now(); + + if (s != APR_SUCCESS && !APR_STATUS_IS_TIMEUP(s)) { + continue; + } + ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_TIMEUP(s)); + ABTS_ASSERT(tc, "Timer returned too late", end - begin - timeout < 1000000); + break; + } + ABTS_ASSERT(tc, "Too many retries", i < MAX_RETRY); + ABTS_INT_EQUAL(tc, 0, apr_thread_mutex_unlock(timeout_mutex)); + APR_ASSERT_SUCCESS(tc, "Unable to destroy the mutex", + apr_thread_mutex_destroy(timeout_mutex)); +} + +#endif /* !APR_HAS_THREADS */ + +#if !APR_HAS_THREADS +static void threads_not_impl(abts_case *tc, void *data) +{ + ABTS_NOT_IMPL(tc, "Threads not implemented on this platform"); +} +#endif + + +abts_suite *testlock(abts_suite *suite) +{ + suite = ADD_SUITE(suite) + +#if !APR_HAS_THREADS + abts_run_test(suite, threads_not_impl, NULL); +#else + abts_run_test(suite, test_thread_mutex, NULL); + abts_run_test(suite, test_thread_timedmutex, NULL); + abts_run_test(suite, test_thread_rwlock, NULL); + abts_run_test(suite, test_cond, NULL); + abts_run_test(suite, test_timeoutcond, NULL); + abts_run_test(suite, test_timeoutmutex, NULL); +#endif + + return suite; +} + diff --git a/test/testlockperf.c b/test/testlockperf.c new file mode 100644 index 00000000000..f89d7900b76 --- /dev/null +++ b/test/testlockperf.c @@ -0,0 +1,348 @@ +/* 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_thread_proc.h" +#include "apr_thread_mutex.h" +#include "apr_thread_rwlock.h" +#include "apr_file_io.h" +#include "apr_errno.h" +#include "apr_general.h" +#include "apr_getopt.h" +#include "errno.h" +#include <stdio.h> +#include <stdlib.h> +#include "testutil.h" + +#if !APR_HAS_THREADS +int main(void) +{ + printf("This program won't work on this platform because there is no " + "support for threads.\n"); + return 0; +} +#else /* !APR_HAS_THREADS */ + +#define DEFAULT_MAX_COUNTER 1000000 +#define MAX_THREADS 6 + +static int verbose = 0; +static long mutex_counter; +static long max_counter = DEFAULT_MAX_COUNTER; + +static apr_thread_mutex_t *thread_lock; +void * APR_THREAD_FUNC thread_mutex_func(apr_thread_t *thd, void *data); +apr_status_t test_thread_mutex(int num_threads); /* apr_thread_mutex_t */ + +static apr_thread_rwlock_t *thread_rwlock; +void * APR_THREAD_FUNC thread_rwlock_func(apr_thread_t *thd, void *data); +apr_status_t test_thread_rwlock(int num_threads); /* apr_thread_rwlock_t */ + +int test_thread_mutex_nested(int num_threads); + +apr_pool_t *pool; +int i = 0, x = 0; + +void * APR_THREAD_FUNC thread_mutex_func(apr_thread_t *thd, void *data) +{ + int i; + + for (i = 0; i < max_counter; i++) { + if (data) { + apr_thread_mutex_timedlock(thread_lock, *(apr_interval_time_t *)data); + } + else { + apr_thread_mutex_lock(thread_lock); + } + mutex_counter++; + apr_thread_mutex_unlock(thread_lock); + } + return NULL; +} + +void * APR_THREAD_FUNC thread_rwlock_func(apr_thread_t *thd, void *data) +{ + int i; + + for (i = 0; i < max_counter; i++) { + apr_thread_rwlock_wrlock(thread_rwlock); + mutex_counter++; + apr_thread_rwlock_unlock(thread_rwlock); + } + return NULL; +} + +int test_thread_mutex(int num_threads) +{ + apr_thread_t *t[MAX_THREADS]; + apr_status_t s[MAX_THREADS]; + apr_time_t time_start, time_stop; + int i; + + mutex_counter = 0; + + printf("apr_thread_mutex_t Tests\n"); + printf("%-60s", " Initializing the apr_thread_mutex_t (UNNESTED)"); + s[0] = apr_thread_mutex_create(&thread_lock, APR_THREAD_MUTEX_UNNESTED, pool); + if (s[0] != APR_SUCCESS) { + printf("Failed!\n"); + return s[0]; + } + printf("OK\n"); + + apr_thread_mutex_lock(thread_lock); + /* set_concurrency(4)? -aaron */ + printf(" Starting %d threads ", num_threads); + for (i = 0; i < num_threads; ++i) { + s[i] = apr_thread_create(&t[i], NULL, thread_mutex_func, NULL, pool); + if (s[i] != APR_SUCCESS) { + printf("Failed!\n"); + return s[i]; + } + } + printf("OK\n"); + + time_start = apr_time_now(); + apr_thread_mutex_unlock(thread_lock); + + /* printf("%-60s", " Waiting for threads to exit"); */ + for (i = 0; i < num_threads; ++i) { + apr_thread_join(&s[i], t[i]); + } + /* printf("OK\n"); */ + + time_stop = apr_time_now(); + printf("microseconds: %" APR_INT64_T_FMT " usec\n", + (time_stop - time_start)); + if (mutex_counter != max_counter * num_threads) + printf("error: counter = %ld\n", mutex_counter); + + return APR_SUCCESS; +} + +int test_thread_mutex_nested(int num_threads) +{ + apr_thread_t *t[MAX_THREADS]; + apr_status_t s[MAX_THREADS]; + apr_time_t time_start, time_stop; + int i; + + mutex_counter = 0; + + printf("apr_thread_mutex_t Tests\n"); + printf("%-60s", " Initializing the apr_thread_mutex_t (NESTED)"); + s[0] = apr_thread_mutex_create(&thread_lock, APR_THREAD_MUTEX_NESTED, pool); + if (s[0] != APR_SUCCESS) { + printf("Failed!\n"); + return s[0]; + } + printf("OK\n"); + + apr_thread_mutex_lock(thread_lock); + /* set_concurrency(4)? -aaron */ + printf(" Starting %d threads ", num_threads); + for (i = 0; i < num_threads; ++i) { + s[i] = apr_thread_create(&t[i], NULL, thread_mutex_func, NULL, pool); + if (s[i] != APR_SUCCESS) { + printf("Failed!\n"); + return s[i]; + } + } + printf("OK\n"); + + time_start = apr_time_now(); + apr_thread_mutex_unlock(thread_lock); + + /* printf("%-60s", " Waiting for threads to exit"); */ + for (i = 0; i < num_threads; ++i) { + apr_thread_join(&s[i], t[i]); + } + /* printf("OK\n"); */ + + time_stop = apr_time_now(); + printf("microseconds: %" APR_INT64_T_FMT " usec\n", + (time_stop - time_start)); + if (mutex_counter != max_counter * num_threads) + printf("error: counter = %ld\n", mutex_counter); + + return APR_SUCCESS; +} + +static int test_thread_mutex_timed(int num_threads) +{ + apr_thread_t *t[MAX_THREADS]; + apr_status_t s[MAX_THREADS]; + apr_time_t time_start, time_stop; + apr_time_t timeout; + int i; + + mutex_counter = 0; + + timeout = apr_time_from_sec(5); + + printf("apr_thread_mutex_t Tests\n"); + printf("%-60s", " Initializing the apr_thread_mutex_t (TIMED)"); + s[0] = apr_thread_mutex_create(&thread_lock, APR_THREAD_MUTEX_TIMED, pool); + if (s[0] != APR_SUCCESS) { + printf("Failed!\n"); + return s[0]; + } + printf("OK\n"); + + apr_thread_mutex_lock(thread_lock); + /* set_concurrency(4)? -aaron */ + printf(" Starting %d threads ", num_threads); + for (i = 0; i < num_threads; ++i) { + s[i] = apr_thread_create(&t[i], NULL, thread_mutex_func, &timeout, pool); + if (s[i] != APR_SUCCESS) { + printf("Failed!\n"); + return s[i]; + } + } + printf("OK\n"); + + time_start = apr_time_now(); + apr_thread_mutex_unlock(thread_lock); + + /* printf("%-60s", " Waiting for threads to exit"); */ + for (i = 0; i < num_threads; ++i) { + apr_thread_join(&s[i], t[i]); + } + /* printf("OK\n"); */ + + time_stop = apr_time_now(); + printf("microseconds: %" APR_INT64_T_FMT " usec\n", + (time_stop - time_start)); + if (mutex_counter != max_counter * num_threads) + printf("error: counter = %ld\n", mutex_counter); + + return APR_SUCCESS; +} + +int test_thread_rwlock(int num_threads) +{ + apr_thread_t *t[MAX_THREADS]; + apr_status_t s[MAX_THREADS]; + apr_time_t time_start, time_stop; + int i; + + mutex_counter = 0; + + printf("apr_thread_rwlock_t Tests\n"); + printf("%-60s", " Initializing the apr_thread_rwlock_t"); + s[0] = apr_thread_rwlock_create(&thread_rwlock, pool); + if (s[0] != APR_SUCCESS) { + printf("Failed!\n"); + return s[0]; + } + printf("OK\n"); + + apr_thread_rwlock_wrlock(thread_rwlock); + /* set_concurrency(4)? -aaron */ + printf(" Starting %d threads ", num_threads); + for (i = 0; i < num_threads; ++i) { + s[i] = apr_thread_create(&t[i], NULL, thread_rwlock_func, NULL, pool); + if (s[i] != APR_SUCCESS) { + printf("Failed!\n"); + return s[i]; + } + } + printf("OK\n"); + + time_start = apr_time_now(); + apr_thread_rwlock_unlock(thread_rwlock); + + /* printf("%-60s", " Waiting for threads to exit"); */ + for (i = 0; i < num_threads; ++i) { + apr_thread_join(&s[i], t[i]); + } + /* printf("OK\n"); */ + + time_stop = apr_time_now(); + printf("microseconds: %" APR_INT64_T_FMT " usec\n", + (time_stop - time_start)); + if (mutex_counter != max_counter * num_threads) + printf("error: counter = %ld\n", mutex_counter); + + return APR_SUCCESS; +} + +int main(int argc, const char * const *argv) +{ + apr_status_t rv; + char errmsg[200]; + apr_getopt_t *opt; + char optchar; + const char *optarg; + + printf("APR Lock Performance Test\n==============\n\n"); + + apr_initialize(); + atexit(apr_terminate); + + if (apr_pool_create(&pool, NULL) != APR_SUCCESS) + exit(-1); + + if ((rv = apr_getopt_init(&opt, pool, argc, argv)) != APR_SUCCESS) { + fprintf(stderr, "Could not set up to parse options: [%d] %s\n", + rv, apr_strerror(rv, errmsg, sizeof errmsg)); + exit(-1); + } + + while ((rv = apr_getopt(opt, "c:v", &optchar, &optarg)) == APR_SUCCESS) { + if (optchar == 'c') { + max_counter = atol(optarg); + } + else if (optchar == 'v') { + verbose = 1; + } + } + + if (rv != APR_SUCCESS && rv != APR_EOF) { + fprintf(stderr, "Could not parse options: [%d] %s\n", + rv, apr_strerror(rv, errmsg, sizeof errmsg)); + exit(-1); + } + + for (i = 1; i <= MAX_THREADS; ++i) { + if ((rv = test_thread_mutex(i)) != APR_SUCCESS) { + fprintf(stderr,"thread_mutex test failed : [%d] %s\n", + rv, apr_strerror(rv, (char*)errmsg, 200)); + exit(-3); + } + + if ((rv = test_thread_mutex_nested(i)) != APR_SUCCESS) { + fprintf(stderr,"thread_mutex (NESTED) test failed : [%d] %s\n", + rv, apr_strerror(rv, (char*)errmsg, 200)); + exit(-4); + } + + if ((rv = test_thread_mutex_timed(i)) != APR_SUCCESS) { + fprintf(stderr,"thread_mutex (TIMED) test failed : [%d] %s\n", + rv, apr_strerror(rv, (char*)errmsg, 200)); + exit(-5); + } + + if ((rv = test_thread_rwlock(i)) != APR_SUCCESS) { + fprintf(stderr,"thread_rwlock test failed : [%d] %s\n", + rv, apr_strerror(rv, (char*)errmsg, 200)); + exit(-6); + } + } + + return 0; +} + +#endif /* !APR_HAS_THREADS */ diff --git a/test/testmd4.c b/test/testmd4.c new file mode 100644 index 00000000000..53a336149e6 --- /dev/null +++ b/test/testmd4.c @@ -0,0 +1,119 @@ +/* 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. + */ +/* This is derived from material copyright RSA Data Security, Inc. + * Their notice is reproduced below in its entirety. + * + * Copyright (C) 1990-2, RSA Data Security, Inc. Created 1990. All + * rights reserved. + * + * RSA Data Security, Inc. makes no representations concerning either + * the merchantability of this software or the suitability of this + * software for any particular purpose. It is provided "as is" + * without express or implied warranty of any kind. + * + * These notices must be retained in any copies of any part of this + * documentation and/or software. + */ + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> + +#include "apr_errno.h" +#include "apr_md4.h" +#include "apr_file_io.h" + +#include "abts.h" +#include "testutil.h" + +static struct { + const char *string; + const char *md4sum; +} md4sums[] = +{ +/* +* Taken from the old md4 test suite. +* MD4 ("") = 31d6cfe0d16ae931b73c59d7e0c089c0 +* MD4 ("a") = bde52cb31de33e46245e05fbdbd6fb24 +* MD4 ("abc") = a448017aaf21d8525fc10ae87aa6729d +* MD4 ("message digest") = d9130a8164549fe818874806e1c7014b +* MD4 ("abcdefghijklmnopqrstuvwxyz") = d79e1c308aa5bbcdeea8ed63df412da9 +* MD4 ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") +* MD4 ("12345678901234567890123456789012345678901234567890123456789012345678901234567890") = e33b4ddc9c38f2199c3e7b164fcc0536 +* +*/ + {"", + "\x31\xd6\xcf\xe0\xd1\x6a\xe9\x31\xb7\x3c\x59\xd7\xe0\xc0\x89\xc0"}, + {"a", + "\xbd\xe5\x2c\xb3\x1d\xe3\x3e\x46\x24\x5e\x05\xfb\xdb\xd6\xfb\x24"}, + {"abc", + "\xa4\x48\x01\x7a\xaf\x21\xd8\x52\x5f\xc1\x0a\xe8\x7a\xa6\x72\x9d"}, + {"message digest", + "\xd9\x13\x0a\x81\x64\x54\x9f\xe8\x18\x87\x48\x06\xe1\xc7\x01\x4b"}, + {"abcdefghijklmnopqrstuvwxyz", + "\xd7\x9e\x1c\x30\x8a\xa5\xbb\xcd\xee\xa8\xed\x63\xdf\x41\x2d\xa9"}, + {"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", + "\x04\x3f\x85\x82\xf2\x41\xdb\x35\x1c\xe6\x27\xe1\x53\xe7\xf0\xe4"}, + {"12345678901234567890123456789012345678901234567890123456789012345678901234567890", + "\xe3\x3b\x4d\xdc\x9c\x38\xf2\x19\x9c\x3e\x7b\x16\x4f\xcc\x05\x36"} +}; + +static int num_sums = sizeof(md4sums) / sizeof(md4sums[0]); +static int count; + +#if 0 +static int MDStringComp(const void *string, const void *sum) +{ + apr_md4_ctx_t context; + unsigned char digest[APR_MD4_DIGESTSIZE]; + unsigned int len = strlen(string); + + apr_md4_init(&context); + apr_md4_update(&context, (unsigned char *)string, len); + apr_md4_final(digest, &context); + return (memcmp(digest, sum, APR_MD4_DIGESTSIZE)); + +} +#endif + +static void test_md4sum(abts_case *tc, void *data) +{ + apr_md4_ctx_t context; + unsigned char digest[APR_MD4_DIGESTSIZE]; + const void *string = md4sums[count].string; + const void *sum = md4sums[count].md4sum; + unsigned int len = strlen(string); + + ABTS_ASSERT(tc, "apr_md4_init", (apr_md4_init(&context) == 0)); + ABTS_ASSERT(tc, "apr_md4_update", + (apr_md4_update(&context, + (unsigned char *)string, len) == 0)); + + ABTS_ASSERT(tc, "apr_md4_final", (apr_md4_final(digest, &context) ==0)); + ABTS_ASSERT(tc, "check for correct md4 digest", + (memcmp(digest, sum, APR_MD4_DIGESTSIZE) == 0)); +} + +abts_suite *testmd4(abts_suite *suite) +{ + suite = ADD_SUITE(suite); + + for (count=0; count < num_sums; count++) { + abts_run_test(suite, test_md4sum, NULL); + } + + return suite; +} diff --git a/test/testmd5.c b/test/testmd5.c new file mode 100644 index 00000000000..4e13da2371a --- /dev/null +++ b/test/testmd5.c @@ -0,0 +1,103 @@ +/* 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 <assert.h> +#include <stdio.h> +#include <stdlib.h> + +#include "apr_md5.h" +#include "apr_xlate.h" +#include "apr_general.h" + +#include "abts.h" +#include "testutil.h" + +static struct { + const char *string; + const char *digest; +} md5sums[] = +{ + {"Jeff was here!", + "\xa5\x25\x8a\x89\x11\xb2\x9d\x1f\x81\x75\x96\x3b\x60\x94\x49\xc0"}, + {"01234567890aBcDeFASDFGHJKLPOIUYTR" + "POIUYTREWQZXCVBN LLLLLLLLLLLLLLL", + "\xd4\x1a\x06\x2c\xc5\xfd\x6f\x24\x67\x68\x56\x7c\x40\x8a\xd5\x69"}, + {"111111118888888888888888*******%%%%%%%%%%#####" + "142134u8097289720432098409289nkjlfkjlmn,m.. ", + "\xb6\xea\x5b\xe8\xca\x45\x8a\x33\xf0\xf1\x84\x6f\xf9\x65\xa8\xe1"}, + {"01234567890aBcDeFASDFGHJKLPOIUYTR" + "POIUYTREWQZXCVBN LLLLLLLLLLLLLLL" + "01234567890aBcDeFASDFGHJKLPOIUYTR" + "POIUYTREWQZXCVBN LLLLLLLLLLLLLLL" + "1", + "\xd1\xa1\xc0\x97\x8a\x60\xbb\xfb\x2a\x25\x46\x9d\xa5\xae\xd0\xb0"} +}; + +static int num_sums = sizeof(md5sums) / sizeof(md5sums[0]); +static int count; + +static void test_md5sum(abts_case *tc, void *data) +{ + apr_md5_ctx_t context; + unsigned char digest[APR_MD5_DIGESTSIZE]; + const void *string = md5sums[count].string; + const void *sum = md5sums[count].digest; + unsigned int len = strlen(string); + + ABTS_ASSERT(tc, "apr_md5_init", (apr_md5_init(&context) == 0)); + ABTS_ASSERT(tc, "apr_md5_update", + (apr_md5_update(&context, string, len) == 0)); + ABTS_ASSERT(tc, "apr_md5_final", (apr_md5_final(digest, &context) + == 0)); + ABTS_ASSERT(tc, "check for correct md5 digest", + (memcmp(digest, sum, APR_MD5_DIGESTSIZE) == 0)); +} + +static void test_md5sum_unaligned(abts_case *tc, void *data) +{ + apr_md5_ctx_t context; + const char *string = "abcdefghijklmnopqrstuvwxyz01234" + "abcdefghijklmnopqrstuvwxyz01234" + "abcdefghijklmnopqrstuvwxyz01234" + "abcdefghijklmnopqrstuvwxyz01234_"; + const char *sum = + "\x93\x17\x22\x78\xee\x30\x82\xb3\xeb\x95\x33\xec\xea\x78\xb7\x89"; + unsigned char digest[APR_MD5_DIGESTSIZE]; + unsigned int i; + + ABTS_ASSERT(tc, "apr_md5_init", (apr_md5_init(&context) == 0)); + for (i = 0; i < 10; i++) { + ABTS_ASSERT(tc, "apr_md5_update", + (apr_md5_update(&context, string, strlen(string)) == 0)); + string++; + } + ABTS_ASSERT(tc, "apr_md5_final", (apr_md5_final(digest, &context) + == 0)); + ABTS_ASSERT(tc, "check for correct md5 digest of unaligned data", + (memcmp(digest, sum, APR_MD5_DIGESTSIZE) == 0)); +} + +abts_suite *testmd5(abts_suite *suite) +{ + suite = ADD_SUITE(suite); + + for (count=0; count < num_sums; count++) { + abts_run_test(suite, test_md5sum, NULL); + } + abts_run_test(suite, test_md5sum_unaligned, NULL); + + return suite; +} diff --git a/test/testmemcache.c b/test/testmemcache.c new file mode 100644 index 00000000000..4ac3694dbfc --- /dev/null +++ b/test/testmemcache.c @@ -0,0 +1,627 @@ +/* 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 "testutil.h" +#include "apr.h" +#include "apu.h" +#include "apr_general.h" +#include "apr_strings.h" +#include "apr_hash.h" +#include "apr_memcache.h" +#include "apr_network_io.h" +#include "apr_thread_proc.h" + +#if APR_HAVE_STDLIB_H +#include <stdlib.h> /* for exit() */ +#endif + +#define HOST "localhost" +#define PORT 11211 + +/* the total number of items to use for set/get testing */ +#define TDATA_SIZE 3000 + +/* some smaller subset of TDATA_SIZE used for multiget testing */ +#define TDATA_SET 100 + +/* our custom hash function just returns this all the time */ +#define HASH_FUNC_RESULT 510 + +/* all keys will be prefixed with this */ +const char prefix[] = "testmemcache"; + +/* text for values we store */ +const char txt[] = +"Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Duis at" +"lacus in ligula hendrerit consectetuer. Vestibulum tristique odio" +"iaculis leo. In massa arcu, ultricies a, laoreet nec, hendrerit non," +"neque. Nulla sagittis sapien ac risus. Morbi ligula dolor, vestibulum" +"nec, viverra id, placerat dapibus, arcu. Curabitur egestas feugiat" +"tellus. Donec dignissim. Nunc ante. Curabitur id lorem. In mollis" +"tortor sit amet eros auctor dapibus. Proin nulla sem, tristique in," +"convallis id, iaculis feugiat cras amet."; + +/* + * this datatype is for our custom server determination function. this might + * be useful if you don't want to rely on simply hashing keys to determine + * where a key belongs, but instead want to write something fancy, or use some + * other kind of configuration data, i.e. a hash plus some data about a + * namespace, or whatever. see my_server_func, and test_memcache_user_funcs + * for the examples. + */ +typedef struct { + const char *someval; + apr_uint32_t which_server; +} my_hash_server_baton; + + +/* this could do something fancy and return some hash result. + * for simplicity, just return the same value, so we can test it later on. + * if you wanted to use some external hashing library or functions for + * consistent hashing, for example, this would be a good place to do it. + */ +static apr_uint32_t my_hash_func(void *baton, const char *data, + apr_size_t data_len) +{ + + return HASH_FUNC_RESULT; +} + +/* + * a fancy function to determine which server to use given some kind of data + * and a hash value. this example actually ignores the hash value itself + * and pulls some number from the *baton, which is a struct that has some + * kind of meaningful stuff in it. + */ +static apr_memcache_server_t *my_server_func(void *baton, + apr_memcache_t *mc, + const apr_uint32_t hash) +{ + apr_memcache_server_t *ms = NULL; + my_hash_server_baton *mhsb = (my_hash_server_baton *)baton; + + if(mc->ntotal == 0) { + return NULL; + } + + if(mc->ntotal < mhsb->which_server) { + return NULL; + } + + ms = mc->live_servers[mhsb->which_server - 1]; + + return ms; +} + +apr_uint16_t firsttime = 0; +static int randval(apr_uint32_t high) +{ + apr_uint32_t i = 0; + double d = 0; + + if (firsttime == 0) { + srand((unsigned) (getpid())); + firsttime = 1; + } + + d = (double) rand() / ((double) RAND_MAX + 1); + i = (int) (d * (high - 0 + 1)); + + return i > 0 ? i : 1; +} + +/* + * general test to make sure we can create the memcache struct and add + * some servers, but not more than we tell it we can add + */ + +static void test_memcache_create(abts_case * tc, void *data) +{ + apr_pool_t *pool = p; + apr_status_t rv; + apr_memcache_t *memcache; + apr_memcache_server_t *server, *s; + apr_uint32_t max_servers = 10; + apr_uint32_t i; + apr_uint32_t hash; + + rv = apr_memcache_create(pool, max_servers, 0, &memcache); + ABTS_ASSERT(tc, "memcache create failed", rv == APR_SUCCESS); + + for (i = 1; i <= max_servers; i++) { + apr_port_t port; + + port = PORT + i; + rv = + apr_memcache_server_create(pool, HOST, PORT + i, 0, 1, 1, 60, &server); + ABTS_ASSERT(tc, "server create failed", rv == APR_SUCCESS); + + rv = apr_memcache_add_server(memcache, server); + ABTS_ASSERT(tc, "server add failed", rv == APR_SUCCESS); + + s = apr_memcache_find_server(memcache, HOST, port); + ABTS_PTR_EQUAL(tc, server, s); + + rv = apr_memcache_disable_server(memcache, s); + ABTS_ASSERT(tc, "server disable failed", rv == APR_SUCCESS); + + rv = apr_memcache_enable_server(memcache, s); + ABTS_ASSERT(tc, "server enable failed", rv == APR_SUCCESS); + + hash = apr_memcache_hash(memcache, prefix, strlen(prefix)); + ABTS_ASSERT(tc, "hash failed", hash > 0); + + s = apr_memcache_find_server_hash(memcache, hash); + ABTS_PTR_NOTNULL(tc, s); + } + + rv = apr_memcache_server_create(pool, HOST, PORT, 0, 1, 1, 60, &server); + ABTS_ASSERT(tc, "server create failed", rv == APR_SUCCESS); + + rv = apr_memcache_add_server(memcache, server); + ABTS_ASSERT(tc, "server add should have failed", rv != APR_SUCCESS); + +} + +/* install our own custom hashing and server selection routines. */ + +static int create_test_hash(apr_pool_t *p, apr_hash_t *h) +{ + int i; + + for (i = 0; i < TDATA_SIZE; i++) { + char *k, *v; + + k = apr_pstrcat(p, prefix, apr_itoa(p, i), NULL); + v = apr_pstrndup(p, txt, randval((apr_uint32_t)strlen(txt))); + + apr_hash_set(h, k, APR_HASH_KEY_STRING, v); + } + + return i; +} + +static void test_memcache_user_funcs(abts_case * tc, void *data) +{ + apr_pool_t *pool = p; + apr_status_t rv; + apr_memcache_t *memcache; + apr_memcache_server_t *found; + apr_uint32_t max_servers = 10; + apr_uint32_t hres; + apr_uint32_t i; + my_hash_server_baton *baton = + apr_pcalloc(pool, sizeof(my_hash_server_baton)); + + rv = apr_memcache_create(pool, max_servers, 0, &memcache); + ABTS_ASSERT(tc, "memcache create failed", rv == APR_SUCCESS); + + /* as noted above, install our custom hash function, and call + * apr_memcache_hash. the return value should be our predefined number, + * and our function just ignores the other args, for simplicity. + */ + memcache->hash_func = my_hash_func; + + hres = apr_memcache_hash(memcache, "whatever", sizeof("whatever") - 1); + ABTS_INT_EQUAL(tc, HASH_FUNC_RESULT, hres); + + /* add some servers */ + for(i = 1; i <= 10; i++) { + apr_memcache_server_t *ms; + + rv = apr_memcache_server_create(pool, HOST, i, 0, 1, 1, 60, &ms); + ABTS_ASSERT(tc, "server create failed", rv == APR_SUCCESS); + + rv = apr_memcache_add_server(memcache, ms); + ABTS_ASSERT(tc, "server add failed", rv == APR_SUCCESS); + } + + /* + * set 'which_server' in our server_baton to find the third server + * which should have the same port. + */ + baton->which_server = 3; + memcache->server_func = my_server_func; + memcache->server_baton = baton; + found = apr_memcache_find_server_hash(memcache, 0); + ABTS_ASSERT(tc, "wrong server found", found->port == baton->which_server); +} + +/* test non data related commands like stats and version */ +static void test_memcache_meta(abts_case * tc, void *data) +{ + apr_pool_t *pool = p; + apr_memcache_t *memcache; + apr_memcache_server_t *server; + apr_memcache_stats_t *stats; + char *result; + apr_status_t rv; + + rv = apr_memcache_create(pool, 1, 0, &memcache); + ABTS_ASSERT(tc, "memcache create failed", rv == APR_SUCCESS); + + rv = apr_memcache_server_create(pool, HOST, PORT, 0, 1, 1, 60, &server); + ABTS_ASSERT(tc, "server create failed", rv == APR_SUCCESS); + + rv = apr_memcache_add_server(memcache, server); + ABTS_ASSERT(tc, "server add failed", rv == APR_SUCCESS); + + rv = apr_memcache_version(server, pool, &result); + ABTS_PTR_NOTNULL(tc, result); + + rv = apr_memcache_stats(server, p, &stats); + ABTS_PTR_NOTNULL(tc, stats); + + ABTS_STR_NEQUAL(tc, stats->version, result, 5); + + /* + * no way to know exactly what will be in most of these, so + * just make sure there is something. + */ + + ABTS_ASSERT(tc, "pid", stats->pid >= 0); + ABTS_ASSERT(tc, "time", stats->time >= 0); + /* ABTS_ASSERT(tc, "pointer_size", stats->pointer_size >= 0); */ + ABTS_ASSERT(tc, "rusage_user", stats->rusage_user >= 0); + ABTS_ASSERT(tc, "rusage_system", stats->rusage_system >= 0); + + ABTS_ASSERT(tc, "curr_items", stats->curr_items >= 0); + ABTS_ASSERT(tc, "total_items", stats->total_items >= 0); + ABTS_ASSERT(tc, "bytes", stats->bytes >= 0); + + ABTS_ASSERT(tc, "curr_connections", stats->curr_connections >= 0); + ABTS_ASSERT(tc, "total_connections", stats->total_connections >= 0); + ABTS_ASSERT(tc, "connection_structures", + stats->connection_structures >= 0); + + ABTS_ASSERT(tc, "cmd_get", stats->cmd_get >= 0); + ABTS_ASSERT(tc, "cmd_set", stats->cmd_set >= 0); + ABTS_ASSERT(tc, "get_hits", stats->get_hits >= 0); + ABTS_ASSERT(tc, "get_misses", stats->get_misses >= 0); + + /* ABTS_ASSERT(tc, "evictions", stats->evictions >= 0); */ + + ABTS_ASSERT(tc, "bytes_read", stats->bytes_read >= 0); + ABTS_ASSERT(tc, "bytes_written", stats->bytes_written >= 0); + ABTS_ASSERT(tc, "limit_maxbytes", stats->limit_maxbytes >= 0); + + /* ABTS_ASSERT(tc, "threads", stats->threads >= 0); */ +} + +/* test add and replace calls */ + +static void test_memcache_addreplace(abts_case * tc, void *data) +{ + apr_pool_t *pool = p; + apr_status_t rv; + apr_memcache_t *memcache; + apr_memcache_server_t *server; + apr_hash_t *tdata; + apr_hash_index_t *hi; + char *result; + apr_size_t len; + + rv = apr_memcache_create(pool, 1, 0, &memcache); + ABTS_ASSERT(tc, "memcache create failed", rv == APR_SUCCESS); + + rv = apr_memcache_server_create(pool, HOST, PORT, 0, 1, 1, 60, &server); + ABTS_ASSERT(tc, "server create failed", rv == APR_SUCCESS); + + rv = apr_memcache_add_server(memcache, server); + ABTS_ASSERT(tc, "server add failed", rv == APR_SUCCESS); + + tdata = apr_hash_make(p); + create_test_hash(pool, tdata); + + for (hi = apr_hash_first(p, tdata); hi; hi = apr_hash_next(hi)) { + const void *k; + void *v; + const char *key; + + apr_hash_this(hi, &k, NULL, &v); + key = k; + + /* doesn't exist yet, fail */ + rv = apr_memcache_replace(memcache, key, v, strlen(v) - 1, 0, 27); + ABTS_ASSERT(tc, "replace should have failed", rv != APR_SUCCESS); + + /* doesn't exist yet, succeed */ + rv = apr_memcache_add(memcache, key, v, strlen(v), 0, 27); + ABTS_ASSERT(tc, "add failed", rv == APR_SUCCESS); + + /* exists now, succeed */ + rv = apr_memcache_replace(memcache, key, "new", sizeof("new") - 1, 0, 27); + ABTS_ASSERT(tc, "replace failed", rv == APR_SUCCESS); + + /* make sure its different */ + rv = apr_memcache_getp(memcache, pool, key, &result, &len, NULL); + ABTS_ASSERT(tc, "get failed", rv == APR_SUCCESS); + ABTS_STR_NEQUAL(tc, result, "new", 3); + + /* exists now, fail */ + rv = apr_memcache_add(memcache, key, v, strlen(v), 0, 27); + ABTS_ASSERT(tc, "add should have failed", rv != APR_SUCCESS); + + /* clean up */ + rv = apr_memcache_delete(memcache, key, 0); + ABTS_ASSERT(tc, "delete failed", rv == APR_SUCCESS); + } +} + +/* basic tests of the increment and decrement commands */ +static void test_memcache_incrdecr(abts_case * tc, void *data) +{ + apr_pool_t *pool = p; + apr_status_t rv; + apr_memcache_t *memcache; + apr_memcache_server_t *server; + apr_uint32_t new; + char *result; + apr_size_t len; + apr_uint32_t i; + + rv = apr_memcache_create(pool, 1, 0, &memcache); + ABTS_ASSERT(tc, "memcache create failed", rv == APR_SUCCESS); + + rv = apr_memcache_server_create(pool, HOST, PORT, 0, 1, 1, 60, &server); + ABTS_ASSERT(tc, "server create failed", rv == APR_SUCCESS); + + rv = apr_memcache_add_server(memcache, server); + ABTS_ASSERT(tc, "server add failed", rv == APR_SUCCESS); + + rv = apr_memcache_set(memcache, prefix, "271", sizeof("271") - 1, 0, 27); + ABTS_ASSERT(tc, "set failed", rv == APR_SUCCESS); + + for( i = 1; i <= TDATA_SIZE; i++) { + apr_uint32_t expect; + + rv = apr_memcache_getp(memcache, pool, prefix, &result, &len, NULL); + ABTS_ASSERT(tc, "get failed", rv == APR_SUCCESS); + + expect = i + atoi(result); + + rv = apr_memcache_incr(memcache, prefix, i, &new); + ABTS_ASSERT(tc, "incr failed", rv == APR_SUCCESS); + + ABTS_INT_EQUAL(tc, expect, new); + + rv = apr_memcache_decr(memcache, prefix, i, &new); + ABTS_ASSERT(tc, "decr failed", rv == APR_SUCCESS); + ABTS_INT_EQUAL(tc, atoi(result), new); + + } + + rv = apr_memcache_getp(memcache, pool, prefix, &result, &len, NULL); + ABTS_ASSERT(tc, "get failed", rv == APR_SUCCESS); + + ABTS_INT_EQUAL(tc, 271, atoi(result)); + + rv = apr_memcache_delete(memcache, prefix, 0); + ABTS_ASSERT(tc, "delete failed", rv == APR_SUCCESS); +} + +/* test the multiget functionality */ +static void test_memcache_multiget(abts_case * tc, void *data) +{ + apr_pool_t *pool = p; + apr_pool_t *tmppool; + apr_status_t rv; + apr_memcache_t *memcache; + apr_memcache_server_t *server; + apr_hash_t *tdata, *values; + apr_hash_index_t *hi; + apr_uint32_t i; + + rv = apr_memcache_create(pool, 1, 0, &memcache); + ABTS_ASSERT(tc, "memcache create failed", rv == APR_SUCCESS); + + rv = apr_memcache_server_create(pool, HOST, PORT, 0, 1, 1, 60, &server); + ABTS_ASSERT(tc, "server create failed", rv == APR_SUCCESS); + + rv = apr_memcache_add_server(memcache, server); + ABTS_ASSERT(tc, "server add failed", rv == APR_SUCCESS); + + values = apr_hash_make(p); + tdata = apr_hash_make(p); + + create_test_hash(pool, tdata); + + for (hi = apr_hash_first(p, tdata); hi; hi = apr_hash_next(hi)) { + const void *k; + void *v; + const char *key; + + apr_hash_this(hi, &k, NULL, &v); + key = k; + + rv = apr_memcache_set(memcache, key, v, strlen(v), 0, 27); + ABTS_ASSERT(tc, "set failed", rv == APR_SUCCESS); + } + + rv = apr_pool_create(&tmppool, pool); + for (i = 0; i < TDATA_SET; i++) + apr_memcache_add_multget_key(pool, + apr_pstrcat(pool, prefix, + apr_itoa(pool, i), NULL), + &values); + + rv = apr_memcache_multgetp(memcache, + tmppool, + pool, + values); + + ABTS_ASSERT(tc, "multgetp failed", rv == APR_SUCCESS); + ABTS_ASSERT(tc, "multgetp returned too few results", + apr_hash_count(values) == TDATA_SET); + + for (hi = apr_hash_first(p, tdata); hi; hi = apr_hash_next(hi)) { + const void *k; + const char *key; + + apr_hash_this(hi, &k, NULL, NULL); + key = k; + + rv = apr_memcache_delete(memcache, key, 0); + ABTS_ASSERT(tc, "delete failed", rv == APR_SUCCESS); + } + +} + +/* test setting and getting */ + +static void test_memcache_setget(abts_case * tc, void *data) +{ + apr_pool_t *pool = p; + apr_status_t rv; + apr_memcache_t *memcache; + apr_memcache_server_t *server; + apr_hash_t *tdata; + apr_hash_index_t *hi; + char *result; + apr_size_t len; + + rv = apr_memcache_create(pool, 1, 0, &memcache); + ABTS_ASSERT(tc, "memcache create failed", rv == APR_SUCCESS); + + rv = apr_memcache_server_create(pool, HOST, PORT, 0, 1, 1, 60, &server); + ABTS_ASSERT(tc, "server create failed", rv == APR_SUCCESS); + + rv = apr_memcache_add_server(memcache, server); + ABTS_ASSERT(tc, "server add failed", rv == APR_SUCCESS); + + tdata = apr_hash_make(pool); + + create_test_hash(pool, tdata); + + for (hi = apr_hash_first(p, tdata); hi; hi = apr_hash_next(hi)) { + const void *k; + void *v; + const char *key; + + apr_hash_this(hi, &k, NULL, &v); + key = k; + + rv = apr_memcache_set(memcache, key, v, strlen(v), 0, 27); + ABTS_ASSERT(tc, "set failed", rv == APR_SUCCESS); + rv = apr_memcache_getp(memcache, pool, key, &result, &len, NULL); + ABTS_ASSERT(tc, "get failed", rv == APR_SUCCESS); + } + + rv = apr_memcache_getp(memcache, pool, "nothere3423", &result, &len, NULL); + + ABTS_ASSERT(tc, "get should have failed", rv != APR_SUCCESS); + + for (hi = apr_hash_first(p, tdata); hi; hi = apr_hash_next(hi)) { + const void *k; + const char *key; + + apr_hash_this(hi, &k, NULL, NULL); + key = k; + + rv = apr_memcache_delete(memcache, key, 0); + ABTS_ASSERT(tc, "delete failed", rv == APR_SUCCESS); + } +} + +/* use apr_socket stuff to see if there is in fact a memcached server + * running on PORT. + */ +static apr_status_t check_mc(void) +{ + apr_pool_t *pool = p; + apr_status_t rv; + apr_socket_t *sock = NULL; + apr_sockaddr_t *sa; + struct iovec vec[2]; + apr_size_t written; + char buf[128]; + apr_size_t len; + + rv = apr_socket_create(&sock, APR_INET, SOCK_STREAM, 0, pool); + if(rv != APR_SUCCESS) { + return rv; + } + + rv = apr_sockaddr_info_get(&sa, HOST, APR_INET, PORT, 0, pool); + if(rv != APR_SUCCESS) { + return rv; + } + + rv = apr_socket_timeout_set(sock, 1 * APR_USEC_PER_SEC); + if (rv != APR_SUCCESS) { + return rv; + } + + rv = apr_socket_connect(sock, sa); + if (rv != APR_SUCCESS) { + return rv; + } + + rv = apr_socket_timeout_set(sock, -1); + if (rv != APR_SUCCESS) { + return rv; + } + + vec[0].iov_base = "version"; + vec[0].iov_len = sizeof("version") - 1; + + vec[1].iov_base = "\r\n"; + vec[1].iov_len = sizeof("\r\n") -1; + + rv = apr_socket_sendv(sock, vec, 2, &written); + if (rv != APR_SUCCESS) { + return rv; + } + + len = sizeof(buf); + rv = apr_socket_recv(sock, buf, &len); + if(rv != APR_SUCCESS) { + return rv; + } + + if(strncmp(buf, "VERSION", sizeof("VERSION")-1) != 0) { + rv = APR_EGENERAL; + } + + apr_socket_close(sock); + return rv; +} + +abts_suite *testmemcache(abts_suite * suite) +{ + apr_status_t rv; + suite = ADD_SUITE(suite); + /* check for a running memcached on the typical port before + * trying to run the tests. succeed if we don't find one. + */ + rv = check_mc(); + if (rv == APR_SUCCESS) { + abts_run_test(suite, test_memcache_create, NULL); + abts_run_test(suite, test_memcache_user_funcs, NULL); + abts_run_test(suite, test_memcache_meta, NULL); + abts_run_test(suite, test_memcache_setget, NULL); + abts_run_test(suite, test_memcache_multiget, NULL); + abts_run_test(suite, test_memcache_addreplace, NULL); + abts_run_test(suite, test_memcache_incrdecr, NULL); + } + else { + abts_log_message("Error %d occurred attempting to reach memcached " + "on %s:%d. Skipping apr_memcache tests...", + rv, HOST, PORT); + } + + return suite; +} diff --git a/test/testmmap.c b/test/testmmap.c index 3f58ec3c6f6..aeff1a66a1f 100644 --- a/test/testmmap.c +++ b/test/testmmap.c @@ -1,135 +1,166 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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 <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> +#include "testutil.h" #include "apr_mmap.h" #include "apr_errno.h" #include "apr_general.h" #include "apr_lib.h" #include "apr_file_io.h" +#include "apr_strings.h" /* hmmm, what is a truly portable define for the max path * length on a platform? */ #define PATH_LEN 255 -int main() +#if !APR_HAS_MMAP +static void not_implemented(abts_case *tc, void *data) +{ + ABTS_NOT_IMPL(tc, "MMAP functions"); +} + +#else + +static char test_string[256]; /* read from the datafile */ +static apr_mmap_t *themmap = NULL; +static apr_file_t *thefile = NULL; +static char *file1; +static apr_finfo_t thisfinfo; +static apr_size_t thisfsize; + +static void create_filename(abts_case *tc, void *data) +{ + char *oldfileptr; + + apr_filepath_get(&file1, 0, p); +#ifndef NETWARE +#ifdef WIN32 + ABTS_TRUE(tc, file1[1] == ':'); +#else + ABTS_TRUE(tc, file1[0] == '/'); +#endif +#endif + ABTS_TRUE(tc, file1[strlen(file1) - 1] != '/'); + + oldfileptr = file1; + file1 = apr_pstrcat(p, file1,"/data/mmap_datafile.txt" ,NULL); + ABTS_TRUE(tc, oldfileptr != file1); +} + +static void test_file_close(abts_case *tc, void *data) +{ + apr_status_t rv; + + rv = apr_file_close(thefile); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); +} + +static void read_expected_contents(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_size_t nbytes = sizeof(test_string) - 1; + + rv = apr_file_read(thefile, test_string, &nbytes); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + test_string[nbytes] = '\0'; + thisfsize = strlen(test_string); +} + +static void test_file_open(abts_case *tc, void *data) +{ + apr_status_t rv; + + rv = apr_file_open(&thefile, file1, APR_FOPEN_READ, + APR_FPROT_UREAD | APR_FPROT_GREAD, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_PTR_NOTNULL(tc, thefile); +} + +static void test_get_filesize(abts_case *tc, void *data) +{ + apr_status_t rv; + + rv = apr_file_info_get(&thisfinfo, APR_FINFO_NORM, thefile); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_ASSERT(tc, "File size mismatch", thisfsize == thisfinfo.size); +} + +static void test_mmap_create(abts_case *tc, void *data) +{ + apr_status_t rv; + + rv = apr_mmap_create(&themmap, thefile, 0, (apr_size_t) thisfinfo.size, + APR_MMAP_READ, p); + ABTS_PTR_NOTNULL(tc, themmap); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); +} + +static void test_mmap_contents(abts_case *tc, void *data) { - ap_pool_t *context; - ap_mmap_t *themmap = NULL; - ap_file_t *thefile = NULL; - ap_finfo_t finfo; - ap_int32_t flag = APR_READ; - char *file1; - - fprintf (stdout,"APR MMAP Test\n*************\n\n"); - - fprintf(stdout,"Initializing........................"); - if (ap_initialize() != APR_SUCCESS) { - fprintf(stderr, "Failed.\n"); - exit(-1); - } - fprintf(stdout,"OK\n"); - atexit(ap_terminate); - - fprintf(stdout,"Creating context...................."); - if (ap_create_pool(&context, NULL) != APR_SUCCESS) { - fprintf(stderr, "Failed.\n"); - exit(-1); - } - fprintf(stdout,"OK\n"); - - file1 = (char*) ap_palloc(context, sizeof(char) * PATH_LEN); - getcwd(file1, PATH_LEN); - strncat(file1,"/testmmap.c",11); - - fprintf(stdout, "Opening file........................"); - if (ap_open(&thefile, file1, flag, APR_UREAD | APR_GREAD, context) != APR_SUCCESS) { - perror("Didn't open file"); - exit(-1); - } - else { - fprintf(stdout, "OK\n"); - } - - fprintf(stderr, "Getting file size..................."); - if (ap_getfileinfo(&finfo, thefile) != APR_SUCCESS) { - perror("Didn't get file information!"); - exit(-1); - } - else { - fprintf(stdout, "%d bytes\n", (int)finfo.size); - } - - fprintf(stdout,"Trying to mmap the file............."); - if (ap_mmap_create(&themmap, thefile, 0, finfo.size, context) != APR_SUCCESS) { - fprintf(stderr,"Failed!\n"); - exit(-1); - } - fprintf(stdout,"OK\n"); - - fprintf(stdout,"Trying to delete the mmap file......"); - if (ap_mmap_delete(themmap) != APR_SUCCESS) { - fprintf(stderr,"Failed!\n"); - exit (-1); - } - fprintf(stdout,"OK\n"); - fprintf (stdout,"\nTest Complete\n"); + ABTS_PTR_NOTNULL(tc, themmap); + ABTS_PTR_NOTNULL(tc, themmap->mm); + ABTS_SIZE_EQUAL(tc, thisfsize, themmap->size); - return 1; + /* Must use nEquals since the string is not guaranteed to be NULL terminated */ + ABTS_STR_NEQUAL(tc, themmap->mm, test_string, thisfsize); } + +static void test_mmap_delete(abts_case *tc, void *data) +{ + apr_status_t rv; + + ABTS_PTR_NOTNULL(tc, themmap); + rv = apr_mmap_delete(themmap); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); +} + +static void test_mmap_offset(abts_case *tc, void *data) +{ + apr_status_t rv; + void *addr; + + ABTS_PTR_NOTNULL(tc, themmap); + rv = apr_mmap_offset(&addr, themmap, 5); + + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + /* Must use nEquals since the string is not guaranteed to be NULL terminated */ + ABTS_STR_NEQUAL(tc, addr, test_string + 5, thisfsize-5); +} +#endif + +abts_suite *testmmap(abts_suite *suite) +{ + suite = ADD_SUITE(suite) + +#if APR_HAS_MMAP + abts_run_test(suite, create_filename, NULL); + abts_run_test(suite, test_file_open, NULL); + abts_run_test(suite, read_expected_contents, NULL); + abts_run_test(suite, test_get_filesize, NULL); + abts_run_test(suite, test_mmap_create, NULL); + abts_run_test(suite, test_mmap_contents, NULL); + abts_run_test(suite, test_mmap_offset, NULL); + abts_run_test(suite, test_mmap_delete, NULL); + abts_run_test(suite, test_file_close, NULL); +#else + abts_run_test(suite, not_implemented, NULL); +#endif + + return suite; +} + diff --git a/test/testmutexscope.c b/test/testmutexscope.c new file mode 100644 index 00000000000..2120fff24f5 --- /dev/null +++ b/test/testmutexscope.c @@ -0,0 +1,234 @@ +/* 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. + */ + +/* This program won't run or check correctly if assert() is disabled. */ +#undef NDEBUG +#include <assert.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> + +#include "apr.h" +#include "apr_general.h" +#include "apr_proc_mutex.h" +#include "apr_global_mutex.h" +#include "apr_thread_proc.h" + +#if !APR_HAS_THREADS +int main(void) +{ + printf("This test requires APR thread support.\n"); + return 0; +} + +#else /* APR_HAS_THREADS */ + +static apr_thread_mutex_t *thread_mutex; +static apr_proc_mutex_t *proc_mutex; +static apr_global_mutex_t *global_mutex; +static apr_pool_t *p; +static volatile int counter; +typedef enum {TEST_GLOBAL, TEST_PROC} test_mode_e; + +static int lock_init(apr_lockmech_e mech, test_mode_e test_mode) +{ + apr_status_t rv; + if (test_mode == TEST_PROC) { + rv = apr_proc_mutex_create(&proc_mutex, + NULL, + mech, + p); + } + else { + rv = apr_global_mutex_create(&global_mutex, + NULL, + mech, + p); + } + return rv; +} + +static void lock_destroy(test_mode_e test_mode) +{ + if (test_mode == TEST_PROC) { + assert(apr_proc_mutex_destroy(proc_mutex) == APR_SUCCESS); + } + else { + assert(apr_global_mutex_destroy(global_mutex) == APR_SUCCESS); + } +} + +static void lock_grab(test_mode_e test_mode) +{ + if (test_mode == TEST_PROC) { + assert(apr_proc_mutex_lock(proc_mutex) == APR_SUCCESS); + } + else { + assert(apr_global_mutex_lock(global_mutex) == APR_SUCCESS); + } +} + +static void lock_release(test_mode_e test_mode) +{ + if (test_mode == TEST_PROC) { + assert(apr_proc_mutex_unlock(proc_mutex) == APR_SUCCESS); + } + else { + assert(apr_global_mutex_unlock(global_mutex) == APR_SUCCESS); + } +} + +static void * APR_THREAD_FUNC eachThread(apr_thread_t *id, void *p) +{ + test_mode_e test_mode = (test_mode_e)p; + + lock_grab(test_mode); + ++counter; + assert(apr_thread_mutex_lock(thread_mutex) == APR_SUCCESS); + assert(apr_thread_mutex_unlock(thread_mutex) == APR_SUCCESS); + lock_release(test_mode); + apr_thread_exit(id, 0); + return NULL; +} + +static void test_mech_mode(apr_lockmech_e mech, const char *mech_name, + test_mode_e test_mode) +{ + apr_thread_t *threads[20]; + int numThreads = 5; + int i; + apr_status_t rv; + + printf("Trying %s mutexes with mechanism `%s'...\n", + test_mode == TEST_GLOBAL ? "global" : "proc", mech_name); + + assert(numThreads <= sizeof(threads) / sizeof(threads[0])); + + assert(apr_pool_create(&p, NULL) == APR_SUCCESS); + + assert(apr_thread_mutex_create(&thread_mutex, 0, p) == APR_SUCCESS); + assert(apr_thread_mutex_lock(thread_mutex) == APR_SUCCESS); + + rv = lock_init(mech, test_mode); + if (rv != APR_SUCCESS) { + char errmsg[256]; + printf("%s mutexes with mechanism `%s': %s\n", + test_mode == TEST_GLOBAL ? "Global" : "Proc", mech_name, + apr_strerror(rv, errmsg, sizeof errmsg)); + if (rv != APR_ENOTIMPL || mech == APR_LOCK_DEFAULT) { + exit(1); + } + return; + } + + counter = 0; + + i = 0; + while (i < numThreads) + { + rv = apr_thread_create(&threads[i], + NULL, + eachThread, + (void *)test_mode, + p); + if (rv != APR_SUCCESS) { + fprintf(stderr, "apr_thread_create->%d\n", rv); + exit(1); + } + ++i; + } + + apr_sleep(apr_time_from_sec(5)); + + if (test_mode == TEST_PROC) { + printf(" mutex mechanism `%s' is %sglobal in scope on this platform.\n", + mech_name, counter == 1 ? "" : "*NOT* "); + } + else { + if (counter != 1) { + fprintf(stderr, "\n!!!apr_global_mutex operations are broken on this " + "platform for mutex mechanism `%s'!\n" + "They don't block out threads within the same process.\n", + mech_name); + fprintf(stderr, "counter value: %d\n", counter); + exit(1); + } + else { + printf(" no problem encountered...\n"); + } + } + + assert(apr_thread_mutex_unlock(thread_mutex) == APR_SUCCESS); + + i = 0; + while (i < numThreads) + { + apr_status_t ignored; + + rv = apr_thread_join(&ignored, + threads[i]); + assert(rv == APR_SUCCESS); + ++i; + } + + lock_destroy(test_mode); + apr_thread_mutex_destroy(thread_mutex); + apr_pool_destroy(p); +} + +static void test_mech(apr_lockmech_e mech, const char *mech_name) +{ + test_mech_mode(mech, mech_name, TEST_PROC); + test_mech_mode(mech, mech_name, TEST_GLOBAL); +} + +int main(void) +{ + struct { + apr_lockmech_e mech; + const char *mech_name; + } lockmechs[] = { + {APR_LOCK_DEFAULT, "default"} +#if APR_HAS_FLOCK_SERIALIZE + ,{APR_LOCK_FLOCK, "flock"} +#endif +#if APR_HAS_SYSVSEM_SERIALIZE + ,{APR_LOCK_SYSVSEM, "sysvsem"} +#endif +#if APR_HAS_POSIXSEM_SERIALIZE + ,{APR_LOCK_POSIXSEM, "posix"} +#endif +#if APR_HAS_FCNTL_SERIALIZE + ,{APR_LOCK_FCNTL, "fcntl"} +#endif +#if APR_HAS_PROC_PTHREAD_SERIALIZE + ,{APR_LOCK_PROC_PTHREAD, "proc_pthread"} +#endif + ,{APR_LOCK_DEFAULT_TIMED, "default_timed"} + }; + int i; + + assert(apr_initialize() == APR_SUCCESS); + + for (i = 0; i < sizeof(lockmechs) / sizeof(lockmechs[0]); i++) { + test_mech(lockmechs[i].mech, lockmechs[i].mech_name); + } + + apr_terminate(); + return 0; +} + +#endif /* APR_HAS_THREADS */ diff --git a/test/testnames.c b/test/testnames.c new file mode 100644 index 00000000000..4fcd3c033f5 --- /dev/null +++ b/test/testnames.c @@ -0,0 +1,387 @@ +/* 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 "testutil.h" +#include "apr_file_io.h" +#include "apr_file_info.h" +#include "apr_errno.h" +#include "apr_general.h" +#include "apr_pools.h" +#include "apr_lib.h" +#include "apr_strings.h" + +#if defined(WIN32) +#include <direct.h> +#endif + +#if defined(WIN32) || defined(OS2) +#define ABS_ROOT "C:/" +#elif defined(NETWARE) +#define ABS_ROOT "SYS:/" +#else +#define ABS_ROOT "/" +#endif + +static void merge_aboveroot(abts_case *tc, void *data) +{ + apr_status_t rv; + char *dstpath = NULL; + char errmsg[256]; + + rv = apr_filepath_merge(&dstpath, ABS_ROOT"foo", ABS_ROOT"bar", APR_FILEPATH_NOTABOVEROOT, + p); + apr_strerror(rv, errmsg, sizeof(errmsg)); + ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_EABOVEROOT(rv)); + ABTS_PTR_EQUAL(tc, NULL, dstpath); + ABTS_STR_EQUAL(tc, "The given path was above the root path", errmsg); +} + +static void merge_belowroot(abts_case *tc, void *data) +{ + apr_status_t rv; + char *dstpath = NULL; + + rv = apr_filepath_merge(&dstpath, ABS_ROOT"foo", ABS_ROOT"foo/bar", + APR_FILEPATH_NOTABOVEROOT, p); + ABTS_PTR_NOTNULL(tc, dstpath); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_STR_EQUAL(tc, ABS_ROOT"foo/bar", dstpath); +} + +static void merge_noflag(abts_case *tc, void *data) +{ + apr_status_t rv; + char *dstpath = NULL; + + rv = apr_filepath_merge(&dstpath, ABS_ROOT"foo", ABS_ROOT"foo/bar", 0, p); + ABTS_PTR_NOTNULL(tc, dstpath); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_STR_EQUAL(tc, ABS_ROOT"foo/bar", dstpath); +} + +static void merge_dotdot(abts_case *tc, void *data) +{ + apr_status_t rv; + char *dstpath = NULL; + + rv = apr_filepath_merge(&dstpath, ABS_ROOT"foo/bar", "../baz", 0, p); + ABTS_PTR_NOTNULL(tc, dstpath); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_STR_EQUAL(tc, ABS_ROOT"foo/baz", dstpath); + + rv = apr_filepath_merge(&dstpath, "", "../test", 0, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_STR_EQUAL(tc, "../test", dstpath); + + /* Very dangerous assumptions here about what the cwd is. However, let's assume + * that the testall is invoked from within apr/test/ so the following test should + * return ../test unless a previously fixed bug remains or the developer changes + * the case of the test directory: + */ + rv = apr_filepath_merge(&dstpath, "", "../test", APR_FILEPATH_TRUENAME, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_STR_EQUAL(tc, "../test", dstpath); +} + +static void merge_dotdot_dotdot_dotdot(abts_case *tc, void *data) +{ + apr_status_t rv; + char *dstpath = NULL; + + rv = apr_filepath_merge(&dstpath, "", + "../../..", APR_FILEPATH_TRUENAME, p); + ABTS_PTR_NOTNULL(tc, dstpath); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_STR_EQUAL(tc, "../../..", dstpath); + + rv = apr_filepath_merge(&dstpath, "", + "../../../", APR_FILEPATH_TRUENAME, p); + ABTS_PTR_NOTNULL(tc, dstpath); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_STR_EQUAL(tc, "../../../", dstpath); +} + +static void merge_secure(abts_case *tc, void *data) +{ + apr_status_t rv; + char *dstpath = NULL; + + rv = apr_filepath_merge(&dstpath, ABS_ROOT"foo/bar", "../bar/baz", 0, p); + ABTS_PTR_NOTNULL(tc, dstpath); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_STR_EQUAL(tc, ABS_ROOT"foo/bar/baz", dstpath); +} + +static void merge_notrel(abts_case *tc, void *data) +{ + apr_status_t rv; + char *dstpath = NULL; + + rv = apr_filepath_merge(&dstpath, ABS_ROOT"foo/bar", "../baz", + APR_FILEPATH_NOTRELATIVE, p); + ABTS_PTR_NOTNULL(tc, dstpath); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_STR_EQUAL(tc, ABS_ROOT"foo/baz", dstpath); +} + +static void merge_notrelfail(abts_case *tc, void *data) +{ + apr_status_t rv; + char *dstpath = NULL; + char errmsg[256]; + + rv = apr_filepath_merge(&dstpath, "foo/bar", "../baz", + APR_FILEPATH_NOTRELATIVE, p); + apr_strerror(rv, errmsg, sizeof(errmsg)); + + ABTS_PTR_EQUAL(tc, NULL, dstpath); + ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_ERELATIVE(rv)); + ABTS_STR_EQUAL(tc, "The given path is relative", errmsg); +} + +static void merge_notabsfail(abts_case *tc, void *data) +{ + apr_status_t rv; + char *dstpath = NULL; + char errmsg[256]; + + rv = apr_filepath_merge(&dstpath, ABS_ROOT"foo/bar", "../baz", + APR_FILEPATH_NOTABSOLUTE, p); + apr_strerror(rv, errmsg, sizeof(errmsg)); + + ABTS_PTR_EQUAL(tc, NULL, dstpath); + ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_EABSOLUTE(rv)); + ABTS_STR_EQUAL(tc, "The given path is absolute", errmsg); +} + +static void merge_notabs(abts_case *tc, void *data) +{ + apr_status_t rv; + char *dstpath = NULL; + + rv = apr_filepath_merge(&dstpath, "foo/bar", "../baz", + APR_FILEPATH_NOTABSOLUTE, p); + + ABTS_PTR_NOTNULL(tc, dstpath); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_STR_EQUAL(tc, "foo/baz", dstpath); +} + +#if defined (WIN32) +static void merge_lowercasedrive(abts_case *tc, void *data) +{ + char current_dir[1024]; + char current_dir_on_C[1024]; + char *dir_on_c; + char *testdir; + apr_status_t rv; + + /* Change the current directory on C: from something like "C:\dir" + to something like "c:\dir" to replicate the failing case. */ + ABTS_PTR_NOTNULL(tc, _getcwd(current_dir, sizeof(current_dir))); + + /* 3 stands for drive C: */ + ABTS_PTR_NOTNULL(tc, _getdcwd(3, current_dir_on_C, + sizeof(current_dir_on_C))); + + /* Use the same path, but now with a lower case driveletter */ + dir_on_c = apr_pstrdup(p, current_dir_on_C); + dir_on_c[0] = (char)tolower(dir_on_c[0]); + + chdir(dir_on_c); + + /* Now merge a drive relative path with an upper case drive letter. */ + rv = apr_filepath_merge(&testdir, NULL, "C:hi", + APR_FILEPATH_NOTRELATIVE, p); + + /* Change back to original directory for next tests */ + chdir("C:\\"); /* Switch to upper case */ + chdir(current_dir_on_C); /* Switch cwd on C: */ + chdir(current_dir); /* Switch back to original cwd */ + + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); +} + +static void merge_shortname(abts_case *tc, void *data) +{ + apr_status_t rv; + char *long_path; + char short_path[MAX_PATH+1]; + DWORD short_len; + char *result_path; + + /* 'A b.c' is not a valid short path, so will have multiple representations + when short path name generation is enabled... but its 'short' path will + most likely be longer than the long path */ + rv = apr_dir_make_recursive("C:/data/short/A b.c", + APR_UREAD | APR_UWRITE | APR_UEXECUTE, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + rv = apr_filepath_merge(&long_path, NULL, "C:/data/short/A b.c", + APR_FILEPATH_NOTRELATIVE, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + short_len = GetShortPathName(long_path, short_path, sizeof(short_path)); + if (short_len > MAX_PATH) + return; /* Unable to test. Impossible shortname */ + + if (! strcmp(long_path, short_path)) + return; /* Unable to test. 8dot3name option is probably not enabled */ + + rv = apr_filepath_merge(&result_path, "", short_path, APR_FILEPATH_TRUENAME, + p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + ABTS_STR_EQUAL(tc, long_path, result_path); +} +#endif + +static void root_absolute(abts_case *tc, void *data) +{ + apr_status_t rv; + const char *root = NULL; + const char *path = ABS_ROOT"foo/bar"; + + rv = apr_filepath_root(&root, &path, 0, p); + + ABTS_PTR_NOTNULL(tc, root); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_STR_EQUAL(tc, ABS_ROOT, root); +} + +static void root_relative(abts_case *tc, void *data) +{ + apr_status_t rv; + const char *root = NULL; + const char *path = "foo/bar"; + char errmsg[256]; + + rv = apr_filepath_root(&root, &path, 0, p); + apr_strerror(rv, errmsg, sizeof(errmsg)); + + ABTS_PTR_EQUAL(tc, NULL, root); + ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_ERELATIVE(rv)); + ABTS_STR_EQUAL(tc, "The given path is relative", errmsg); +} + +static void root_from_slash(abts_case *tc, void *data) +{ + apr_status_t rv; + const char *root = NULL; + const char *path = "//"; + + rv = apr_filepath_root(&root, &path, APR_FILEPATH_TRUENAME, p); + +#if defined(WIN32) || defined(OS2) + ABTS_INT_EQUAL(tc, APR_EINCOMPLETE, rv); + ABTS_STR_EQUAL(tc, "//", root); +#else + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_STR_EQUAL(tc, "/", root); +#endif + ABTS_STR_EQUAL(tc, "", path); +} + +static void root_from_cwd_and_back(abts_case *tc, void *data) +{ + apr_status_t rv; + const char *root = NULL; + const char *path = "//"; + char *origpath; + char *testpath; +#if defined(WIN32) || defined(OS2) || defined(NETWARE) + int hadfailed; +#endif + + ABTS_INT_EQUAL(tc, APR_SUCCESS, apr_filepath_get(&origpath, 0, p)); + path = origpath; + rv = apr_filepath_root(&root, &path, APR_FILEPATH_TRUENAME, p); + +#if defined(WIN32) || defined(OS2) + hadfailed = tc->failed; + /* It appears some mingw/cygwin and more modern builds can return + * a lowercase drive designation, but we canonicalize to uppercase + */ + ABTS_INT_EQUAL(tc, toupper(origpath[0]), root[0]); + ABTS_INT_EQUAL(tc, ':', root[1]); + ABTS_INT_EQUAL(tc, '/', root[2]); + ABTS_INT_EQUAL(tc, 0, root[3]); + ABTS_STR_EQUAL(tc, origpath + 3, path); +#elif defined(NETWARE) + ABTS_INT_EQUAL(tc, origpath[0], root[0]); + { + char *pt = strchr(root, ':'); + ABTS_PTR_NOTNULL(tc, pt); + ABTS_INT_EQUAL(tc, ':', pt[0]); + ABTS_INT_EQUAL(tc, '/', pt[1]); + ABTS_INT_EQUAL(tc, 0, pt[2]); + pt = strchr(origpath, ':'); + ABTS_PTR_NOTNULL(tc, pt); + ABTS_STR_EQUAL(tc, (pt+2), path); + } +#else + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_STR_EQUAL(tc, "/", root); + ABTS_STR_EQUAL(tc, origpath + 1, path); +#endif + + rv = apr_filepath_merge(&testpath, root, path, + APR_FILEPATH_TRUENAME + | APR_FILEPATH_NOTABOVEROOT + | APR_FILEPATH_NOTRELATIVE, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); +#if defined(WIN32) || defined(OS2) || defined(NETWARE) + hadfailed = tc->failed; +#endif + /* The API doesn't promise equality!!! + * apr_filepath_get never promised a canonical filepath. + * We'll emit noise under verbose so the user is aware, + * but translate this back to success. + */ + ABTS_STR_EQUAL(tc, origpath, testpath); +#if defined(WIN32) || defined(OS2) || defined(NETWARE) + if (!hadfailed) tc->failed = 0; +#endif +} + + +abts_suite *testnames(abts_suite *suite) +{ + suite = ADD_SUITE(suite) + + abts_run_test(suite, merge_aboveroot, NULL); + abts_run_test(suite, merge_belowroot, NULL); + abts_run_test(suite, merge_noflag, NULL); + abts_run_test(suite, merge_dotdot, NULL); + abts_run_test(suite, merge_secure, NULL); + abts_run_test(suite, merge_notrel, NULL); + abts_run_test(suite, merge_notrelfail, NULL); + abts_run_test(suite, merge_notabs, NULL); + abts_run_test(suite, merge_notabsfail, NULL); + abts_run_test(suite, merge_dotdot_dotdot_dotdot, NULL); +#if defined(WIN32) + abts_run_test(suite, merge_lowercasedrive, NULL); + abts_run_test(suite, merge_shortname, NULL); +#endif + + abts_run_test(suite, root_absolute, NULL); + abts_run_test(suite, root_relative, NULL); + abts_run_test(suite, root_from_slash, NULL); + abts_run_test(suite, root_from_cwd_and_back, NULL); + + return suite; +} + diff --git a/test/testoc.c b/test/testoc.c index dbdd26efe54..923bd4b6df6 100644 --- a/test/testoc.c +++ b/test/testoc.c @@ -1,149 +1,120 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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 "testutil.h" #include "apr_thread_proc.h" #include "apr_errno.h" #include "apr_general.h" #include "apr_lib.h" -#include "errno.h" -#include <stdio.h> -#include <stdlib.h> -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif +#include "apr_strings.h" + +#if APR_HAS_OTHER_CHILD + +static char reasonstr[256]; -void ocmaint(int reason, void *data, int status) +static void ocmaint(int reason, void *data, int status) { - fprintf(stdout,"[CHILD] Maintenance routine called...."); - fflush(stdout); switch (reason) { case APR_OC_REASON_DEATH: - fprintf(stdout, "Died correctly\n"); + apr_cpystrn(reasonstr, "APR_OC_REASON_DEATH", + strlen("APR_OC_REASON_DEATH") + 1); break; case APR_OC_REASON_LOST: - fprintf(stdout, "APR_OC_REASON_LOST\n"); + apr_cpystrn(reasonstr, "APR_OC_REASON_LOST", + strlen("APR_OC_REASON_LOST") + 1); + break; case APR_OC_REASON_UNWRITABLE: - fprintf(stdout, "APR_OC_REASON_UNWRITEABLE\n"); + apr_cpystrn(reasonstr, "APR_OC_REASON_UNWRITEABLE", + strlen("APR_OC_REASON_UNWRITEABLE") + 1); + break; case APR_OC_REASON_RESTART: - fprintf(stdout, "APR_OC_REASON_RESTART\n"); - fprintf(stdout, "OC maintentance called for reason other than death\n"); + apr_cpystrn(reasonstr, "APR_OC_REASON_RESTART", + strlen("APR_OC_REASON_RESTART") + 1); break; } } -int main(int argc, char *argv[]) +#ifndef SIGKILL +#define SIGKILL 1 +#endif + +/* It would be great if we could stress this stuff more, and make the test + * more granular. + */ +static void test_child_kill(abts_case *tc, void *data) { - ap_pool_t *context; - ap_pool_t *cont2; - ap_status_t status = 0; - ap_ssize_t nbytes = 0; - ap_proc_t *newproc = NULL; - ap_procattr_t *procattr = NULL; - char *args[3]; - - if (argc > 1) { - while (1); - } + apr_file_t *std = NULL; + apr_proc_t newproc; + apr_procattr_t *procattr = NULL; + const char *args[3]; + apr_status_t rv; - if (ap_initialize() != APR_SUCCESS) { - fprintf(stderr, "Couldn't initialize."); - exit(-1); - } - atexit(ap_terminate); - if (ap_create_pool(&context, NULL) != APR_SUCCESS) { - fprintf(stderr, "Couldn't allocate context."); - exit(-1); - } - - args[0] = ap_pstrdup(context, "testoc"); - args[1] = ap_pstrdup(context, "-X"); + args[0] = apr_pstrdup(p, "occhild" EXTENSION); + args[1] = apr_pstrdup(p, "-X"); args[2] = NULL; - fprintf(stdout, "[PARENT] Creating procattr............."); - fflush(stdout); - if (ap_createprocattr_init(&procattr, context) != APR_SUCCESS) { - fprintf(stderr, "Could not create attr\n"); - exit(-1);; - } - fprintf(stdout, "OK\n"); - - fprintf(stdout, "[PARENT] Starting other child.........."); - fflush(stdout); - if (ap_create_process(&newproc, "../testoc", args, NULL, procattr, context) - != APR_SUCCESS) { - fprintf(stderr, "error starting other child\n"); - exit(-1); - } - fprintf(stdout, "OK\n"); + rv = apr_procattr_create(&procattr, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + rv = apr_procattr_io_set(procattr, APR_FULL_BLOCK, APR_NO_PIPE, + APR_NO_PIPE); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); - ap_register_other_child(newproc, ocmaint, NULL, -1, context); + rv = apr_procattr_cmdtype_set(procattr, APR_PROGRAM_ENV); + APR_ASSERT_SUCCESS(tc, "Couldn't set copy environment", rv); - fprintf(stdout, "[PARENT] Sending SIGKILL to child......"); - fflush(stdout); - if (ap_kill(newproc, SIGKILL) != APR_SUCCESS) { - fprintf(stderr,"couldn't send the signal!\n"); - exit(-1); - } - fprintf(stdout,"OK\n"); + rv = apr_proc_create(&newproc, TESTBINPATH "occhild" EXTENSION, args, NULL, procattr, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_PTR_NOTNULL(tc, newproc.in); + ABTS_PTR_EQUAL(tc, NULL, newproc.out); + ABTS_PTR_EQUAL(tc, NULL, newproc.err); + + std = newproc.in; + + apr_proc_other_child_register(&newproc, ocmaint, NULL, std, p); + + apr_sleep(apr_time_from_sec(1)); + rv = apr_proc_kill(&newproc, SIGKILL); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); /* allow time for things to settle... */ - sleep(1); - - fprintf(stdout, "[PARENT] Checking on children..........\n"); - ap_check_other_child(); + apr_sleep(apr_time_from_sec(3)); - return 1; + apr_proc_other_child_refresh_all(APR_OC_REASON_RUNNING); + ABTS_STR_EQUAL(tc, "APR_OC_REASON_DEATH", reasonstr); } +#else + +static void oc_not_impl(abts_case *tc, void *data) +{ + ABTS_NOT_IMPL(tc, "Other child logic not implemented on this platform"); +} +#endif + +abts_suite *testoc(abts_suite *suite) +{ + suite = ADD_SUITE(suite) + +#if !APR_HAS_OTHER_CHILD + abts_run_test(suite, oc_not_impl, NULL); +#else + + abts_run_test(suite, test_child_kill, NULL); + +#endif + return suite; +} diff --git a/test/testpass.c b/test/testpass.c new file mode 100644 index 00000000000..4ba5c69525e --- /dev/null +++ b/test/testpass.c @@ -0,0 +1,217 @@ +/* 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 <stdio.h> +#include <stdlib.h> + +#include "apr_errno.h" +#include "apr_strings.h" +#include "apr_file_io.h" +#include "apr_thread_pool.h" +#include "apr_md5.h" +#include "apr_sha1.h" + +#include "abts.h" +#include "testutil.h" + +#if defined(WIN32) || defined(BEOS) || defined(NETWARE) +#define CRYPT_ALGO_SUPPORTED 0 +#else +#define CRYPT_ALGO_SUPPORTED 1 +#endif + +#if defined __GLIBC_PREREQ +#if __GLIBC_PREREQ(2,7) +#define GLIBCSHA_ALGO_SUPPORTED +#endif +#endif + +#if CRYPT_ALGO_SUPPORTED + +static struct { + const char *password; + const char *hash; +} passwords[] = +{ +/* + passwords and hashes created with Apache's htpasswd utility like this: + + htpasswd -c -b passwords pass1 pass1 + htpasswd -b passwords pass2 pass2 + htpasswd -b passwords pass3 pass3 + htpasswd -b passwords pass4 pass4 + htpasswd -b passwords pass5 pass5 + htpasswd -b passwords pass6 pass6 + htpasswd -b passwords pass7 pass7 + htpasswd -b passwords pass8 pass8 + (insert Perl one-liner to convert to initializer :) ) + */ + {"pass1", "1fWDc9QWYCWrQ"}, + {"pass2", "1fiGx3u7QoXaM"}, + {"pass3", "1fzijMylTiwCs"}, + {"pass4", "nHUYc8U2UOP7s"}, + {"pass5", "nHpETGLGPwAmA"}, + {"pass6", "nHbsbWmJ3uyhc"}, + {"pass7", "nHQ3BbF0Y9vpI"}, + {"pass8", "nHZA1rViSldQk"} +}; +static int num_passwords = sizeof(passwords) / sizeof(passwords[0]); + +static void test_crypt(abts_case *tc, void *data) +{ + int i; + + for (i = 0; i < num_passwords; i++) { + APR_ASSERT_SUCCESS(tc, "check for valid password", + apr_password_validate(passwords[i].password, + passwords[i].hash)); + } +} + +#if APR_HAS_THREADS + +static void * APR_THREAD_FUNC testing_thread(apr_thread_t *thd, + void *data) +{ + abts_case *tc = data; + int i; + + for (i = 0; i < 100; i++) { + test_crypt(tc, NULL); + } + + return APR_SUCCESS; +} + +#define NUM_THR 20 + +/* test for threadsafe crypt() */ +static void test_threadsafe(abts_case *tc, void *data) +{ + int i; + apr_status_t rv; + apr_thread_pool_t *thrp; + + rv = apr_thread_pool_create(&thrp, NUM_THR/2, NUM_THR, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + for (i = 0; i < NUM_THR; i++) { + rv = apr_thread_pool_push(thrp, testing_thread, tc, 0, NULL); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + } + + apr_thread_pool_destroy(thrp); +} +#endif + +#endif /* CRYPT_ALGO_SUPPORTED */ + +static void test_shapass(abts_case *tc, void *data) +{ + const char *pass = "hellojed"; + const char *pass2 = "hellojed2"; + char hash[100]; + + apr_sha1_base64(pass, strlen(pass), hash); + + APR_ASSERT_SUCCESS(tc, "SHA1 password validated", + apr_password_validate(pass, hash)); + APR_ASSERT_FAILURE(tc, "wrong SHA1 password should not validate", + apr_password_validate(pass2, hash)); +} + +static void test_md5pass(abts_case *tc, void *data) +{ + const char *pass = "hellojed", *salt = "sardine"; + const char *pass2 = "hellojed2"; + char hash[100]; + + apr_md5_encode(pass, salt, hash, sizeof hash); + + APR_ASSERT_SUCCESS(tc, "MD5 password validated", + apr_password_validate(pass, hash)); + APR_ASSERT_FAILURE(tc, "wrong MD5 password should not validate", + apr_password_validate(pass2, hash)); +} + +#ifdef GLIBCSHA_ALGO_SUPPORTED + +static struct { + const char *password; + const char *hash; +} glibc_sha_pws[] = { + /* SHA256 */ + { "secret1", "$5$0123456789abcdef$SFX.CooXBS8oXsbAPgU/UyiCodhrLQ19sBgvcA3Zh1D" }, + { "secret2", "$5$rounds=100000$0123456789abcdef$dLXfO5m4d.xv8G66kpz2LyL0.Mi5wjLlH0m7rtgyhyB" }, + /* SHA512 */ + { "secret3", "$6$0123456789abcdef$idOsOfoWwnCQkJm9hd2hxS4NnEs9nBA9poOFXsvtrYSoSHaOToCfyUoZwKe.ZCZnq7D95tGVoi2jxZZMyVwTL1" }, + { "secret4", "$6$rounds=100000$0123456789abcdef$ZiAMjbeA.iIGTWxq2oks9Bvz9sfxaoGPgAtpwimPEwFwkSNMTK7lLwABzzldds/n4UgCQ16HqawPrCrePr4YX1" }, + { NULL, NULL } +}; + +static void test_glibc_shapass(abts_case *tc, void *data) +{ + int i = 0; + while (glibc_sha_pws[i].password) { + APR_ASSERT_SUCCESS(tc, "check for valid glibc crypt-sha password", + apr_password_validate(glibc_sha_pws[i].password, + glibc_sha_pws[i].hash)); + i++; + } +} +#endif + +static void test_bcryptpass(abts_case *tc, void *data) +{ + const char *pass = "hellojed"; + const char *pass2 = "hellojed2"; + unsigned char salt[] = "sardine_sardine"; + char hash[100]; + const char *hash2 = "$2a$08$qipUJiI9fySUN38hcbz.lucXvAmtgowKOWYtB9y3CXyl6lTknruou"; + const char *pass3 = "foobar"; + + APR_ASSERT_SUCCESS(tc, "bcrypt encode password", + apr_bcrypt_encode(pass, 5, salt, sizeof(salt), hash, + sizeof(hash))); + + APR_ASSERT_SUCCESS(tc, "bcrypt password validated", + apr_password_validate(pass, hash)); + APR_ASSERT_FAILURE(tc, "wrong bcrypt password should not validate", + apr_password_validate(pass2, hash)); + APR_ASSERT_SUCCESS(tc, "bcrypt password validated", + apr_password_validate(pass3, hash2)); +} + + +abts_suite *testpass(abts_suite *suite) +{ + suite = ADD_SUITE(suite); + +#if CRYPT_ALGO_SUPPORTED + abts_run_test(suite, test_crypt, NULL); +#if APR_HAS_THREADS + abts_run_test(suite, test_threadsafe, NULL); +#endif +#endif /* CRYPT_ALGO_SUPPORTED */ + abts_run_test(suite, test_shapass, NULL); + abts_run_test(suite, test_md5pass, NULL); + abts_run_test(suite, test_bcryptpass, NULL); +#ifdef GLIBCSHA_ALGO_SUPPORTED + abts_run_test(suite, test_glibc_shapass, NULL); +#endif + + return suite; +} diff --git a/test/testpath.c b/test/testpath.c new file mode 100644 index 00000000000..b05ae9917e0 --- /dev/null +++ b/test/testpath.c @@ -0,0 +1,138 @@ +/* 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 "testutil.h" +#include "apr_file_info.h" +#include "apr_errno.h" +#include "apr_pools.h" +#include "apr_tables.h" + +#if defined(WIN32) || defined(NETWARE) || defined(OS2) +#define PSEP ";" +#define DSEP "\\" +#else +#define PSEP ":" +#define DSEP "/" +#endif + +#define PX "" +#define P1 "first path" +#define P2 "second" DSEP "path" +#define P3 "th ird" DSEP "path" +#define P4 "fourth" DSEP "pa th" +#define P5 "fifthpath" + +static const char *parts_in[] = { P1, P2, P3, PX, P4, P5 }; +static const char *path_in = P1 PSEP P2 PSEP P3 PSEP PX PSEP P4 PSEP P5; +static const int parts_in_count = sizeof(parts_in)/sizeof(*parts_in); + +static const char *parts_out[] = { P1, P2, P3, P4, P5 }; +static const char *path_out = P1 PSEP P2 PSEP P3 PSEP P4 PSEP P5; +static const int parts_out_count = sizeof(parts_out)/sizeof(*parts_out); + +static void list_split_multi(abts_case *tc, void *data) +{ + int i; + apr_status_t rv; + apr_array_header_t *pathelts; + + pathelts = NULL; + rv = apr_filepath_list_split(&pathelts, path_in, p); + ABTS_PTR_NOTNULL(tc, pathelts); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_INT_EQUAL(tc, parts_out_count, pathelts->nelts); + for (i = 0; i < pathelts->nelts; ++i) + ABTS_STR_EQUAL(tc, parts_out[i], ((char**)pathelts->elts)[i]); +} + +static void list_split_single(abts_case *tc, void *data) +{ + int i; + apr_status_t rv; + apr_array_header_t *pathelts; + + for (i = 0; i < parts_in_count; ++i) + { + pathelts = NULL; + rv = apr_filepath_list_split(&pathelts, parts_in[i], p); + ABTS_PTR_NOTNULL(tc, pathelts); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + if (parts_in[i][0] == '\0') + ABTS_INT_EQUAL(tc, 0, pathelts->nelts); + else + { + ABTS_INT_EQUAL(tc, 1, pathelts->nelts); + ABTS_STR_EQUAL(tc, parts_in[i], *(char**)pathelts->elts); + } + } +} + +static void list_merge_multi(abts_case *tc, void *data) +{ + int i; + char *liststr; + apr_status_t rv; + apr_array_header_t *pathelts; + + pathelts = apr_array_make(p, parts_in_count, sizeof(const char*)); + for (i = 0; i < parts_in_count; ++i) + *(const char**)apr_array_push(pathelts) = parts_in[i]; + + liststr = NULL; + rv = apr_filepath_list_merge(&liststr, pathelts, p); + ABTS_PTR_NOTNULL(tc, liststr); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_STR_EQUAL(tc, liststr, path_out); +} + +static void list_merge_single(abts_case *tc, void *data) +{ + int i; + char *liststr; + apr_status_t rv; + apr_array_header_t *pathelts; + + pathelts = apr_array_make(p, 1, sizeof(const char*)); + apr_array_push(pathelts); + for (i = 0; i < parts_in_count; ++i) + { + *(const char**)pathelts->elts = parts_in[i]; + liststr = NULL; + rv = apr_filepath_list_merge(&liststr, pathelts, p); + if (parts_in[i][0] == '\0') + ABTS_PTR_EQUAL(tc, NULL, liststr); + else + { + ABTS_PTR_NOTNULL(tc, liststr); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_STR_EQUAL(tc, liststr, parts_in[i]); + } + } +} + + +abts_suite *testpath(abts_suite *suite) +{ + suite = ADD_SUITE(suite) + + abts_run_test(suite, list_split_multi, NULL); + abts_run_test(suite, list_split_single, NULL); + abts_run_test(suite, list_merge_multi, NULL); + abts_run_test(suite, list_merge_single, NULL); + + return suite; +} + diff --git a/test/testpipe.c b/test/testpipe.c index 1c96ac92ab4..810ffe7b505 100644 --- a/test/testpipe.c +++ b/test/testpipe.c @@ -1,117 +1,235 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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 <stdio.h> +#include <stdlib.h> + +#include "testutil.h" #include "apr_file_io.h" #include "apr_errno.h" #include "apr_general.h" #include "apr_lib.h" -#include <stdlib.h> -#ifdef BEOS -#include <unistd.h> -#endif +#include "apr_thread_proc.h" +#include "apr_strings.h" + +static apr_file_t *readp = NULL; +static apr_file_t *writep = NULL; + +static void create_pipe(abts_case *tc, void *data) +{ + apr_status_t rv; + + rv = apr_file_pipe_create(&readp, &writep, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_PTR_NOTNULL(tc, readp); + ABTS_PTR_NOTNULL(tc, writep); +} + +static void close_pipe(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_size_t nbytes = 256; + char buf[256]; + + rv = apr_file_close(readp); + rv = apr_file_close(writep); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); -int test_filedel(ap_pool_t *); -int testdirs(ap_pool_t *); + rv = apr_file_read(readp, buf, &nbytes); + ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_EBADF(rv)); +} -int main() +static void set_timeout(abts_case *tc, void *data) { - ap_pool_t *context; - ap_file_t *readp = NULL; - ap_file_t *writep = NULL; - ap_size_t nbytes; + apr_status_t rv; + apr_interval_time_t timeout; + + rv = apr_file_pipe_create_pools(&readp, &writep, APR_WRITE_BLOCK, p, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_PTR_NOTNULL(tc, readp); + ABTS_PTR_NOTNULL(tc, writep); + + rv = apr_file_pipe_timeout_get(writep, &timeout); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_ASSERT(tc, "Timeout mismatch, expected -1", timeout == -1); + + rv = apr_file_pipe_timeout_set(readp, apr_time_from_sec(1)); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + rv = apr_file_pipe_timeout_get(readp, &timeout); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_ASSERT(tc, "Timeout mismatch, expected 1 second", + timeout == apr_time_from_sec(1)); +} + +static void read_write(abts_case *tc, void *data) +{ + apr_status_t rv; char *buf; + apr_size_t nbytes; + + nbytes = strlen("this is a test"); + buf = (char *)apr_palloc(p, nbytes + 1); - if (ap_initialize() != APR_SUCCESS) { - fprintf(stderr, "Couldn't initialize."); - exit(-1); - } - atexit(ap_terminate); - if (ap_create_pool(&context, NULL) != APR_SUCCESS) { - fprintf(stderr, "Couldn't allocate context."); - exit(-1); - } + rv = apr_file_pipe_create_pools(&readp, &writep, APR_WRITE_BLOCK, p, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_PTR_NOTNULL(tc, readp); + ABTS_PTR_NOTNULL(tc, writep); - fprintf(stdout, "Testing pipe functions.\n"); + rv = apr_file_pipe_timeout_set(readp, apr_time_from_sec(1)); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); - fprintf(stdout, "\tCreating pipes......."); - if (ap_create_pipe(&readp, &writep, context) != APR_SUCCESS) { - perror("Didn't create the pipe"); - exit(-1); - } - else { - fprintf(stdout, "OK\n"); + if (!rv) { + rv = apr_file_read(readp, buf, &nbytes); + ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_TIMEUP(rv)); + ABTS_SIZE_EQUAL(tc, 0, nbytes); } +} + +static void read_write_notimeout(abts_case *tc, void *data) +{ + apr_status_t rv; + char *buf = "this is a test"; + char *input; + apr_size_t nbytes; - fprintf(stdout, "\tSetting pipe timeout......."); - if (ap_set_pipe_timeout(readp, 1 * AP_USEC_PER_SEC) != APR_SUCCESS) { - perror("Couldn't set a timeout"); - exit(-1); - } else { - fprintf(stdout, "OK\n"); - } - - fprintf(stdout, "\tReading from the file......."); - nbytes = (ap_ssize_t)strlen("this is a test"); - buf = (char *)ap_palloc(context, nbytes + 1); - if (ap_read(readp, buf, &nbytes) == APR_TIMEUP) { - fprintf(stdout, "OK\n"); - } - else { - fprintf(stdout, "The timeout didn't work :-(\n"); - exit(-1); - } + nbytes = strlen("this is a test"); - return 1; + rv = apr_file_pipe_create(&readp, &writep, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_PTR_NOTNULL(tc, readp); + ABTS_PTR_NOTNULL(tc, writep); + + rv = apr_file_write(writep, buf, &nbytes); + ABTS_SIZE_EQUAL(tc, strlen("this is a test"), nbytes); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + nbytes = 256; + input = apr_pcalloc(p, nbytes + 1); + rv = apr_file_read(readp, input, &nbytes); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_SIZE_EQUAL(tc, strlen("this is a test"), nbytes); + ABTS_STR_EQUAL(tc, "this is a test", input); } + +static void test_pipe_writefull(abts_case *tc, void *data) +{ + int iterations = 1000; + int i; + int bytes_per_iteration = 8000; + char *buf = (char *)calloc(bytes_per_iteration, 1); + char responsebuf[128]; + apr_size_t nbytes; + int bytes_processed; + apr_proc_t proc = {0}; + apr_procattr_t *procattr; + const char *args[2]; + apr_status_t rv; + apr_exit_why_e why; + + rv = apr_procattr_create(&procattr, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + rv = apr_procattr_io_set(procattr, APR_CHILD_BLOCK, APR_CHILD_BLOCK, + APR_CHILD_BLOCK); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + rv = apr_procattr_cmdtype_set(procattr, APR_PROGRAM_ENV); + APR_ASSERT_SUCCESS(tc, "Couldn't set copy environment", rv); + + rv = apr_procattr_error_check_set(procattr, 1); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + args[0] = "readchild" EXTENSION; + args[1] = NULL; + rv = apr_proc_create(&proc, TESTBINPATH "readchild" EXTENSION, args, NULL, procattr, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + rv = apr_file_pipe_timeout_set(proc.in, apr_time_from_sec(10)); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + rv = apr_file_pipe_timeout_set(proc.out, apr_time_from_sec(10)); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + i = iterations; + do { + rv = apr_file_write_full(proc.in, buf, bytes_per_iteration, NULL); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + } while (--i); + + free(buf); + + rv = apr_file_close(proc.in); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + nbytes = sizeof(responsebuf); + rv = apr_file_read(proc.out, responsebuf, &nbytes); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + bytes_processed = (int)apr_strtoi64(responsebuf, NULL, 10); + ABTS_INT_EQUAL(tc, iterations * bytes_per_iteration, bytes_processed); + + ABTS_ASSERT(tc, "wait for child process", + apr_proc_wait(&proc, NULL, &why, APR_WAIT) == APR_CHILD_DONE); + + ABTS_ASSERT(tc, "child terminated normally", why == APR_PROC_EXIT); +} + +static void wait_pipe(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_interval_time_t delay = 200000; + apr_time_t start_time; + apr_time_t end_time; + apr_size_t nbytes; + + rv = apr_file_pipe_create(&readp, &writep, p); + APR_ASSERT_SUCCESS(tc, "Couldn't create pipe", rv); + + rv = apr_file_pipe_timeout_set(readp, delay); + APR_ASSERT_SUCCESS(tc, "Couldn't set pipe timeout", rv); + + start_time = apr_time_now(); + rv = apr_file_pipe_wait(readp, APR_WAIT_READ); + ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_TIMEUP(rv)); + + end_time = apr_time_now(); + ABTS_ASSERT(tc, "apr_file_pipe_wait() waited for the time out", end_time - start_time >= delay); + + nbytes = 4; + rv = apr_file_write(writep, "data", &nbytes); + APR_ASSERT_SUCCESS(tc, "Couldn't write to pipe", rv); + + rv = apr_file_pipe_wait(readp, APR_WAIT_READ); + APR_ASSERT_SUCCESS(tc, "Wait for pipe failed", rv); +} + +abts_suite *testpipe(abts_suite *suite) +{ + suite = ADD_SUITE(suite) + + abts_run_test(suite, create_pipe, NULL); + abts_run_test(suite, close_pipe, NULL); + abts_run_test(suite, set_timeout, NULL); + abts_run_test(suite, close_pipe, NULL); + abts_run_test(suite, read_write, NULL); + abts_run_test(suite, close_pipe, NULL); + abts_run_test(suite, read_write_notimeout, NULL); + abts_run_test(suite, test_pipe_writefull, NULL); + abts_run_test(suite, close_pipe, NULL); + abts_run_test(suite, wait_pipe, NULL); + + return suite; +} + diff --git a/test/testpoll.c b/test/testpoll.c new file mode 100644 index 00000000000..9f90af2dd50 --- /dev/null +++ b/test/testpoll.c @@ -0,0 +1,965 @@ +/* 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 "testutil.h" +#include "apr_strings.h" +#include "apr_errno.h" +#include "apr_general.h" +#include "apr_lib.h" +#include "apr_network_io.h" +#include "apr_poll.h" + +#define SMALL_NUM_SOCKETS 3 +/* We can't use 64 here, because some platforms *ahem* Solaris *ahem* have + * a default limit of 64 open file descriptors per process. If we use + * 64, the test will fail even though the code is correct. + */ +#define LARGE_NUM_SOCKETS 50 + +static apr_socket_t *s[LARGE_NUM_SOCKETS]; +static apr_sockaddr_t *sa[LARGE_NUM_SOCKETS]; +static apr_pollset_t *pollset; +static apr_pollcb_t *pollcb; + +/* ###: tests surrounded by ifdef OLD_POLL_INTERFACE either need to be + * converted to use the pollset interface or removed. */ + +#ifdef OLD_POLL_INTERFACE +static apr_pollfd_t *pollarray; +static apr_pollfd_t *pollarray_large; +#endif + +/* default_pollset_impl can be overridden temporarily to control + * testcases which don't specify an implementation explicitly + */ +static int default_pollset_impl = APR_POLLSET_DEFAULT; + +static void make_socket(apr_socket_t **sock, apr_sockaddr_t **sa, + apr_port_t port, apr_pool_t *p, abts_case *tc) +{ + apr_status_t rv; + + rv = apr_sockaddr_info_get(sa, "127.0.0.1", APR_UNSPEC, port, 0, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + rv = apr_socket_create(sock, (*sa)->family, SOCK_DGRAM, 0, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + rv = apr_socket_bind((*sock), (*sa)); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); +} + +#ifdef OLD_POLL_INTERFACE +static void check_sockets(const apr_pollfd_t *pollarray, + apr_socket_t **sockarray, int which, int pollin, + abts_case *tc) +{ + apr_status_t rv; + apr_int16_t event; + char *str; + + rv = apr_poll_revents_get(&event, sockarray[which], + (apr_pollfd_t *)pollarray); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + if (pollin) { + str = apr_psprintf(p, "Socket %d not signalled when it should be", + which); + ABTS_ASSERT(tc, str, event & APR_POLLIN); + } else { + str = apr_psprintf(p, "Socket %d signalled when it should not be", + which); + ABTS_ASSERT(tc, str, !(event & APR_POLLIN)); + } +} +#endif + +static void send_msg(apr_socket_t **sockarray, apr_sockaddr_t **sas, int which, + abts_case *tc) +{ + apr_size_t len = 5; + apr_status_t rv; + + ABTS_PTR_NOTNULL(tc, sockarray[which]); + + rv = apr_socket_sendto(sockarray[which], sas[which], 0, "hello", &len); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_SIZE_EQUAL(tc, strlen("hello"), len); +} + +static void recv_msg(apr_socket_t **sockarray, int which, apr_pool_t *p, + abts_case *tc) +{ + apr_size_t buflen = 5; + char *buffer = apr_pcalloc(p, sizeof(char) * (buflen + 1)); + apr_sockaddr_t *recsa; + apr_status_t rv; + + ABTS_PTR_NOTNULL(tc, sockarray[which]); + + apr_sockaddr_info_get(&recsa, "127.0.0.1", APR_UNSPEC, 7770, 0, p); + + rv = apr_socket_recvfrom(recsa, sockarray[which], 0, buffer, &buflen); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_SIZE_EQUAL(tc, strlen("hello"), buflen); + ABTS_STR_EQUAL(tc, "hello", buffer); +} + + +static void create_all_sockets(abts_case *tc, void *data) +{ + int i; + + for (i = 0; i < LARGE_NUM_SOCKETS; i++){ + make_socket(&s[i], &sa[i], 7777 + i, p, tc); + } +} + +#ifdef OLD_POLL_INTERFACE +static void setup_small_poll(abts_case *tc, void *data) +{ + apr_status_t rv; + int i; + + rv = apr_poll_setup(&pollarray, SMALL_NUM_SOCKETS, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + for (i = 0; i < SMALL_NUM_SOCKETS;i++){ + ABTS_INT_EQUAL(tc, 0, pollarray[i].reqevents); + ABTS_INT_EQUAL(tc, 0, pollarray[i].rtnevents); + + rv = apr_poll_socket_add(pollarray, s[i], APR_POLLIN); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_PTR_EQUAL(tc, s[i], pollarray[i].desc.s); + } +} + +static void setup_large_poll(abts_case *tc, void *data) +{ + apr_status_t rv; + int i; + + rv = apr_poll_setup(&pollarray_large, LARGE_NUM_SOCKETS, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + for (i = 0; i < LARGE_NUM_SOCKETS;i++){ + ABTS_INT_EQUAL(tc, 0, pollarray_large[i].reqevents); + ABTS_INT_EQUAL(tc, 0, pollarray_large[i].rtnevents); + + rv = apr_poll_socket_add(pollarray_large, s[i], APR_POLLIN); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_PTR_EQUAL(tc, s[i], pollarray_large[i].desc.s); + } +} + +static void nomessage(abts_case *tc, void *data) +{ + apr_status_t rv; + int srv = SMALL_NUM_SOCKETS; + + rv = apr_poll(pollarray, SMALL_NUM_SOCKETS, &srv, 2 * APR_USEC_PER_SEC); + ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_TIMEUP(rv)); + check_sockets(pollarray, s, 0, 0, tc); + check_sockets(pollarray, s, 1, 0, tc); + check_sockets(pollarray, s, 2, 0, tc); +} + +static void send_2(abts_case *tc, void *data) +{ + apr_status_t rv; + int srv = SMALL_NUM_SOCKETS; + + send_msg(s, sa, 2, tc); + + rv = apr_poll(pollarray, SMALL_NUM_SOCKETS, &srv, 2 * APR_USEC_PER_SEC); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + check_sockets(pollarray, s, 0, 0, tc); + check_sockets(pollarray, s, 1, 0, tc); + check_sockets(pollarray, s, 2, 1, tc); +} + +static void recv_2_send_1(abts_case *tc, void *data) +{ + apr_status_t rv; + int srv = SMALL_NUM_SOCKETS; + + recv_msg(s, 2, p, tc); + send_msg(s, sa, 1, tc); + + rv = apr_poll(pollarray, SMALL_NUM_SOCKETS, &srv, 2 * APR_USEC_PER_SEC); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + check_sockets(pollarray, s, 0, 0, tc); + check_sockets(pollarray, s, 1, 1, tc); + check_sockets(pollarray, s, 2, 0, tc); +} + +static void send_2_signaled_1(abts_case *tc, void *data) +{ + apr_status_t rv; + int srv = SMALL_NUM_SOCKETS; + + send_msg(s, sa, 2, tc); + + rv = apr_poll(pollarray, SMALL_NUM_SOCKETS, &srv, 2 * APR_USEC_PER_SEC); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + check_sockets(pollarray, s, 0, 0, tc); + check_sockets(pollarray, s, 1, 1, tc); + check_sockets(pollarray, s, 2, 1, tc); +} + +static void recv_1_send_0(abts_case *tc, void *data) +{ + apr_status_t rv; + int srv = SMALL_NUM_SOCKETS; + + recv_msg(s, 1, p, tc); + send_msg(s, sa, 0, tc); + + rv = apr_poll(pollarray, SMALL_NUM_SOCKETS, &srv, 2 * APR_USEC_PER_SEC); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + check_sockets(pollarray, s, 0, 1, tc); + check_sockets(pollarray, s, 1, 0, tc); + check_sockets(pollarray, s, 2, 1, tc); +} + +static void clear_all_signalled(abts_case *tc, void *data) +{ + apr_status_t rv; + int srv = SMALL_NUM_SOCKETS; + + recv_msg(s, 0, p, tc); + recv_msg(s, 2, p, tc); + + rv = apr_poll(pollarray, SMALL_NUM_SOCKETS, &srv, 2 * APR_USEC_PER_SEC); + ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_TIMEUP(rv)); + check_sockets(pollarray, s, 0, 0, tc); + check_sockets(pollarray, s, 1, 0, tc); + check_sockets(pollarray, s, 2, 0, tc); +} + +static void send_large_pollarray(abts_case *tc, void *data) +{ + apr_status_t rv; + int lrv = LARGE_NUM_SOCKETS; + int i; + + send_msg(s, sa, LARGE_NUM_SOCKETS - 1, tc); + + rv = apr_poll(pollarray_large, LARGE_NUM_SOCKETS, &lrv, + 2 * APR_USEC_PER_SEC); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + for (i = 0; i < LARGE_NUM_SOCKETS; i++) { + if (i == (LARGE_NUM_SOCKETS - 1)) { + check_sockets(pollarray_large, s, i, 1, tc); + } + else { + check_sockets(pollarray_large, s, i, 0, tc); + } + } +} + +static void recv_large_pollarray(abts_case *tc, void *data) +{ + apr_status_t rv; + int lrv = LARGE_NUM_SOCKETS; + int i; + + recv_msg(s, LARGE_NUM_SOCKETS - 1, p, tc); + + rv = apr_poll(pollarray_large, LARGE_NUM_SOCKETS, &lrv, + 2 * APR_USEC_PER_SEC); + ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_TIMEUP(rv)); + + for (i = 0; i < LARGE_NUM_SOCKETS; i++) { + check_sockets(pollarray_large, s, i, 0, tc); + } +} +#endif + +static void setup_pollset(abts_case *tc, void *data) +{ + apr_status_t rv; + rv = apr_pollset_create_ex(&pollset, LARGE_NUM_SOCKETS, p, 0, + default_pollset_impl); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); +} + +static void multi_event_pollset(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_pollfd_t socket_pollfd; + int lrv; + const apr_pollfd_t *descs = NULL; + + ABTS_PTR_NOTNULL(tc, s[0]); + socket_pollfd.desc_type = APR_POLL_SOCKET; + socket_pollfd.reqevents = APR_POLLIN | APR_POLLOUT; + socket_pollfd.desc.s = s[0]; + socket_pollfd.client_data = s[0]; + rv = apr_pollset_add(pollset, &socket_pollfd); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + send_msg(s, sa, 0, tc); + + rv = apr_pollset_poll(pollset, -1, &lrv, &descs); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + if (lrv == 1) { + int ev = descs[0].rtnevents; + ABTS_PTR_EQUAL(tc, s[0], descs[0].desc.s); + ABTS_PTR_EQUAL(tc, s[0], descs[0].client_data); + ABTS_ASSERT(tc, "either or both of APR_POLLIN, APR_POLLOUT returned", + ((ev & APR_POLLIN) != 0) || ((ev & APR_POLLOUT) != 0)); + } + else if (lrv == 2) { + ABTS_PTR_EQUAL(tc, s[0], descs[0].desc.s); + ABTS_PTR_EQUAL(tc, s[0], descs[0].client_data); + ABTS_PTR_EQUAL(tc, s[0], descs[1].desc.s); + ABTS_PTR_EQUAL(tc, s[0], descs[1].client_data); + ABTS_ASSERT(tc, "returned events incorrect", + ((descs[0].rtnevents | descs[1].rtnevents) + == (APR_POLLIN | APR_POLLOUT)) + && descs[0].rtnevents != descs[1].rtnevents); + } + else { + ABTS_ASSERT(tc, "either one or two events returned", + lrv == 1 || lrv == 2); + } + + recv_msg(s, 0, p, tc); + + rv = apr_pollset_poll(pollset, 0, &lrv, &descs); + ABTS_INT_EQUAL(tc, 0, APR_STATUS_IS_TIMEUP(rv)); + ABTS_INT_EQUAL(tc, 1, lrv); + ABTS_PTR_EQUAL(tc, s[0], descs[0].desc.s); + ABTS_INT_EQUAL(tc, APR_POLLOUT, descs[0].rtnevents); + ABTS_PTR_EQUAL(tc, s[0], descs[0].client_data); + + rv = apr_pollset_remove(pollset, &socket_pollfd); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); +} + +static void add_sockets_pollset(abts_case *tc, void *data) +{ + apr_status_t rv; + int i; + + for (i = 0; i < LARGE_NUM_SOCKETS;i++){ + apr_pollfd_t socket_pollfd; + + ABTS_PTR_NOTNULL(tc, s[i]); + + socket_pollfd.desc_type = APR_POLL_SOCKET; + socket_pollfd.reqevents = APR_POLLIN; + socket_pollfd.desc.s = s[i]; + socket_pollfd.client_data = s[i]; + rv = apr_pollset_add(pollset, &socket_pollfd); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + } +} + +static void nomessage_pollset(abts_case *tc, void *data) +{ + apr_status_t rv; + int lrv; + const apr_pollfd_t *descs = NULL; + + rv = apr_pollset_poll(pollset, 0, &lrv, &descs); + ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_TIMEUP(rv)); + ABTS_INT_EQUAL(tc, 0, lrv); + ABTS_PTR_EQUAL(tc, NULL, descs); +} + +static void send0_pollset(abts_case *tc, void *data) +{ + apr_status_t rv; + const apr_pollfd_t *descs = NULL; + int num; + + send_msg(s, sa, 0, tc); + rv = apr_pollset_poll(pollset, -1, &num, &descs); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_INT_EQUAL(tc, 1, num); + ABTS_PTR_NOTNULL(tc, descs); + + ABTS_PTR_EQUAL(tc, s[0], descs[0].desc.s); + ABTS_PTR_EQUAL(tc, s[0], descs[0].client_data); +} + +static void recv0_pollset(abts_case *tc, void *data) +{ + apr_status_t rv; + int lrv; + const apr_pollfd_t *descs = NULL; + + recv_msg(s, 0, p, tc); + rv = apr_pollset_poll(pollset, 0, &lrv, &descs); + ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_TIMEUP(rv)); + ABTS_INT_EQUAL(tc, 0, lrv); + ABTS_PTR_EQUAL(tc, NULL, descs); +} + +static void send_middle_pollset(abts_case *tc, void *data) +{ + apr_status_t rv; + const apr_pollfd_t *descs = NULL; + int num; + + send_msg(s, sa, 2, tc); + send_msg(s, sa, 5, tc); + rv = apr_pollset_poll(pollset, -1, &num, &descs); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_PTR_NOTNULL(tc, descs); + ABTS_ASSERT(tc, "either one or two events returned", + num == 1 || num == 2); + + /* The poll might only see the first sent message, in which + * case we just don't bother checking this assertion */ + if (num == 2) { + ABTS_ASSERT(tc, "Incorrect socket in result set", + ((descs[0].desc.s == s[2]) && (descs[1].desc.s == s[5])) || + ((descs[0].desc.s == s[5]) && (descs[1].desc.s == s[2]))); + } +} + +static void clear_middle_pollset(abts_case *tc, void *data) +{ + apr_status_t rv; + int lrv; + const apr_pollfd_t *descs = NULL; + + recv_msg(s, 2, p, tc); + recv_msg(s, 5, p, tc); + + rv = apr_pollset_poll(pollset, 0, &lrv, &descs); + ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_TIMEUP(rv)); + ABTS_INT_EQUAL(tc, 0, lrv); + ABTS_PTR_EQUAL(tc, NULL, descs); +} + +static void send_last_pollset(abts_case *tc, void *data) +{ + apr_status_t rv; + const apr_pollfd_t *descs = NULL; + int num; + + send_msg(s, sa, LARGE_NUM_SOCKETS - 1, tc); + rv = apr_pollset_poll(pollset, -1, &num, &descs); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_INT_EQUAL(tc, 1, num); + ABTS_PTR_NOTNULL(tc, descs); + + ABTS_PTR_EQUAL(tc, s[LARGE_NUM_SOCKETS - 1], descs[0].desc.s); + ABTS_PTR_EQUAL(tc, s[LARGE_NUM_SOCKETS - 1], descs[0].client_data); +} + +static void clear_last_pollset(abts_case *tc, void *data) +{ + apr_status_t rv; + int lrv; + const apr_pollfd_t *descs = NULL; + + recv_msg(s, LARGE_NUM_SOCKETS - 1, p, tc); + + rv = apr_pollset_poll(pollset, 0, &lrv, &descs); + ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_TIMEUP(rv)); + ABTS_INT_EQUAL(tc, 0, lrv); + ABTS_PTR_EQUAL(tc, NULL, descs); +} + +static void close_all_sockets(abts_case *tc, void *data) +{ + apr_status_t rv; + int i; + + for (i = 0; i < LARGE_NUM_SOCKETS; i++){ + rv = apr_socket_close(s[i]); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + } +} + +static void pollset_remove(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_pollset_t *pollset; + const apr_pollfd_t *hot_files; + apr_pollfd_t pfd; + apr_int32_t num; + + rv = apr_pollset_create_ex(&pollset, 5, p, 0, + default_pollset_impl); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + pfd.p = p; + pfd.desc_type = APR_POLL_SOCKET; + pfd.reqevents = APR_POLLOUT; + + pfd.desc.s = s[0]; + pfd.client_data = (void *)1; + rv = apr_pollset_add(pollset, &pfd); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + pfd.desc.s = s[1]; + pfd.client_data = (void *)2; + rv = apr_pollset_add(pollset, &pfd); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + pfd.desc.s = s[2]; + pfd.client_data = (void *)3; + rv = apr_pollset_add(pollset, &pfd); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + pfd.desc.s = s[3]; + pfd.client_data = (void *)4; + rv = apr_pollset_add(pollset, &pfd); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + rv = apr_pollset_poll(pollset, 1000, &num, &hot_files); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_INT_EQUAL(tc, 4, num); + + /* now remove the pollset element referring to desc s[1] */ + pfd.desc.s = s[1]; + pfd.client_data = (void *)999; /* not used on this call */ + rv = apr_pollset_remove(pollset, &pfd); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + /* this time only three should match */ + rv = apr_pollset_poll(pollset, 1000, &num, &hot_files); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_INT_EQUAL(tc, 3, num); + ABTS_PTR_EQUAL(tc, (void *)1, hot_files[0].client_data); + ABTS_PTR_EQUAL(tc, s[0], hot_files[0].desc.s); + ABTS_PTR_EQUAL(tc, (void *)3, hot_files[1].client_data); + ABTS_PTR_EQUAL(tc, s[2], hot_files[1].desc.s); + ABTS_PTR_EQUAL(tc, (void *)4, hot_files[2].client_data); + ABTS_PTR_EQUAL(tc, s[3], hot_files[2].desc.s); + + /* now remove the pollset elements referring to desc s[2] */ + pfd.desc.s = s[2]; + pfd.client_data = (void *)999; /* not used on this call */ + rv = apr_pollset_remove(pollset, &pfd); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + /* this time only two should match */ + rv = apr_pollset_poll(pollset, 1000, &num, &hot_files); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_INT_EQUAL(tc, 2, num); + ABTS_ASSERT(tc, "Incorrect socket in result set", + ((hot_files[0].desc.s == s[0]) && (hot_files[1].desc.s == s[3])) || + ((hot_files[0].desc.s == s[3]) && (hot_files[1].desc.s == s[0]))); + ABTS_ASSERT(tc, "Incorrect client data in result set", + ((hot_files[0].client_data == (void *)1) && + (hot_files[1].client_data == (void *)4)) || + ((hot_files[0].client_data == (void *)4) && + (hot_files[1].client_data == (void *)1))); +} + +#define POLLCB_PREREQ \ + do { \ + if (pollcb == NULL) { \ + ABTS_NOT_IMPL(tc, "pollcb interface not supported"); \ + return; \ + } \ + } while (0) + +static void setup_pollcb(abts_case *tc, void *data) +{ + apr_status_t rv; + rv = apr_pollcb_create(&pollcb, LARGE_NUM_SOCKETS, p, 0); + if (rv == APR_ENOTIMPL) { + pollcb = NULL; + ABTS_NOT_IMPL(tc, "pollcb interface not supported"); + } + else { + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + } +} + +typedef struct pollcb_baton_t { + abts_case *tc; + int count; +} pollcb_baton_t; + +static apr_status_t trigger_pollcb_cb(void *baton, apr_pollfd_t *descriptor) +{ + pollcb_baton_t *pcb = (pollcb_baton_t *) baton; + ABTS_PTR_EQUAL(pcb->tc, s[0], descriptor->desc.s); + ABTS_PTR_EQUAL(pcb->tc, s[0], descriptor->client_data); + pcb->count++; + return APR_SUCCESS; +} + +static void trigger_pollcb(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_pollfd_t socket_pollfd; + pollcb_baton_t pcb; + + POLLCB_PREREQ; + + ABTS_PTR_NOTNULL(tc, s[0]); + socket_pollfd.desc_type = APR_POLL_SOCKET; + socket_pollfd.reqevents = APR_POLLIN; + socket_pollfd.desc.s = s[0]; + socket_pollfd.client_data = s[0]; + rv = apr_pollcb_add(pollcb, &socket_pollfd); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + send_msg(s, sa, 0, tc); + pcb.tc = tc; + pcb.count = 0; + rv = apr_pollcb_poll(pollcb, -1, trigger_pollcb_cb, &pcb); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_INT_EQUAL(tc, 1, pcb.count); + + rv = apr_pollcb_remove(pollcb, &socket_pollfd); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); +} + +static void timeout_pollcb(abts_case *tc, void *data) +{ + apr_status_t rv; + pollcb_baton_t pcb; + + POLLCB_PREREQ; + + pcb.count = 0; + pcb.tc = tc; + + rv = apr_pollcb_poll(pollcb, 1, trigger_pollcb_cb, &pcb); + ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_TIMEUP(rv)); + ABTS_INT_EQUAL(tc, 0, pcb.count); +} + +static void timeout_pollin_pollcb(abts_case *tc, void *data) +{ + apr_status_t rv; + pollcb_baton_t pcb; + apr_pollfd_t socket_pollfd; + + POLLCB_PREREQ; + + recv_msg(s, 0, p, tc); + + ABTS_PTR_NOTNULL(tc, s[0]); + socket_pollfd.desc_type = APR_POLL_SOCKET; + socket_pollfd.reqevents = APR_POLLIN; + socket_pollfd.desc.s = s[0]; + socket_pollfd.client_data = s[0]; + rv = apr_pollcb_add(pollcb, &socket_pollfd); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + pcb.count = 0; + pcb.tc = tc; + + rv = apr_pollcb_poll(pollcb, 1, trigger_pollcb_cb, &pcb); + ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_TIMEUP(rv)); + ABTS_INT_EQUAL(tc, 0, pcb.count); + + rv = apr_pollcb_remove(pollcb, &socket_pollfd); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); +} + +static void pollset_default(abts_case *tc, void *data) +{ + apr_status_t rv1, rv2; + apr_pollset_t *pollset; + + /* verify that APR will successfully create a pollset if an invalid method + * is specified as long as APR_POLLSET_NODEFAULT isn't specified + * (no platform has both APR_POLLSET_PORT and APR_POLLSET_KQUEUE, so at + * least one create call will succeed after having to switch to the default + * type) + */ + rv1 = apr_pollset_create_ex(&pollset, 1, p, 0, APR_POLLSET_PORT); + + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv1); + ABTS_PTR_NOTNULL(tc, pollset); + + rv1 = apr_pollset_create_ex(&pollset, 1, p, 0, APR_POLLSET_KQUEUE); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv1); + ABTS_PTR_NOTNULL(tc, pollset); + + /* verify that APR will fail to create a pollset if an invalid method is + * specified along with APR_POLLSET_NODEFAULT + * (no platform has both APR_POLLSET_PORT and APR_POLLSET_KQUEUE, so at + * least one create call will fail since it can't switch to the default + * type) + */ + rv1 = apr_pollset_create_ex(&pollset, 1, p, APR_POLLSET_NODEFAULT, + APR_POLLSET_PORT); + + if (rv1 == APR_SUCCESS) { + ABTS_PTR_NOTNULL(tc, pollset); + } + + rv2 = apr_pollset_create_ex(&pollset, 1, p, APR_POLLSET_NODEFAULT, + APR_POLLSET_KQUEUE); + if (rv2 == APR_SUCCESS) { + ABTS_PTR_NOTNULL(tc, pollset); + } + + ABTS_ASSERT(tc, + "failure using APR_POLLSET_NODEFAULT with unsupported method", + rv1 != APR_SUCCESS || rv2 != APR_SUCCESS); +} + +static void pollcb_default(abts_case *tc, void *data) +{ + apr_status_t rv1, rv2; + apr_pollcb_t *pollcb; + + /* verify that APR will successfully create a pollcb if an invalid method + * is specified as long as APR_POLLSET_NODEFAULT isn't specified + * (no platform has both APR_POLLSET_PORT and APR_POLLSET_KQUEUE, so at + * least one create call will succeed after having to switch to the default + * type) + */ + rv1 = apr_pollcb_create_ex(&pollcb, 1, p, 0, APR_POLLSET_PORT); + if (rv1 == APR_ENOTIMPL) { + ABTS_NOT_IMPL(tc, "pollcb interface not supported"); + return; + } + + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv1); + ABTS_PTR_NOTNULL(tc, pollcb); + + rv1 = apr_pollcb_create_ex(&pollcb, 1, p, 0, APR_POLLSET_KQUEUE); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv1); + ABTS_PTR_NOTNULL(tc, pollcb); + + /* verify that APR will fail to create a pollcb if an invalid method is + * specified along with APR_POLLSET_NODEFAULT + * (no platform has both APR_POLLSET_PORT and APR_POLLSET_KQUEUE, so at + * least one create call will fail since it can't switch to the default + * type) + */ + rv1 = apr_pollcb_create_ex(&pollcb, 1, p, APR_POLLSET_NODEFAULT, + APR_POLLSET_PORT); + + if (rv1 == APR_SUCCESS) { + ABTS_PTR_NOTNULL(tc, pollcb); + } + + rv2 = apr_pollcb_create_ex(&pollcb, 1, p, APR_POLLSET_NODEFAULT, + APR_POLLSET_KQUEUE); + if (rv2 == APR_SUCCESS) { + ABTS_PTR_NOTNULL(tc, pollcb); + } + + ABTS_ASSERT(tc, + "failure using APR_POLLSET_NODEFAULT with unsupported method", + rv1 != APR_SUCCESS || rv2 != APR_SUCCESS); + + + /* verify basic behavior for another method fallback case (this caused + * APR to crash before r834029) + */ + + rv1 = apr_pollcb_create_ex(&pollcb, 1, p, 0, APR_POLLSET_POLL); + if (rv1 != APR_ENOTIMPL) { + ABTS_INT_EQUAL(tc, rv1, APR_SUCCESS); + ABTS_PTR_NOTNULL(tc, pollcb); + } +} + +static void pollset_wakeup(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_pollfd_t socket_pollfd; + apr_pollset_t *pollset; + apr_int32_t num; + const apr_pollfd_t *descriptors; + int i; + + rv = apr_pollset_create_ex(&pollset, 1, p, APR_POLLSET_WAKEABLE, + default_pollset_impl); + if (rv == APR_ENOTIMPL) { + ABTS_NOT_IMPL(tc, "apr_pollset_wakeup() not supported"); + return; + } + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + /* Send wakeup but no data; apr_pollset_poll() should return APR_EINTR. + * Do it twice to test implementations that need to re-arm the events after + * poll()ing (e.g. APR_POLLSET_PORT), hence verify that the wakeup pipe is + * still in the place afterward. + */ + for (i = 0; i < 2; ++i) { + rv = apr_pollset_wakeup(pollset); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + rv = apr_pollset_poll(pollset, -1, &num, &descriptors); + ABTS_INT_EQUAL(tc, APR_EINTR, rv); + } + + /* send wakeup and data; apr_pollset_poll() should return APR_SUCCESS */ + socket_pollfd.desc_type = APR_POLL_SOCKET; + socket_pollfd.reqevents = APR_POLLIN; + socket_pollfd.desc.s = s[0]; + socket_pollfd.client_data = s[0]; + rv = apr_pollset_add(pollset, &socket_pollfd); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + send_msg(s, sa, 0, tc); apr_sleep(1000); + + rv = apr_pollset_wakeup(pollset); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + rv = apr_pollset_poll(pollset, -1, &num, &descriptors); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_INT_EQUAL(tc, 1, num); +} + +/* Should never be invoked */ +static apr_status_t wakeup_pollcb_cb(void *baton, apr_pollfd_t *descriptor) +{ + abts_case *tc = (abts_case *) baton; + + ABTS_FAIL(tc, "pollcb callback invoked on apr_pollcb_wakeup()"); + return APR_SUCCESS; +} + +static void pollcb_wakeup(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_pollcb_t *pcb; + + rv = apr_pollcb_create(&pcb, 1, p, APR_POLLSET_WAKEABLE); + if (rv == APR_ENOTIMPL) { + ABTS_NOT_IMPL(tc, "pollcb interface not supported"); + return; + } + else { + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + } + + rv = apr_pollcb_wakeup(pcb); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + rv = apr_pollcb_poll(pcb, -1, wakeup_pollcb_cb, tc); + ABTS_INT_EQUAL(tc, APR_EINTR, rv); +} + +static void justsleep(abts_case *tc, void *data) +{ + apr_int32_t nsds; + const apr_pollfd_t *hot_files; + apr_pollset_t *pollset; + apr_status_t rv; + apr_time_t t1, t2; + int i; + apr_pollset_method_e methods[] = { + APR_POLLSET_DEFAULT, + APR_POLLSET_SELECT, + APR_POLLSET_KQUEUE, + APR_POLLSET_PORT, + APR_POLLSET_EPOLL, + APR_POLLSET_POLL}; + + nsds = 1; + t1 = apr_time_now(); + rv = apr_poll(NULL, 0, &nsds, apr_time_from_msec(200)); + t2 = apr_time_now(); + ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_TIMEUP(rv)); + ABTS_INT_EQUAL(tc, 0, nsds); + ABTS_ASSERT(tc, + "apr_poll() didn't sleep", + (t2 - t1) > apr_time_from_msec(100)); + + for (i = 0; i < sizeof methods / sizeof methods[0]; i++) { + rv = apr_pollset_create_ex(&pollset, 5, p, 0, methods[i]); + if (rv != APR_ENOTIMPL) { + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + nsds = 1; + t1 = apr_time_now(); + rv = apr_pollset_poll(pollset, apr_time_from_msec(200), &nsds, + &hot_files); + t2 = apr_time_now(); + ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_TIMEUP(rv)); + ABTS_INT_EQUAL(tc, 0, nsds); + ABTS_ASSERT(tc, + "apr_pollset_poll() didn't sleep", + (t2 - t1) > apr_time_from_msec(100)); + + rv = apr_pollset_destroy(pollset); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + } + + rv = apr_pollcb_create_ex(&pollcb, 5, p, 0, methods[0]); + if (rv != APR_ENOTIMPL) { + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + t1 = apr_time_now(); + rv = apr_pollcb_poll(pollcb, apr_time_from_msec(200), NULL, NULL); + t2 = apr_time_now(); + ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_TIMEUP(rv)); + ABTS_ASSERT(tc, + "apr_pollcb_poll() didn't sleep", + (t2 - t1) > apr_time_from_msec(100)); + + /* no apr_pollcb_destroy() */ + } + } +} + +abts_suite *testpoll(abts_suite *suite) +{ + suite = ADD_SUITE(suite) + + abts_run_test(suite, create_all_sockets, NULL); + +#ifdef OLD_POLL_INTERFACE + abts_run_test(suite, setup_small_poll, NULL); + abts_run_test(suite, setup_large_poll, NULL); + abts_run_test(suite, nomessage, NULL); + abts_run_test(suite, send_2, NULL); + abts_run_test(suite, recv_2_send_1, NULL); + abts_run_test(suite, send_2_signaled_1, NULL); + abts_run_test(suite, recv_1_send_0, NULL); + abts_run_test(suite, clear_all_signalled, NULL); + abts_run_test(suite, send_large_pollarray, NULL); + abts_run_test(suite, recv_large_pollarray, NULL); +#endif + + abts_run_test(suite, setup_pollset, NULL); + abts_run_test(suite, multi_event_pollset, NULL); + abts_run_test(suite, add_sockets_pollset, NULL); + abts_run_test(suite, nomessage_pollset, NULL); + abts_run_test(suite, send0_pollset, NULL); + abts_run_test(suite, recv0_pollset, NULL); + abts_run_test(suite, send_middle_pollset, NULL); + abts_run_test(suite, clear_middle_pollset, NULL); + abts_run_test(suite, send_last_pollset, NULL); + abts_run_test(suite, clear_last_pollset, NULL); + abts_run_test(suite, pollset_remove, NULL); + abts_run_test(suite, close_all_sockets, NULL); + abts_run_test(suite, create_all_sockets, NULL); + abts_run_test(suite, setup_pollcb, NULL); + abts_run_test(suite, trigger_pollcb, NULL); + abts_run_test(suite, timeout_pollcb, NULL); + abts_run_test(suite, timeout_pollin_pollcb, NULL); + abts_run_test(suite, pollset_wakeup, NULL); + abts_run_test(suite, pollcb_wakeup, NULL); + abts_run_test(suite, close_all_sockets, NULL); + abts_run_test(suite, pollset_default, NULL); + abts_run_test(suite, pollcb_default, NULL); + abts_run_test(suite, justsleep, NULL); + + return suite; +} + diff --git a/test/testpools.c b/test/testpools.c new file mode 100644 index 00000000000..8b00393893b --- /dev/null +++ b/test/testpools.c @@ -0,0 +1,164 @@ +/* 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_general.h" +#include "apr_pools.h" +#include "apr_errno.h" +#include "apr_file_io.h" +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#if APR_HAVE_UNISTD_H +#include <unistd.h> +#endif +#include "testutil.h" + +#define ALLOC_BYTES 1024 + +static apr_pool_t *pmain = NULL; +static apr_pool_t *pchild = NULL; + +static void alloc_bytes(abts_case *tc, void *data) +{ + int i; + char *alloc; + + alloc = apr_palloc(pmain, ALLOC_BYTES); + ABTS_PTR_NOTNULL(tc, alloc); + + for (i=0;i<ALLOC_BYTES;i++) { + char *ptr = alloc + i; + *ptr = 0xa; + } + /* This is just added to get the positive. If this test fails, the + * suite will seg fault. + */ + ABTS_TRUE(tc, 1); +} + +static void calloc_bytes(abts_case *tc, void *data) +{ + int i; + char *alloc; + + alloc = apr_pcalloc(pmain, ALLOC_BYTES); + ABTS_PTR_NOTNULL(tc, alloc); + + for (i=0;i<ALLOC_BYTES;i++) { + char *ptr = alloc + i; + ABTS_TRUE(tc, *ptr == '\0'); + } +} + +static void parent_pool(abts_case *tc, void *data) +{ + apr_status_t rv; + + rv = apr_pool_create(&pmain, NULL); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_PTR_NOTNULL(tc, pmain); +} + +static void child_pool(abts_case *tc, void *data) +{ + apr_status_t rv; + + rv = apr_pool_create(&pchild, pmain); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_PTR_NOTNULL(tc, pchild); +} + +static void test_ancestor(abts_case *tc, void *data) +{ + ABTS_INT_EQUAL(tc, 1, apr_pool_is_ancestor(pmain, pchild)); +} + +static void test_notancestor(abts_case *tc, void *data) +{ + ABTS_INT_EQUAL(tc, 0, apr_pool_is_ancestor(pchild, pmain)); +} + +static apr_status_t success_cleanup(void *data) +{ + return APR_SUCCESS; +} + +static char *checker_data = "Hello, world."; + +static apr_status_t checker_cleanup(void *data) +{ + return data == checker_data ? APR_SUCCESS : APR_EGENERAL; +} + +static void test_cleanups(abts_case *tc, void *data) +{ + apr_status_t rv; + int n; + + /* do this several times to test the cleanup freelist handling. */ + for (n = 0; n < 5; n++) { + apr_pool_cleanup_register(pchild, NULL, success_cleanup, + success_cleanup); + apr_pool_cleanup_register(pchild, checker_data, checker_cleanup, + success_cleanup); + apr_pool_cleanup_register(pchild, NULL, checker_cleanup, + success_cleanup); + + rv = apr_pool_cleanup_run(p, NULL, success_cleanup); + ABTS_ASSERT(tc, "nullop cleanup run OK", rv == APR_SUCCESS); + rv = apr_pool_cleanup_run(p, checker_data, checker_cleanup); + ABTS_ASSERT(tc, "cleanup passed correct data", rv == APR_SUCCESS); + rv = apr_pool_cleanup_run(p, NULL, checker_cleanup); + ABTS_ASSERT(tc, "cleanup passed correct data", rv == APR_EGENERAL); + + if (n == 2) { + /* clear the pool to check that works */ + apr_pool_clear(pchild); + } + + if (n % 2 == 0) { + /* throw another random cleanup into the mix */ + apr_pool_cleanup_register(pchild, NULL, + apr_pool_cleanup_null, + apr_pool_cleanup_null); + } + } +} + +static void test_tags(abts_case *tc, void *data) +{ + ABTS_PTR_EQUAL(tc, NULL, apr_pool_get_tag(pmain)); + apr_pool_tag(pmain, "main pool"); + ABTS_STR_EQUAL(tc, "main pool", apr_pool_get_tag(pmain)); +} + +abts_suite *testpool(abts_suite *suite) +{ + suite = ADD_SUITE(suite) + + abts_run_test(suite, parent_pool, NULL); + abts_run_test(suite, child_pool, NULL); + abts_run_test(suite, test_ancestor, NULL); + abts_run_test(suite, test_notancestor, NULL); + abts_run_test(suite, alloc_bytes, NULL); + abts_run_test(suite, calloc_bytes, NULL); + abts_run_test(suite, test_cleanups, NULL); + abts_run_test(suite, test_tags, NULL); + + return suite; +} + diff --git a/test/testproc.c b/test/testproc.c index 74903d24672..c86fb2997b5 100644 --- a/test/testproc.c +++ b/test/testproc.c @@ -1,192 +1,174 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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_thread_proc.h" #include "apr_errno.h" #include "apr_general.h" #include "apr_lib.h" -#include "errno.h" -#ifndef WIN32 -#include <unistd.h> -#endif -#include <stdio.h> -#include <stdlib.h> -#include <signal.h> -#include <string.h> - -int test_filedel(void); -int testdirs(void); - -int main(int argc, char *argv[]) +#include "apr_strings.h" +#include "testutil.h" + +#define TESTSTR "This is a test" + +#define PROC_CHILD_NAME TESTBINPATH "proc_child" EXTENSION + +static char *proc_child; + +static apr_proc_t newproc; + +static void test_create_proc(abts_case *tc, void *data) { - ap_pool_t *context; - ap_proc_t *newproc; - ap_procattr_t *attr; - ap_file_t *testfile = NULL; - ap_ssize_t length; + const char *args[2]; + apr_procattr_t *attr; + apr_file_t *testfile = NULL; + apr_status_t rv; + apr_size_t length; char *buf; - char *args[3]; - char *teststr; - - if (ap_initialize() != APR_SUCCESS) { - fprintf(stderr, "Couldn't initialize."); - exit(-1); - } - atexit(ap_terminate); - ap_create_pool(&context, NULL); - - - if (argc > 1) { - teststr = ap_palloc(context, 256); - teststr = fgets(teststr, 256, stdin); - fprintf(stdout, "%s", teststr); - exit(1); - } - teststr = ap_pstrdup(context, "Whooo Hoooo\0"); - - fprintf(stdout, "Creating directory for later use......."); - if (ap_make_dir("proctest", APR_UREAD | APR_UWRITE | APR_UEXECUTE, context) != APR_SUCCESS) { - fprintf(stderr, "Could not create dir\n"); - exit(-1); - } - fprintf(stdout, "OK\n"); - - fprintf(stdout, "Creating procattr......."); - if (ap_createprocattr_init(&attr, context) != APR_SUCCESS) { - fprintf(stderr, "Could not create attr\n"); - exit(-1);; - } - fprintf(stdout, "OK.\n"); - - fprintf(stdout, "Setting attr pipes, all three......."); - if (ap_setprocattr_io(attr, APR_FULL_BLOCK, - APR_CHILD_BLOCK, APR_NO_PIPE) != APR_SUCCESS) { - fprintf(stderr, "Could not set pipes attr\n"); - exit(-1); - } - fprintf(stdout, "OK.\n"); - - fprintf(stdout, "Setting attr dir......."); - if (ap_setprocattr_dir(attr, "proctest") != APR_SUCCESS) { - fprintf(stderr, "Could not set directory attr\n"); - exit(-1); - } - fprintf(stdout, "OK.\n"); - - fprintf(stdout, "Setting attr cmd type......."); - if (ap_setprocattr_cmdtype(attr, APR_PROGRAM) != APR_SUCCESS) { - fprintf(stderr, "Could not set cmd type attr\n"); - exit(-1); - } - fprintf(stdout, "OK.\n"); - - args[0] = ap_pstrdup(context, "testproc"); - args[1] = ap_pstrdup(context, "-X"); - args[2] = NULL; + + rv = apr_procattr_create(&attr, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + rv = apr_procattr_io_set(attr, APR_FULL_BLOCK, APR_FULL_BLOCK, + APR_NO_PIPE); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + rv = apr_procattr_dir_set(attr, "data"); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + rv = apr_procattr_cmdtype_set(attr, APR_PROGRAM_ENV); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + args[0] = "proc_child" EXTENSION; + args[1] = NULL; - fprintf(stdout, "Creating a new process......."); - if (ap_create_process(&newproc, "../testproc", args, NULL, attr, context) != APR_SUCCESS) { - fprintf(stderr, "Could not create the new process\n"); - exit(-1); - } - fprintf(stdout, "OK.\n"); - - fprintf(stdout, "Grabbing child's stdin......."); - if (ap_get_childin(&testfile, newproc) != APR_SUCCESS) { - fprintf(stderr, "Could not get child's stdout\n"); - exit(-1); - } - fprintf(stdout, "OK.\n"); + rv = apr_proc_create(&newproc, proc_child, args, NULL, + attr, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + testfile = newproc.in; + + length = strlen(TESTSTR); + rv = apr_file_write(testfile, TESTSTR, &length); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_SIZE_EQUAL(tc, strlen(TESTSTR), length); + + testfile = newproc.out; length = 256; - fprintf(stdout, "Writing the data to child......."); - if (ap_write(testfile, teststr, &length) == APR_SUCCESS) { - fprintf(stdout,"OK\n"); - } - else fprintf(stderr, "Write failed.\n"); - - fprintf(stdout, "Grabbing child's stdout......."); - if (ap_get_childout(&testfile, newproc) != APR_SUCCESS) { - fprintf(stderr, "Could not get child's stdout\n"); - exit(-1); - } - fprintf(stdout, "OK.\n"); + buf = apr_pcalloc(p, length); + rv = apr_file_read(testfile, buf, &length); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_STR_EQUAL(tc, TESTSTR, buf); +} + +static void test_proc_wait(abts_case *tc, void *data) +{ + apr_status_t rv; + + rv = apr_proc_wait(&newproc, NULL, NULL, APR_WAIT); + ABTS_INT_EQUAL(tc, APR_CHILD_DONE, rv); +} + +static void test_file_redir(abts_case *tc, void *data) +{ + apr_file_t *testout = NULL; + apr_file_t *testerr = NULL; + apr_off_t offset; + apr_status_t rv; + const char *args[2]; + apr_procattr_t *attr; + apr_file_t *testfile = NULL; + apr_size_t length; + char *buf; + + testfile = NULL; + rv = apr_file_open(&testfile, "data/stdin", + APR_FOPEN_READ | APR_FOPEN_WRITE | APR_FOPEN_CREATE | APR_FOPEN_EXCL, + APR_FPROT_OS_DEFAULT, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + rv = apr_file_open(&testout, "data/stdout", + APR_FOPEN_READ | APR_FOPEN_WRITE | APR_FOPEN_CREATE | APR_FOPEN_EXCL, + APR_FPROT_OS_DEFAULT, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + rv = apr_file_open(&testerr, "data/stderr", + APR_FOPEN_READ | APR_FOPEN_WRITE | APR_FOPEN_CREATE | APR_FOPEN_EXCL, + APR_FPROT_OS_DEFAULT, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + length = strlen(TESTSTR); + apr_file_write(testfile, TESTSTR, &length); + offset = 0; + rv = apr_file_seek(testfile, APR_SET, &offset); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_ASSERT(tc, "File position mismatch, expected 0", offset == 0); + + rv = apr_procattr_create(&attr, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + rv = apr_procattr_child_in_set(attr, testfile, NULL); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + rv = apr_procattr_child_out_set(attr, testout, NULL); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + rv = apr_procattr_child_err_set(attr, testerr, NULL); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + rv = apr_procattr_dir_set(attr, "data"); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + rv = apr_procattr_cmdtype_set(attr, APR_PROGRAM_ENV); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + args[0] = "proc_child"; + args[1] = NULL; + + rv = apr_proc_create(&newproc, proc_child, args, NULL, + attr, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + rv = apr_proc_wait(&newproc, NULL, NULL, APR_WAIT); + ABTS_INT_EQUAL(tc, APR_CHILD_DONE, rv); + + offset = 0; + rv = apr_file_seek(testout, APR_SET, &offset); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); length = 256; - fprintf(stdout, "Checking the data read from pipe to child......."); - buf = ap_pcalloc(context, length); - if (ap_read(testfile, buf, &length) == APR_SUCCESS) { - if (!strcmp(buf, teststr)) - fprintf(stdout,"OK\n"); - else fprintf(stderr, "Uh-Oh\n"); - } - else fprintf(stderr, "Read failed.\n"); - - fprintf(stdout, "Waiting for child to die......."); - if (ap_wait_proc(newproc, APR_WAIT) != APR_CHILD_DONE) { - fprintf(stderr, "Wait for child failed\n"); - exit(-1); - } - fprintf(stdout, "OK\n"); - - fprintf(stdout, "Removing directory......."); - if (ap_remove_dir("proctest", context) != APR_SUCCESS) { - fprintf(stderr, "Could not remove directory.\n"); - exit(-1); - } - fprintf(stdout, "OK\n"); - - return(1); + buf = apr_pcalloc(p, length); + rv = apr_file_read(testout, buf, &length); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_STR_EQUAL(tc, TESTSTR, buf); + + + apr_file_close(testfile); + apr_file_close(testout); + apr_file_close(testerr); + + rv = apr_file_remove("data/stdin", p);; + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + rv = apr_file_remove("data/stdout", p);; + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + rv = apr_file_remove("data/stderr", p);; + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); +} + +abts_suite *testproc(abts_suite *suite) +{ + suite = ADD_SUITE(suite) + + apr_filepath_merge(&proc_child, NULL, PROC_CHILD_NAME, 0, p); + abts_run_test(suite, test_create_proc, NULL); + abts_run_test(suite, test_proc_wait, NULL); + abts_run_test(suite, test_file_redir, NULL); + + return suite; } diff --git a/test/testproc.dsp b/test/testproc.dsp deleted file mode 100644 index b0a547c8288..00000000000 --- a/test/testproc.dsp +++ /dev/null @@ -1,91 +0,0 @@ -# Microsoft Developer Studio Project File - Name="testproc" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 5.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Console Application" 0x0103 - -CFG=testproc - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "testproc.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "testproc.mak" CFG="testproc - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "testproc - Win32 Release" (based on\ - "Win32 (x86) Console Application") -!MESSAGE "testproc - Win32 Debug" (based on "Win32 (x86) Console Application") -!MESSAGE - -# Begin Project -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -RSC=rc.exe - -!IF "$(CFG)" == "testproc - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /W3 /GX /O2 /I "..\include" /I "..\..\include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD BASE RSC /l 0x409 /d "NDEBUG" -# ADD RSC /l 0x409 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 -# ADD LINK32 ..\Release\aprlib.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"..\Release\testproc.exe" - -!ELSEIF "$(CFG)" == "testproc - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "testproc" -# PROP BASE Intermediate_Dir "testproc" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "testproc" -# PROP Intermediate_Dir "testproc" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /I "..\include" /I "..\..\include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FD /c -# SUBTRACT CPP /YX /Yc /Yu -# ADD BASE RSC /l 0x409 /d "_DEBUG" -# ADD RSC /l 0x409 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept -# ADD LINK32 ..\Debug\aprlib.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"..\Debug\testproc.exe" /pdbtype:sept - -!ENDIF - -# Begin Target - -# Name "testproc - Win32 Release" -# Name "testproc - Win32 Debug" -# Begin Source File - -SOURCE=.\testproc.c -# End Source File -# End Target -# End Project diff --git a/test/testproc.rbb b/test/testproc.rbb deleted file mode 100644 index ac2c738bc44..00000000000 --- a/test/testproc.rbb +++ /dev/null @@ -1,148 +0,0 @@ -/* ==================================================================== - * Copyright (c) 2000 The Apache Software Foundation. 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 acknowledgment: - * "This product includes software developed by the Apache Software Foundation - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * 4. The names "Apache Server" and "Apache Software Foundation" must not be used to - * endorse or promote products derived from this software without - * prior written permission. For written permission, please contact - * apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache" - * nor may "Apache" appear in their names without prior written - * permission of the Apache Software Foundation. - * - * 6. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the Apache Software Foundation - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * THIS SOFTWARE IS PROVIDED BY THE Apache Software Foundation ``AS IS'' AND ANY - * EXPRESSED 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 Apache Software Foundation OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. - * For more information on the Apache Software Foundation and the Apache HTTP server - * project, please see <http://www.apache.org/>. - * - */ - -#include "apr_thread_proc.h" -#include "apr_errno.h" -#include "apr_general.h" -#include "apr_lib.h" -#include "errno.h" -#ifndef WIN32 -#include <unistd.h> -#endif -#include <stdio.h> -#include <signal.h> -#include <string.h> - -int test_filedel(void); -int testdirs(void); - -int main(int argc, char *argv[]) -{ - ap_context_t *context; - ap_proc_t *newproc; - ap_procattr_t *attr; - ap_file_t *testfile; - ap_ssize_t length; - char *buf; - char *args[3]; - char *teststr; - - ap_create_context(NULL, NULL, &context); - - teststr = ap_pstrdup(context, "Whooo Hoooo\n"); - - if (argc > 1) { - fprintf(stdout, "%s", teststr); - exit(1); - } - fprintf(stdout, "Creating procattr......."); - if (ap_createprocattr_init(context, &attr) != APR_SUCCESS) { - fprintf(stderr, "Could not create attr\n"); - exit(-1);; - } - fprintf(stdout, "OK.\n"); - - fprintf(stdout, "Setting attr pipes, all three......."); - if (ap_setprocattr_io(attr, 1, 1, 0) != APR_SUCCESS) { - fprintf(stderr, "Could not set pipes attr\n"); - exit(-1); - } - fprintf(stdout, "OK.\n"); - - fprintf(stdout, "Setting attr dir......."); - if (ap_setprocattr_dir(attr, "proctest") != APR_SUCCESS) { - fprintf(stderr, "Could not set directory attr\n"); - exit(-1); - } - fprintf(stdout, "OK.\n"); - - fprintf(stdout, "Setting attr cmd type......."); - if (ap_setprocattr_cmdtype(attr, APR_PROGRAM) != APR_SUCCESS) { - fprintf(stderr, "Could not set cmd type attr\n"); - exit(-1); - } - fprintf(stdout, "OK.\n"); - - args[0] = ap_pstrdup(context, "testproc"); - args[1] = ap_pstrdup(context, "-X"); - args[2] = NULL; - - fprintf(stdout, "Creating a new process......."); - if (ap_create_process(context, "../testproc", args, NULL, attr, &newproc) != APR_SUCCESS) { - fprintf(stderr, "Could not create the new process\n"); - exit(-1); - } - fprintf(stdout, "OK.\n"); - - fprintf(stdout, "Grabbing child's stdout......."); - if (ap_get_childout(newproc, &testfile) != APR_SUCCESS) { - fprintf(stderr, "Could not get child's stdout\n"); - exit(-1); - } - fprintf(stdout, "OK.\n"); - - length = 256; - fprintf(stdout, "Checking the data read from pipe to child......."); - buf = ap_pcalloc(context, length); - if (ap_read(testfile, buf, &length) == APR_SUCCESS) { - if (!strcmp(buf, teststr)) - fprintf(stdout,"OK\n"); - else fprintf(stderr, "Uh-Oh\n"); - } - else fprintf(stderr, "Read failed.\n"); - - return(1); -} - diff --git a/test/testprocmutex.c b/test/testprocmutex.c new file mode 100644 index 00000000000..24cc4418977 --- /dev/null +++ b/test/testprocmutex.c @@ -0,0 +1,287 @@ +/* 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_shm.h" +#include "apr_thread_proc.h" +#include "apr_file_io.h" +#include "apr_proc_mutex.h" +#include "apr_errno.h" +#include "apr_general.h" +#include "apr_strings.h" +#include "apr_getopt.h" +#include <stdio.h> +#include <stdlib.h> +#include "testutil.h" + +#if APR_HAS_FORK + +#define MAX_ITER 200 +#define CHILDREN 6 +#define MAX_COUNTER (MAX_ITER * CHILDREN) +#define MAX_WAIT_USEC (1000*1000) + +static apr_proc_mutex_t *proc_lock; +static volatile int *x; + +typedef struct lockmech { + apr_lockmech_e num; + const char *name; +} lockmech_t; + +/* a slower more racy way to implement (*x)++ */ +static int increment(int n) +{ + apr_sleep(1); + return n+1; +} + +static void make_child(abts_case *tc, int trylock, apr_proc_t **proc, apr_pool_t *p) +{ + apr_status_t rv; + + *proc = apr_pcalloc(p, sizeof(**proc)); + + /* slight delay to allow things to settle */ + apr_sleep (1); + + rv = apr_proc_fork(*proc, p); + if (rv == APR_INCHILD) { + int i = 0; + /* The parent process has setup all processes to call apr_terminate + * at exit. But, that means that all processes must also call + * apr_initialize at startup. You cannot have an unequal number + * of apr_terminate and apr_initialize calls. If you do, bad things + * will happen. In this case, the bad thing is that if the mutex + * is a semaphore, it will be destroyed before all of the processes + * die. That means that the test will most likely fail. + */ + apr_initialize(); + + if (apr_proc_mutex_child_init(&proc_lock, NULL, p)) + exit(1); + + do { + if (trylock > 0) { + int wait_usec = 0; + + while ((rv = apr_proc_mutex_trylock(proc_lock))) { + if (!APR_STATUS_IS_EBUSY(rv)) + exit(1); + if (++wait_usec >= MAX_WAIT_USEC) + exit(1); + apr_sleep(1); + } + } + else if (trylock < 0) { + int wait_usec = 0; + + while ((rv = apr_proc_mutex_timedlock(proc_lock, 1))) { + if (!APR_STATUS_IS_TIMEUP(rv)) + exit(1); + if (++wait_usec >= MAX_WAIT_USEC) + exit(1); + } + } + else { + if (apr_proc_mutex_lock(proc_lock)) + exit(1); + } + + i++; + *x = increment(*x); + if (apr_proc_mutex_unlock(proc_lock)) + exit(1); + } while (i < MAX_ITER); + exit(0); + } + + ABTS_ASSERT(tc, "fork failed", rv == APR_INPARENT); +} + +/* Wait for a child process and check it terminated with success. */ +static void await_child(abts_case *tc, apr_proc_t *proc) +{ + int code; + apr_exit_why_e why; + apr_status_t rv; + + rv = apr_proc_wait(proc, &code, &why, APR_WAIT); + ABTS_ASSERT(tc, "child did not terminate with success", + rv == APR_CHILD_DONE && why == APR_PROC_EXIT && code == 0); +} + +static void test_exclusive(abts_case *tc, const char *lockname, + lockmech_t *mech) +{ + apr_proc_t *child[CHILDREN]; + apr_status_t rv; + int n; + + rv = apr_proc_mutex_create(&proc_lock, lockname, mech->num, p); + APR_ASSERT_SUCCESS(tc, "create the mutex", rv); + + for (n = 0; n < CHILDREN; n++) + make_child(tc, 0, &child[n], p); + + for (n = 0; n < CHILDREN; n++) + await_child(tc, child[n]); + + ABTS_ASSERT(tc, "Locks don't appear to work", *x == MAX_COUNTER); + + rv = apr_proc_mutex_trylock(proc_lock); + if (rv == APR_ENOTIMPL) { + fprintf(stderr, "%s_trylock() not implemented, ", mech->name); + ABTS_ASSERT(tc, "Default timed trylock not implemented", + mech->num != APR_LOCK_DEFAULT && + mech->num != APR_LOCK_DEFAULT_TIMED); + } + else { + APR_ASSERT_SUCCESS(tc, "check for trylock", rv); + + for (n = 0; n < 2; n++) { + rv = apr_proc_mutex_trylock(proc_lock); + /* Some mech (eg. flock or fcntl) may succeed when the + * lock is re-acquired in the same process. + */ + if (rv != APR_SUCCESS) { + ABTS_ASSERT(tc, + apr_psprintf(p, "%s_trylock() should be busy => %pm", + mech->name, &rv), + APR_STATUS_IS_EBUSY(rv)); + } + } + + rv = apr_proc_mutex_unlock(proc_lock); + APR_ASSERT_SUCCESS(tc, "unlock after trylock check", rv); + + *x = 0; + + for (n = 0; n < CHILDREN; n++) + make_child(tc, 1, &child[n], p); + + for (n = 0; n < CHILDREN; n++) + await_child(tc, child[n]); + + ABTS_ASSERT(tc, "Locks don't appear to work with trylock", + *x == MAX_COUNTER); + } + + rv = apr_proc_mutex_timedlock(proc_lock, 1); + if (rv == APR_ENOTIMPL) { + fprintf(stderr, "%s_timedlock() not implemented, ", mech->name); + ABTS_ASSERT(tc, "Default timed timedlock not implemented", + mech->num != APR_LOCK_DEFAULT_TIMED); + } + else { + APR_ASSERT_SUCCESS(tc, "check for timedlock", rv); + + for (n = 0; n < 2; n++) { + rv = apr_proc_mutex_timedlock(proc_lock, 1); + /* Some mech (eg. flock or fcntl) may succeed when the + * lock is re-acquired in the same process. + */ + if (rv != APR_SUCCESS) { + ABTS_ASSERT(tc, + apr_psprintf(p, "%s_timedlock() should time out => %pm", + mech->name, &rv), + APR_STATUS_IS_TIMEUP(rv)); + } + } + + rv = apr_proc_mutex_unlock(proc_lock); + APR_ASSERT_SUCCESS(tc, "unlock after timedlock check", rv); + + *x = 0; + + for (n = 0; n < CHILDREN; n++) + make_child(tc, -1, &child[n], p); + + for (n = 0; n < CHILDREN; n++) + await_child(tc, child[n]); + + ABTS_ASSERT(tc, "Locks don't appear to work with timedlock", + *x == MAX_COUNTER); + } +} + +static void proc_mutex(abts_case *tc, void *data) +{ + apr_status_t rv; + const char *shmname = "tpm.shm"; + apr_shm_t *shm; + + /* Use anonymous shm if available. */ + rv = apr_shm_create(&shm, sizeof(int), NULL, p); + if (rv == APR_ENOTIMPL) { + apr_file_remove(shmname, p); + rv = apr_shm_create(&shm, sizeof(int), shmname, p); + } + + APR_ASSERT_SUCCESS(tc, "create shm segment", rv); + if (rv != APR_SUCCESS) + return; + + x = apr_shm_baseaddr_get(shm); + test_exclusive(tc, NULL, data); + rv = apr_shm_destroy(shm); + APR_ASSERT_SUCCESS(tc, "Error destroying shared memory block", rv); +} + + +abts_suite *testprocmutex(abts_suite *suite) +{ + lockmech_t lockmechs[] = { + {APR_LOCK_DEFAULT, "default"} +#if APR_HAS_FLOCK_SERIALIZE + ,{APR_LOCK_FLOCK, "flock"} +#endif +#if APR_HAS_SYSVSEM_SERIALIZE + ,{APR_LOCK_SYSVSEM, "sysvsem"} +#endif +#if APR_HAS_POSIXSEM_SERIALIZE + ,{APR_LOCK_POSIXSEM, "posix"} +#endif +#if APR_HAS_FCNTL_SERIALIZE + ,{APR_LOCK_FCNTL, "fcntl"} +#endif +#if APR_HAS_PROC_PTHREAD_SERIALIZE + ,{APR_LOCK_PROC_PTHREAD, "proc_pthread"} +#endif + ,{APR_LOCK_DEFAULT_TIMED, "default_timed"} + }; + int i; + + suite = ADD_SUITE(suite) + for (i = 0; i < sizeof(lockmechs) / sizeof(lockmechs[0]); i++) { + abts_run_test(suite, proc_mutex, &lockmechs[i]); + } + return suite; +} + +#else /* APR_HAS_FORK */ + +static void proc_mutex(abts_case *tc, void *data) +{ + ABTS_NOT_IMPL(tc, "APR lacks fork() support"); +} + +abts_suite *testprocmutex(abts_suite *suite) +{ + suite = ADD_SUITE(suite); + abts_run_test(suite, proc_mutex, NULL); + return suite; +} +#endif /* APR_HAS_FORK */ diff --git a/test/testqueue.c b/test/testqueue.c new file mode 100644 index 00000000000..264e4d3a1cd --- /dev/null +++ b/test/testqueue.c @@ -0,0 +1,185 @@ +/* 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 "apu.h" +#include "apr_queue.h" +#include "apr_thread_pool.h" +#include "apr_time.h" +#include "abts.h" +#include "testutil.h" + +#if APR_HAS_THREADS + +#define NUMBER_CONSUMERS 3 +#define CONSUMER_ACTIVITY 4 +#define NUMBER_PRODUCERS 4 +#define PRODUCER_ACTIVITY 5 +#define QUEUE_SIZE 100 + +static apr_queue_t *queue; + +static void * APR_THREAD_FUNC consumer(apr_thread_t *thd, void *data) +{ + long sleeprate; + abts_case *tc = data; + apr_status_t rv; + void *v; + + sleeprate = 1000000/CONSUMER_ACTIVITY; + apr_sleep((rand() % 4) * 1000000); /* sleep random seconds */ + + while (1) + { + rv = apr_queue_pop(queue, &v); + + if (rv == APR_EINTR) + continue; + + if (rv == APR_EOF) + break; + + ABTS_TRUE(tc, v == NULL); + ABTS_TRUE(tc, rv == APR_SUCCESS); + + apr_sleep(sleeprate); /* sleep this long to acheive our rate */ + } + + return NULL; +} + +static void * APR_THREAD_FUNC producer(apr_thread_t *thd, void *data) +{ + long sleeprate; + abts_case *tc = data; + apr_status_t rv; + + sleeprate = 1000000/PRODUCER_ACTIVITY; + apr_sleep((rand() % 4) * 1000000); /* sleep random seconds */ + + while (1) + { + rv = apr_queue_push(queue, NULL); + + if (rv == APR_EINTR) + continue; + + if (rv == APR_EOF) + break; + + ABTS_TRUE(tc, rv == APR_SUCCESS); + + apr_sleep(sleeprate); /* sleep this long to acheive our rate */ + } + + return NULL; +} + +static void test_queue_producer_consumer(abts_case *tc, void *data) +{ + unsigned int i; + apr_status_t rv; + apr_thread_pool_t *thrp; + + /* XXX: non-portable */ + srand((unsigned int)apr_time_now()); + + rv = apr_queue_create(&queue, QUEUE_SIZE, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + rv = apr_thread_pool_create(&thrp, 0, NUMBER_CONSUMERS + NUMBER_PRODUCERS, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + for (i = 0; i < NUMBER_CONSUMERS; i++) { + rv = apr_thread_pool_push(thrp, consumer, tc, 0, NULL); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + } + + for (i = 0; i < NUMBER_PRODUCERS; i++) { + rv = apr_thread_pool_push(thrp, producer, tc, 0, NULL); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + } + + apr_sleep(5000000); /* sleep 5 seconds */ + + rv = apr_queue_term(queue); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + rv = apr_thread_pool_destroy(thrp); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); +} + +static void test_queue_timeout(abts_case *tc, void *data) +{ + apr_queue_t *q; + apr_status_t rv; + apr_time_t start; + unsigned int i; + void *value; + + rv = apr_queue_create(&q, 5, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + for (i = 0; i < 2; ++i) { + rv = apr_queue_timedpush(q, NULL, apr_time_from_msec(1)); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + } + for (i = 0; i < 3; ++i) { + rv = apr_queue_trypush(q, NULL); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + } + + start = apr_time_now(); + rv = apr_queue_timedpush(q, NULL, apr_time_from_msec(1)); + ABTS_TRUE(tc, APR_STATUS_IS_TIMEUP(rv)); + ABTS_TRUE(tc, apr_time_now() - start >= apr_time_from_msec(1)); + + rv = apr_queue_trypush(q, NULL); + ABTS_TRUE(tc, APR_STATUS_IS_EAGAIN(rv)); + + for (i = 0; i < 2; ++i) { + rv = apr_queue_timedpop(q, &value, apr_time_from_msec(1)); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + } + for (i = 0; i < 3; ++i) { + rv = apr_queue_trypop(q, &value); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + } + + start = apr_time_now(); + rv = apr_queue_timedpop(q, &value, apr_time_from_sec(1)); + ABTS_TRUE(tc, APR_STATUS_IS_TIMEUP(rv)); + ABTS_TRUE(tc, apr_time_now() - start >= apr_time_from_msec(1)); + + rv = apr_queue_trypop(q, &value); + ABTS_TRUE(tc, APR_STATUS_IS_EAGAIN(rv)); + + rv = apr_queue_term(q); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); +} + +#endif /* APR_HAS_THREADS */ + +abts_suite *testqueue(abts_suite *suite) +{ + suite = ADD_SUITE(suite); + +#if APR_HAS_THREADS + abts_run_test(suite, test_queue_producer_consumer, NULL); + abts_run_test(suite, test_queue_timeout, NULL); +#endif /* APR_HAS_THREADS */ + + return suite; +} diff --git a/test/testrand.c b/test/testrand.c new file mode 100644 index 00000000000..46c55d29f79 --- /dev/null +++ b/test/testrand.c @@ -0,0 +1,359 @@ +/* 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_general.h" +#include "apr_pools.h" +#include "apr_random.h" +#include "apr_thread_proc.h" +#include <stdio.h> +#include <stdlib.h> +#include "testutil.h" + +#define RANDOM_BUF_SZ 128 + +static void hexdump(const char *msg, const unsigned char *b, int n) +{ + int i; + + printf("\n%s", msg); + for (i = 0; i < n; ++i) { +#if 0 + if ((i & 0xf) == 0) + printf("%04x", i); + printf(" %02x", b[i]); + if ((i & 0xf) == 0xf) + printf("\n"); +#else + printf("0x%02x,", b[i]); + if ((i & 7) == 7) + printf("\n"); +#endif + } + printf("\n"); +} + +static apr_random_t *r; + +typedef apr_status_t APR_THREAD_FUNC rnd_fn(apr_random_t * r, void *b, + apr_size_t n); + +static void rand_run_kat(abts_case *tc, rnd_fn *f, apr_random_t *r, + const unsigned char expected[RANDOM_BUF_SZ]) +{ + unsigned char c[RANDOM_BUF_SZ]; + apr_status_t rv; + + rv = f(r, c, RANDOM_BUF_SZ); + ABTS_INT_EQUAL(tc, 0, rv); + if (rv) + return; + if (memcmp(c, expected, RANDOM_BUF_SZ)) { + hexdump("Generated: ", c, RANDOM_BUF_SZ); + hexdump("Expected: ", expected, RANDOM_BUF_SZ); + ABTS_FAIL(tc, "Randomness mismatch"); + } +} + +#if APR_HAS_FORK +static int rand_check_kat(rnd_fn *f, apr_random_t *r, + const unsigned char expected[RANDOM_BUF_SZ], + apr_file_t *readp, apr_file_t *writep) +{ + apr_size_t nbytes = RANDOM_BUF_SZ; + apr_size_t cmd_size = 1; + unsigned char c[RANDOM_BUF_SZ]; + char ack; + apr_status_t rv; + + rv = f(r, c, RANDOM_BUF_SZ); + if (rv) + return 2; + rv = 0; + if (memcmp(c, expected, RANDOM_BUF_SZ)) { + rv = 1; + } else { + hexdump("Generated: ", c, RANDOM_BUF_SZ); + hexdump("Previous: ", expected, RANDOM_BUF_SZ); + } + /* Report back our random values for comparison in another child */ + apr_file_write(writep, c, &nbytes); + /* Wait for our parent ack the data */ + apr_file_read(readp, &ack, &cmd_size); + return rv; +} +#endif + +static void rand_add_zeroes(apr_random_t *r) +{ + static unsigned char c[2048]; + + apr_random_add_entropy(r, c, sizeof c); +} + +static void rand_run_seed_short(abts_case *tc, rnd_fn *f, apr_random_t *r, + int count) +{ + int i; + apr_status_t rv; + char c[1]; + + for (i = 0; i < count; ++i) + rand_add_zeroes(r); + rv = f(r, c, 1); + ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_ENOTENOUGHENTROPY(rv)); +} + +static void rand_seed_short(abts_case *tc, void *data) +{ + r = apr_random_standard_new(p); + rand_run_seed_short(tc, apr_random_insecure_bytes, r, 32); +} + +static void rand_kat(abts_case *tc, void *data) +{ + unsigned char expected[RANDOM_BUF_SZ] = { + 0x82, 0x04, 0xad, 0xd2, 0x0b, 0xd5, 0xac, 0xda, + 0x3d, 0x85, 0x58, 0x38, 0x54, 0x6b, 0x69, 0x45, + 0x37, 0x4c, 0xc7, 0xd7, 0x87, 0xeb, 0xbf, 0xd9, + 0xb1, 0xb8, 0xb8, 0x2d, 0x9b, 0x33, 0x6e, 0x97, + 0x04, 0x1d, 0x4c, 0xb0, 0xd1, 0xdf, 0x3d, 0xac, + 0xd2, 0xaa, 0xfa, 0xcd, 0x96, 0xb7, 0xcf, 0xb1, + 0x8e, 0x3d, 0xb3, 0xe5, 0x37, 0xa9, 0x95, 0xb4, + 0xaa, 0x3d, 0x11, 0x1a, 0x08, 0x20, 0x21, 0x9f, + 0xdb, 0x08, 0x3a, 0xb9, 0x57, 0x9f, 0xf2, 0x1f, + 0x27, 0xdc, 0xb6, 0xc0, 0x85, 0x08, 0x05, 0xbb, + 0x13, 0xbe, 0xb1, 0xe9, 0x63, 0x2a, 0xe2, 0xa4, + 0x23, 0x15, 0x2a, 0x10, 0xbf, 0xdf, 0x09, 0xb3, + 0xc7, 0xfb, 0x2d, 0x87, 0x48, 0x19, 0xfb, 0xc0, + 0x15, 0x8c, 0xcb, 0xc6, 0xbd, 0x89, 0x38, 0x69, + 0xa3, 0xae, 0xa3, 0x21, 0x58, 0x50, 0xe7, 0xc4, + 0x87, 0xec, 0x2e, 0xb1, 0x2d, 0x6a, 0xbd, 0x46 + }; + + rand_add_zeroes(r); + rand_run_kat(tc, apr_random_insecure_bytes, r, expected); +} + +static void rand_seed_short2(abts_case *tc, void *data) +{ + rand_run_seed_short(tc, apr_random_secure_bytes, r, 320); +} + +static void rand_kat2(abts_case *tc, void *data) +{ + unsigned char expected[RANDOM_BUF_SZ] = { + 0x38, 0x8f, 0x01, 0x29, 0x5a, 0x5c, 0x1f, 0xa8, + 0x00, 0xde, 0x16, 0x4c, 0xe5, 0xf7, 0x1f, 0x58, + 0xc0, 0x67, 0xe2, 0x98, 0x3d, 0xde, 0x4a, 0x75, + 0x61, 0x3f, 0x23, 0xd8, 0x45, 0x7a, 0x10, 0x60, + 0x59, 0x9b, 0xd6, 0xaf, 0xcb, 0x0a, 0x2e, 0x34, + 0x9c, 0x39, 0x5b, 0xd0, 0xbc, 0x9a, 0xf0, 0x7b, + 0x7f, 0x40, 0x8b, 0x33, 0xc0, 0x0e, 0x2a, 0x56, + 0xfc, 0xe5, 0xab, 0xde, 0x7b, 0x13, 0xf5, 0xec, + 0x15, 0x68, 0xb8, 0x09, 0xbc, 0x2c, 0x15, 0xf0, + 0x7b, 0xef, 0x2a, 0x97, 0x19, 0xa8, 0x69, 0x51, + 0xdf, 0xb0, 0x5f, 0x1a, 0x4e, 0xdf, 0x42, 0x02, + 0x71, 0x36, 0xa7, 0x25, 0x64, 0x85, 0xe2, 0x72, + 0xc7, 0x87, 0x4d, 0x7d, 0x15, 0xbb, 0x15, 0xd1, + 0xb1, 0x62, 0x0b, 0x25, 0xd9, 0xd3, 0xd9, 0x5a, + 0xe3, 0x47, 0x1e, 0xae, 0x67, 0xb4, 0x19, 0x9e, + 0xed, 0xd2, 0xde, 0xce, 0x18, 0x70, 0x57, 0x12 + }; + + rand_add_zeroes(r); + rand_run_kat(tc, apr_random_secure_bytes, r, expected); +} + +static void rand_barrier(abts_case *tc, void *data) +{ + apr_random_barrier(r); + rand_run_seed_short(tc, apr_random_secure_bytes, r, 320); +} + +static void rand_kat3(abts_case *tc, void *data) +{ + unsigned char expected[RANDOM_BUF_SZ] = { + 0xe8, 0xe7, 0xc9, 0x45, 0xe2, 0x2a, 0x54, 0xb2, + 0xdd, 0xe0, 0xf9, 0xbc, 0x3d, 0xf9, 0xce, 0x3c, + 0x4c, 0xbd, 0xc9, 0xe2, 0x20, 0x4a, 0x35, 0x1c, + 0x04, 0x52, 0x7f, 0xb8, 0x0f, 0x60, 0x89, 0x63, + 0x8a, 0xbe, 0x0a, 0x44, 0xac, 0x5d, 0xd8, 0xeb, + 0x24, 0x7d, 0xd1, 0xda, 0x4d, 0x86, 0x9b, 0x94, + 0x26, 0x56, 0x4a, 0x5e, 0x30, 0xea, 0xd4, 0xa9, + 0x9a, 0xdf, 0xdd, 0xb6, 0xb1, 0x15, 0xe0, 0xfa, + 0x28, 0xa4, 0xd6, 0x95, 0xa4, 0xf1, 0xd8, 0x6e, + 0xeb, 0x8c, 0xa4, 0xac, 0x34, 0xfe, 0x06, 0x92, + 0xc5, 0x09, 0x99, 0x86, 0xdc, 0x5a, 0x3c, 0x92, + 0xc8, 0x3e, 0x52, 0x00, 0x4d, 0x01, 0x43, 0x6f, + 0x69, 0xcf, 0xe2, 0x60, 0x9c, 0x23, 0xb3, 0xa5, + 0x5f, 0x51, 0x47, 0x8c, 0x07, 0xde, 0x60, 0xc6, + 0x04, 0xbf, 0x32, 0xd6, 0xdc, 0xb7, 0x31, 0x01, + 0x29, 0x51, 0x51, 0xb3, 0x19, 0x6e, 0xe4, 0xf8 + }; + + rand_run_kat(tc, apr_random_insecure_bytes, r, expected); +} + +static void rand_kat4(abts_case *tc, void *data) +{ + unsigned char expected[RANDOM_BUF_SZ] = { + 0x7d, 0x0e, 0xc4, 0x4e, 0x3e, 0xac, 0x86, 0x50, + 0x37, 0x95, 0x7a, 0x98, 0x23, 0x26, 0xa7, 0xbf, + 0x60, 0xfb, 0xa3, 0x70, 0x90, 0xc3, 0x58, 0xc6, + 0xbd, 0xd9, 0x5e, 0xa6, 0x77, 0x62, 0x7a, 0x5c, + 0x96, 0x83, 0x7f, 0x80, 0x3d, 0xf4, 0x9c, 0xcc, + 0x9b, 0x0c, 0x8c, 0xe1, 0x72, 0xa8, 0xfb, 0xc9, + 0xc5, 0x43, 0x91, 0xdc, 0x9d, 0x92, 0xc2, 0xce, + 0x1c, 0x5e, 0x36, 0xc7, 0x87, 0xb1, 0xb4, 0xa3, + 0xc8, 0x69, 0x76, 0xfc, 0x35, 0x75, 0xcb, 0x08, + 0x2f, 0xe3, 0x98, 0x76, 0x37, 0x80, 0x04, 0x5c, + 0xb8, 0xb0, 0x7f, 0xb2, 0xda, 0xe3, 0xa3, 0xba, + 0xed, 0xff, 0xf5, 0x9d, 0x3b, 0x7b, 0xf3, 0x32, + 0x6c, 0x50, 0xa5, 0x3e, 0xcc, 0xe1, 0x84, 0x9c, + 0x17, 0x9e, 0x80, 0x64, 0x09, 0xbb, 0x62, 0xf1, + 0x95, 0xf5, 0x2c, 0xc6, 0x9f, 0x6a, 0xee, 0x6d, + 0x17, 0x35, 0x5f, 0x35, 0x8d, 0x55, 0x0c, 0x07 + }; + + rand_add_zeroes(r); + rand_run_kat(tc, apr_random_secure_bytes, r, expected); +} + +#if APR_HAS_FORK +static void rand_fork(abts_case *tc, void *data) +{ + apr_proc_t proc; + apr_status_t rv; + apr_size_t nbytes = RANDOM_BUF_SZ; + apr_size_t cmd_size = 1; + char cmd = 'X'; + unsigned char expected[RANDOM_BUF_SZ] = { + 0xac, 0x93, 0xd2, 0x5c, 0xc7, 0xf5, 0x8d, 0xc2, + 0xd8, 0x8d, 0xb6, 0x7a, 0x94, 0xe1, 0x83, 0x4c, + 0x26, 0xe2, 0x38, 0x6d, 0xf5, 0xbd, 0x9d, 0x6e, + 0x91, 0x77, 0x3a, 0x4b, 0x9b, 0xef, 0x9b, 0xa3, + 0x9f, 0xf6, 0x6d, 0x0c, 0xdc, 0x4b, 0x02, 0xe9, + 0x5d, 0x3d, 0xfc, 0x92, 0x6b, 0xdf, 0xc9, 0xef, + 0xb9, 0xa8, 0x74, 0x09, 0xa3, 0xff, 0x64, 0x8d, + 0x19, 0xc1, 0x31, 0x31, 0x17, 0xe1, 0xb7, 0x7a, + 0xe7, 0x55, 0x14, 0x92, 0x05, 0xe3, 0x1e, 0xb8, + 0x9b, 0x1b, 0xdc, 0xac, 0x0e, 0x15, 0x08, 0xa2, + 0x93, 0x13, 0xf6, 0x04, 0xc6, 0x9d, 0xf8, 0x7f, + 0x26, 0x32, 0x68, 0x43, 0x2e, 0x5a, 0x4f, 0x47, + 0xe8, 0xf8, 0x59, 0xb7, 0xfb, 0xbe, 0x30, 0x04, + 0xb6, 0x63, 0x6f, 0x19, 0xf3, 0x2c, 0xd4, 0xeb, + 0x32, 0x8a, 0x54, 0x01, 0xd0, 0xaf, 0x3f, 0x13, + 0xc1, 0x7f, 0x10, 0x2e, 0x08, 0x1c, 0x28, 0x4b, + }; + + apr_file_t *readdatap = NULL; + apr_file_t *writedatap = NULL; + apr_file_t *readcmdp = NULL; + apr_file_t *writecmdp = NULL; + apr_pool_t *p; + int i; + + apr_pool_create(&p, NULL); + /* Set up data pipe for children */ + rv = apr_file_pipe_create(&readdatap, &writedatap, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_PTR_NOTNULL(tc, readdatap); + ABTS_PTR_NOTNULL(tc, writedatap); + /* Set up cmd pipe for children */ + rv = apr_file_pipe_create(&readcmdp, &writecmdp, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_PTR_NOTNULL(tc, readcmdp); + ABTS_PTR_NOTNULL(tc, writecmdp); + + rand_run_kat(tc, apr_random_secure_bytes, r, expected); + + for (i = 0; i< 10; i++) + { + rv = apr_proc_fork(&proc, p); + if (rv == APR_INCHILD) { + int n = rand_check_kat(apr_random_secure_bytes, r, expected, readcmdp, writedatap); + exit(n); + } + else if (rv == APR_INPARENT) { + int exitcode; + apr_exit_why_e why; + + /* Read the random data generated by child */ + rv = apr_file_read(readdatap, expected, &nbytes); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + /* Tell child to finish */ + rv = apr_file_write(writecmdp, &cmd, &cmd_size); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + apr_proc_wait(&proc, &exitcode, &why, APR_WAIT); + if (why != APR_PROC_EXIT) { + ABTS_FAIL(tc, "Child terminated abnormally"); + } + else if (exitcode == 0) { + if (i == 0) + { + ABTS_FAIL(tc, "Child produced our randomness"); + } else + { + ABTS_FAIL(tc, "Child produced randomness of previous child"); + } + } + else if (exitcode == 2) { + ABTS_FAIL(tc, "Child randomness failed"); + } + else if (exitcode != 1) { + ABTS_FAIL(tc, "Unknown child error"); + } + } else { + ABTS_FAIL(tc, "Fork failed"); + } + } + +} +#endif + +static void rand_exists(abts_case *tc, void *data) +{ +#if !APR_HAS_RANDOM + ABTS_NOT_IMPL(tc, "apr_generate_random_bytes"); +#else + unsigned char c[42]; + + /* There must be a better way to test random-ness, but I don't know + * what it is right now. + */ + APR_ASSERT_SUCCESS(tc, "apr_generate_random_bytes failed", + apr_generate_random_bytes(c, sizeof c)); +#endif +} + +abts_suite *testrand(abts_suite *suite) +{ + suite = ADD_SUITE(suite) + + abts_run_test(suite, rand_exists, NULL); + abts_run_test(suite, rand_seed_short, NULL); + abts_run_test(suite, rand_kat, NULL); + abts_run_test(suite, rand_seed_short2, NULL); + abts_run_test(suite, rand_kat2, NULL); + abts_run_test(suite, rand_barrier, NULL); + abts_run_test(suite, rand_kat3, NULL); + abts_run_test(suite, rand_kat4, NULL); +#if APR_HAS_FORK + abts_run_test(suite, rand_fork, NULL); +#endif + + return suite; +} diff --git a/test/testredis.c b/test/testredis.c new file mode 100644 index 00000000000..4b654322f54 --- /dev/null +++ b/test/testredis.c @@ -0,0 +1,552 @@ +/* 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 "testutil.h" +#include "apr.h" +#include "apu.h" +#include "apr_general.h" +#include "apr_strings.h" +#include "apr_hash.h" +#include "apr_redis.h" +#include "apr_network_io.h" + +#include <stdio.h> +#if APR_HAVE_STDLIB_H +#include <stdlib.h> /* for exit() */ +#endif + +#define HOST "localhost" +#define PORT 6379 + +/* the total number of items to use for set/get testing */ +#define TDATA_SIZE 3000 + +/* some smaller subset of TDATA_SIZE used for multiget testing */ +#define TDATA_SET 100 + +/* our custom hash function just returns this all the time */ +#define HASH_FUNC_RESULT 510 + +/* all keys will be prefixed with this */ +static const char prefix[] = "testredis"; + +/* text for values we store */ +static const char txt[] = +"Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Duis at" +"lacus in ligula hendrerit consectetuer. Vestibulum tristique odio" +"iaculis leo. In massa arcu, ultricies a, laoreet nec, hendrerit non," +"neque. Nulla sagittis sapien ac risus. Morbi ligula dolor, vestibulum" +"nec, viverra id, placerat dapibus, arcu. Curabitur egestas feugiat" +"tellus. Donec dignissim. Nunc ante. Curabitur id lorem. In mollis" +"tortor sit amet eros auctor dapibus. Proin nulla sem, tristique in," +"convallis id, iaculis feugiat cras amet."; + +/* + * this datatype is for our custom server determination function. this might + * be useful if you don't want to rely on simply hashing keys to determine + * where a key belongs, but instead want to write something fancy, or use some + * other kind of configuration data, i.e. a hash plus some data about a + * namespace, or whatever. see my_server_func, and test_redis_user_funcs + * for the examples. + */ +typedef struct { + const char *someval; + apr_uint32_t which_server; +} my_hash_server_baton; + + +/* this could do something fancy and return some hash result. + * for simplicity, just return the same value, so we can test it later on. + * if you wanted to use some external hashing library or functions for + * consistent hashing, for example, this would be a good place to do it. + */ +static apr_uint32_t my_hash_func(void *baton, const char *data, + apr_size_t data_len) +{ + + return HASH_FUNC_RESULT; +} + +/* + * a fancy function to determine which server to use given some kind of data + * and a hash value. this example actually ignores the hash value itself + * and pulls some number from the *baton, which is a struct that has some + * kind of meaningful stuff in it. + */ +static apr_redis_server_t *my_server_func(void *baton, + apr_redis_t *mc, + const apr_uint32_t hash) +{ + apr_redis_server_t *ms = NULL; + my_hash_server_baton *mhsb = (my_hash_server_baton *)baton; + + if(mc->ntotal == 0) { + return NULL; + } + + if(mc->ntotal < mhsb->which_server) { + return NULL; + } + + ms = mc->live_servers[mhsb->which_server - 1]; + + return ms; +} + +static apr_uint16_t firsttime = 0; +static int randval(apr_uint32_t high) +{ + apr_uint32_t i = 0; + double d = 0; + + if (firsttime == 0) { + srand((unsigned) (getpid())); + firsttime = 1; + } + + d = (double) rand() / ((double) RAND_MAX + 1); + i = (int) (d * (high - 0 + 1)); + + return i > 0 ? i : 1; +} + +/* + * general test to make sure we can create the redis struct and add + * some servers, but not more than we tell it we can add + */ + +static void test_redis_create(abts_case * tc, void *data) +{ + apr_pool_t *pool = p; + apr_status_t rv; + apr_redis_t *redis; + apr_redis_server_t *server, *s; + apr_uint32_t max_servers = 10; + apr_uint32_t i; + apr_uint32_t hash; + + rv = apr_redis_create(pool, max_servers, 0, &redis); + ABTS_ASSERT(tc, "redis create failed", rv == APR_SUCCESS); + + for (i = 1; i <= max_servers; i++) { + apr_port_t port; + + port = PORT + i; + rv = + apr_redis_server_create(pool, HOST, PORT + i, 0, 1, 1, 60, 60, &server); + ABTS_ASSERT(tc, "server create failed", rv == APR_SUCCESS); + + rv = apr_redis_add_server(redis, server); + ABTS_ASSERT(tc, "server add failed", rv == APR_SUCCESS); + + s = apr_redis_find_server(redis, HOST, port); + ABTS_PTR_EQUAL(tc, server, s); + + rv = apr_redis_disable_server(redis, s); + ABTS_ASSERT(tc, "server disable failed", rv == APR_SUCCESS); + + rv = apr_redis_enable_server(redis, s); + ABTS_ASSERT(tc, "server enable failed", rv == APR_SUCCESS); + + hash = apr_redis_hash(redis, prefix, strlen(prefix)); + ABTS_ASSERT(tc, "hash failed", hash > 0); + + s = apr_redis_find_server_hash(redis, hash); + ABTS_PTR_NOTNULL(tc, s); + } + + rv = apr_redis_server_create(pool, HOST, PORT, 0, 1, 1, 60, 60, &server); + ABTS_ASSERT(tc, "server create failed", rv == APR_SUCCESS); + + rv = apr_redis_add_server(redis, server); + ABTS_ASSERT(tc, "server add should have failed", rv != APR_SUCCESS); + +} + +/* install our own custom hashing and server selection routines. */ + +static int create_test_hash(apr_pool_t *p, apr_hash_t *h) +{ + int i; + + for (i = 0; i < TDATA_SIZE; i++) { + char *k, *v; + + k = apr_pstrcat(p, prefix, apr_itoa(p, i), NULL); + v = apr_pstrndup(p, txt, randval((apr_uint32_t)strlen(txt))); + + apr_hash_set(h, k, APR_HASH_KEY_STRING, v); + } + + return i; +} + +static void test_redis_user_funcs(abts_case * tc, void *data) +{ + apr_pool_t *pool = p; + apr_status_t rv; + apr_redis_t *redis; + apr_redis_server_t *found; + apr_uint32_t max_servers = 10; + apr_uint32_t hres; + apr_uint32_t i; + my_hash_server_baton *baton = + apr_pcalloc(pool, sizeof(my_hash_server_baton)); + + rv = apr_redis_create(pool, max_servers, 0, &redis); + ABTS_ASSERT(tc, "redis create failed", rv == APR_SUCCESS); + + /* as noted above, install our custom hash function, and call + * apr_redis_hash. the return value should be our predefined number, + * and our function just ignores the other args, for simplicity. + */ + redis->hash_func = my_hash_func; + + hres = apr_redis_hash(redis, "whatever", sizeof("whatever") - 1); + ABTS_INT_EQUAL(tc, HASH_FUNC_RESULT, hres); + + /* add some servers */ + for(i = 1; i <= 10; i++) { + apr_redis_server_t *ms; + + rv = apr_redis_server_create(pool, HOST, i, 0, 1, 1, 60, 60, &ms); + ABTS_ASSERT(tc, "server create failed", rv == APR_SUCCESS); + + rv = apr_redis_add_server(redis, ms); + ABTS_ASSERT(tc, "server add failed", rv == APR_SUCCESS); + } + + /* + * set 'which_server' in our server_baton to find the third server + * which should have the same port. + */ + baton->which_server = 3; + redis->server_func = my_server_func; + redis->server_baton = baton; + found = apr_redis_find_server_hash(redis, 0); + ABTS_ASSERT(tc, "wrong server found", found->port == baton->which_server); +} + +/* test non data related commands like stats and version */ +static void test_redis_meta(abts_case * tc, void *data) +{ + apr_pool_t *pool = p; + apr_redis_t *redis; + apr_redis_server_t *server; + apr_redis_stats_t *stats; + char *result; + apr_status_t rv; + + rv = apr_redis_create(pool, 1, 0, &redis); + ABTS_ASSERT(tc, "redis create failed", rv == APR_SUCCESS); + + rv = apr_redis_server_create(pool, HOST, PORT, 0, 1, 1, 60, 60, &server); + ABTS_ASSERT(tc, "server create failed", rv == APR_SUCCESS); + + rv = apr_redis_add_server(redis, server); + ABTS_ASSERT(tc, "server add failed", rv == APR_SUCCESS); + + rv = apr_redis_version(server, pool, &result); + ABTS_PTR_NOTNULL(tc, result); + + rv = apr_redis_stats(server, p, &stats); + ABTS_PTR_NOTNULL(tc, stats); + + /* + * no way to know exactly what will be in most of these, so + * just make sure there is something. + */ + ABTS_ASSERT(tc, "major", stats->major >= 1); + ABTS_ASSERT(tc, "minor", stats->minor >= 0); + ABTS_ASSERT(tc, "patch", stats->patch >= 0); + ABTS_ASSERT(tc, "process_id", stats->process_id >= 0); + ABTS_ASSERT(tc, "uptime_in_seconds", stats->uptime_in_seconds >= 0); + ABTS_ASSERT(tc, "arch_bits", stats->arch_bits >= 0); + ABTS_ASSERT(tc, "connected_clients", stats->connected_clients >= 0); + ABTS_ASSERT(tc, "blocked_clients", stats->blocked_clients >= 0); + ABTS_ASSERT(tc, "maxmemory", stats->maxmemory >= 0); + ABTS_ASSERT(tc, "used_memory", stats->used_memory >= 0); + ABTS_ASSERT(tc, "total_system_memory", stats->total_system_memory >= 0); + ABTS_ASSERT(tc, "total_connections_received", stats->total_connections_received >= 0); + ABTS_ASSERT(tc, "total_commands_processed", stats->total_commands_processed >= 0); + ABTS_ASSERT(tc, "total_net_input_bytes", stats->total_net_input_bytes >= 0); + ABTS_ASSERT(tc, "total_net_output_bytes", stats->total_net_output_bytes >= 0); + ABTS_ASSERT(tc, "keyspace_hits", stats->keyspace_hits >= 0); + ABTS_ASSERT(tc, "keyspace_misses", stats->keyspace_misses >= 0); + ABTS_ASSERT(tc, "role", stats->role >= 0); + ABTS_ASSERT(tc, "connected_slaves", stats->connected_slaves >= 0); + ABTS_ASSERT(tc, "used_cpu_sys", stats->used_cpu_sys >= 0); + ABTS_ASSERT(tc, "used_cpu_user", stats->used_cpu_user >= 0); + ABTS_ASSERT(tc, "cluster_enabled", stats->cluster_enabled >= 0); +} + + +/* basic tests of the increment and decrement commands */ +static void test_redis_incrdecr(abts_case * tc, void *data) +{ + apr_pool_t *pool = p; + apr_status_t rv; + apr_redis_t *redis; + apr_redis_server_t *server; + apr_uint32_t new; + char *result; + apr_size_t len; + apr_uint32_t i; + + rv = apr_redis_create(pool, 1, 0, &redis); + ABTS_ASSERT(tc, "redis create failed", rv == APR_SUCCESS); + + rv = apr_redis_server_create(pool, HOST, PORT, 0, 1, 1, 60, 60, &server); + ABTS_ASSERT(tc, "server create failed", rv == APR_SUCCESS); + + rv = apr_redis_add_server(redis, server); + ABTS_ASSERT(tc, "server add failed", rv == APR_SUCCESS); + + rv = apr_redis_set(redis, prefix, "271", sizeof("271") - 1, 27); + ABTS_ASSERT(tc, "set failed", rv == APR_SUCCESS); + + for( i = 1; i <= TDATA_SIZE; i++) { + apr_uint32_t expect; + + rv = apr_redis_getp(redis, pool, prefix, &result, &len, NULL); + ABTS_ASSERT(tc, "get failed", rv == APR_SUCCESS); + + expect = i + atoi(result); + + rv = apr_redis_incr(redis, prefix, i, &new); + ABTS_ASSERT(tc, "incr failed", rv == APR_SUCCESS); + + ABTS_INT_EQUAL(tc, expect, new); + + rv = apr_redis_decr(redis, prefix, i, &new); + ABTS_ASSERT(tc, "decr failed", rv == APR_SUCCESS); + + ABTS_INT_EQUAL(tc, atoi(result), new); + + } + + rv = apr_redis_getp(redis, pool, prefix, &result, &len, NULL); + ABTS_ASSERT(tc, "get failed", rv == APR_SUCCESS); + + ABTS_INT_EQUAL(tc, 271, atoi(result)); + + rv = apr_redis_delete(redis, prefix, 0); + ABTS_ASSERT(tc, "delete failed", rv == APR_SUCCESS); +} + + +/* test setting and getting */ + +static void test_redis_setget(abts_case * tc, void *data) +{ + apr_pool_t *pool = p; + apr_status_t rv; + apr_redis_t *redis; + apr_redis_server_t *server; + apr_hash_t *tdata; + apr_hash_index_t *hi; + char *result; + apr_size_t len; + + rv = apr_redis_create(pool, 1, 0, &redis); + ABTS_ASSERT(tc, "redis create failed", rv == APR_SUCCESS); + + rv = apr_redis_server_create(pool, HOST, PORT, 0, 1, 1, 60, 60, &server); + ABTS_ASSERT(tc, "server create failed", rv == APR_SUCCESS); + + rv = apr_redis_add_server(redis, server); + ABTS_ASSERT(tc, "server add failed", rv == APR_SUCCESS); + + tdata = apr_hash_make(pool); + + create_test_hash(pool, tdata); + + for (hi = apr_hash_first(p, tdata); hi; hi = apr_hash_next(hi)) { + const void *k; + void *v; + const char *key; + + apr_hash_this(hi, &k, NULL, &v); + key = k; + + rv = apr_redis_set(redis, key, v, strlen(v), 27); + ABTS_ASSERT(tc, "set failed", rv == APR_SUCCESS); + rv = apr_redis_getp(redis, pool, key, &result, &len, NULL); + ABTS_ASSERT(tc, "get failed", rv == APR_SUCCESS); + } + + rv = apr_redis_getp(redis, pool, "nothere3423", &result, &len, NULL); + + ABTS_ASSERT(tc, "get should have failed", rv != APR_SUCCESS); + + for (hi = apr_hash_first(p, tdata); hi; hi = apr_hash_next(hi)) { + const void *k; + const char *key; + + apr_hash_this(hi, &k, NULL, NULL); + key = k; + + rv = apr_redis_delete(redis, key, 0); + ABTS_ASSERT(tc, "delete failed", rv == APR_SUCCESS); + } +} + +/* test setting and getting */ + +static void test_redis_setexget(abts_case * tc, void *data) +{ + apr_pool_t *pool = p; + apr_status_t rv; + apr_redis_t *redis; + apr_redis_server_t *server; + apr_hash_t *tdata; + apr_hash_index_t *hi; + char *result; + apr_size_t len; + + rv = apr_redis_create(pool, 1, 0, &redis); + ABTS_ASSERT(tc, "redis create failed", rv == APR_SUCCESS); + + rv = apr_redis_server_create(pool, HOST, PORT, 0, 1, 1, 60, 60, &server); + ABTS_ASSERT(tc, "server create failed", rv == APR_SUCCESS); + + rv = apr_redis_add_server(redis, server); + ABTS_ASSERT(tc, "server add failed", rv == APR_SUCCESS); + + tdata = apr_hash_make(pool); + + create_test_hash(pool, tdata); + + for (hi = apr_hash_first(p, tdata); hi; hi = apr_hash_next(hi)) { + const void *k; + void *v; + const char *key; + + apr_hash_this(hi, &k, NULL, &v); + key = k; + + rv = apr_redis_ping(server); + ABTS_ASSERT(tc, "ping failed", rv == APR_SUCCESS); + rv = apr_redis_setex(redis, key, v, strlen(v), 10, 27); + ABTS_ASSERT(tc, "set failed", rv == APR_SUCCESS); + rv = apr_redis_getp(redis, pool, key, &result, &len, NULL); + ABTS_ASSERT(tc, "get failed", rv == APR_SUCCESS); + } + + rv = apr_redis_getp(redis, pool, "nothere3423", &result, &len, NULL); + + ABTS_ASSERT(tc, "get should have failed", rv != APR_SUCCESS); + + for (hi = apr_hash_first(p, tdata); hi; hi = apr_hash_next(hi)) { + const void *k; + const char *key; + + apr_hash_this(hi, &k, NULL, NULL); + key = k; + + rv = apr_redis_delete(redis, key, 0); + ABTS_ASSERT(tc, "delete failed", rv == APR_SUCCESS); + } +} + +/* use apr_socket stuff to see if there is in fact a Redis server + * running on PORT. + */ +static apr_status_t check_redis(void) +{ + apr_pool_t *pool = p; + apr_status_t rv; + apr_socket_t *sock = NULL; + apr_sockaddr_t *sa; + struct iovec vec[2]; + apr_size_t written; + char buf[128]; + apr_size_t len; + + rv = apr_socket_create(&sock, APR_INET, SOCK_STREAM, 0, pool); + if(rv != APR_SUCCESS) { + return rv; + } + + rv = apr_sockaddr_info_get(&sa, HOST, APR_INET, PORT, 0, pool); + if(rv != APR_SUCCESS) { + return rv; + } + + rv = apr_socket_timeout_set(sock, 1 * APR_USEC_PER_SEC); + if (rv != APR_SUCCESS) { + return rv; + } + + rv = apr_socket_connect(sock, sa); + if (rv != APR_SUCCESS) { + return rv; + } + + rv = apr_socket_timeout_set(sock, -1); + if (rv != APR_SUCCESS) { + return rv; + } + + vec[0].iov_base = "PING"; + vec[0].iov_len = sizeof("PING") - 1; + + vec[1].iov_base = "\r\n"; + vec[1].iov_len = sizeof("\r\n") -1; + + rv = apr_socket_sendv(sock, vec, 2, &written); + if (rv != APR_SUCCESS) { + return rv; + } + + len = sizeof(buf); + rv = apr_socket_recv(sock, buf, &len); + if(rv != APR_SUCCESS) { + return rv; + } + if(strncmp(buf, "+PONG", sizeof("+PONG")-1) != 0) { + rv = APR_EGENERAL; + } + + apr_socket_close(sock); + return rv; +} + +abts_suite *testredis(abts_suite * suite) +{ + apr_status_t rv; + suite = ADD_SUITE(suite); + /* check for a running redis on the typical port before + * trying to run the tests. succeed if we don't find one. + */ + rv = check_redis(); + if (rv == APR_SUCCESS) { + abts_run_test(suite, test_redis_create, NULL); + abts_run_test(suite, test_redis_user_funcs, NULL); + abts_run_test(suite, test_redis_meta, NULL); + abts_run_test(suite, test_redis_setget, NULL); + abts_run_test(suite, test_redis_setexget, NULL); + /* abts_run_test(suite, test_redis_multiget, NULL); */ + abts_run_test(suite, test_redis_incrdecr, NULL); + } + else { + abts_log_message("Error %d occurred attempting to reach Redis " + "on %s:%d. Skipping apr_redis tests...", + rv, HOST, PORT); + } + + return suite; +} diff --git a/test/testreslist.c b/test/testreslist.c new file mode 100644 index 00000000000..36333a1533e --- /dev/null +++ b/test/testreslist.c @@ -0,0 +1,272 @@ +/* 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 <stdio.h> +#include <stdlib.h> + +#include "apr_general.h" +#include "apu.h" +#include "apr_reslist.h" +#include "apr_thread_pool.h" + +#if APR_HAVE_TIME_H +#include <time.h> +#endif /* APR_HAVE_TIME_H */ + +#include "abts.h" +#include "testutil.h" + +#if APR_HAS_THREADS + +#define RESLIST_MIN 3 +#define RESLIST_SMAX 10 +#define RESLIST_HMAX 20 +#define RESLIST_TTL APR_TIME_C(35000) /* 35 ms */ +#define CONSUMER_THREADS 25 +#define CONSUMER_ITERATIONS 250 +#define CONSTRUCT_SLEEP_TIME APR_TIME_C(25000) /* 25 ms */ +#define DESTRUCT_SLEEP_TIME APR_TIME_C(10000) /* 10 ms */ +#define WORK_DELAY_SLEEP_TIME APR_TIME_C(15000) /* 15 ms */ + +typedef struct { + apr_interval_time_t sleep_upon_construct; + apr_interval_time_t sleep_upon_destruct; + int c_count; + int d_count; +} my_parameters_t; + +typedef struct { + int id; +} my_resource_t; + +/* Linear congruential generator */ +static apr_uint32_t lgc(apr_uint32_t a) +{ + apr_uint64_t z = a; + z *= 279470273; + z %= APR_UINT64_C(4294967291); + return (apr_uint32_t)z; +} + +static apr_status_t my_constructor(void **resource, void *params, + apr_pool_t *pool) +{ + my_resource_t *res; + my_parameters_t *my_params = params; + + /* Create some resource */ + res = apr_palloc(pool, sizeof(*res)); + res->id = my_params->c_count++; + + /* Sleep for awhile, to simulate construction overhead. */ + apr_sleep(my_params->sleep_upon_construct); + + /* Set the resource so it can be managed by the reslist */ + *resource = res; + return APR_SUCCESS; +} + +static apr_status_t my_destructor(void *resource, void *params, + apr_pool_t *pool) +{ + my_resource_t *res = resource; + my_parameters_t *my_params = params; + res->id = my_params->d_count++; + + apr_sleep(my_params->sleep_upon_destruct); + + return APR_SUCCESS; +} + +typedef struct { + int tid; + abts_case *tc; + apr_reslist_t *reslist; + apr_interval_time_t work_delay_sleep; +} my_thread_info_t; + +/* MAX_UINT * .95 = 2**32 * .95 = 4080218931u */ +#define PERCENT95th 4080218931u + +static void * APR_THREAD_FUNC resource_consuming_thread(apr_thread_t *thd, + void *data) +{ + int i; + apr_uint32_t chance; + void *vp; + apr_status_t rv; + my_resource_t *res; + my_thread_info_t *thread_info = data; + apr_reslist_t *rl = thread_info->reslist; + +#if APR_HAS_RANDOM + apr_generate_random_bytes((void*)&chance, sizeof(chance)); +#else + chance = (apr_uint32_t)(apr_time_now() % APR_TIME_C(4294967291)); +#endif + + for (i = 0; i < CONSUMER_ITERATIONS; i++) { + rv = apr_reslist_acquire(rl, &vp); + ABTS_INT_EQUAL(thread_info->tc, APR_SUCCESS, rv); + res = vp; + apr_sleep(thread_info->work_delay_sleep); + + /* simulate a 5% chance of the resource being bad */ + chance = lgc(chance); + if ( chance < PERCENT95th ) { + rv = apr_reslist_release(rl, res); + ABTS_INT_EQUAL(thread_info->tc, APR_SUCCESS, rv); + } else { + rv = apr_reslist_invalidate(rl, res); + ABTS_INT_EQUAL(thread_info->tc, APR_SUCCESS, rv); + } + } + + return APR_SUCCESS; +} + +static void test_timeout(abts_case *tc, apr_reslist_t *rl) +{ + apr_status_t rv; + my_resource_t *resources[RESLIST_HMAX]; + void *vp; + int i; + + apr_reslist_timeout_set(rl, 1000); + + /* deplete all possible resources from the resource list + * so that the next call will block until timeout is reached + * (since there are no other threads to make a resource + * available) + */ + + for (i = 0; i < RESLIST_HMAX; i++) { + rv = apr_reslist_acquire(rl, (void**)&resources[i]); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + } + + /* next call will block until timeout is reached */ + rv = apr_reslist_acquire(rl, &vp); + ABTS_TRUE(tc, APR_STATUS_IS_TIMEUP(rv)); + + /* release the resources; otherwise the destroy operation + * will blow + */ + for (i = 0; i < RESLIST_HMAX; i++) { + rv = apr_reslist_release(rl, resources[i]); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + } +} + +static void test_shrinking(abts_case *tc, apr_reslist_t *rl) +{ + apr_status_t rv; + my_resource_t *resources[RESLIST_HMAX]; + my_resource_t *res; + void *vp; + int i; + int sleep_time = RESLIST_TTL / RESLIST_HMAX; + + /* deplete all possible resources from the resource list */ + for (i = 0; i < RESLIST_HMAX; i++) { + rv = apr_reslist_acquire(rl, (void**)&resources[i]); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + } + + /* Free all resources above RESLIST_SMAX - 1 */ + for (i = RESLIST_SMAX - 1; i < RESLIST_HMAX; i++) { + rv = apr_reslist_release(rl, resources[i]); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + } + + for (i = 0; i < RESLIST_HMAX; i++) { + rv = apr_reslist_acquire(rl, &vp); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + res = vp; + apr_sleep(sleep_time); + rv = apr_reslist_release(rl, res); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + } + apr_sleep(sleep_time); + + /* + * Now free the remaining elements. This should trigger the shrinking of + * the list + */ + for (i = 0; i < RESLIST_SMAX - 1; i++) { + rv = apr_reslist_release(rl, resources[i]); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + } +} + +static void test_reslist(abts_case *tc, void *data) +{ + int i; + apr_status_t rv; + apr_reslist_t *rl; + my_parameters_t *params; + apr_thread_pool_t *thrp; + my_thread_info_t thread_info[CONSUMER_THREADS]; + + rv = apr_thread_pool_create(&thrp, CONSUMER_THREADS/2, CONSUMER_THREADS, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + /* Create some parameters that will be passed into each + * constructor and destructor call. */ + params = apr_pcalloc(p, sizeof(*params)); + params->sleep_upon_construct = CONSTRUCT_SLEEP_TIME; + params->sleep_upon_destruct = DESTRUCT_SLEEP_TIME; + + /* We're going to want 10 blocks of data from our target rmm. */ + rv = apr_reslist_create(&rl, RESLIST_MIN, RESLIST_SMAX, RESLIST_HMAX, + RESLIST_TTL, my_constructor, my_destructor, + params, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + for (i = 0; i < CONSUMER_THREADS; i++) { + thread_info[i].tid = i; + thread_info[i].tc = tc; + thread_info[i].reslist = rl; + thread_info[i].work_delay_sleep = WORK_DELAY_SLEEP_TIME; + rv = apr_thread_pool_push(thrp, resource_consuming_thread, + &thread_info[i], 0, NULL); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + } + + rv = apr_thread_pool_destroy(thrp); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + test_timeout(tc, rl); + + test_shrinking(tc, rl); + ABTS_INT_EQUAL(tc, RESLIST_SMAX, params->c_count - params->d_count); + + rv = apr_reslist_destroy(rl); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); +} + +#endif /* APR_HAS_THREADS */ + +abts_suite *testreslist(abts_suite *suite) +{ + suite = ADD_SUITE(suite); + +#if APR_HAS_THREADS + abts_run_test(suite, test_reslist, NULL); +#endif + + return suite; +} diff --git a/test/testrmm.c b/test/testrmm.c new file mode 100644 index 00000000000..4f8fb5ec2c3 --- /dev/null +++ b/test/testrmm.c @@ -0,0 +1,191 @@ +/* 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_shm.h" +#include "apr_rmm.h" +#include "apr_errno.h" +#include "apr_general.h" +#include "apr_lib.h" +#include "apr_strings.h" +#include "apr_time.h" +#include "abts.h" +#include "testutil.h" + +#if APR_HAS_SHARED_MEMORY + +#define FRAG_SIZE 80 +#define FRAG_COUNT 10 +#define SHARED_SIZE (apr_size_t)(FRAG_SIZE * FRAG_COUNT * sizeof(char*)) + +static void test_rmm(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_pool_t *pool; + apr_shm_t *shm; + apr_rmm_t *rmm; + apr_size_t size, fragsize; + apr_rmm_off_t *off, off2; + int i; + void *entity; + + rv = apr_pool_create(&pool, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + /* We're going to want 10 blocks of data from our target rmm. */ + size = SHARED_SIZE + apr_rmm_overhead_get(FRAG_COUNT + 1); + rv = apr_shm_create(&shm, size, NULL, pool); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + if (rv != APR_SUCCESS) + return; + + rv = apr_rmm_init(&rmm, NULL, apr_shm_baseaddr_get(shm), size, pool); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + if (rv != APR_SUCCESS) + return; + + /* Creating each fragment of size fragsize */ + fragsize = SHARED_SIZE / FRAG_COUNT; + off = apr_palloc(pool, FRAG_COUNT * sizeof(apr_rmm_off_t)); + for (i = 0; i < FRAG_COUNT; i++) { + off[i] = apr_rmm_malloc(rmm, fragsize); + } + + /* Checking for out of memory allocation */ + off2 = apr_rmm_malloc(rmm, FRAG_SIZE * FRAG_COUNT); + ABTS_TRUE(tc, !off2); + + /* Checking each fragment for address alignment */ + for (i = 0; i < FRAG_COUNT; i++) { + char *c = apr_rmm_addr_get(rmm, off[i]); + apr_size_t sc = (apr_size_t)c; + + ABTS_TRUE(tc, !!off[i]); + ABTS_TRUE(tc, !(sc & 7)); + } + + /* Setting each fragment to a unique value */ + for (i = 0; i < FRAG_COUNT; i++) { + int j; + char **c = apr_rmm_addr_get(rmm, off[i]); + for (j = 0; j < FRAG_SIZE; j++, c++) { + *c = apr_itoa(pool, i + j); + } + } + + /* Checking each fragment for its unique value */ + for (i = 0; i < FRAG_COUNT; i++) { + int j; + char **c = apr_rmm_addr_get(rmm, off[i]); + for (j = 0; j < FRAG_SIZE; j++, c++) { + char *d = apr_itoa(pool, i + j); + ABTS_STR_EQUAL(tc, d, *c); + } + } + + /* Freeing each fragment */ + for (i = 0; i < FRAG_COUNT; i++) { + rv = apr_rmm_free(rmm, off[i]); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + } + + /* Creating one large segment */ + off[0] = apr_rmm_calloc(rmm, SHARED_SIZE); + + /* Setting large segment */ + for (i = 0; i < FRAG_COUNT * FRAG_SIZE; i++) { + char **c = apr_rmm_addr_get(rmm, off[0]); + c[i] = apr_itoa(pool, i); + } + + /* Freeing large segment */ + rv = apr_rmm_free(rmm, off[0]); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + /* Creating each fragment of size fragsize */ + for (i = 0; i < FRAG_COUNT; i++) { + off[i] = apr_rmm_malloc(rmm, fragsize); + } + + /* Freeing each fragment backwards */ + for (i = FRAG_COUNT - 1; i >= 0; i--) { + rv = apr_rmm_free(rmm, off[i]); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + } + + /* Creating one large segment (again) */ + off[0] = apr_rmm_calloc(rmm, SHARED_SIZE); + + /* Freeing large segment */ + rv = apr_rmm_free(rmm, off[0]); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + /* Checking realloc */ + off[0] = apr_rmm_calloc(rmm, SHARED_SIZE - 100); + off[1] = apr_rmm_calloc(rmm, 100); + ABTS_TRUE(tc, !!off[0]); + ABTS_TRUE(tc, !!off[1]); + + entity = apr_rmm_addr_get(rmm, off[1]); + rv = apr_rmm_free(rmm, off[0]); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + { + unsigned char *c = entity; + + /* Fill in the region; the first half with zereos, which will + * likely catch the apr_rmm_realloc offset calculation bug by + * making it think the old region was zero length. */ + for (i = 0; i < 100; i++) { + c[i] = (i < 50) ? 0 : i; + } + } + + /* now we can realloc off[1] and get many more bytes */ + off[0] = apr_rmm_realloc(rmm, entity, SHARED_SIZE - 100); + ABTS_TRUE(tc, !!off[0]); + + { + unsigned char *c = apr_rmm_addr_get(rmm, off[0]); + + /* fill in the region */ + for (i = 0; i < 100; i++) { + ABTS_TRUE(tc, c[i] == (i < 50 ? 0 : i)); + } + } + + rv = apr_rmm_destroy(rmm); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + rv = apr_shm_destroy(shm); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + apr_pool_destroy(pool); +} + +#endif /* APR_HAS_SHARED_MEMORY */ + +abts_suite *testrmm(abts_suite *suite) +{ + suite = ADD_SUITE(suite); + +#if APR_HAS_SHARED_MEMORY + abts_run_test(suite, test_rmm, NULL); +#endif + + return suite; +} diff --git a/test/testshm.c b/test/testshm.c new file mode 100644 index 00000000000..73870690631 --- /dev/null +++ b/test/testshm.c @@ -0,0 +1,332 @@ +/* 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 "testutil.h" +#include "apr_shm.h" +#include "apr_errno.h" +#include "apr_general.h" +#include "apr_lib.h" +#include "apr_strings.h" +#include "apr_thread_proc.h" +#include "apr_time.h" +#include "testshm.h" +#include "apr.h" + +#if APR_HAVE_STDLIB_H +#include <stdlib.h> +#endif + +#if APR_HAS_SHARED_MEMORY + +#if APR_HAS_FORK +static int msgwait(int sleep_sec, int first_box, int last_box) +{ + int i; + int recvd = 0; + apr_time_t start = apr_time_now(); + apr_interval_time_t sleep_duration = apr_time_from_sec(sleep_sec); + while (apr_time_now() - start < sleep_duration) { + for (i = first_box; i < last_box; i++) { + if (boxes[i].msgavail && !strcmp(boxes[i].msg, MSG)) { + recvd++; + boxes[i].msgavail = 0; /* reset back to 0 */ + /* reset the msg field. 1024 is a magic number and it should + * be a macro, but I am being lazy. + */ + memset(boxes[i].msg, 0, 1024); + } + } + apr_sleep(apr_time_make(0, 10000)); /* 10ms */ + } + return recvd; +} + +static void msgput(int boxnum, char *msg) +{ + apr_cpystrn(boxes[boxnum].msg, msg, strlen(msg) + 1); + boxes[boxnum].msgavail = 1; +} +#endif /* APR_HAS_FORK */ + +static void test_anon_create(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_shm_t *shm = NULL; + + rv = apr_shm_create(&shm, SHARED_SIZE, NULL, p); + APR_ASSERT_SUCCESS(tc, "Error allocating shared memory block", rv); + ABTS_PTR_NOTNULL(tc, shm); + + rv = apr_shm_destroy(shm); + APR_ASSERT_SUCCESS(tc, "Error destroying shared memory block", rv); +} + +static void test_check_size(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_shm_t *shm = NULL; + apr_size_t retsize; + + rv = apr_shm_create(&shm, SHARED_SIZE, NULL, p); + APR_ASSERT_SUCCESS(tc, "Error allocating shared memory block", rv); + ABTS_PTR_NOTNULL(tc, shm); + + retsize = apr_shm_size_get(shm); + ABTS_SIZE_EQUAL(tc, SHARED_SIZE, retsize); + + rv = apr_shm_destroy(shm); + APR_ASSERT_SUCCESS(tc, "Error destroying shared memory block", rv); +} + +static void test_shm_allocate(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_shm_t *shm = NULL; + + rv = apr_shm_create(&shm, SHARED_SIZE, NULL, p); + APR_ASSERT_SUCCESS(tc, "Error allocating shared memory block", rv); + ABTS_PTR_NOTNULL(tc, shm); + + boxes = apr_shm_baseaddr_get(shm); + ABTS_PTR_NOTNULL(tc, boxes); + + rv = apr_shm_destroy(shm); + APR_ASSERT_SUCCESS(tc, "Error destroying shared memory block", rv); +} + +#if APR_HAS_FORK +static void test_anon(abts_case *tc, void *data) +{ + apr_proc_t proc; + apr_status_t rv; + apr_shm_t *shm; + apr_size_t retsize; + int cnt, i; + int recvd; + + rv = apr_shm_create(&shm, SHARED_SIZE, NULL, p); + APR_ASSERT_SUCCESS(tc, "Error allocating shared memory block", rv); + ABTS_PTR_NOTNULL(tc, shm); + + retsize = apr_shm_size_get(shm); + ABTS_INT_EQUAL(tc, SHARED_SIZE, retsize); + + boxes = apr_shm_baseaddr_get(shm); + ABTS_PTR_NOTNULL(tc, boxes); + + rv = apr_proc_fork(&proc, p); + if (rv == APR_INCHILD) { /* child */ + int num = msgwait(5, 0, N_BOXES); + /* exit with the number of messages received so that the parent + * can check that all messages were received. + */ + exit(num); + } + else if (rv == APR_INPARENT) { /* parent */ + i = N_BOXES; + cnt = 0; + while (cnt++ < N_MESSAGES) { + if ((i-=3) < 0) { + i += N_BOXES; /* start over at the top */ + } + msgput(i, MSG); + apr_sleep(apr_time_make(0, 10000)); + } + } + else { + ABTS_FAIL(tc, "apr_proc_fork failed"); + } + /* wait for the child */ + rv = apr_proc_wait(&proc, &recvd, NULL, APR_WAIT); + ABTS_INT_EQUAL(tc, N_MESSAGES, recvd); + + rv = apr_shm_destroy(shm); + APR_ASSERT_SUCCESS(tc, "Error destroying shared memory block", rv); +} +#endif + +static void test_named(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_shm_t *shm = NULL; + apr_size_t retsize; + apr_proc_t pidproducer, pidconsumer; + apr_procattr_t *attr1 = NULL, *attr2 = NULL; + int sent, received; + apr_exit_why_e why; + const char *args[4]; + + apr_shm_remove(SHARED_FILENAME, p); + + rv = apr_shm_create(&shm, SHARED_SIZE, SHARED_FILENAME, p); + APR_ASSERT_SUCCESS(tc, "Error allocating shared memory block", rv); + if (rv != APR_SUCCESS) { + return; + } + ABTS_PTR_NOTNULL(tc, shm); + + retsize = apr_shm_size_get(shm); + ABTS_SIZE_EQUAL(tc, SHARED_SIZE, retsize); + + boxes = apr_shm_baseaddr_get(shm); + ABTS_PTR_NOTNULL(tc, boxes); + + rv = apr_procattr_create(&attr1, p); + ABTS_PTR_NOTNULL(tc, attr1); + APR_ASSERT_SUCCESS(tc, "Couldn't create attr1", rv); + + rv = apr_procattr_cmdtype_set(attr1, APR_PROGRAM_ENV); + APR_ASSERT_SUCCESS(tc, "Couldn't set copy environment", rv); + + args[0] = apr_pstrdup(p, "testshmproducer" EXTENSION); + args[1] = NULL; + rv = apr_proc_create(&pidproducer, TESTBINPATH "testshmproducer" EXTENSION, args, + NULL, attr1, p); + APR_ASSERT_SUCCESS(tc, "Couldn't launch producer", rv); + + rv = apr_procattr_create(&attr2, p); + ABTS_PTR_NOTNULL(tc, attr2); + APR_ASSERT_SUCCESS(tc, "Couldn't create attr2", rv); + + rv = apr_procattr_cmdtype_set(attr2, APR_PROGRAM_ENV); + APR_ASSERT_SUCCESS(tc, "Couldn't set copy environment", rv); + + args[0] = apr_pstrdup(p, "testshmconsumer" EXTENSION); + rv = apr_proc_create(&pidconsumer, TESTBINPATH "testshmconsumer" EXTENSION, args, + NULL, attr2, p); + APR_ASSERT_SUCCESS(tc, "Couldn't launch consumer", rv); + + rv = apr_proc_wait(&pidconsumer, &received, &why, APR_WAIT); + ABTS_INT_EQUAL(tc, APR_CHILD_DONE, rv); + ABTS_INT_EQUAL(tc, APR_PROC_EXIT, why); + + rv = apr_proc_wait(&pidproducer, &sent, &why, APR_WAIT); + ABTS_INT_EQUAL(tc, APR_CHILD_DONE, rv); + ABTS_INT_EQUAL(tc, APR_PROC_EXIT, why); + + /* Cleanup before testing that producer and consumer worked correctly. + * This way, if they didn't succeed, we can just run this test again + * without having to cleanup manually. + */ + APR_ASSERT_SUCCESS(tc, "Error destroying shared memory", + apr_shm_destroy(shm)); + + ABTS_INT_EQUAL(tc, sent, received); + +} + +static void test_named_remove(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_shm_t *shm, *shm2; + + apr_shm_remove(SHARED_FILENAME, p); + + rv = apr_shm_create(&shm, SHARED_SIZE, SHARED_FILENAME, p); + APR_ASSERT_SUCCESS(tc, "Error allocating shared memory block", rv); + if (rv != APR_SUCCESS) { + return; + } + ABTS_PTR_NOTNULL(tc, shm); + + rv = apr_shm_remove(SHARED_FILENAME, p); + + /* On platforms which acknowledge the removal of the shared resource, + * ensure another of the same name may be created after removal; + */ + if (rv == APR_SUCCESS) + { + rv = apr_shm_create(&shm2, SHARED_SIZE, SHARED_FILENAME, p); + APR_ASSERT_SUCCESS(tc, "Error allocating shared memory block", rv); + if (rv != APR_SUCCESS) { + return; + } + ABTS_PTR_NOTNULL(tc, shm2); + + rv = apr_shm_destroy(shm2); + APR_ASSERT_SUCCESS(tc, "Error destroying shared memory block", rv); + } + + rv = apr_shm_destroy(shm); + APR_ASSERT_SUCCESS(tc, "Error destroying shared memory block", rv); + + /* Now ensure no named resource remains which we may attach to */ + rv = apr_shm_attach(&shm, SHARED_FILENAME, p); + ABTS_TRUE(tc, rv != 0); +} + +static void test_named_delete(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_shm_t *shm, *shm2; + + apr_shm_remove(SHARED_FILENAME, p); + + rv = apr_shm_create(&shm, SHARED_SIZE, SHARED_FILENAME, p); + APR_ASSERT_SUCCESS(tc, "Error allocating shared memory block", rv); + if (rv != APR_SUCCESS) { + return; + } + ABTS_PTR_NOTNULL(tc, shm); + + rv = apr_shm_delete(shm); + + /* On platforms which acknowledge the removal of the shared resource, + * ensure another of the same name may be created after removal; + */ + if (rv == APR_SUCCESS) + { + rv = apr_shm_create(&shm2, SHARED_SIZE, SHARED_FILENAME, p); + APR_ASSERT_SUCCESS(tc, "Error allocating shared memory block", rv); + if (rv != APR_SUCCESS) { + return; + } + ABTS_PTR_NOTNULL(tc, shm2); + + rv = apr_shm_destroy(shm2); + APR_ASSERT_SUCCESS(tc, "Error destroying shared memory block", rv); + } + + rv = apr_shm_destroy(shm); + APR_ASSERT_SUCCESS(tc, "Error destroying shared memory block", rv); + + /* Now ensure no named resource remains which we may attach to */ + rv = apr_shm_attach(&shm, SHARED_FILENAME, p); + ABTS_TRUE(tc, rv != 0); +} + +#endif + +abts_suite *testshm(abts_suite *suite) +{ + suite = ADD_SUITE(suite) + +#if APR_HAS_SHARED_MEMORY + abts_run_test(suite, test_anon_create, NULL); + abts_run_test(suite, test_check_size, NULL); + abts_run_test(suite, test_shm_allocate, NULL); +#if APR_HAS_FORK + abts_run_test(suite, test_anon, NULL); +#endif + abts_run_test(suite, test_named, NULL); + abts_run_test(suite, test_named_remove, NULL); + abts_run_test(suite, test_named_delete, NULL); +#endif + + return suite; +} + + diff --git a/test/testshm.h b/test/testshm.h new file mode 100644 index 00000000000..5b24a9d4271 --- /dev/null +++ b/test/testshm.h @@ -0,0 +1,33 @@ +/* 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. + */ + +#ifndef TESTSHM_H +#define TESTSHM_H + +typedef struct mbox { + char msg[1024]; + int msgavail; +} mbox; +mbox *boxes; + +#define N_BOXES 10 +#define SHARED_SIZE (apr_size_t)(N_BOXES * sizeof(mbox)) +#define SHARED_FILENAME "data/apr.testshm.shm" +#define N_MESSAGES 100 +#define MSG "Sending a message" + +#endif + diff --git a/test/testshmconsumer.c b/test/testshmconsumer.c new file mode 100644 index 00000000000..6a2a3c30d3e --- /dev/null +++ b/test/testshmconsumer.c @@ -0,0 +1,94 @@ +/* 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_shm.h" +#include "apr_errno.h" +#include "apr_general.h" +#include "apr_lib.h" +#include "apr_strings.h" +#include "apr_time.h" +#include "testshm.h" +#include "apr.h" + +#if APR_HAVE_STDLIB_H +#include <stdlib.h> +#endif + + +#if APR_HAS_SHARED_MEMORY + +static int msgwait(int sleep_sec, int first_box, int last_box) +{ + int i; + int recvd = 0; + apr_time_t start = apr_time_now(); + apr_interval_time_t sleep_duration = apr_time_from_sec(sleep_sec); + while (apr_time_now() - start < sleep_duration) { + for (i = first_box; i < last_box; i++) { + if (boxes[i].msgavail && !strcmp(boxes[i].msg, MSG)) { + recvd++; + boxes[i].msgavail = 0; /* reset back to 0 */ + memset(boxes[i].msg, 0, 1024); + } + } + apr_sleep(apr_time_from_sec(1)); + } + return recvd; +} + +int main(void) +{ + apr_status_t rv; + apr_pool_t *pool; + apr_shm_t *shm; + int recvd; + + apr_initialize(); + + if (apr_pool_create(&pool, NULL) != APR_SUCCESS) { + exit(-1); + } + + rv = apr_shm_attach(&shm, SHARED_FILENAME, pool); + if (rv != APR_SUCCESS) { + exit(-2); + } + + boxes = apr_shm_baseaddr_get(shm); + + /* consume messages on all of the boxes */ + recvd = msgwait(30, 0, N_BOXES); /* wait for 30 seconds for messages */ + + rv = apr_shm_detach(shm); + if (rv != APR_SUCCESS) { + exit(-3); + } + + return recvd; +} + +#else /* APR_HAS_SHARED_MEMORY */ + +int main(void) +{ + /* Just return, this program will never be called, so we don't need + * to print a message + */ + return 0; +} + +#endif /* APR_HAS_SHARED_MEMORY */ + diff --git a/test/testshmem.c b/test/testshmem.c deleted file mode 100644 index 1da1e28f8a7..00000000000 --- a/test/testshmem.c +++ /dev/null @@ -1,146 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#include "apr_shmem.h" -#include "apr_lock.h" -#include "apr_errno.h" -#include "apr_general.h" -#include "apr_lib.h" -#include "errno.h" -#include <stdio.h> -#include <stdlib.h> -/*#include <process.h>*/ -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif - -typedef struct mbox { - char msg[1024]; - int msgavail; -} mbox; -ap_pool_t *context; -mbox *boxes; - -void msgwait(int boxnum) -{ - volatile int test = 0; - while (test == 0) { - sleep(0); - test = boxes[boxnum].msgavail; - } - fprintf(stdout, "\nreceived a message in box %d, message was: %s\n", - boxnum, boxes[boxnum].msg); -} - -void msgput(int boxnum, char *msg) -{ - fprintf(stdout, "Sending message to box %d\n", boxnum); - ap_cpystrn(boxes[boxnum].msg, msg, strlen(msg)); - boxes[boxnum].msgavail = 1; -} - -int main() -{ - ap_shmem_t *shm; - pid_t pid; - int size; - - ap_initialize(); - - fprintf(stdout, "Initializing the context......."); - if (ap_create_pool(&context, NULL) != APR_SUCCESS) { - fprintf(stderr, "could not initialize\n"); - exit(-1); - } - fprintf(stdout, "OK\n"); - - fprintf(stdout, "Creating shared memory block......."); - if (ap_shm_init(&shm, 1048576, NULL, context) != APR_SUCCESS) { - fprintf(stderr, "Error allocating shared memory block\n"); - exit(-1); - } - fprintf(stdout, "OK\n"); - - fprintf(stdout, "Allocating shared memory......."); - size = sizeof(mbox) * 2; - boxes = ap_shm_calloc(shm, size); - if (boxes == NULL) { - fprintf(stderr, "Error creating message boxes.\n"); - exit(-1); - } - fprintf(stdout, "OK\n"); - - fprintf(stdout, "Creating a child process\n"); - pid = fork(); - if (pid == 0) { -sleep(1); - if (ap_open_shmem(shm) == APR_SUCCESS) { - msgwait(1); - msgput(0, "Msg received\n"); - } else { - puts( "Child: unable to get access to shared memory" ); - } - exit(1); - } - else if (pid > 0) { - msgput(1, "Sending a message\n"); -sleep(1); - msgwait(0); - exit(1); - } - else { - fprintf(stderr, "Error creating a child process\n"); - exit(1); - } -} diff --git a/test/testshmproducer.c b/test/testshmproducer.c new file mode 100644 index 00000000000..58eb94fcd3f --- /dev/null +++ b/test/testshmproducer.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_shm.h" +#include "apr_errno.h" +#include "apr_general.h" +#include "apr_lib.h" +#include "apr_strings.h" +#include "apr_time.h" +#include "testshm.h" +#include "apr.h" + +#if APR_HAVE_STDLIB_H +#include <stdlib.h> +#endif + + +#if APR_HAS_SHARED_MEMORY +static void msgput(int boxnum, char *msg) +{ + apr_cpystrn(boxes[boxnum].msg, msg, strlen(msg) + 1); + boxes[boxnum].msgavail = 1; +} + +int main(void) +{ + apr_status_t rv; + apr_pool_t *pool; + apr_shm_t *shm; + int i; + int sent = 0; + + apr_initialize(); + + if (apr_pool_create(&pool, NULL) != APR_SUCCESS) { + exit(-1); + } + + rv = apr_shm_attach(&shm, SHARED_FILENAME, pool); + if (rv != APR_SUCCESS) { + exit(-2); + } + + boxes = apr_shm_baseaddr_get(shm); + + /* produce messages on all of the boxes, in descending order, + * Yes, we could just return N_BOXES, but I want to have a double-check + * in this code. The original code actually sent N_BOXES - 1 messages, + * so rather than rely on possibly buggy code, this way we know that we + * are returning the right number. + */ + for (i = N_BOXES - 1, sent = 0; i >= 0; i--, sent++) { + msgput(i, MSG); + apr_sleep(apr_time_from_sec(1)); + } + + rv = apr_shm_detach(shm); + if (rv != APR_SUCCESS) { + exit(-3); + } + + return sent; +} + +#else /* APR_HAS_SHARED_MEMORY */ + +int main(void) +{ + /* Just return, this program will never be launched, so there is no + * reason to print a message. + */ + return 0; +} + +#endif /* APR_HAS_SHARED_MEMORY */ + diff --git a/test/testsig.dsp b/test/testsig.dsp deleted file mode 100644 index c88c6be9669..00000000000 --- a/test/testsig.dsp +++ /dev/null @@ -1,90 +0,0 @@ -# Microsoft Developer Studio Project File - Name="testsig" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 5.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Console Application" 0x0103 - -CFG=testsig - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "testsig.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "testsig.mak" CFG="testsig - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "testsig - Win32 Release" (based on "Win32 (x86) Console Application") -!MESSAGE "testsig - Win32 Debug" (based on "Win32 (x86) Console Application") -!MESSAGE - -# Begin Project -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -RSC=rc.exe - -!IF "$(CFG)" == "testsig - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /W3 /GX /O2 /I "..\include" /I "..\..\include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD BASE RSC /l 0x409 /d "NDEBUG" -# ADD RSC /l 0x409 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 -# ADD LINK32 ..\lib\Debug\lib.lib ..\misc\win32\Debug\misc.lib ..\threadproc\win32\Debug\threadproc.lib ..\file_io\win32\Debug\file_io.lib ..\time\win32\Debug\time.lib ..\locks\win32\Debug\locks.lib ..\network_io\win32\Debug\network_io.lib ..\signal\win32\Debug\signal.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 - -!ELSEIF "$(CFG)" == "testsig - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "testsig_" -# PROP BASE Intermediate_Dir "testsig_" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "testsig" -# PROP Intermediate_Dir "testsig" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /I "..\include" /I "..\..\include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FD /c -# SUBTRACT CPP /YX /Yc /Yu -# ADD BASE RSC /l 0x409 /d "_DEBUG" -# ADD RSC /l 0x409 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept -# ADD LINK32 ..\lib\Debug\lib.lib ..\misc\win32\Debug\misc.lib ..\threadproc\win32\Debug\threadproc.lib ..\file_io\win32\Debug\file_io.lib ..\time\win32\Debug\time.lib ..\locks\win32\Debug\locks.lib ..\network_io\win32\Debug\network_io.lib ..\signal\win32\Debug\signal.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"ab.exe" /pdbtype:sept - -!ENDIF - -# Begin Target - -# Name "testsig - Win32 Release" -# Name "testsig - Win32 Debug" -# Begin Source File - -SOURCE=.\testsig.c -# End Source File -# End Target -# End Project diff --git a/test/testsiphash.c b/test/testsiphash.c new file mode 100644 index 00000000000..58321adebd8 --- /dev/null +++ b/test/testsiphash.c @@ -0,0 +1,148 @@ +/* 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 <stdio.h> +#include <stdlib.h> + +#include "apr_siphash.h" + +#include "abts.h" +#include "testutil.h" + +/* + * Wrapped test vectors from the authors, see + * https://131002.net/siphash/siphash24.c + */ +typedef unsigned char u8; +#define crypto_auth apr_siphash24_auth + +#define MAXLEN 64 + +/* + SipHash-2-4 output with + k = 00 01 02 ... + and + in = (empty string) + in = 00 (1 byte) + in = 00 01 (2 bytes) + in = 00 01 02 (3 bytes) + ... + in = 00 01 02 ... 3e (63 bytes) +*/ +static const u8 vectors[MAXLEN][8] = +{ + { 0x31, 0x0e, 0x0e, 0xdd, 0x47, 0xdb, 0x6f, 0x72, }, + { 0xfd, 0x67, 0xdc, 0x93, 0xc5, 0x39, 0xf8, 0x74, }, + { 0x5a, 0x4f, 0xa9, 0xd9, 0x09, 0x80, 0x6c, 0x0d, }, + { 0x2d, 0x7e, 0xfb, 0xd7, 0x96, 0x66, 0x67, 0x85, }, + { 0xb7, 0x87, 0x71, 0x27, 0xe0, 0x94, 0x27, 0xcf, }, + { 0x8d, 0xa6, 0x99, 0xcd, 0x64, 0x55, 0x76, 0x18, }, + { 0xce, 0xe3, 0xfe, 0x58, 0x6e, 0x46, 0xc9, 0xcb, }, + { 0x37, 0xd1, 0x01, 0x8b, 0xf5, 0x00, 0x02, 0xab, }, + { 0x62, 0x24, 0x93, 0x9a, 0x79, 0xf5, 0xf5, 0x93, }, + { 0xb0, 0xe4, 0xa9, 0x0b, 0xdf, 0x82, 0x00, 0x9e, }, + { 0xf3, 0xb9, 0xdd, 0x94, 0xc5, 0xbb, 0x5d, 0x7a, }, + { 0xa7, 0xad, 0x6b, 0x22, 0x46, 0x2f, 0xb3, 0xf4, }, + { 0xfb, 0xe5, 0x0e, 0x86, 0xbc, 0x8f, 0x1e, 0x75, }, + { 0x90, 0x3d, 0x84, 0xc0, 0x27, 0x56, 0xea, 0x14, }, + { 0xee, 0xf2, 0x7a, 0x8e, 0x90, 0xca, 0x23, 0xf7, }, + { 0xe5, 0x45, 0xbe, 0x49, 0x61, 0xca, 0x29, 0xa1, }, + { 0xdb, 0x9b, 0xc2, 0x57, 0x7f, 0xcc, 0x2a, 0x3f, }, + { 0x94, 0x47, 0xbe, 0x2c, 0xf5, 0xe9, 0x9a, 0x69, }, + { 0x9c, 0xd3, 0x8d, 0x96, 0xf0, 0xb3, 0xc1, 0x4b, }, + { 0xbd, 0x61, 0x79, 0xa7, 0x1d, 0xc9, 0x6d, 0xbb, }, + { 0x98, 0xee, 0xa2, 0x1a, 0xf2, 0x5c, 0xd6, 0xbe, }, + { 0xc7, 0x67, 0x3b, 0x2e, 0xb0, 0xcb, 0xf2, 0xd0, }, + { 0x88, 0x3e, 0xa3, 0xe3, 0x95, 0x67, 0x53, 0x93, }, + { 0xc8, 0xce, 0x5c, 0xcd, 0x8c, 0x03, 0x0c, 0xa8, }, + { 0x94, 0xaf, 0x49, 0xf6, 0xc6, 0x50, 0xad, 0xb8, }, + { 0xea, 0xb8, 0x85, 0x8a, 0xde, 0x92, 0xe1, 0xbc, }, + { 0xf3, 0x15, 0xbb, 0x5b, 0xb8, 0x35, 0xd8, 0x17, }, + { 0xad, 0xcf, 0x6b, 0x07, 0x63, 0x61, 0x2e, 0x2f, }, + { 0xa5, 0xc9, 0x1d, 0xa7, 0xac, 0xaa, 0x4d, 0xde, }, + { 0x71, 0x65, 0x95, 0x87, 0x66, 0x50, 0xa2, 0xa6, }, + { 0x28, 0xef, 0x49, 0x5c, 0x53, 0xa3, 0x87, 0xad, }, + { 0x42, 0xc3, 0x41, 0xd8, 0xfa, 0x92, 0xd8, 0x32, }, + { 0xce, 0x7c, 0xf2, 0x72, 0x2f, 0x51, 0x27, 0x71, }, + { 0xe3, 0x78, 0x59, 0xf9, 0x46, 0x23, 0xf3, 0xa7, }, + { 0x38, 0x12, 0x05, 0xbb, 0x1a, 0xb0, 0xe0, 0x12, }, + { 0xae, 0x97, 0xa1, 0x0f, 0xd4, 0x34, 0xe0, 0x15, }, + { 0xb4, 0xa3, 0x15, 0x08, 0xbe, 0xff, 0x4d, 0x31, }, + { 0x81, 0x39, 0x62, 0x29, 0xf0, 0x90, 0x79, 0x02, }, + { 0x4d, 0x0c, 0xf4, 0x9e, 0xe5, 0xd4, 0xdc, 0xca, }, + { 0x5c, 0x73, 0x33, 0x6a, 0x76, 0xd8, 0xbf, 0x9a, }, + { 0xd0, 0xa7, 0x04, 0x53, 0x6b, 0xa9, 0x3e, 0x0e, }, + { 0x92, 0x59, 0x58, 0xfc, 0xd6, 0x42, 0x0c, 0xad, }, + { 0xa9, 0x15, 0xc2, 0x9b, 0xc8, 0x06, 0x73, 0x18, }, + { 0x95, 0x2b, 0x79, 0xf3, 0xbc, 0x0a, 0xa6, 0xd4, }, + { 0xf2, 0x1d, 0xf2, 0xe4, 0x1d, 0x45, 0x35, 0xf9, }, + { 0x87, 0x57, 0x75, 0x19, 0x04, 0x8f, 0x53, 0xa9, }, + { 0x10, 0xa5, 0x6c, 0xf5, 0xdf, 0xcd, 0x9a, 0xdb, }, + { 0xeb, 0x75, 0x09, 0x5c, 0xcd, 0x98, 0x6c, 0xd0, }, + { 0x51, 0xa9, 0xcb, 0x9e, 0xcb, 0xa3, 0x12, 0xe6, }, + { 0x96, 0xaf, 0xad, 0xfc, 0x2c, 0xe6, 0x66, 0xc7, }, + { 0x72, 0xfe, 0x52, 0x97, 0x5a, 0x43, 0x64, 0xee, }, + { 0x5a, 0x16, 0x45, 0xb2, 0x76, 0xd5, 0x92, 0xa1, }, + { 0xb2, 0x74, 0xcb, 0x8e, 0xbf, 0x87, 0x87, 0x0a, }, + { 0x6f, 0x9b, 0xb4, 0x20, 0x3d, 0xe7, 0xb3, 0x81, }, + { 0xea, 0xec, 0xb2, 0xa3, 0x0b, 0x22, 0xa8, 0x7f, }, + { 0x99, 0x24, 0xa4, 0x3c, 0xc1, 0x31, 0x57, 0x24, }, + { 0xbd, 0x83, 0x8d, 0x3a, 0xaf, 0xbf, 0x8d, 0xb7, }, + { 0x0b, 0x1a, 0x2a, 0x32, 0x65, 0xd5, 0x1a, 0xea, }, + { 0x13, 0x50, 0x79, 0xa3, 0x23, 0x1c, 0xe6, 0x60, }, + { 0x93, 0x2b, 0x28, 0x46, 0xe4, 0xd7, 0x06, 0x66, }, + { 0xe1, 0x91, 0x5f, 0x5c, 0xb1, 0xec, 0xa4, 0x6c, }, + { 0xf3, 0x25, 0x96, 0x5c, 0xa1, 0x6d, 0x62, 0x9f, }, + { 0x57, 0x5f, 0xf2, 0x8e, 0x60, 0x38, 0x1b, 0xe5, }, + { 0x72, 0x45, 0x06, 0xeb, 0x4c, 0x32, 0x8a, 0x95, } +}; + +static int test_vectors(void) +{ + u8 in[MAXLEN], out[8], k[16]; + int i; + int ok = 1; + + for( i = 0; i < 16; ++i ) k[i] = i; + + for( i = 0; i < MAXLEN; ++i ) + { + in[i] = i; + crypto_auth( out, in, i, k ); + + if ( memcmp( out, vectors[i], 8 ) ) + { + printf( "test vector failed for %d bytes\n", i ); + ok = 0; + } + } + + return ok; +} + +static void test_siphash_vectors(abts_case *tc, void *data) +{ + ABTS_ASSERT(tc, "SipHash-2-4 test vectors", test_vectors()); +} + +abts_suite *testsiphash(abts_suite *suite) +{ + suite = ADD_SUITE(suite); + + abts_run_test(suite, test_siphash_vectors, NULL); + + return suite; +} diff --git a/test/testskiplist.c b/test/testskiplist.c new file mode 100644 index 00000000000..e1f64bad658 --- /dev/null +++ b/test/testskiplist.c @@ -0,0 +1,546 @@ +/* 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 "testutil.h" +#include "apr.h" +#include "apr_strings.h" +#include "apr_general.h" +#include "apr_pools.h" +#include "apr_skiplist.h" +#if APR_HAVE_STDIO_H +#include <stdio.h> +#endif +#if APR_HAVE_STDLIB_H +#include <stdlib.h> +#endif +#if APR_HAVE_STRING_H +#include <string.h> +#endif + +static apr_pool_t *ptmp = NULL; +static apr_skiplist *skiplist = NULL; + +static int skiplist_get_size(abts_case *tc, apr_skiplist *sl) +{ + size_t size = 0; + apr_skiplistnode *n; + for (n = apr_skiplist_getlist(sl); n; apr_skiplist_next(sl, &n)) { + ++size; + } + ABTS_TRUE(tc, size == apr_skiplist_size(sl)); + return size; +} + +static void skiplist_init(abts_case *tc, void *data) +{ + apr_time_t now = apr_time_now(); + srand((unsigned int)(((now >> 32) ^ now) & 0xffffffff)); + + ABTS_INT_EQUAL(tc, APR_SUCCESS, apr_skiplist_init(&skiplist, p)); + ABTS_PTR_NOTNULL(tc, skiplist); + apr_skiplist_set_compare(skiplist, (apr_skiplist_compare)strcmp, + (apr_skiplist_compare)strcmp); +} + +static void skiplist_find(abts_case *tc, void *data) +{ + const char *val; + + ABTS_PTR_NOTNULL(tc, apr_skiplist_insert(skiplist, "baton")); + val = apr_skiplist_find(skiplist, "baton", NULL); + ABTS_PTR_NOTNULL(tc, val); + ABTS_STR_EQUAL(tc, "baton", val); +} + +static void skiplist_dontfind(abts_case *tc, void *data) +{ + const char *val; + + val = apr_skiplist_find(skiplist, "keynotthere", NULL); + ABTS_PTR_EQUAL(tc, NULL, (void *)val); +} + +static void skiplist_insert(abts_case *tc, void *data) +{ + const char *val; + int i, height = 0; + + for (i = 0; i < 10; ++i) { + ABTS_PTR_EQUAL(tc, NULL, apr_skiplist_insert(skiplist, "baton")); + ABTS_TRUE(tc, 1 == skiplist_get_size(tc, skiplist)); + val = apr_skiplist_find(skiplist, "baton", NULL); + ABTS_PTR_NOTNULL(tc, val); + ABTS_STR_EQUAL(tc, "baton", val); + + if (height == 0) { + height = apr_skiplist_height(skiplist); + } + else { + ABTS_INT_EQUAL(tc, height, apr_skiplist_height(skiplist)); + } + } + + ABTS_PTR_NOTNULL(tc, apr_skiplist_insert(skiplist, "foo")); + ABTS_TRUE(tc, 2 == skiplist_get_size(tc, skiplist)); + val = apr_skiplist_find(skiplist, "foo", NULL); + ABTS_PTR_NOTNULL(tc, val); + ABTS_STR_EQUAL(tc, "foo", val); + + ABTS_PTR_NOTNULL(tc, apr_skiplist_insert(skiplist, "atfirst")); + ABTS_TRUE(tc, 3 == skiplist_get_size(tc, skiplist)); + val = apr_skiplist_find(skiplist, "atfirst", NULL); + ABTS_PTR_NOTNULL(tc, val); + ABTS_STR_EQUAL(tc, "atfirst", val); +} + +#define NUM_ADDS 100 +static void skiplist_add(abts_case *tc, void *data) +{ + const char *val; + size_t i, n = 0; + + apr_skiplist_remove_all(skiplist, NULL); + ABTS_TRUE(tc, 0 == skiplist_get_size(tc, skiplist)); + + for (i = 0; i < NUM_ADDS; ++i) { + n++; + ABTS_PTR_NOTNULL(tc, apr_skiplist_add(skiplist, "daton")); + ABTS_TRUE(tc, n == skiplist_get_size(tc, skiplist)); + val = apr_skiplist_find(skiplist, "daton", NULL); + ABTS_PTR_NOTNULL(tc, val); + ABTS_STR_EQUAL(tc, "daton", val); + + n++; + ABTS_PTR_NOTNULL(tc, apr_skiplist_add(skiplist, "baton")); + ABTS_TRUE(tc, n == skiplist_get_size(tc, skiplist)); + val = apr_skiplist_find(skiplist, "baton", NULL); + ABTS_PTR_NOTNULL(tc, val); + ABTS_STR_EQUAL(tc, "baton", val); + + n++; + ABTS_PTR_NOTNULL(tc, apr_skiplist_add(skiplist, "caton")); + ABTS_TRUE(tc, n == skiplist_get_size(tc, skiplist)); + val = apr_skiplist_find(skiplist, "caton", NULL); + ABTS_PTR_NOTNULL(tc, val); + ABTS_STR_EQUAL(tc, "caton", val); + + n++; + ABTS_PTR_NOTNULL(tc, apr_skiplist_add(skiplist, "aaton")); + ABTS_TRUE(tc, n == skiplist_get_size(tc, skiplist)); + val = apr_skiplist_find(skiplist, "aaton", NULL); + ABTS_PTR_NOTNULL(tc, val); + ABTS_STR_EQUAL(tc, "aaton", val); + } +} + +static void skiplist_replace(abts_case *tc, void *data) +{ + const char *val; + size_t n = skiplist_get_size(tc, skiplist); + + n -= NUM_ADDS - 1; + apr_skiplist_replace(skiplist, "daton", NULL); + ABTS_TRUE(tc, n == skiplist_get_size(tc, skiplist)); + val = apr_skiplist_find(skiplist, "daton", NULL); + ABTS_PTR_NOTNULL(tc, val); + ABTS_STR_EQUAL(tc, "daton", val); + + n -= NUM_ADDS - 1; + apr_skiplist_replace(skiplist, "baton", NULL); + ABTS_TRUE(tc, n == skiplist_get_size(tc, skiplist)); + val = apr_skiplist_find(skiplist, "baton", NULL); + ABTS_PTR_NOTNULL(tc, val); + ABTS_STR_EQUAL(tc, "baton", val); + + n -= NUM_ADDS - 1; + apr_skiplist_replace(skiplist, "caton", NULL); + ABTS_TRUE(tc, n == skiplist_get_size(tc, skiplist)); + val = apr_skiplist_find(skiplist, "caton", NULL); + ABTS_PTR_NOTNULL(tc, val); + ABTS_STR_EQUAL(tc, "caton", val); + + n -= NUM_ADDS - 1; + apr_skiplist_replace(skiplist, "aaton", NULL); + ABTS_TRUE(tc, n == skiplist_get_size(tc, skiplist)); + val = apr_skiplist_find(skiplist, "aaton", NULL); + ABTS_PTR_NOTNULL(tc, val); + ABTS_STR_EQUAL(tc, "aaton", val); + + ABTS_TRUE(tc, n == 4); +} + +static void skiplist_destroy(abts_case *tc, void *data) +{ + apr_skiplist_destroy(skiplist, NULL); + ABTS_TRUE(tc, 0 == apr_skiplist_size(skiplist)); + ABTS_TRUE(tc, 1 == apr_skiplist_height(skiplist)); + ABTS_TRUE(tc, NULL == apr_skiplist_getlist(skiplist)); +} + +static void skiplist_size(abts_case *tc, void *data) +{ + const char *val; + + ABTS_TRUE(tc, 0 == skiplist_get_size(tc, skiplist)); + + ABTS_PTR_NOTNULL(tc, apr_skiplist_insert(skiplist, "abc")); + ABTS_PTR_NOTNULL(tc, apr_skiplist_insert(skiplist, "ghi")); + ABTS_PTR_NOTNULL(tc, apr_skiplist_insert(skiplist, "def")); + val = apr_skiplist_find(skiplist, "abc", NULL); + ABTS_PTR_NOTNULL(tc, val); + ABTS_STR_EQUAL(tc, "abc", val); + val = apr_skiplist_find(skiplist, "ghi", NULL); + ABTS_PTR_NOTNULL(tc, val); + ABTS_STR_EQUAL(tc, "ghi", val); + val = apr_skiplist_find(skiplist, "def", NULL); + ABTS_PTR_NOTNULL(tc, val); + ABTS_STR_EQUAL(tc, "def", val); + + ABTS_TRUE(tc, 3 == skiplist_get_size(tc, skiplist)); + apr_skiplist_destroy(skiplist, NULL); +} + +static void skiplist_remove(abts_case *tc, void *data) +{ + const char *val; + + ABTS_TRUE(tc, 0 == skiplist_get_size(tc, skiplist)); + + ABTS_PTR_NOTNULL(tc, apr_skiplist_add(skiplist, "baton")); + ABTS_TRUE(tc, 1 == skiplist_get_size(tc, skiplist)); + val = apr_skiplist_find(skiplist, "baton", NULL); + ABTS_PTR_NOTNULL(tc, val); + ABTS_STR_EQUAL(tc, "baton", val); + + ABTS_PTR_NOTNULL(tc, apr_skiplist_add(skiplist, "baton")); + ABTS_TRUE(tc, 2 == skiplist_get_size(tc, skiplist)); + val = apr_skiplist_find(skiplist, "baton", NULL); + ABTS_PTR_NOTNULL(tc, val); + ABTS_STR_EQUAL(tc, "baton", val); + + ABTS_TRUE(tc, apr_skiplist_remove(skiplist, "baton", NULL) != 0); + ABTS_TRUE(tc, 1 == skiplist_get_size(tc, skiplist)); + val = apr_skiplist_find(skiplist, "baton", NULL); + ABTS_PTR_NOTNULL(tc, val); + ABTS_STR_EQUAL(tc, "baton", val); + + ABTS_PTR_NOTNULL(tc, apr_skiplist_add(skiplist, "baton")); + ABTS_TRUE(tc, 2 == skiplist_get_size(tc, skiplist)); + val = apr_skiplist_find(skiplist, "baton", NULL); + ABTS_PTR_NOTNULL(tc, val); + ABTS_STR_EQUAL(tc, "baton", val); + + /* remove all "baton"s */ + while (apr_skiplist_remove(skiplist, "baton", NULL)) + ; + ABTS_TRUE(tc, 0 == skiplist_get_size(tc, skiplist)); + val = apr_skiplist_find(skiplist, "baton", NULL); + ABTS_PTR_EQUAL(tc, NULL, val); +} + +#define NUM_RAND (100) +#define NUM_FIND (3 * NUM_RAND) +static void skiplist_random_loop(abts_case *tc, void *data) +{ + char **batons; + apr_skiplist *sl; + const char *val; + int i; + + ABTS_INT_EQUAL(tc, APR_SUCCESS, apr_skiplist_init(&sl, ptmp)); + apr_skiplist_set_compare(sl, (apr_skiplist_compare)strcmp, + (apr_skiplist_compare)strcmp); + apr_skiplist_set_preheight(sl, 7); + ABTS_INT_EQUAL(tc, 7, apr_skiplist_preheight(sl)); + + batons = apr_palloc(ptmp, NUM_FIND * sizeof(char*)); + + for (i = 0; i < NUM_FIND; ++i) { + if (i < NUM_RAND) { + batons[i] = apr_psprintf(ptmp, "%.6u", rand() % 1000000); + } + else { + batons[i] = apr_pstrdup(ptmp, batons[i % NUM_RAND]); + } + ABTS_PTR_NOTNULL(tc, apr_skiplist_add(sl, batons[i])); + val = apr_skiplist_find(sl, batons[i], NULL); + ABTS_PTR_NOTNULL(tc, val); + ABTS_STR_EQUAL(tc, batons[i], val); + } + + apr_pool_clear(ptmp); +} + +typedef struct elem { + int b; + int a; +} elem; + + +static void add_int_to_skiplist(abts_case *tc, apr_skiplist *list, int n){ + int* a = apr_skiplist_alloc(list, sizeof(int)); + *a = n; + ABTS_PTR_NOTNULL(tc, apr_skiplist_add(list, a)); +} + +static void add_elem_to_skiplist(abts_case *tc, apr_skiplist *list, elem n){ + elem* a = apr_skiplist_alloc(list, sizeof(elem)); + *a = n; + ABTS_PTR_NOTNULL(tc, apr_skiplist_add(list, a)); +} + +static int comp(void *a, void *b){ + return *((int*) a) - *((int*) b); +} + +static int scomp(void *a, void *b){ + return ((elem*) a)->a - ((elem*) b)->a; +} + +static int ecomp(void *a, void *b) +{ + elem const * const e1 = a; + elem const * const e2 = b; + if (e1->a < e2->a) { + return -1; + } + else if (e1->a > e2->a) { + return +1; + } + else if (e1->b < e2->b) { + return -1; + } + else if (e1->b > e2->b) { + return +1; + } + else { + return 0; + } +} + +/* Some tests below add multiple duplicates and then try to remove each one + * individually, in arbitrary order. + * + * Using apr_skiplist_remove_compare(..., scomp, NULL) would not work because + * it will likely remove any duplicate (the first one) encountered on the path, + * hence possibly not the expected one. + * + * Using apr_skiplist_remove_compare(..., ecomp, NULL) works provided all the + * duplicates (same a) don't also have the same b (which is the case in the + * test below), hence uniqueness is cooked in the elem itself. + * + * Another possibility is to rely on unique pointers, and then cook a remove + * function, like the following skiplist_remove_scomp(), which will go straight + * to the last duplicate (using scomp) and then iterate on the previous elems + * until pointers match. + * + * Providing uniqueness in the elem itself is the more clean/efficient option, + * but if all you have is a unique pointer the pattern in the function may be + * worth it ( or it's just a way to test several skiplist functionalities :) + */ +static void skiplist_remove_scomp(abts_case *tc, apr_skiplist *list, elem *n) +{ + elem *e; + apr_skiplistnode *iter = NULL; + e = apr_skiplist_last(list, n, &iter); + while (e && e != n) { + ABTS_INT_EQUAL(tc, 0, scomp(n, e)); + e = apr_skiplist_previous(list, &iter); + } + ABTS_PTR_EQUAL(tc, n, apr_skiplist_element(iter)); + apr_skiplist_remove_node(list, iter, NULL); +} + +static void skiplist_test(abts_case *tc, void *data) { + int test_elems = 10; + int i = 0, j = 0; + int *val = NULL; + elem *val2 = NULL; + apr_skiplist * list = NULL; + apr_skiplist * list2 = NULL; + apr_skiplist * list3 = NULL; + apr_skiplist * list4 = NULL; + int first_forty_two = 42, + second_forty_two = 42; + apr_array_header_t *array; + elem t1, t2, t3, t4, t5; + t1.a = 1; t1.b = 1; + t2.a = 42; t2.b = 1; + t3.a = 42; t3.b = 2; + t4.a = 42; t4.b = 3; + t5.a = 142; t5.b = 1; + + ABTS_INT_EQUAL(tc, APR_SUCCESS, apr_skiplist_init(&list, ptmp)); + apr_skiplist_set_compare(list, comp, comp); + + /* insert 10 objects */ + for (i = 0; i < test_elems; ++i){ + add_int_to_skiplist(tc, list, i); + } + + /* remove all objects */ + while ((val = apr_skiplist_pop(list, NULL))){ + ABTS_INT_EQUAL(tc, *val, j++); + } + + /* insert 10 objects again */ + for (i = test_elems; i < test_elems+test_elems; ++i){ + add_int_to_skiplist(tc, list, i); + } + + j = test_elems; + while ((val = apr_skiplist_pop(list, NULL))){ + ABTS_INT_EQUAL(tc, *val, j++); + } + + /* empty */ + val = apr_skiplist_pop(list, NULL); + ABTS_PTR_EQUAL(tc, val, NULL); + + add_int_to_skiplist(tc, list, 42); + val = apr_skiplist_pop(list, NULL); + ABTS_INT_EQUAL(tc, *val, 42); + + /* empty */ + val = apr_skiplist_pop(list, NULL); + ABTS_PTR_EQUAL(tc, val, NULL); + + ABTS_PTR_NOTNULL(tc, apr_skiplist_add(list, &first_forty_two)); + add_int_to_skiplist(tc, list, 1); + add_int_to_skiplist(tc, list, 142); + ABTS_PTR_NOTNULL(tc, apr_skiplist_add(list, &second_forty_two)); + val = apr_skiplist_peek(list); + ABTS_INT_EQUAL(tc, *val, 1); + val = apr_skiplist_pop(list, NULL); + ABTS_INT_EQUAL(tc, *val, 1); + val = apr_skiplist_peek(list); + ABTS_PTR_EQUAL(tc, val, &first_forty_two); + ABTS_INT_EQUAL(tc, *val, 42); + val = apr_skiplist_pop(list, NULL); + ABTS_PTR_EQUAL(tc, val, &first_forty_two); + ABTS_INT_EQUAL(tc, *val, 42); + val = apr_skiplist_pop(list, NULL); + ABTS_PTR_EQUAL(tc, val, &second_forty_two); + ABTS_INT_EQUAL(tc, *val, 42); + val = apr_skiplist_peek(list); + ABTS_INT_EQUAL(tc, *val, 142); + + ABTS_INT_EQUAL(tc, APR_SUCCESS, apr_skiplist_init(&list2, ptmp)); + apr_skiplist_set_compare(list2, scomp, scomp); + add_elem_to_skiplist(tc, list2, t2); + add_elem_to_skiplist(tc, list2, t1); + add_elem_to_skiplist(tc, list2, t3); + add_elem_to_skiplist(tc, list2, t5); + add_elem_to_skiplist(tc, list2, t4); + val2 = apr_skiplist_pop(list2, NULL); + ABTS_INT_EQUAL(tc, val2->a, 1); + val2 = apr_skiplist_pop(list2, NULL); + ABTS_INT_EQUAL(tc, val2->a, 42); + ABTS_INT_EQUAL(tc, val2->b, 1); + val2 = apr_skiplist_pop(list2, NULL); + ABTS_INT_EQUAL(tc, val2->a, 42); + ABTS_INT_EQUAL(tc, val2->b, 2); + val2 = apr_skiplist_pop(list2, NULL); + ABTS_INT_EQUAL(tc, val2->a, 42); + ABTS_INT_EQUAL(tc, val2->b, 3); + val2 = apr_skiplist_pop(list2, NULL); + ABTS_INT_EQUAL(tc, val2->a, 142); + ABTS_INT_EQUAL(tc, val2->b, 1); + + ABTS_INT_EQUAL(tc, APR_SUCCESS, apr_skiplist_init(&list3, ptmp)); + apr_skiplist_set_compare(list3, ecomp, ecomp); + array = apr_array_make(ptmp, 10, sizeof(elem *)); + for (i = 0; i < 10; ++i) { + elem *e = apr_palloc(ptmp, sizeof *e); + e->a = 4224; + e->b = i; + APR_ARRAY_PUSH(array, elem *) = e; + ABTS_PTR_NOTNULL(tc, apr_skiplist_insert(list3, e)); + } + for (i = 0; i < 5; ++i) { + elem *e = APR_ARRAY_IDX(array, i, elem *); + val2 = apr_skiplist_find(list3, e, NULL); + ABTS_PTR_EQUAL(tc, e, val2); + ABTS_TRUE(tc, apr_skiplist_remove(list3, e, NULL) != 0); + } + for (i = 0; i < 5; ++i) { + elem *e = APR_ARRAY_IDX(array, 9 - i, elem *); + val2 = apr_skiplist_find(list3, e, NULL); + ABTS_PTR_EQUAL(tc, e, val2); + ABTS_TRUE(tc, apr_skiplist_remove(list3, e, NULL) != 0); + } + + ABTS_INT_EQUAL(tc, APR_SUCCESS, apr_skiplist_init(&list4, ptmp)); + apr_skiplist_set_compare(list4, scomp, scomp); + for (i = 0; i < 5; ++i){ + add_elem_to_skiplist(tc, list4, t1); + } + for (i = 0; i < 5; ++i){ + add_elem_to_skiplist(tc, list4, t2); + } + ABTS_PTR_NOTNULL(tc, apr_skiplist_add(list4, &t2)); + for (i = 0; i < 5; ++i){ + add_elem_to_skiplist(tc, list4, t2); + } + for (i = 0; i < 5; ++i){ + add_elem_to_skiplist(tc, list4, t3); + } + ABTS_PTR_NOTNULL(tc, apr_skiplist_add(list4, &t3)); + for (i = 0; i < 5; ++i){ + add_elem_to_skiplist(tc, list4, t3); + } + for (i = 0; i < 5; ++i){ + add_elem_to_skiplist(tc, list4, t4); + } + ABTS_PTR_NOTNULL(tc, apr_skiplist_add(list4, &t4)); + for (i = 0; i < 5; ++i){ + add_elem_to_skiplist(tc, list4, t4); + } + for (i = 0; i < 5; ++i){ + add_elem_to_skiplist(tc, list4, t5); + } + skiplist_remove_scomp(tc, list4, &t2); + skiplist_remove_scomp(tc, list4, &t3); + skiplist_remove_scomp(tc, list4, &t4); + + apr_pool_clear(ptmp); +} + + +abts_suite *testskiplist(abts_suite *suite) +{ + suite = ADD_SUITE(suite) + + apr_pool_create(&ptmp, p); + + abts_run_test(suite, skiplist_init, NULL); + abts_run_test(suite, skiplist_find, NULL); + abts_run_test(suite, skiplist_dontfind, NULL); + abts_run_test(suite, skiplist_insert, NULL); + abts_run_test(suite, skiplist_add, NULL); + abts_run_test(suite, skiplist_replace, NULL); + abts_run_test(suite, skiplist_destroy, NULL); + abts_run_test(suite, skiplist_size, NULL); + abts_run_test(suite, skiplist_remove, NULL); + abts_run_test(suite, skiplist_random_loop, NULL); + + abts_run_test(suite, skiplist_test, NULL); + + apr_pool_destroy(ptmp); + + return suite; +} + diff --git a/test/testsleep.c b/test/testsleep.c new file mode 100644 index 00000000000..eff24ddf6ea --- /dev/null +++ b/test/testsleep.c @@ -0,0 +1,53 @@ +/* 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 "time.h" +#include "apr_thread_proc.h" +#include "apr_errno.h" +#include "apr_general.h" +#include "apr_lib.h" +#include <stdio.h> +#include <stdlib.h> +#include "testutil.h" + +#define SLEEP_INTERVAL 5 + +static void sleep_one(abts_case *tc, void *data) +{ + time_t pretime = time(NULL); + time_t posttime; + time_t timediff; + + apr_sleep(apr_time_from_sec(SLEEP_INTERVAL)); + posttime = time(NULL); + + /* normalize the timediff. We should have slept for SLEEP_INTERVAL, so + * we should just subtract that out. + */ + timediff = posttime - pretime - SLEEP_INTERVAL; + ABTS_TRUE(tc, timediff >= 0); + ABTS_TRUE(tc, timediff <= 1); +} + +abts_suite *testsleep(abts_suite *suite) +{ + suite = ADD_SUITE(suite) + + abts_run_test(suite, sleep_one, NULL); + + return suite; +} + diff --git a/test/testsock.c b/test/testsock.c index 98f164480be..23a0073fe42 100644 --- a/test/testsock.c +++ b/test/testsock.c @@ -1,134 +1,768 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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 <stdio.h> -#include <stdlib.h> -#include <signal.h> +#include "testutil.h" +#include "testsock.h" #include "apr_thread_proc.h" +#include "apr_network_io.h" #include "apr_errno.h" #include "apr_general.h" #include "apr_lib.h" +#include "apr_strings.h" +#include "apr_poll.h" +#define APR_WANT_BYTEFUNC +#include "apr_want.h" -#define STRLEN 15 +#define UNIX_SOCKET_NAME "/tmp/apr-socket" +#define IPV4_SOCKET_NAME "127.0.0.1" +static char *socket_name = NULL; +static int socket_type = APR_INET; -int main(int argc, char *argv[]) +static void launch_child(abts_case *tc, apr_proc_t *proc, const char *arg1, apr_pool_t *p) { - ap_pool_t *context; + apr_procattr_t *procattr; + const char *args[4]; + apr_status_t rv; - ap_procattr_t *attr1 = NULL; - ap_procattr_t *attr2 = NULL; - ap_proc_t *proc1 = NULL; - ap_proc_t *proc2 = NULL; - ap_status_t s1; - ap_status_t s2; - char *args[2]; + rv = apr_procattr_create(&procattr, p); + APR_ASSERT_SUCCESS(tc, "Couldn't create procattr", rv); - fprintf(stdout, "Initializing........."); - if (ap_initialize() != APR_SUCCESS) { - fprintf(stderr, "Something went wrong\n"); - exit(-1); - } - fprintf(stdout, "OK\n"); - atexit(ap_terminate); + rv = apr_procattr_io_set(procattr, APR_NO_PIPE, APR_NO_PIPE, + APR_NO_PIPE); + APR_ASSERT_SUCCESS(tc, "Couldn't set io in procattr", rv); + + rv = apr_procattr_error_check_set(procattr, 1); + APR_ASSERT_SUCCESS(tc, "Couldn't set error check in procattr", rv); + + rv = apr_procattr_cmdtype_set(procattr, APR_PROGRAM_ENV); + APR_ASSERT_SUCCESS(tc, "Couldn't set copy environment", rv); + + args[0] = "sockchild" EXTENSION; + args[1] = arg1; + args[2] = socket_name; + args[3] = NULL; + rv = apr_proc_create(proc, TESTBINPATH "sockchild" EXTENSION, args, NULL, + procattr, p); + APR_ASSERT_SUCCESS(tc, "Couldn't launch program", rv); +} + +static int wait_child(abts_case *tc, apr_proc_t *proc) +{ + int exitcode; + apr_exit_why_e why; + + ABTS_ASSERT(tc, "Error waiting for child process", + apr_proc_wait(proc, &exitcode, &why, APR_WAIT) == APR_CHILD_DONE); + + ABTS_ASSERT(tc, "child terminated normally", why == APR_PROC_EXIT); + return exitcode; +} + +static void test_addr_info(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_sockaddr_t *sa; + int rc; + + rv = apr_sockaddr_info_get(&sa, NULL, APR_UNSPEC, 80, 0, p); + APR_ASSERT_SUCCESS(tc, "Problem generating sockaddr", rv); + + rc = apr_sockaddr_is_wildcard(sa); + ABTS_INT_NEQUAL(tc, 0, rc); + + rv = apr_sockaddr_info_get(&sa, "127.0.0.1", APR_UNSPEC, 80, 0, p); + APR_ASSERT_SUCCESS(tc, "Problem generating sockaddr", rv); + ABTS_STR_EQUAL(tc, "127.0.0.1", sa->hostname); + + rc = apr_sockaddr_is_wildcard(sa); + ABTS_INT_EQUAL(tc, 0, rc); + + rv = apr_sockaddr_info_get(&sa, "127.0.0.1", APR_UNSPEC, 0, 0, p); + APR_ASSERT_SUCCESS(tc, "Problem generating sockaddr", rv); + ABTS_STR_EQUAL(tc, "127.0.0.1", sa->hostname); + ABTS_INT_EQUAL(tc, 0, sa->port); + ABTS_INT_EQUAL(tc, 0, ntohs(sa->sa.sin.sin_port)); +} + +static void test_addr_copy(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_sockaddr_t *sa1, *sa2; + int rc; + const char *hosts[] = { + "127.0.0.1", +#if APR_HAVE_IPV6 + "::1", +#endif + NULL + }, **host = hosts; + + /* Loop up to and including NULL */ + do { + rv = apr_sockaddr_info_get(&sa1, *host, APR_UNSPEC, 80, 0, p); + APR_ASSERT_SUCCESS(tc, "Problem generating sockaddr", rv); + + rv = apr_sockaddr_info_copy(&sa2, sa1, p); + APR_ASSERT_SUCCESS(tc, "Problem copying sockaddr", rv); + + ABTS_PTR_NOTNULL(tc, sa1); + do { + ABTS_PTR_NOTNULL(tc, sa2); + + rc = apr_sockaddr_equal(sa2, sa1); + ABTS_INT_NEQUAL(tc, 0, rc); + ABTS_INT_EQUAL(tc, 80, sa1->port); + ABTS_INT_EQUAL(tc, sa2->port, sa1->port); + ABTS_INT_EQUAL(tc, 80, ntohs(sa1->sa.sin.sin_port)); + ABTS_INT_EQUAL(tc, ntohs(sa2->sa.sin.sin_port), ntohs(sa1->sa.sin.sin_port)); + + if (*host) { + ABTS_PTR_NOTNULL(tc, sa1->hostname); + ABTS_PTR_NOTNULL(tc, sa2->hostname); + ABTS_STR_EQUAL(tc, *host, sa1->hostname); + ABTS_STR_EQUAL(tc, sa1->hostname, sa2->hostname); + ABTS_TRUE(tc, sa1->hostname != sa2->hostname); + } + else { + ABTS_PTR_EQUAL(tc, NULL, sa1->hostname); + ABTS_PTR_EQUAL(tc, NULL, sa2->hostname); + } + + } while ((sa2 = sa2->next, sa1 = sa1->next)); + ABTS_PTR_EQUAL(tc, NULL, sa2); + + } while (*host++); +} + +static void test_serv_by_name(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_sockaddr_t *sa; + + rv = apr_sockaddr_info_get(&sa, NULL, APR_UNSPEC, 0, 0, p); + APR_ASSERT_SUCCESS(tc, "Problem generating sockaddr", rv); + + rv = apr_getservbyname(sa, "ftp"); + APR_ASSERT_SUCCESS(tc, "Problem getting ftp service", rv); + ABTS_INT_EQUAL(tc, 21, sa->port); + + rv = apr_getservbyname(sa, "complete_and_utter_rubbish"); + APR_ASSERT_SUCCESS(tc, "Problem getting non-existent service", !rv); + + rv = apr_getservbyname(sa, "telnet"); + APR_ASSERT_SUCCESS(tc, "Problem getting telnet service", rv); + ABTS_INT_EQUAL(tc, 23, sa->port); +} - fprintf(stdout, "Creating context......."); - if (ap_create_pool(&context, NULL) != APR_SUCCESS) { - fprintf(stderr, "Could not create context\n"); - exit(-1); +static apr_socket_t *setup_socket(abts_case *tc) +{ + apr_status_t rv; + apr_sockaddr_t *sa; + apr_socket_t *sock; + + rv = apr_sockaddr_info_get(&sa, socket_name, socket_type, 8021, 0, p); + APR_ASSERT_SUCCESS(tc, "Problem generating sockaddr", rv); + + rv = apr_socket_create(&sock, sa->family, SOCK_STREAM, APR_PROTO_TCP, p); + APR_ASSERT_SUCCESS(tc, "Problem creating socket", rv); + + rv = apr_socket_opt_set(sock, APR_SO_REUSEADDR, 1); + APR_ASSERT_SUCCESS(tc, "Could not set REUSEADDR on socket", rv); + + rv = apr_socket_bind(sock, sa); + APR_ASSERT_SUCCESS(tc, "Problem binding to port", rv); + if (rv) return NULL; + + rv = apr_socket_listen(sock, 5); + APR_ASSERT_SUCCESS(tc, "Problem listening on socket", rv); + + return sock; +} + +static void test_create_bind_listen(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_socket_t *sock = setup_socket(tc); + + if (!sock) return; + + rv = apr_socket_close(sock); + APR_ASSERT_SUCCESS(tc, "Problem closing socket", rv); +} + +static void test_send(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_socket_t *sock; + apr_socket_t *sock2; + apr_proc_t proc; + int protocol; + apr_size_t length; + + sock = setup_socket(tc); + if (!sock) return; + + launch_child(tc, &proc, "read", p); + + rv = apr_socket_accept(&sock2, sock, p); + APR_ASSERT_SUCCESS(tc, "Problem with receiving connection", rv); + + apr_socket_protocol_get(sock2, &protocol); + ABTS_INT_EQUAL(tc, APR_PROTO_TCP, protocol); + + length = strlen(DATASTR); + apr_socket_send(sock2, DATASTR, &length); + + /* Make sure that the client received the data we sent */ + ABTS_SIZE_EQUAL(tc, strlen(DATASTR), wait_child(tc, &proc)); + + rv = apr_socket_close(sock2); + APR_ASSERT_SUCCESS(tc, "Problem closing connected socket", rv); + rv = apr_socket_close(sock); + APR_ASSERT_SUCCESS(tc, "Problem closing socket", rv); +} + +static void test_recv(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_socket_t *sock; + apr_socket_t *sock2; + apr_proc_t proc; + int protocol; + apr_size_t length = STRLEN; + char datastr[STRLEN]; + + sock = setup_socket(tc); + if (!sock) return; + + launch_child(tc, &proc, "write", p); + + rv = apr_socket_accept(&sock2, sock, p); + APR_ASSERT_SUCCESS(tc, "Problem with receiving connection", rv); + + apr_socket_protocol_get(sock2, &protocol); + ABTS_INT_EQUAL(tc, APR_PROTO_TCP, protocol); + + memset(datastr, 0, STRLEN); + apr_socket_recv(sock2, datastr, &length); + + /* Make sure that the server received the data we sent */ + ABTS_STR_EQUAL(tc, DATASTR, datastr); + ABTS_SIZE_EQUAL(tc, strlen(datastr), wait_child(tc, &proc)); + + rv = apr_socket_close(sock2); + APR_ASSERT_SUCCESS(tc, "Problem closing connected socket", rv); + rv = apr_socket_close(sock); + APR_ASSERT_SUCCESS(tc, "Problem closing socket", rv); +} + +static void test_atreadeof(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_socket_t *sock; + apr_socket_t *sock2; + apr_proc_t proc; + apr_size_t length = STRLEN; + char datastr[STRLEN]; + int atreadeof = -1; + + sock = setup_socket(tc); + if (!sock) return; + + launch_child(tc, &proc, "write", p); + + rv = apr_socket_accept(&sock2, sock, p); + APR_ASSERT_SUCCESS(tc, "Problem with receiving connection", rv); + + /* Check that the remote socket is still open */ + rv = apr_socket_atreadeof(sock2, &atreadeof); + APR_ASSERT_SUCCESS(tc, "Determine whether at EOF, #1", rv); + ABTS_INT_EQUAL(tc, 0, atreadeof); + + memset(datastr, 0, STRLEN); + apr_socket_recv(sock2, datastr, &length); + + /* Make sure that the server received the data we sent */ + ABTS_STR_EQUAL(tc, DATASTR, datastr); + ABTS_SIZE_EQUAL(tc, strlen(datastr), wait_child(tc, &proc)); + + /* The child is dead, so should be the remote socket */ + rv = apr_socket_atreadeof(sock2, &atreadeof); + APR_ASSERT_SUCCESS(tc, "Determine whether at EOF, #2", rv); + ABTS_INT_EQUAL(tc, 1, atreadeof); + + rv = apr_socket_close(sock2); + APR_ASSERT_SUCCESS(tc, "Problem closing connected socket", rv); + + launch_child(tc, &proc, "close", p); + + rv = apr_socket_accept(&sock2, sock, p); + APR_ASSERT_SUCCESS(tc, "Problem with receiving connection", rv); + + /* The child closed the socket as soon as it could... */ + rv = apr_socket_atreadeof(sock2, &atreadeof); + APR_ASSERT_SUCCESS(tc, "Determine whether at EOF, #3", rv); + if (!atreadeof) { /* ... but perhaps not yet; wait a moment */ + apr_sleep(apr_time_from_msec(5)); + rv = apr_socket_atreadeof(sock2, &atreadeof); + APR_ASSERT_SUCCESS(tc, "Determine whether at EOF, #4", rv); } - fprintf(stdout, "OK\n"); + ABTS_INT_EQUAL(tc, 1, atreadeof); + wait_child(tc, &proc); + + rv = apr_socket_close(sock2); + APR_ASSERT_SUCCESS(tc, "Problem closing connected socket", rv); + + rv = apr_socket_close(sock); + APR_ASSERT_SUCCESS(tc, "Problem closing socket", rv); +} + +static void test_timeout(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_socket_t *sock; + apr_socket_t *sock2; + apr_proc_t proc; + int protocol; + int exit; + + sock = setup_socket(tc); + if (!sock) return; + + launch_child(tc, &proc, "read", p); + + rv = apr_socket_accept(&sock2, sock, p); + APR_ASSERT_SUCCESS(tc, "Problem with receiving connection", rv); + + apr_socket_protocol_get(sock2, &protocol); + ABTS_INT_EQUAL(tc, APR_PROTO_TCP, protocol); + + exit = wait_child(tc, &proc); + ABTS_INT_EQUAL(tc, SOCKET_TIMEOUT, exit); - fprintf(stdout, "This test relies on the process test working. Please\n"); - fprintf(stdout, "run that test first, and only run this test when it\n"); - fprintf(stdout, "completes successfully. Alternatively, you could run\n"); - fprintf(stdout, "server and client by yourself.\n"); + /* We didn't write any data, so make sure the child program returns + * an error. + */ + rv = apr_socket_close(sock2); + APR_ASSERT_SUCCESS(tc, "Problem closing connected socket", rv); + rv = apr_socket_close(sock); + APR_ASSERT_SUCCESS(tc, "Problem closing socket", rv); +} + +static void test_print_addr(abts_case *tc, void *data) +{ + apr_sockaddr_t *sa; + apr_status_t rv; + char *s; - fprintf(stdout, "Creating children to run network tests.......\n"); - s1 = ap_createprocattr_init(&attr1, context); - s2 = ap_createprocattr_init(&attr2, context); + rv = apr_sockaddr_info_get(&sa, "0.0.0.0", APR_INET, 80, 0, p); + APR_ASSERT_SUCCESS(tc, "Problem generating sockaddr", rv); - if (s1 != APR_SUCCESS || s2 != APR_SUCCESS) { - fprintf(stderr, "Problem creating proc attrs\n"); - exit(-1); + s = apr_psprintf(p, "foo %pI bar", sa); + + ABTS_STR_EQUAL(tc, "foo 0.0.0.0:80 bar", s); + +#if APR_HAVE_IPV6 + rv = apr_sockaddr_info_get(&sa, "::ffff:0.0.0.0", APR_INET6, 80, 0, p); + APR_ASSERT_SUCCESS(tc, "Problem generating sockaddr", rv); + if (rv == APR_SUCCESS) + ABTS_TRUE(tc, sa != NULL); + if (rv == APR_SUCCESS && sa) { + /* sa should now be a v4-mapped IPv6 address. */ + char buf[128]; + int rc; + + rc = apr_sockaddr_is_wildcard(sa); + ABTS_INT_NEQUAL(tc, 0, rc); + + memset(buf, 'z', sizeof buf); + + APR_ASSERT_SUCCESS(tc, "could not get IP address", + apr_sockaddr_ip_getbuf(buf, 22, sa)); + + ABTS_STR_EQUAL(tc, "0.0.0.0", buf); } +#endif +} - args[0] = ap_pstrdup(context, "server"); - args[1] = NULL; - s1 = ap_create_process(&proc1, "./server", args, NULL, attr1, context); +static void test_get_addr(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_socket_t *ld, *sd, *cd; + apr_sockaddr_t *sa, *ca; + apr_pool_t *subp; + char *a, *b; + + APR_ASSERT_SUCCESS(tc, "create subpool", apr_pool_create(&subp, p)); + + ld = setup_socket(tc); + if (!ld) return; + + APR_ASSERT_SUCCESS(tc, + "get local address of bound socket", + apr_socket_addr_get(&sa, APR_LOCAL, ld)); + + rv = apr_socket_create(&cd, sa->family, SOCK_STREAM, + APR_PROTO_TCP, subp); + APR_ASSERT_SUCCESS(tc, "create client socket", rv); - args[0] = ap_pstrdup(context, "client"); - s2 = ap_create_process(&proc2, "./client", args, NULL, attr2, context); + APR_ASSERT_SUCCESS(tc, "enable non-block mode", + apr_socket_opt_set(cd, APR_SO_NONBLOCK, 1)); - if (s1 != APR_SUCCESS || s2 != APR_SUCCESS) { - fprintf(stderr, "Problem spawning new process\n"); - exit(-1); + /* It is valid for a connect() on a socket with NONBLOCK set to + * succeed (if the connection can be established synchronously), + * but if it does, this test cannot proceed. */ + rv = apr_socket_connect(cd, sa); + if (rv == APR_SUCCESS) { + apr_socket_close(ld); + apr_socket_close(cd); + ABTS_NOT_IMPL(tc, "Cannot test if connect completes " + "synchronously"); + return; } - while ((s1 = ap_wait_proc(proc1, APR_NOWAIT)) != APR_CHILD_DONE || - (s2 = ap_wait_proc(proc2, APR_NOWAIT)) != APR_CHILD_DONE) { - continue; + if (!APR_STATUS_IS_EINPROGRESS(rv)) { + apr_socket_close(ld); + apr_socket_close(cd); + APR_ASSERT_SUCCESS(tc, "connect to listener", rv); + return; + } + + APR_ASSERT_SUCCESS(tc, "accept connection", + apr_socket_accept(&sd, ld, subp)); + + { + /* wait for writability */ + apr_pollfd_t pfd; + int n; + + pfd.p = p; + pfd.desc_type = APR_POLL_SOCKET; + pfd.reqevents = APR_POLLOUT|APR_POLLHUP; + pfd.desc.s = cd; + pfd.client_data = NULL; + + APR_ASSERT_SUCCESS(tc, "poll for connect completion", + apr_poll(&pfd, 1, &n, 5 * APR_USEC_PER_SEC)); + } - if (s1 == APR_SUCCESS) { - ap_kill(proc2, SIGTERM); - ap_wait_proc(proc2, APR_WAIT); + APR_ASSERT_SUCCESS(tc, "get local address of server socket", + apr_socket_addr_get(&sa, APR_LOCAL, sd)); + APR_ASSERT_SUCCESS(tc, "get remote address of client socket", + apr_socket_addr_get(&ca, APR_REMOTE, cd)); + + /* Test that the pool of the returned sockaddr objects exactly + * match the socket. */ + ABTS_PTR_EQUAL(tc, subp, sa->pool); + ABTS_PTR_EQUAL(tc, subp, ca->pool); + + /* Check equivalence. */ + a = apr_psprintf(p, "%pI fam=%d", sa, sa->family); + b = apr_psprintf(p, "%pI fam=%d", ca, ca->family); + ABTS_STR_EQUAL(tc, a, b); + + /* Check pool of returned sockaddr, as above. */ + APR_ASSERT_SUCCESS(tc, "get local address of client socket", + apr_socket_addr_get(&sa, APR_LOCAL, cd)); + APR_ASSERT_SUCCESS(tc, "get remote address of server socket", + apr_socket_addr_get(&ca, APR_REMOTE, sd)); + + /* Check equivalence. */ + a = apr_psprintf(p, "%pI fam=%d", sa, sa->family); + b = apr_psprintf(p, "%pI fam=%d", ca, ca->family); + ABTS_STR_EQUAL(tc, a, b); + + ABTS_PTR_EQUAL(tc, subp, sa->pool); + ABTS_PTR_EQUAL(tc, subp, ca->pool); + + apr_socket_close(cd); + apr_socket_close(sd); + apr_socket_close(ld); + + apr_pool_destroy(subp); +} + +static void test_wait(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_socket_t *server; + apr_socket_t *server_connection; + apr_sockaddr_t *server_addr; + apr_socket_t *client; + apr_interval_time_t delay = 200000; + apr_time_t start_time; + apr_time_t end_time; + apr_size_t nbytes; + int connected = FALSE; + + server = setup_socket(tc); + if (!server) return; + + rv = apr_sockaddr_info_get(&server_addr, socket_name, socket_type, 8021, 0, p); + APR_ASSERT_SUCCESS(tc, "setting up sockaddr", rv); + + rv = apr_socket_create(&client, server_addr->family, SOCK_STREAM, 0, p); + APR_ASSERT_SUCCESS(tc, "creating client socket", rv); + + rv = apr_socket_timeout_set(client, 0); + APR_ASSERT_SUCCESS(tc, "setting client socket timeout", rv); + + rv = apr_socket_connect(client, server_addr); + + if (rv == APR_SUCCESS) { + connected = TRUE; } else { - ap_kill(proc1, SIGTERM); - ap_wait_proc(proc1, APR_WAIT); + ABTS_ASSERT(tc, "connecting client to server", APR_STATUS_IS_EINPROGRESS(rv)); + } + + rv = apr_socket_accept(&server_connection, server, p); + APR_ASSERT_SUCCESS(tc, "accepting client connection", rv); + + if (!connected) { + rv = apr_socket_connect(client, server_addr); + APR_ASSERT_SUCCESS(tc, "connecting client to server", rv); } - fprintf(stdout, "Network test completed.\n"); - return 1; + rv = apr_socket_timeout_set(client, delay); + APR_ASSERT_SUCCESS(tc, "setting client socket timeout", rv); + + start_time = apr_time_now(); + rv = apr_socket_wait(client, APR_WAIT_READ); + ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_TIMEUP(rv)); + + end_time = apr_time_now(); + ABTS_ASSERT(tc, "apr_socket_wait() waited for the time out", end_time - start_time >= delay); + + nbytes = 4; + rv = apr_socket_send(server_connection, "data", &nbytes); + APR_ASSERT_SUCCESS(tc, "Couldn't write to client", rv); + + rv = apr_socket_wait(client, APR_WAIT_READ); + APR_ASSERT_SUCCESS(tc, "Wait for socket failed", rv); + + rv = apr_socket_close(server); + APR_ASSERT_SUCCESS(tc, "couldn't close server socket", rv); } + +/* Make sure that setting a connected socket non-blocking works + * when the listening socket was non-blocking. + * If APR thinks that non-blocking is inherited but it really + * isn't, this testcase will fail. + */ +static void test_nonblock_inheritance(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_socket_t *sock; + apr_socket_t *sock2; + apr_proc_t proc; + char buffer[10]; + apr_size_t length; + int tries; + + sock = setup_socket(tc); + if (!sock) return; + + rv = apr_socket_opt_set(sock, APR_SO_NONBLOCK, 1); + APR_ASSERT_SUCCESS(tc, "Could not make listening socket nonblocking", rv); + + launch_child(tc, &proc, "write_after_delay", p); + + tries = 10; + while (tries--) { + rv = apr_socket_accept(&sock2, sock, p); + if (!APR_STATUS_IS_EAGAIN(rv)) { + break; + } + apr_sleep(apr_time_from_msec(50)); + } + APR_ASSERT_SUCCESS(tc, "Problem with receiving connection", rv); + + rv = apr_socket_opt_set(sock2, APR_SO_NONBLOCK, 1); + APR_ASSERT_SUCCESS(tc, "Could not make connected socket nonblocking", rv); + + length = sizeof buffer; + rv = apr_socket_recv(sock2, buffer, &length); + ABTS_ASSERT(tc, "should have gotten EAGAIN", APR_STATUS_IS_EAGAIN(rv)); + + wait_child(tc, &proc); + + rv = apr_socket_close(sock2); + APR_ASSERT_SUCCESS(tc, "Problem closing connected socket", rv); + rv = apr_socket_close(sock); + APR_ASSERT_SUCCESS(tc, "Problem closing socket", rv); +} + +static void test_freebind(abts_case *tc, void *data) +{ +#ifdef IP_FREEBIND + apr_status_t rv; + apr_socket_t *sock; + apr_sockaddr_t *sa; + apr_int32_t on; + + /* RFC 5737 address */ + rv = apr_sockaddr_info_get(&sa, "192.0.2.1", APR_INET, 8080, 0, p); + APR_ASSERT_SUCCESS(tc, "Problem generating sockaddr", rv); + + rv = apr_socket_create(&sock, sa->family, SOCK_STREAM, APR_PROTO_TCP, p); + APR_ASSERT_SUCCESS(tc, "Problem creating socket", rv); + + rv = apr_socket_opt_set(sock, APR_SO_REUSEADDR, 1); + APR_ASSERT_SUCCESS(tc, "Could not set REUSEADDR on socket", rv); + + rv = apr_socket_opt_set(sock, APR_SO_FREEBIND, 1); + APR_ASSERT_SUCCESS(tc, "Could not enable FREEBIND option", rv); + + rv = apr_socket_opt_get(sock, APR_SO_FREEBIND, &on); + APR_ASSERT_SUCCESS(tc, "Could not retrieve FREEBIND option", rv); + ABTS_INT_EQUAL(tc, 1, on); + + rv = apr_socket_bind(sock, sa); + APR_ASSERT_SUCCESS(tc, "Problem binding to port with FREEBIND", rv); + + rv = apr_socket_close(sock); + APR_ASSERT_SUCCESS(tc, "Problem closing socket", rv); +#endif +} + +#define TEST_ZONE_ADDR "fe80::1" + +#ifdef __linux__ +/* Reasonable bet that "lo" will exist. */ +#define TEST_ZONE_NAME "lo" +/* ... fill in other platforms here */ +#endif + +#ifdef TEST_ZONE_NAME +#define TEST_ZONE_FULLADDR TEST_ZONE_ADDR "%" TEST_ZONE_NAME +#endif + +static void test_zone(abts_case *tc, void *data) +{ +#if APR_HAVE_IPV6 + apr_sockaddr_t *sa; + apr_status_t rv; + const char *name = NULL; + apr_uint32_t id = 0; + + rv = apr_sockaddr_info_get(&sa, "127.0.0.1", APR_INET, 8080, 0, p); + APR_ASSERT_SUCCESS(tc, "Problem generating sockaddr", rv); + + /* Fail for an IPv4 address! */ + ABTS_INT_EQUAL(tc, APR_EBADIP, + apr_sockaddr_zone_set(sa, "1")); + ABTS_INT_EQUAL(tc, APR_EBADIP, + apr_sockaddr_zone_get(sa, &name, &id, p)); + + rv = apr_sockaddr_info_get(&sa, "::1", APR_INET6, 8080, 0, p); + APR_ASSERT_SUCCESS(tc, "Problem generating sockaddr", rv); + + /* Fail for an address which isn't link-local */ + ABTS_INT_EQUAL(tc, APR_EBADIP, apr_sockaddr_zone_set(sa, "1")); + + rv = apr_sockaddr_info_get(&sa, TEST_ZONE_ADDR, APR_INET6, 8080, 0, p); + APR_ASSERT_SUCCESS(tc, "Problem generating sockaddr", rv); + + ABTS_INT_EQUAL(tc, APR_EBADIP, apr_sockaddr_zone_get(sa, &name, &id, p)); + +#ifdef TEST_ZONE_NAME + { + apr_sockaddr_t *sa2; + char buf[50]; + + APR_ASSERT_SUCCESS(tc, "Set zone to " TEST_ZONE_NAME, + apr_sockaddr_zone_set(sa, TEST_ZONE_NAME)); + + APR_ASSERT_SUCCESS(tc, "Get zone", + apr_sockaddr_zone_get(sa, NULL, NULL, p)); + + APR_ASSERT_SUCCESS(tc, "Get zone", + apr_sockaddr_zone_get(sa, &name, &id, p)); + ABTS_STR_EQUAL(tc, TEST_ZONE_NAME, name); + ABTS_INT_NEQUAL(tc, 0, id); /* Only guarantee is that it should be non-zero */ + + /* Check string translation. */ + APR_ASSERT_SUCCESS(tc, "get IP address", + apr_sockaddr_ip_getbuf(buf, 50, sa)); + ABTS_STR_EQUAL(tc, TEST_ZONE_FULLADDR, buf); + + memset(buf, 'A', sizeof buf); + ABTS_INT_EQUAL(tc, APR_ENOSPC, apr_sockaddr_ip_getbuf(buf, strlen(TEST_ZONE_ADDR), sa)); + ABTS_INT_EQUAL(tc, APR_ENOSPC, apr_sockaddr_ip_getbuf(buf, strlen(TEST_ZONE_FULLADDR), sa)); + + APR_ASSERT_SUCCESS(tc, "get IP address", + apr_sockaddr_ip_getbuf(buf, strlen(TEST_ZONE_FULLADDR) + 1, sa)); + /* Check for overflow. */ + ABTS_INT_EQUAL(tc, 'A', buf[strlen(buf) + 1]); + + rv = apr_sockaddr_info_copy(&sa2, sa, p); + APR_ASSERT_SUCCESS(tc, "Problem copying sockaddr", rv); + + /* Copy copied zone matches */ + APR_ASSERT_SUCCESS(tc, "Get zone", + apr_sockaddr_zone_get(sa2, &name, &id, p)); + ABTS_STR_EQUAL(tc, TEST_ZONE_NAME, name); + ABTS_INT_NEQUAL(tc, 0, id); /* Only guarantee is that it should be non-zero */ + + /* Should match self and copy */ + ABTS_INT_NEQUAL(tc, 0, apr_sockaddr_equal(sa, sa)); + ABTS_INT_NEQUAL(tc, 0, apr_sockaddr_equal(sa2, sa2)); + ABTS_INT_NEQUAL(tc, 0, apr_sockaddr_equal(sa2, sa)); + + /* Should not match against copy without zone set. */ + rv = apr_sockaddr_info_get(&sa2, TEST_ZONE_ADDR, APR_INET6, 8080, 0, p); + APR_ASSERT_SUCCESS(tc, "Problem generating sockaddr", rv); + + ABTS_INT_EQUAL(tc, 0, apr_sockaddr_equal(sa2, sa)); + } +#endif /* TEST_ZONE_NAME */ +#endif /* APR_HAVE_IPV6 */ +} + +abts_suite *testsock(abts_suite *suite) +{ + suite = ADD_SUITE(suite) + socket_name = IPV4_SOCKET_NAME; + abts_run_test(suite, test_addr_info, NULL); + abts_run_test(suite, test_addr_copy, NULL); + abts_run_test(suite, test_serv_by_name, NULL); + abts_run_test(suite, test_create_bind_listen, NULL); + abts_run_test(suite, test_send, NULL); + abts_run_test(suite, test_recv, NULL); + abts_run_test(suite, test_atreadeof, NULL); + abts_run_test(suite, test_timeout, NULL); + abts_run_test(suite, test_print_addr, NULL); + abts_run_test(suite, test_get_addr, NULL); + abts_run_test(suite, test_wait, NULL); + abts_run_test(suite, test_nonblock_inheritance, NULL); + abts_run_test(suite, test_freebind, NULL); + abts_run_test(suite, test_zone, NULL); +#if APR_HAVE_SOCKADDR_UN + socket_name = UNIX_SOCKET_NAME; + socket_type = APR_UNIX; + /* in case AF_UNIX socket exists from a previous run: */ + apr_file_remove(socket_name, p); + abts_run_test(suite, test_create_bind_listen, NULL); + abts_run_test(suite, test_send, NULL); + abts_run_test(suite, test_recv, NULL); + abts_run_test(suite, test_timeout, NULL); + abts_run_test(suite, test_wait, NULL); +#endif + return suite; +} + diff --git a/test/testsock.dsp b/test/testsock.dsp deleted file mode 100644 index ea18db0c7d9..00000000000 --- a/test/testsock.dsp +++ /dev/null @@ -1,91 +0,0 @@ -# Microsoft Developer Studio Project File - Name="testsock" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 5.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Console Application" 0x0103 - -CFG=testsock - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "testsock.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "testsock.mak" CFG="testsock - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "testsock - Win32 Release" (based on\ - "Win32 (x86) Console Application") -!MESSAGE "testsock - Win32 Debug" (based on "Win32 (x86) Console Application") -!MESSAGE - -# Begin Project -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -RSC=rc.exe - -!IF "$(CFG)" == "testsock - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /W3 /GX /O2 /I "..\include" /I "..\..\include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD BASE RSC /l 0x409 /d "NDEBUG" -# ADD RSC /l 0x409 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 -# ADD LINK32 ..\Release\aprlib.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"..\Release\testsock.exe" - -!ELSEIF "$(CFG)" == "testsock - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "testsock" -# PROP BASE Intermediate_Dir "testsock" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "testsock" -# PROP Intermediate_Dir "testsock" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /I "..\include" /I "..\..\include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FD /c -# SUBTRACT CPP /YX /Yc /Yu -# ADD BASE RSC /l 0x409 /d "_DEBUG" -# ADD RSC /l 0x409 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept -# ADD LINK32 ..\Debug\aprlib.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"..\Debug\testsock.exe" /pdbtype:sept - -!ENDIF - -# Begin Target - -# Name "testsock - Win32 Release" -# Name "testsock - Win32 Debug" -# Begin Source File - -SOURCE=.\testsock.c -# End Source File -# End Target -# End Project diff --git a/test/testsock.h b/test/testsock.h new file mode 100644 index 00000000000..12a44f76537 --- /dev/null +++ b/test/testsock.h @@ -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. + */ + +#ifndef TESTSOCK_H +#define TESTSOCK_H + +#define DATASTR "This is a test" +#define STRLEN 8092 + +/* This is a hack. We can't return APR_TIMEOUT from sockchild, because + * Unix OSes only return the least significant 8 bits of the return code, + * which means that instead of receiving 70007, testsock gets 119. But, + * we also don't want to return -1, because we use that value for general + * errors from sockchild. So, we define 1 to mean that the read/write + * operation timed out. This means that we can't write a test that tries + * to send a single character between ends of the socket. + */ +#define SOCKET_TIMEOUT 1 + +#endif + diff --git a/test/testsockets.c b/test/testsockets.c new file mode 100644 index 00000000000..2a7499aa781 --- /dev/null +++ b/test/testsockets.c @@ -0,0 +1,238 @@ +/* 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_network_io.h" +#include "apr_errno.h" +#include "apr_general.h" +#include "apr_lib.h" +#include "testutil.h" + +#define STRLEN 21 + +static void tcp_socket(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_socket_t *sock = NULL; + int type; + + rv = apr_socket_create(&sock, APR_INET, SOCK_STREAM, 0, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_PTR_NOTNULL(tc, sock); + + rv = apr_socket_type_get(sock, &type); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_INT_EQUAL(tc, SOCK_STREAM, type); + + apr_socket_close(sock); +} + +static void udp_socket(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_socket_t *sock = NULL; + int type; + + rv = apr_socket_create(&sock, APR_INET, SOCK_DGRAM, 0, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_PTR_NOTNULL(tc, sock); + + rv = apr_socket_type_get(sock, &type); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_INT_EQUAL(tc, SOCK_DGRAM, type); + + apr_socket_close(sock); +} + +#if APR_HAVE_IPV6 +static void tcp6_socket(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_socket_t *sock = NULL; + + rv = apr_socket_create(&sock, APR_INET6, SOCK_STREAM, 0, p); + if (APR_STATUS_IS_EAFNOSUPPORT(rv)) { + ABTS_NOT_IMPL(tc, "IPv6 not enabled"); + return; + } + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_PTR_NOTNULL(tc, sock); + apr_socket_close(sock); +} + +static void udp6_socket(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_socket_t *sock = NULL; + + rv = apr_socket_create(&sock, APR_INET6, SOCK_DGRAM, 0, p); + if (APR_STATUS_IS_EAFNOSUPPORT(rv)) { + ABTS_NOT_IMPL(tc, "IPv6 not enabled"); + return; + } + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_PTR_NOTNULL(tc, sock); + apr_socket_close(sock); +} +#endif + +static void sendto_receivefrom_helper(abts_case *tc, const char *addr, + int family) +{ + apr_status_t rv; + apr_socket_t *sock = NULL; + apr_socket_t *sock2 = NULL; + char sendbuf[STRLEN] = "APR_INET, SOCK_DGRAM"; + char recvbuf[80]; + char *ip_addr; + apr_port_t fromport; + apr_sockaddr_t *from; + apr_sockaddr_t *to; + apr_size_t len = 30; + + rv = apr_socket_create(&sock, family, SOCK_DGRAM, 0, p); +#if APR_HAVE_IPV6 + if ((family == APR_INET6) && APR_STATUS_IS_EAFNOSUPPORT(rv)) { + ABTS_NOT_IMPL(tc, "IPv6 not enabled"); + return; + } +#endif + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + if (rv != APR_SUCCESS) + return; + rv = apr_socket_create(&sock2, family, SOCK_DGRAM, 0, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + if (rv != APR_SUCCESS) + return; + + rv = apr_sockaddr_info_get(&to, addr, family, 7772, 0, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + rv = apr_sockaddr_info_get(&from, addr, family, 7771, 0, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + rv = apr_socket_opt_set(sock, APR_SO_REUSEADDR, 1); + APR_ASSERT_SUCCESS(tc, "Could not set REUSEADDR on socket", rv); + rv = apr_socket_opt_set(sock2, APR_SO_REUSEADDR, 1); + APR_ASSERT_SUCCESS(tc, "Could not set REUSEADDR on socket2", rv); + + rv = apr_socket_bind(sock, to); + APR_ASSERT_SUCCESS(tc, "Could not bind socket", rv); + if (rv != APR_SUCCESS) + return; + rv = apr_mcast_hops(sock, 10); + APR_ASSERT_SUCCESS(tc, "Could not set multicast hops", rv); + if (rv != APR_SUCCESS) + return; + + rv = apr_socket_bind(sock2, from); + APR_ASSERT_SUCCESS(tc, "Could not bind second socket", rv); + if (rv != APR_SUCCESS) + return; + + len = STRLEN; + rv = apr_socket_sendto(sock2, to, 0, sendbuf, &len); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_SIZE_EQUAL(tc, STRLEN, len); + + /* fill the "from" sockaddr with a random address from another + * family to ensure that recvfrom sets it up properly. */ +#if APR_HAVE_IPV6 + if (family == APR_INET) + rv = apr_sockaddr_info_get(&from, "3ffE:816e:abcd:1234::1", + APR_INET6, 4242, 0, p); + else +#endif + rv = apr_sockaddr_info_get(&from, "127.1.2.3", APR_INET, 4242, 0, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + len = 80; + rv = apr_socket_recvfrom(from, sock, 0, recvbuf, &len); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_SIZE_EQUAL(tc, STRLEN, len); + ABTS_STR_EQUAL(tc, "APR_INET, SOCK_DGRAM", recvbuf); + + apr_sockaddr_ip_get(&ip_addr, from); + fromport = from->port; + ABTS_STR_EQUAL(tc, addr, ip_addr); + ABTS_INT_EQUAL(tc, 7771, fromport); + + apr_socket_close(sock); + apr_socket_close(sock2); +} + +static void sendto_receivefrom(abts_case *tc, void *data) +{ + int failed; + sendto_receivefrom_helper(tc, "127.0.0.1", APR_INET); + failed = tc->failed; tc->failed = 0; + ABTS_TRUE(tc, !failed); +} + +#if APR_HAVE_IPV6 +static void sendto_receivefrom6(abts_case *tc, void *data) +{ + int failed; + sendto_receivefrom_helper(tc, "::1", APR_INET6); + failed = tc->failed; tc->failed = 0; + ABTS_TRUE(tc, !failed); +} +#endif + +static void socket_userdata(abts_case *tc, void *data) +{ + apr_socket_t *sock1, *sock2; + apr_status_t rv; + void *user; + const char *key = "GENERICKEY"; + + rv = apr_socket_create(&sock1, AF_INET, SOCK_STREAM, 0, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + rv = apr_socket_create(&sock2, AF_INET, SOCK_STREAM, 0, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + rv = apr_socket_data_set(sock1, "SOCK1", key, NULL); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + rv = apr_socket_data_set(sock2, "SOCK2", key, NULL); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + rv = apr_socket_data_get(&user, key, sock1); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_STR_EQUAL(tc, "SOCK1", user); + rv = apr_socket_data_get(&user, key, sock2); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_STR_EQUAL(tc, "SOCK2", user); +} + +abts_suite *testsockets(abts_suite *suite) +{ + suite = ADD_SUITE(suite) + + abts_run_test(suite, tcp_socket, NULL); + abts_run_test(suite, udp_socket, NULL); + + abts_run_test(suite, sendto_receivefrom, NULL); + +#if APR_HAVE_IPV6 + abts_run_test(suite, tcp6_socket, NULL); + abts_run_test(suite, udp6_socket, NULL); + + abts_run_test(suite, sendto_receivefrom6, NULL); +#endif + + abts_run_test(suite, socket_userdata, NULL); + + return suite; +} + diff --git a/test/testsockopt.c b/test/testsockopt.c new file mode 100644 index 00000000000..203e2c39ff7 --- /dev/null +++ b/test/testsockopt.c @@ -0,0 +1,139 @@ +/* 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_network_io.h" +#include "apr_errno.h" +#include "apr_general.h" +#include "apr_lib.h" +#include "testutil.h" + +static apr_socket_t *sock = NULL; + +static void create_socket(abts_case *tc, void *data) +{ + apr_status_t rv; + + rv = apr_socket_create(&sock, APR_INET, SOCK_STREAM, 0, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_PTR_NOTNULL(tc, sock); +} + +static void set_keepalive(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_int32_t ck; + + rv = apr_socket_opt_set(sock, APR_SO_KEEPALIVE, 1); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + rv = apr_socket_opt_get(sock, APR_SO_KEEPALIVE, &ck); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_INT_EQUAL(tc, 1, ck); +} + +static void set_debug(abts_case *tc, void *data) +{ + apr_status_t rv1, rv2; + apr_int32_t ck; + + /* On some platforms APR_SO_DEBUG can only be set as root; just test + * for get/set consistency of this option. */ + rv1 = apr_socket_opt_set(sock, APR_SO_DEBUG, 1); + rv2 = apr_socket_opt_get(sock, APR_SO_DEBUG, &ck); + APR_ASSERT_SUCCESS(tc, "get SO_DEBUG option", rv2); + if (rv1 == APR_SUCCESS) { + ABTS_INT_EQUAL(tc, 1, ck); + } else { + ABTS_INT_EQUAL(tc, 0, ck); + } +} + +static void remove_keepalive(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_int32_t ck; + + rv = apr_socket_opt_get(sock, APR_SO_KEEPALIVE, &ck); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_INT_EQUAL(tc, 1, ck); + + rv = apr_socket_opt_set(sock, APR_SO_KEEPALIVE, 0); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + rv = apr_socket_opt_get(sock, APR_SO_KEEPALIVE, &ck); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_INT_EQUAL(tc, 0, ck); +} + +static void corkable(abts_case *tc, void *data) +{ +#if !APR_HAVE_CORKABLE_TCP + ABTS_NOT_IMPL(tc, "TCP isn't corkable"); +#else + apr_status_t rv; + apr_int32_t ck; + + rv = apr_socket_opt_set(sock, APR_TCP_NODELAY, 1); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + rv = apr_socket_opt_get(sock, APR_TCP_NODELAY, &ck); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_INT_EQUAL(tc, 1, ck); + + rv = apr_socket_opt_set(sock, APR_TCP_NOPUSH, 1); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + rv = apr_socket_opt_get(sock, APR_TCP_NOPUSH, &ck); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_INT_EQUAL(tc, 1, ck); + + rv = apr_socket_opt_get(sock, APR_TCP_NODELAY, &ck); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + /* TCP_NODELAY is now in an unknown state; it may be zero if + * TCP_NOPUSH and TCP_NODELAY are mutually exclusive on this + * platform, e.g. Linux < 2.6. */ + + rv = apr_socket_opt_set(sock, APR_TCP_NOPUSH, 0); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + rv = apr_socket_opt_get(sock, APR_TCP_NODELAY, &ck); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_INT_EQUAL(tc, 1, ck); +#endif +} + +static void close_socket(abts_case *tc, void *data) +{ + apr_status_t rv; + + rv = apr_socket_close(sock); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); +} + +abts_suite *testsockopt(abts_suite *suite) +{ + suite = ADD_SUITE(suite) + + abts_run_test(suite, create_socket, NULL); + abts_run_test(suite, set_keepalive, NULL); + abts_run_test(suite, set_debug, NULL); + abts_run_test(suite, remove_keepalive, NULL); + abts_run_test(suite, corkable, NULL); + abts_run_test(suite, close_socket, NULL); + + return suite; +} + diff --git a/test/teststr.c b/test/teststr.c new file mode 100644 index 00000000000..d9a5054758a --- /dev/null +++ b/test/teststr.c @@ -0,0 +1,418 @@ +/* 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 "testutil.h" + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#if APR_HAVE_LIMITS_H +#include <limits.h> +#endif + +#include "apr_general.h" +#include "apr_strings.h" +#include "apr_cstr.h" +#include "apr_errno.h" + +/* I haven't bothered to check for APR_ENOTIMPL here, AFAIK, all string + * functions exist on all platforms. + */ + +static void test_strtok(abts_case *tc, void *data) +{ + struct { + char *input; + char *sep; + } + cases[] = { + { + "", + "Z" + }, + { + " asdf jkl; 77889909 \r\n\1\2\3Z", + " \r\n\3\2\1" + }, + { + NULL, /* but who cares if apr_strtok() segfaults? */ + " \t" + }, +#if 0 /* don't do this... you deserve to segfault */ + { + "a b c ", + NULL + }, +#endif + { + " a b c ", + "" + }, + { + "a b c ", + " " + } + }; + int curtc; + + for (curtc = 0; curtc < sizeof cases / sizeof cases[0]; curtc++) { + char *retval1, *retval2; + char *str1, *str2; + char *state; + + str1 = apr_pstrdup(p, cases[curtc].input); + str2 = apr_pstrdup(p, cases[curtc].input); + + do { + retval1 = apr_strtok(str1, cases[curtc].sep, &state); + retval2 = strtok(str2, cases[curtc].sep); + + if (!retval1) { + ABTS_TRUE(tc, retval2 == NULL); + } + else { + ABTS_TRUE(tc, retval2 != NULL); + ABTS_STR_EQUAL(tc, retval2, retval1); + } + + str1 = str2 = NULL; /* make sure we pass NULL on subsequent calls */ + } while (retval1); + } +} + +static void snprintf_noNULL(abts_case *tc, void *data) +{ + char buff[100]; + char *testing = apr_palloc(p, 10); + + testing[0] = 't'; + testing[1] = 'e'; + testing[2] = 's'; + testing[3] = 't'; + testing[4] = 'i'; + testing[5] = 'n'; + testing[6] = 'g'; + + /* If this test fails, we are going to seg fault. */ + apr_snprintf(buff, sizeof(buff), "%.*s", 7, testing); + ABTS_STR_NEQUAL(tc, buff, testing, 7); +} + +static void snprintf_0NULL(abts_case *tc, void *data) +{ + int rv; + + rv = apr_snprintf(NULL, 0, "%sBAR", "FOO"); + ABTS_INT_EQUAL(tc, 6, rv); +} + +static void snprintf_0nonNULL(abts_case *tc, void *data) +{ + int rv; + char *buff = "testing"; + + rv = apr_snprintf(buff, 0, "%sBAR", "FOO"); + ABTS_INT_EQUAL(tc, 6, rv); + ABTS_ASSERT(tc, "buff unmangled", strcmp(buff, "FOOBAR") != 0); +} + +static void snprintf_underflow(abts_case *tc, void *data) +{ + char buf[20]; + int rv; + + rv = apr_snprintf(buf, sizeof buf, "%.2f", (double)0.0001); + ABTS_INT_EQUAL(tc, 4, rv); + ABTS_STR_EQUAL(tc, "0.00", buf); + + rv = apr_snprintf(buf, sizeof buf, "%.2f", (double)0.001); + ABTS_INT_EQUAL(tc, 4, rv); + ABTS_STR_EQUAL(tc, "0.00", buf); + + rv = apr_snprintf(buf, sizeof buf, "%.2f", (double)0.01); + ABTS_INT_EQUAL(tc, 4, rv); + ABTS_STR_EQUAL(tc, "0.01", buf); +} + +static void string_error(abts_case *tc, void *data) +{ + char buf[128], *rv; + apr_status_t n; + + buf[0] = '\0'; + rv = apr_strerror(APR_ENOENT, buf, sizeof buf); + ABTS_PTR_EQUAL(tc, buf, rv); + ABTS_TRUE(tc, strlen(buf) > 0); + + rv = apr_strerror(APR_TIMEUP, buf, sizeof buf); + ABTS_PTR_EQUAL(tc, buf, rv); + ABTS_STR_EQUAL(tc, "The timeout specified has expired", buf); + + /* throw some randomish numbers at it to check for robustness */ + for (n = 1; n < 1000000; n *= 2) { + apr_strerror(n, buf, sizeof buf); + } +} + +#define SIZE 180000 +static void string_long(abts_case *tc, void *data) +{ + char s[SIZE + 1]; + + memset(s, 'A', SIZE); + s[SIZE] = '\0'; + + apr_psprintf(p, "%s", s); +} + +/* ### FIXME: apr.h/apr_strings.h should provide these! */ +#define MY_LLONG_MAX (APR_INT64_C(9223372036854775807)) +#define MY_LLONG_MIN (-MY_LLONG_MAX - APR_INT64_C(1)) + +static void string_strtoi64(abts_case *tc, void *data) +{ + static const struct { + int errnum, base; + const char *in, *end; + apr_int64_t result; + } ts[] = { + + /* base 10 tests */ + { 0, 10, "123545", NULL, APR_INT64_C(123545) }, + { 0, 10, " 123545", NULL, APR_INT64_C(123545) }, + { 0, 10, " +123545", NULL, APR_INT64_C(123545) }, + { 0, 10, "-123545", NULL, APR_INT64_C(-123545) }, + { 0, 10, " 00000123545", NULL, APR_INT64_C(123545) }, + { 0, 10, "123545ZZZ", "ZZZ", APR_INT64_C(123545) }, + { 0, 10, " 123545 ", " ", APR_INT64_C(123545) }, + + /* base 16 tests */ + { 0, 16, "1E299", NULL, APR_INT64_C(123545) }, + { 0, 16, "1e299", NULL, APR_INT64_C(123545) }, + { 0, 16, "0x1e299", NULL, APR_INT64_C(123545) }, + { 0, 16, "0X1E299", NULL, APR_INT64_C(123545) }, + { 0, 16, "+1e299", NULL, APR_INT64_C(123545) }, + { 0, 16, "-1e299", NULL, APR_INT64_C(-123545) }, + { 0, 16, " -1e299", NULL, APR_INT64_C(-123545) }, + + /* automatic base detection tests */ + { 0, 0, "123545", NULL, APR_INT64_C(123545) }, + { 0, 0, "0x1e299", NULL, APR_INT64_C(123545) }, + { 0, 0, " 0x1e299", NULL, APR_INT64_C(123545) }, + { 0, 0, "+0x1e299", NULL, APR_INT64_C(123545) }, + { 0, 0, "-0x1e299", NULL, APR_INT64_C(-123545) }, + + /* large number tests */ + { 0, 10, "8589934605", NULL, APR_INT64_C(8589934605) }, + { 0, 10, "-8589934605", NULL, APR_INT64_C(-8589934605) }, + { 0, 16, "0x20000000D", NULL, APR_INT64_C(8589934605) }, + { 0, 16, "-0x20000000D", NULL, APR_INT64_C(-8589934605) }, + { 0, 16, " 0x20000000D", NULL, APR_INT64_C(8589934605) }, + { 0, 16, " 0x20000000D", NULL, APR_INT64_C(8589934605) }, + + /* error cases */ + { ERANGE, 10, "999999999999999999999999999999999", "", MY_LLONG_MAX }, + { ERANGE, 10, "-999999999999999999999999999999999", "", MY_LLONG_MIN }, + +#if 0 + /* C99 doesn't require EINVAL for an invalid range. */ + { EINVAL, 99, "", (void *)-1 /* don't care */, 0 }, +#endif + + /* some strtoll implementations give EINVAL when no conversion + * is performed. */ + { -1 /* don't care */, 10, "zzz", "zzz", APR_INT64_C(0) }, + { -1 /* don't care */, 10, "", NULL, APR_INT64_C(0) } + + }; + int n; + + for (n = 0; n < sizeof(ts)/sizeof(ts[0]); n++) { + char *end = "end ptr not changed"; + apr_int64_t result; + int errnum; + + errno = 0; + result = apr_strtoi64(ts[n].in, &end, ts[n].base); + errnum = errno; + + ABTS_ASSERT(tc, + apr_psprintf(p, "for '%s': result was %" APR_INT64_T_FMT + " not %" APR_INT64_T_FMT, ts[n].in, + result, ts[n].result), + result == ts[n].result); + + if (ts[n].errnum != -1) { + ABTS_ASSERT(tc, + apr_psprintf(p, "for '%s': errno was %d not %d", ts[n].in, + errnum, ts[n].errnum), + ts[n].errnum == errnum); + } + + if (ts[n].end == NULL) { + /* end must point to NUL terminator of .in */ + ABTS_PTR_EQUAL(tc, ts[n].in + strlen(ts[n].in), end); + } else if (ts[n].end != (void *)-1) { + ABTS_ASSERT(tc, + apr_psprintf(p, "for '%s', end was '%s' not '%s'", + ts[n].in, end, ts[n].end), + strcmp(ts[n].end, end) == 0); + } + } +} + +static void string_strtoff(abts_case *tc, void *data) +{ + apr_off_t off; + + ABTS_ASSERT(tc, "strtoff fails on out-of-range integer", + apr_strtoff(&off, "999999999999999999999999999999", + NULL, 10) != APR_SUCCESS); + + ABTS_ASSERT(tc, "strtoff failed for 1234", + apr_strtoff(&off, "1234", NULL, 10) == APR_SUCCESS); + + ABTS_ASSERT(tc, "strtoff failed to parse 1234", off == 1234); +} + +/* random-ish checks for strfsize buffer overflows */ +static void overflow_strfsize(abts_case *tc, void *data) +{ + apr_off_t off; + char buf[7]; + + buf[5] = '$'; + buf[6] = '@'; + + for (off = -9999; off < 20000; off++) { + apr_strfsize(off, buf); + } + for (; off < 9999999; off += 9) { + apr_strfsize(off, buf); + } + for (; off < 999999999; off += 999) { + apr_strfsize(off, buf); + } + for (off = 1; off < LONG_MAX && off > 0; off *= 2) { + apr_strfsize(off, buf); + apr_strfsize(off + 1, buf); + apr_strfsize(off - 1, buf); + } + + ABTS_ASSERT(tc, "strfsize overflowed", buf[5] == '$'); + ABTS_ASSERT(tc, "strfsize overflowed", buf[6] == '@'); +} + +static void string_strfsize(abts_case *tc, void *data) +{ + static const struct { + apr_off_t size; + const char *buf; + } ts[] = { + { -1, " - " }, + { 0, " 0 " }, + { 666, "666 " }, + { 1024, "1.0K" }, + { 1536, "1.5K" }, + { 2048, "2.0K" }, + { 1293874, "1.2M" }, + { 9999999, "9.5M" }, + { 103809024, " 99M" }, + { 1047527424, "1.0G" } /* "999M" would be more correct */ + }; + apr_size_t n; + + for (n = 0; n < sizeof(ts)/sizeof(ts[0]); n++) { + char buf[6], *ret; + + buf[5] = '%'; + + ret = apr_strfsize(ts[n].size, buf); + ABTS_ASSERT(tc, "strfsize returned wrong buffer", ret == buf); + ABTS_ASSERT(tc, "strfsize overflowed", buf[5] == '%'); + + ABTS_STR_EQUAL(tc, ts[n].buf, ret); + } +} + +static void string_cpystrn(abts_case *tc, void *data) +{ + char buf[6], *ret; + + buf[5] = 'Z'; + + ret = apr_cpystrn(buf, "123456", 5); + + ABTS_STR_EQUAL(tc, "1234", buf); + ABTS_PTR_EQUAL(tc, buf + 4, ret); + ABTS_TRUE(tc, *ret == '\0'); + ABTS_TRUE(tc, ret[1] == 'Z'); +} + +static void snprintf_overflow(abts_case *tc, void *data) +{ + char buf[4]; + int rv; + + buf[2] = '4'; + buf[3] = '2'; + + rv = apr_snprintf(buf, 2, "%s", "a"); + ABTS_INT_EQUAL(tc, 1, rv); + + rv = apr_snprintf(buf, 2, "%s", "abcd"); + ABTS_INT_EQUAL(tc, 1, rv); + + ABTS_STR_EQUAL(tc, "a", buf); + + /* Check the buffer really hasn't been overflowed. */ + ABTS_TRUE(tc, buf[2] == '4' && buf[3] == '2'); +} + +static void skip_prefix(abts_case *tc, void *data) +{ + ABTS_STR_EQUAL(tc, apr_cstr_skip_prefix("12345", "12345"), ""); + ABTS_STR_EQUAL(tc, apr_cstr_skip_prefix("12345", "123"), "45"); + ABTS_STR_EQUAL(tc, apr_cstr_skip_prefix("12345", ""), "12345"); + ABTS_STR_EQUAL(tc, apr_cstr_skip_prefix("12345", "23"), NULL); + ABTS_STR_EQUAL(tc, apr_cstr_skip_prefix("1", "12"), NULL); + ABTS_STR_EQUAL(tc, apr_cstr_skip_prefix("", ""), ""); + ABTS_STR_EQUAL(tc, apr_cstr_skip_prefix("", "12"), NULL); +} + +abts_suite *teststr(abts_suite *suite) +{ + suite = ADD_SUITE(suite) + + abts_run_test(suite, snprintf_0NULL, NULL); + abts_run_test(suite, snprintf_0nonNULL, NULL); + abts_run_test(suite, snprintf_noNULL, NULL); + abts_run_test(suite, snprintf_underflow, NULL); + abts_run_test(suite, test_strtok, NULL); + abts_run_test(suite, string_error, NULL); + abts_run_test(suite, string_long, NULL); + abts_run_test(suite, string_strtoi64, NULL); + abts_run_test(suite, string_strtoff, NULL); + abts_run_test(suite, overflow_strfsize, NULL); + abts_run_test(suite, string_strfsize, NULL); + abts_run_test(suite, string_cpystrn, NULL); + abts_run_test(suite, snprintf_overflow, NULL); + abts_run_test(suite, skip_prefix, NULL); + + return suite; +} + diff --git a/test/teststrmatch.c b/test/teststrmatch.c new file mode 100644 index 00000000000..b6a4a12267f --- /dev/null +++ b/test/teststrmatch.c @@ -0,0 +1,92 @@ +/* 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 "testutil.h" + +#include "apr.h" +#include "apr_general.h" +#include "apr_strmatch.h" +#if APR_HAVE_STDLIB_H +#include <stdlib.h> +#endif +#define APR_WANT_STDIO +#define APR_WANT_STRFUNC +#include "apr_want.h" + +static void test_str(abts_case *tc, void *data) +{ + apr_pool_t *pool = p; + const apr_strmatch_pattern *pattern; + const apr_strmatch_pattern *pattern_nocase; + const apr_strmatch_pattern *pattern_onechar; + const apr_strmatch_pattern *pattern_zero; + const char *match = NULL; + const char *input1 = "string that contains a patterN..."; + const char *input2 = "string that contains a pattern..."; + const char *input3 = "pattern at the start of a string"; + const char *input4 = "string that ends with a pattern"; + const char *input5 = "patter\200n not found, negative chars in input"; + const char *input6 = "patter\200n, negative chars, contains pattern..."; + + pattern = apr_strmatch_precompile(pool, "pattern", 1); + ABTS_PTR_NOTNULL(tc, pattern); + + pattern_nocase = apr_strmatch_precompile(pool, "pattern", 0); + ABTS_PTR_NOTNULL(tc, pattern_nocase); + + pattern_onechar = apr_strmatch_precompile(pool, "g", 0); + ABTS_PTR_NOTNULL(tc, pattern_onechar); + + pattern_zero = apr_strmatch_precompile(pool, "", 0); + ABTS_PTR_NOTNULL(tc, pattern_zero); + + match = apr_strmatch(pattern, input1, strlen(input1)); + ABTS_PTR_EQUAL(tc, NULL, match); + + match = apr_strmatch(pattern, input2, strlen(input2)); + ABTS_PTR_EQUAL(tc, input2 + 23, match); + + match = apr_strmatch(pattern_onechar, input1, strlen(input1)); + ABTS_PTR_EQUAL(tc, input1 + 5, match); + + match = apr_strmatch(pattern_zero, input1, strlen(input1)); + ABTS_PTR_EQUAL(tc, input1, match); + + match = apr_strmatch(pattern_nocase, input1, strlen(input1)); + ABTS_PTR_EQUAL(tc, input1 + 23, match); + + match = apr_strmatch(pattern, input3, strlen(input3)); + ABTS_PTR_EQUAL(tc, input3, match); + + match = apr_strmatch(pattern, input4, strlen(input4)); + ABTS_PTR_EQUAL(tc, input4 + 24, match); + + match = apr_strmatch(pattern, input5, strlen(input5)); + ABTS_PTR_EQUAL(tc, NULL, match); + + match = apr_strmatch(pattern, input6, strlen(input6)); + ABTS_PTR_EQUAL(tc, input6 + 35, match); +} + +abts_suite *teststrmatch(abts_suite *suite) +{ + suite = ADD_SUITE(suite); + + abts_run_test(suite, test_str, NULL); + + return suite; +} + diff --git a/test/teststrnatcmp.c b/test/teststrnatcmp.c new file mode 100644 index 00000000000..3a5e4c67ba7 --- /dev/null +++ b/test/teststrnatcmp.c @@ -0,0 +1,78 @@ +/* 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_file_io.h" +#include "apr_errno.h" +#include "apr_strings.h" +#include "testutil.h" + +static void less0(abts_case *tc, void *data) +{ + int rv = apr_strnatcmp("a", "b"); + ABTS_ASSERT(tc, "didn't compare simple strings properly", rv < 0); +} + +static void str_equal(abts_case *tc, void *data) +{ + int rv = apr_strnatcmp("a", "a"); + ABTS_ASSERT(tc, "didn't compare simple strings properly", rv == 0); +} + +static void more0(abts_case *tc, void *data) +{ + int rv = apr_strnatcmp("b", "a"); + ABTS_ASSERT(tc, "didn't compare simple strings properly", rv > 0); +} + +static void less_ignore_case(abts_case *tc, void *data) +{ + int rv = apr_strnatcasecmp("a", "B"); + ABTS_ASSERT(tc, "didn't compare simple strings properly", rv < 0); +} + +static void str_equal_ignore_case(abts_case *tc, void *data) +{ + int rv = apr_strnatcasecmp("a", "A"); + ABTS_ASSERT(tc, "didn't compare simple strings properly", rv == 0); +} + +static void more_ignore_case(abts_case *tc, void *data) +{ + int rv = apr_strnatcasecmp("b", "A"); + ABTS_ASSERT(tc, "didn't compare simple strings properly", rv > 0); +} + +static void natcmp(abts_case *tc, void *data) +{ + int rv = apr_strnatcasecmp("a2", "a10"); + ABTS_ASSERT(tc, "didn't compare simple strings properly", rv < 0); +} + +abts_suite *teststrnatcmp(abts_suite *suite) +{ + suite = ADD_SUITE(suite) + + abts_run_test(suite, less0, NULL); + abts_run_test(suite, str_equal, NULL); + abts_run_test(suite, more0, NULL); + abts_run_test(suite, less_ignore_case, NULL); + abts_run_test(suite, str_equal_ignore_case, NULL); + abts_run_test(suite, more_ignore_case, NULL); + abts_run_test(suite, natcmp, NULL); + + return suite; +} + diff --git a/test/testtable.c b/test/testtable.c new file mode 100644 index 00000000000..0a9960f12c8 --- /dev/null +++ b/test/testtable.c @@ -0,0 +1,245 @@ +/* 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 "testutil.h" +#include "apr.h" +#include "apr_strings.h" +#include "apr_general.h" +#include "apr_pools.h" +#include "apr_tables.h" +#if APR_HAVE_STDIO_H +#include <stdio.h> +#endif +#if APR_HAVE_STDLIB_H +#include <stdlib.h> +#endif +#if APR_HAVE_STRING_H +#include <string.h> +#endif + +static apr_array_header_t *a1 = NULL; +static apr_table_t *t1 = NULL; + +static void array_clear(abts_case *tc, void *data) +{ + a1 = apr_array_make(p, 2, sizeof(const char *)); + APR_ARRAY_PUSH(a1, const char *) = "foo"; + APR_ARRAY_PUSH(a1, const char *) = "bar"; + apr_array_clear(a1); + ABTS_INT_EQUAL(tc, 0, a1->nelts); +} + +static void table_make(abts_case *tc, void *data) +{ + t1 = apr_table_make(p, 5); + ABTS_PTR_NOTNULL(tc, t1); +} + +static void table_get(abts_case *tc, void *data) +{ + const char *val; + + apr_table_set(t1, "foo", "bar"); + val = apr_table_get(t1, "foo"); + ABTS_STR_EQUAL(tc, "bar", val); +} + +static void table_getm(abts_case *tc, void *data) +{ + const char *orig, *val; + apr_pool_t *subp; + + apr_pool_create(&subp, p); + + orig = "bar"; + apr_table_setn(t1, "foo", orig); + val = apr_table_getm(subp, t1, "foo"); + ABTS_PTR_EQUAL(tc, orig, val); + ABTS_STR_EQUAL(tc, "bar", val); + apr_table_add(t1, "foo", "baz"); + val = apr_table_getm(subp, t1, "foo"); + ABTS_STR_EQUAL(tc, "bar,baz", val); + + apr_pool_destroy(subp); +} + +static void table_set(abts_case *tc, void *data) +{ + const char *val; + + apr_table_set(t1, "setkey", "bar"); + apr_table_set(t1, "setkey", "2ndtry"); + val = apr_table_get(t1, "setkey"); + ABTS_STR_EQUAL(tc, "2ndtry", val); +} + +static void table_getnotthere(abts_case *tc, void *data) +{ + const char *val; + + val = apr_table_get(t1, "keynotthere"); + ABTS_PTR_EQUAL(tc, NULL, (void *)val); +} + +static void table_add(abts_case *tc, void *data) +{ + const char *val; + + apr_table_add(t1, "addkey", "bar"); + apr_table_add(t1, "addkey", "foo"); + val = apr_table_get(t1, "addkey"); + ABTS_STR_EQUAL(tc, "bar", val); + +} + +static void table_nelts(abts_case *tc, void *data) +{ + const char *val; + apr_table_t *t = apr_table_make(p, 1); + + apr_table_set(t, "abc", "def"); + apr_table_set(t, "def", "abc"); + apr_table_set(t, "foo", "zzz"); + val = apr_table_get(t, "foo"); + ABTS_STR_EQUAL(tc, "zzz", val); + val = apr_table_get(t, "abc"); + ABTS_STR_EQUAL(tc, "def", val); + val = apr_table_get(t, "def"); + ABTS_STR_EQUAL(tc, "abc", val); + ABTS_INT_EQUAL(tc, 3, apr_table_elts(t)->nelts); +} + +static void table_clear(abts_case *tc, void *data) +{ + apr_table_clear(t1); + ABTS_INT_EQUAL(tc, 0, apr_table_elts(t1)->nelts); +} + +static void table_unset(abts_case *tc, void *data) +{ + const char *val; + apr_table_t *t = apr_table_make(p, 1); + + apr_table_set(t, "a", "1"); + apr_table_set(t, "b", "2"); + apr_table_unset(t, "b"); + ABTS_INT_EQUAL(tc, 1, apr_table_elts(t)->nelts); + val = apr_table_get(t, "a"); + ABTS_STR_EQUAL(tc, "1", val); + val = apr_table_get(t, "b"); + ABTS_PTR_EQUAL(tc, (void *)NULL, (void *)val); +} + +static void table_overlap(abts_case *tc, void *data) +{ + const char *val; + apr_table_t *t1 = apr_table_make(p, 1); + apr_table_t *t2 = apr_table_make(p, 1); + + apr_table_addn(t1, "a", "0"); + apr_table_addn(t1, "g", "7"); + apr_table_addn(t2, "a", "1"); + apr_table_addn(t2, "b", "2"); + apr_table_addn(t2, "c", "3"); + apr_table_addn(t2, "b", "2.0"); + apr_table_addn(t2, "d", "4"); + apr_table_addn(t2, "e", "5"); + apr_table_addn(t2, "b", "2."); + apr_table_addn(t2, "f", "6"); + apr_table_overlap(t1, t2, APR_OVERLAP_TABLES_SET); + + ABTS_INT_EQUAL(tc, 7, apr_table_elts(t1)->nelts); + val = apr_table_get(t1, "a"); + ABTS_STR_EQUAL(tc, "1", val); + val = apr_table_get(t1, "b"); + ABTS_STR_EQUAL(tc, "2.", val); + val = apr_table_get(t1, "c"); + ABTS_STR_EQUAL(tc, "3", val); + val = apr_table_get(t1, "d"); + ABTS_STR_EQUAL(tc, "4", val); + val = apr_table_get(t1, "e"); + ABTS_STR_EQUAL(tc, "5", val); + val = apr_table_get(t1, "f"); + ABTS_STR_EQUAL(tc, "6", val); + val = apr_table_get(t1, "g"); + ABTS_STR_EQUAL(tc, "7", val); +} + +static void table_overlap2(abts_case *tc, void *data) +{ + apr_pool_t *subp; + apr_table_t *t1, *t2; + + apr_pool_create(&subp, p); + + t1 = apr_table_make(subp, 1); + t2 = apr_table_make(p, 1); + apr_table_addn(t1, "t1", "one"); + apr_table_addn(t2, "t2", "two"); + + apr_table_overlap(t1, t2, APR_OVERLAP_TABLES_SET); + + ABTS_INT_EQUAL(tc, 2, apr_table_elts(t1)->nelts); + + ABTS_STR_EQUAL(tc, "one", apr_table_get(t1, "t1")); + ABTS_STR_EQUAL(tc, "two", apr_table_get(t1, "t2")); + +} + +static void table_overlap3(abts_case *tc, void *data) +{ + apr_pool_t *subp; + apr_table_t *t1, *t2; + + apr_pool_create(&subp, p); + + t1 = apr_table_make(subp, 1); + t2 = apr_table_make(p, 1); + apr_table_addn(t1, "t1", "one"); + apr_table_addn(t1, "t1", "overlay"); + apr_table_addn(t2, "t2", "two"); + apr_table_addn(t2, "t2", "overlay"); + + apr_table_overlap(t1, t2, APR_OVERLAP_TABLES_ADD); + + ABTS_INT_EQUAL(tc, 4, apr_table_elts(t1)->nelts); + + ABTS_STR_EQUAL(tc, "one", apr_table_get(t1, "t1")); + ABTS_STR_EQUAL(tc, "two", apr_table_get(t1, "t2")); + +} + +abts_suite *testtable(abts_suite *suite) +{ + suite = ADD_SUITE(suite) + + abts_run_test(suite, array_clear, NULL); + abts_run_test(suite, table_make, NULL); + abts_run_test(suite, table_get, NULL); + abts_run_test(suite, table_getm, NULL); + abts_run_test(suite, table_set, NULL); + abts_run_test(suite, table_getnotthere, NULL); + abts_run_test(suite, table_add, NULL); + abts_run_test(suite, table_nelts, NULL); + abts_run_test(suite, table_clear, NULL); + abts_run_test(suite, table_unset, NULL); + abts_run_test(suite, table_overlap, NULL); + abts_run_test(suite, table_overlap2, NULL); + abts_run_test(suite, table_overlap3, NULL); + + return suite; +} + diff --git a/test/testtemp.c b/test/testtemp.c new file mode 100644 index 00000000000..1f1143ee359 --- /dev/null +++ b/test/testtemp.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 "testutil.h" +#include "apr_file_io.h" +#include "apr_strings.h" + +static void test_temp_dir(abts_case *tc, void *data) +{ + const char *tempdir = NULL; + apr_status_t rv; + + rv = apr_temp_dir_get(&tempdir, p); + APR_ASSERT_SUCCESS(tc, "Error finding Temporary Directory", rv); + ABTS_PTR_NOTNULL(tc, tempdir); +} + +static void test_mktemp(abts_case *tc, void *data) +{ + apr_file_t *f = NULL; + const char *tempdir = NULL; + char *filetemplate; + apr_status_t rv; + + rv = apr_temp_dir_get(&tempdir, p); + APR_ASSERT_SUCCESS(tc, "Error finding Temporary Directory", rv); + + filetemplate = apr_pstrcat(p, tempdir, "/tempfileXXXXXX", NULL); + rv = apr_file_mktemp(&f, filetemplate, 0, p); + APR_ASSERT_SUCCESS(tc, "Error opening Temporary file", rv); +} + +abts_suite *testtemp(abts_suite *suite) +{ + suite = ADD_SUITE(suite) + + abts_run_test(suite, test_temp_dir, NULL); + abts_run_test(suite, test_mktemp, NULL); + + return suite; +} + diff --git a/test/testthread.c b/test/testthread.c index f82f496ce69..f3df3678659 100644 --- a/test/testthread.c +++ b/test/testthread.c @@ -1,176 +1,132 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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_thread_proc.h" -#include "apr_lock.h" #include "apr_errno.h" #include "apr_general.h" -#include "errno.h" -#include <stdio.h> -#ifdef BEOS -#include <unistd.h> -#endif +#include "apr_time.h" +#include "testutil.h" +#if APR_HAS_THREADS -void * API_THREAD_FUNC thread_func1(void *data); -void * API_THREAD_FUNC thread_func2(void *data); -void * API_THREAD_FUNC thread_func3(void *data); -void * API_THREAD_FUNC thread_func4(void *data); +static apr_thread_mutex_t *thread_lock; +static apr_thread_once_t *control = NULL; +static int x = 0; +static int value = 0; +static apr_thread_t *t1; +static apr_thread_t *t2; +static apr_thread_t *t3; +static apr_thread_t *t4; -ap_lock_t *thread_lock; -ap_pool_t *context; -int x = 0; +/* just some made up number to check on later */ +static apr_status_t exit_ret_val = 123; -void * API_THREAD_FUNC thread_func1(void *data) +static void init_func(void) { - int i; - for (i = 0; i < 10000; i++) { - ap_lock(thread_lock); - x++; - ap_unlock(thread_lock); - } - return NULL; -} + value++; +} -void * API_THREAD_FUNC thread_func2(void *data) +static void * APR_THREAD_FUNC thread_func1(apr_thread_t *thd, void *data) { int i; + + apr_thread_once(control, init_func); + for (i = 0; i < 10000; i++) { - ap_lock(thread_lock); + apr_thread_mutex_lock(thread_lock); x++; - ap_unlock(thread_lock); + apr_thread_mutex_unlock(thread_lock); } + apr_thread_exit(thd, exit_ret_val); return NULL; } -void * API_THREAD_FUNC thread_func3(void *data) +static void thread_init(abts_case *tc, void *data) { - int i; - for (i = 0; i < 10000; i++) { - ap_lock(thread_lock); - x++; - ap_unlock(thread_lock); - } - return NULL; -} + apr_status_t rv; + + rv = apr_thread_once_init(&control, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); -void * API_THREAD_FUNC thread_func4(void *data) + rv = apr_thread_mutex_create(&thread_lock, APR_THREAD_MUTEX_DEFAULT, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); +} + +static void create_threads(abts_case *tc, void *data) { - int i; - for (i = 0; i < 10000; i++) { - ap_lock(thread_lock); - x++; - ap_unlock(thread_lock); - } - return NULL; -} + apr_status_t rv; + + rv = apr_thread_create(&t1, NULL, thread_func1, NULL, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + rv = apr_thread_create(&t2, NULL, thread_func1, NULL, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + rv = apr_thread_create(&t3, NULL, thread_func1, NULL, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + rv = apr_thread_create(&t4, NULL, thread_func1, NULL, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); +} -int main() +static void join_threads(abts_case *tc, void *data) { - ap_thread_t *t1; - ap_thread_t *t2; - ap_thread_t *t3; - ap_thread_t *t4; - ap_status_t s1; - ap_status_t s2; - ap_status_t s3; - ap_status_t s4; - - ap_initialize(); - - fprintf(stdout, "Initializing the context......."); - if (ap_create_pool(&context, NULL) != APR_SUCCESS) { - fprintf(stderr, "could not initialize\n"); - exit(-1); - } - fprintf(stdout, "OK\n"); + apr_status_t s; + + apr_thread_join(&s, t1); + ABTS_INT_EQUAL(tc, exit_ret_val, s); + apr_thread_join(&s, t2); + ABTS_INT_EQUAL(tc, exit_ret_val, s); + apr_thread_join(&s, t3); + ABTS_INT_EQUAL(tc, exit_ret_val, s); + apr_thread_join(&s, t4); + ABTS_INT_EQUAL(tc, exit_ret_val, s); +} - fprintf(stdout, "Initializing the lock......."); - s1 = ap_create_lock(&thread_lock, APR_MUTEX, APR_INTRAPROCESS, "lock.file", context); - if (s1 != APR_SUCCESS) { - fprintf(stderr, "Could not create lock\n"); - exit(-1); - } - fprintf(stdout, "OK\n"); - - fprintf(stdout, "Starting all the threads......."); - s1 = ap_create_thread(&t1, NULL, thread_func1, NULL, context); - s2 = ap_create_thread(&t2, NULL, thread_func2, NULL, context); - s3 = ap_create_thread(&t3, NULL, thread_func3, NULL, context); - s4 = ap_create_thread(&t4, NULL, thread_func4, NULL, context); - if (s1 != APR_SUCCESS || s2 != APR_SUCCESS || - s3 != APR_SUCCESS || s4 != APR_SUCCESS) { - fprintf(stderr, "Error starting thread\n"); - exit(-1); - } - fprintf(stdout, "OK\n"); - - fprintf(stdout, "Waiting for threads to exit......."); - ap_thread_join(&s1, t1); - ap_thread_join(&s2, t2); - ap_thread_join(&s3, t3); - ap_thread_join(&s4, t4); - fprintf (stdout, "OK\n"); - - fprintf(stdout, "Checking if locks worked......."); - if (x != 40000) { - fprintf(stderr, "The locks didn't work???? %d\n", x); - } - else { - fprintf(stdout, "Everything is working!\n"); - } +static void check_locks(abts_case *tc, void *data) +{ + ABTS_INT_EQUAL(tc, 40000, x); +} - return 1; +static void check_thread_once(abts_case *tc, void *data) +{ + ABTS_INT_EQUAL(tc, 1, value); } + +#else + +static void threads_not_impl(abts_case *tc, void *data) +{ + ABTS_NOT_IMPL(tc, "Threads not implemented on this platform"); +} + +#endif + +abts_suite *testthread(abts_suite *suite) +{ + suite = ADD_SUITE(suite) + +#if !APR_HAS_THREADS + abts_run_test(suite, threads_not_impl, NULL); +#else + abts_run_test(suite, thread_init, NULL); + abts_run_test(suite, create_threads, NULL); + abts_run_test(suite, join_threads, NULL); + abts_run_test(suite, check_locks, NULL); + abts_run_test(suite, check_thread_once, NULL); +#endif + + return suite; +} + diff --git a/test/testthread.dsp b/test/testthread.dsp deleted file mode 100644 index a4b798f0cff..00000000000 --- a/test/testthread.dsp +++ /dev/null @@ -1,92 +0,0 @@ -# Microsoft Developer Studio Project File - Name="testthread" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 5.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Console Application" 0x0103 - -CFG=testthread - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "testthread.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "testthread.mak" CFG="testthread - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "testthread - Win32 Release" (based on\ - "Win32 (x86) Console Application") -!MESSAGE "testthread - Win32 Debug" (based on\ - "Win32 (x86) Console Application") -!MESSAGE - -# Begin Project -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -RSC=rc.exe - -!IF "$(CFG)" == "testthread - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /W3 /GX /O2 /I "..\include" /I "..\..\include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD BASE RSC /l 0x409 /d "NDEBUG" -# ADD RSC /l 0x409 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 -# ADD LINK32 ..\Release\aprlib.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"..\Release\testthread.exe" - -!ELSEIF "$(CFG)" == "testthread - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /I "..\include" /I "..\..\include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FD /c -# SUBTRACT CPP /YX /Yc /Yu -# ADD BASE RSC /l 0x409 /d "_DEBUG" -# ADD RSC /l 0x409 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept -# ADD LINK32 ..\Debug\aprlib.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"..\Debug\testthread.exe" /pdbtype:sept - -!ENDIF - -# Begin Target - -# Name "testthread - Win32 Release" -# Name "testthread - Win32 Debug" -# Begin Source File - -SOURCE=.\testthread.c -# End Source File -# End Target -# End Project diff --git a/test/testtime.c b/test/testtime.c index 05c3c4d77dc..fadef97c47d 100644 --- a/test/testtime.c +++ b/test/testtime.c @@ -1,103 +1,316 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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_time.h" #include "apr_errno.h" #include "apr_general.h" -#include "errno.h" -#include <stdio.h> -#ifdef BEOS -#include <unistd.h> -#endif +#include "apr_lib.h" +#include "testutil.h" +#include "apr_strings.h" +#include <time.h> + +#define STR_SIZE 45 + +/* The time value is used throughout the tests, so just make this a global. + * Also, we need a single value that we can test for the positive tests, so + * I chose the number below, it corresponds to: + * 2002-09-14 12:05:36.186711 -25200 [257 Sat]. + * Which happens to be when I wrote the new tests. + */ +static apr_time_t now = APR_INT64_C(1032030336186711); +/* 2012-08-11 16:00:55.151600 -14400 [224 Sat] DST */ +static apr_time_t leap_year_now = APR_INT64_C(1344715255151600); + +static char* print_time (apr_pool_t *pool, const apr_time_exp_t *xt) +{ + return apr_psprintf (pool, + "%04d-%02d-%02d %02d:%02d:%02d.%06d %+05d [%d %s]%s", + xt->tm_year + 1900, + xt->tm_mon + 1, + xt->tm_mday, + xt->tm_hour, + xt->tm_min, + xt->tm_sec, + xt->tm_usec, + xt->tm_gmtoff, + xt->tm_yday + 1, + apr_day_snames[xt->tm_wday], + (xt->tm_isdst ? " DST" : "")); +} + + +static void test_now(abts_case *tc, void *data) +{ + apr_time_t timediff; + apr_time_t current; + time_t os_now; + + current = apr_time_now(); + time(&os_now); -int main() + timediff = os_now - (current / APR_USEC_PER_SEC); + /* Even though these are called so close together, there is the chance + * that the time will be slightly off, so accept anything between -1 and + * 1 second. + */ + ABTS_ASSERT(tc, "apr_time and OS time do not agree", + (timediff > -2) && (timediff < 2)); +} + +static void test_gmtstr(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_time_exp_t xt; + + rv = apr_time_exp_gmt(&xt, now); + if (rv == APR_ENOTIMPL) { + ABTS_NOT_IMPL(tc, "apr_time_exp_gmt"); + } + ABTS_TRUE(tc, rv == APR_SUCCESS); + ABTS_STR_EQUAL(tc, "2002-09-14 19:05:36.186711 +0000 [257 Sat]", + print_time(p, &xt)); +} + +static void test_exp_lt(abts_case *tc, void *data) { - ap_time_t now; - ap_exploded_time_t xt; - ap_time_t imp; + apr_time_t test_times[] = {0, 0, 0}; + int i; + + test_times[0] = now; + test_times[1] = leap_year_now; - fprintf(stdout, "Testing Time functions.\n"); + for (i = 0; test_times[i] != 0; i++) { + apr_status_t rv; + apr_time_exp_t xt; + time_t posix_secs = (time_t)apr_time_sec(test_times[i]); + struct tm *posix_exp = localtime(&posix_secs); - fprintf(stdout, "\tap_now......."); - now = ap_now(); - fprintf(stdout, "OK\n"); + rv = apr_time_exp_lt(&xt, test_times[i]); + if (rv == APR_ENOTIMPL) { + ABTS_NOT_IMPL(tc, "apr_time_exp_lt"); + } + ABTS_TRUE(tc, rv == APR_SUCCESS); - fprintf(stdout, "\tap_explode_localtime......."); - if (ap_explode_localtime(&xt, now) != APR_SUCCESS) { - fprintf(stderr, "Couldn't explode the time\n"); - exit(-1); +#define CHK_FIELD(f) \ + ABTS_ASSERT(tc, "Mismatch in " #f, posix_exp->f == xt.f) + + CHK_FIELD(tm_sec); + CHK_FIELD(tm_min); + CHK_FIELD(tm_hour); + CHK_FIELD(tm_mday); + CHK_FIELD(tm_mon); + CHK_FIELD(tm_year); + CHK_FIELD(tm_wday); + CHK_FIELD(tm_yday); + CHK_FIELD(tm_isdst); +#undef CHK_FIELD } - fprintf(stdout, "OK\n"); - - fprintf(stdout, "\tap_explode_gmt......."); - if (ap_explode_gmt(&xt, now) != APR_SUCCESS) { - fprintf(stderr, "Couldn't explode the time\n"); - exit(-1); +} + +static void test_exp_get_gmt(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_time_exp_t xt; + apr_time_t imp; + apr_int64_t hr_off_64; + + rv = apr_time_exp_gmt(&xt, now); + ABTS_TRUE(tc, rv == APR_SUCCESS); + rv = apr_time_exp_get(&imp, &xt); + if (rv == APR_ENOTIMPL) { + ABTS_NOT_IMPL(tc, "apr_time_exp_get"); } - fprintf(stdout, "OK\n"); + ABTS_TRUE(tc, rv == APR_SUCCESS); + hr_off_64 = (apr_int64_t) xt.tm_gmtoff * APR_USEC_PER_SEC; + ABTS_TRUE(tc, now + hr_off_64 == imp); +} + +static void test_exp_get_lt(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_time_exp_t xt; + apr_time_t imp; + apr_int64_t hr_off_64; - fprintf(stdout, "\tap_implode_time........"); - if (ap_implode_time(&imp, &xt) != APR_SUCCESS) { - fprintf(stderr, "Couldn't implode the time\n"); - exit(-1); + rv = apr_time_exp_lt(&xt, now); + ABTS_TRUE(tc, rv == APR_SUCCESS); + rv = apr_time_exp_get(&imp, &xt); + if (rv == APR_ENOTIMPL) { + ABTS_NOT_IMPL(tc, "apr_time_exp_get"); } - if (imp != now) { - fprintf(stderr, "implode/explode mismatch\n"); - exit(-1); + ABTS_TRUE(tc, rv == APR_SUCCESS); + hr_off_64 = (apr_int64_t) xt.tm_gmtoff * APR_USEC_PER_SEC; + ABTS_TRUE(tc, now + hr_off_64 == imp); +} + +static void test_imp_gmt(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_time_exp_t xt; + apr_time_t imp; + + rv = apr_time_exp_gmt(&xt, now); + ABTS_TRUE(tc, rv == APR_SUCCESS); + rv = apr_time_exp_gmt_get(&imp, &xt); + if (rv == APR_ENOTIMPL) { + ABTS_NOT_IMPL(tc, "apr_time_exp_gmt_get"); } - fprintf(stdout, "OK\n"); + ABTS_TRUE(tc, rv == APR_SUCCESS); + ABTS_TRUE(tc, now == imp); +} + +static void test_rfcstr(abts_case *tc, void *data) +{ + apr_status_t rv; + char str[STR_SIZE]; + + rv = apr_rfc822_date(str, now); + if (rv == APR_ENOTIMPL) { + ABTS_NOT_IMPL(tc, "apr_rfc822_date"); + } + ABTS_TRUE(tc, rv == APR_SUCCESS); + ABTS_STR_EQUAL(tc, "Sat, 14 Sep 2002 19:05:36 GMT", str); +} + +static void test_ctime(abts_case *tc, void *data) +{ + apr_status_t rv; + char apr_str[STR_SIZE]; + char libc_str[STR_SIZE]; + apr_time_t now_sec = apr_time_sec(now); + time_t posix_sec = (time_t) now_sec; + + rv = apr_ctime(apr_str, now); + if (rv == APR_ENOTIMPL) { + ABTS_NOT_IMPL(tc, "apr_ctime"); + } + ABTS_TRUE(tc, rv == APR_SUCCESS); + strcpy(libc_str, ctime(&posix_sec)); + *strchr(libc_str, '\n') = '\0'; + + ABTS_STR_EQUAL(tc, libc_str, apr_str); +} + +static void test_strftime(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_time_exp_t xt; + char *str = NULL; + apr_size_t sz; + + rv = apr_time_exp_gmt(&xt, now); + str = apr_palloc(p, STR_SIZE + 1); + rv = apr_strftime(str, &sz, STR_SIZE, "%R %A %d %B %Y", &xt); + if (rv == APR_ENOTIMPL) { + ABTS_NOT_IMPL(tc, "apr_strftime"); + } + ABTS_TRUE(tc, rv == APR_SUCCESS); + ABTS_STR_EQUAL(tc, "19:05 Saturday 14 September 2002", str); +} + +static void test_strftimesmall(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_time_exp_t xt; + char str[STR_SIZE]; + apr_size_t sz; + + rv = apr_time_exp_gmt(&xt, now); + rv = apr_strftime(str, &sz, STR_SIZE, "%T", &xt); + if (rv == APR_ENOTIMPL) { + ABTS_NOT_IMPL(tc, "apr_strftime"); + } + ABTS_TRUE(tc, rv == APR_SUCCESS); + ABTS_STR_EQUAL(tc, "19:05:36", str); +} + +static void test_exp_tz(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_time_exp_t xt; + apr_int32_t hr_off = -5 * 3600; /* 5 hours in seconds */ + + rv = apr_time_exp_tz(&xt, now, hr_off); + if (rv == APR_ENOTIMPL) { + ABTS_NOT_IMPL(tc, "apr_time_exp_tz"); + } + ABTS_TRUE(tc, rv == APR_SUCCESS); + ABTS_TRUE(tc, (xt.tm_usec == 186711) && + (xt.tm_sec == 36) && + (xt.tm_min == 5) && + (xt.tm_hour == 14) && + (xt.tm_mday == 14) && + (xt.tm_mon == 8) && + (xt.tm_year == 102) && + (xt.tm_wday == 6) && + (xt.tm_yday == 256)); +} + +static void test_strftimeoffset(abts_case *tc, void *data) +{ + apr_status_t rv; + apr_time_exp_t xt; + char str[STR_SIZE]; + apr_size_t sz; + apr_int32_t hr_off = -5 * 3600; /* 5 hours in seconds */ + + apr_time_exp_tz(&xt, now, hr_off); + rv = apr_strftime(str, &sz, STR_SIZE, "%T", &xt); + if (rv == APR_ENOTIMPL) { + ABTS_NOT_IMPL(tc, "apr_strftime"); + } + ABTS_TRUE(tc, rv == APR_SUCCESS); +} + +/* 0.9.4 and earlier rejected valid dates in 2038 */ +static void test_2038(abts_case *tc, void *data) +{ + apr_time_exp_t xt; + apr_time_t t; + + /* 2038-01-19T03:14:07.000000Z */ + xt.tm_year = 138; + xt.tm_mon = 0; + xt.tm_mday = 19; + xt.tm_hour = 3; + xt.tm_min = 14; + xt.tm_sec = 7; + + APR_ASSERT_SUCCESS(tc, "explode January 19th, 2038", + apr_time_exp_get(&t, &xt)); +} + +abts_suite *testtime(abts_suite *suite) +{ + suite = ADD_SUITE(suite) + + abts_run_test(suite, test_now, NULL); + abts_run_test(suite, test_gmtstr, NULL); + abts_run_test(suite, test_exp_lt, NULL); + abts_run_test(suite, test_exp_get_gmt, NULL); + abts_run_test(suite, test_exp_get_lt, NULL); + abts_run_test(suite, test_imp_gmt, NULL); + abts_run_test(suite, test_rfcstr, NULL); + abts_run_test(suite, test_ctime, NULL); + abts_run_test(suite, test_strftime, NULL); + abts_run_test(suite, test_strftimesmall, NULL); + abts_run_test(suite, test_exp_tz, NULL); + abts_run_test(suite, test_strftimeoffset, NULL); + abts_run_test(suite, test_2038, NULL); - return 1; -} + return suite; +} diff --git a/test/testud.c b/test/testud.c new file mode 100644 index 00000000000..7132d6cf78e --- /dev/null +++ b/test/testud.c @@ -0,0 +1,91 @@ +/* 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 <stdio.h> +#include <stdlib.h> +#include "apr_file_io.h" +#include "apr_errno.h" +#include "apr_general.h" +#include "apr_lib.h" +#include "apr_strings.h" +#include "testutil.h" + +static apr_pool_t *pool; +static char *testdata; +static int cleanup_called = 0; + +static apr_status_t string_cleanup(void *data) +{ + cleanup_called = 1; + return APR_SUCCESS; +} + +static void set_userdata(abts_case *tc, void *data) +{ + apr_status_t rv; + + rv = apr_pool_userdata_set(testdata, "TEST", string_cleanup, pool); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); +} + +static void get_userdata(abts_case *tc, void *data) +{ + apr_status_t rv; + void *retdata; + + rv = apr_pool_userdata_get(&retdata, "TEST", pool); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_STR_EQUAL(tc, testdata, retdata); +} + +static void get_nonexistkey(abts_case *tc, void *data) +{ + apr_status_t rv; + void *retdata; + + rv = apr_pool_userdata_get(&retdata, "DOESNTEXIST", pool); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_PTR_EQUAL(tc, NULL, retdata); +} + +static void post_pool_clear(abts_case *tc, void *data) +{ + apr_status_t rv; + void *retdata; + + rv = apr_pool_userdata_get(&retdata, "DOESNTEXIST", pool); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + ABTS_PTR_EQUAL(tc, NULL, retdata); +} + +abts_suite *testud(abts_suite *suite) +{ + suite = ADD_SUITE(suite) + + apr_pool_create(&pool, p); + testdata = apr_pstrdup(pool, "This is a test\n"); + + abts_run_test(suite, set_userdata, NULL); + abts_run_test(suite, get_userdata, NULL); + abts_run_test(suite, get_nonexistkey, NULL); + + apr_pool_clear(pool); + + abts_run_test(suite, post_pool_clear, NULL); + + return suite; +} + diff --git a/test/testuri.c b/test/testuri.c new file mode 100644 index 00000000000..d0b51e16cfb --- /dev/null +++ b/test/testuri.c @@ -0,0 +1,331 @@ +/* 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 <stdio.h> +#include <stdlib.h> + +#include "testutil.h" +#include "apr_general.h" +#include "apr_strings.h" +#include "apr_uri.h" + +struct aup_test { + const char *uri; + apr_status_t rv; + const char *scheme; + const char *hostinfo; + const char *user; + const char *password; + const char *hostname; + const char *port_str; + const char *path; + const char *query; + const char *fragment; + apr_port_t port; +}; + +struct aup_test aup_tests[] = +{ + { "http://[/::1]/index.html", APR_EGENERAL }, + { "http://[", APR_EGENERAL }, + { "http://[?::1]/index.html", APR_EGENERAL }, + + { + "http://127.0.0.1:9999/asdf.html", + 0, "http", "127.0.0.1:9999", NULL, NULL, "127.0.0.1", "9999", "/asdf.html", NULL, NULL, 9999 + }, + { + "http://127.0.0.1:9999a/asdf.html", + APR_EGENERAL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0 + }, + { + "http://[::127.0.0.1]:9999/asdf.html", + 0, "http", "[::127.0.0.1]:9999", NULL, NULL, "::127.0.0.1", "9999", "/asdf.html", NULL, NULL, 9999 + }, + { + "http://[::127.0.0.1]:9999a/asdf.html", + APR_EGENERAL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0 + }, + { + "/error/include/top.html", + 0, NULL, NULL, NULL, NULL, NULL, NULL, "/error/include/top.html", NULL, NULL, 0 + }, + { + "/error/include/../contact.html.var", + 0, NULL, NULL, NULL, NULL, NULL, NULL, "/error/include/../contact.html.var", NULL, NULL, 0 + }, + { + "/", + 0, NULL, NULL, NULL, NULL, NULL, NULL, "/", NULL, NULL, 0 + }, + { + "/manual/", + 0, NULL, NULL, NULL, NULL, NULL, NULL, "/manual/", NULL, NULL, 0 + }, + { + "/cocoon/developing/graphics/Using%20Databases-label_over.jpg", + 0, NULL, NULL, NULL, NULL, NULL, NULL, "/cocoon/developing/graphics/Using%20Databases-label_over.jpg", NULL, NULL, 0 + }, + { + "http://sonyamt:garbage@127.0.0.1/filespace/", + 0, "http", "sonyamt:garbage@127.0.0.1", "sonyamt", "garbage", "127.0.0.1", NULL, "/filespace/", NULL, NULL, 0 + }, + { + "http://sonyamt:garbage@[fe80::1]/filespace/", + 0, "http", "sonyamt:garbage@[fe80::1]", "sonyamt", "garbage", "fe80::1", NULL, "/filespace/", NULL, NULL, 0 + }, + { + "http://sonyamt@[fe80::1]/filespace/?arg1=store", + 0, "http", "sonyamt@[fe80::1]", "sonyamt", NULL, "fe80::1", NULL, "/filespace/", "arg1=store", NULL, 0 + }, + { + "http://localhost", + 0, "http", "localhost", NULL, NULL, "localhost", NULL, NULL, NULL, NULL, 0 + }, + { + "//www.apache.org/", + 0, NULL, "www.apache.org", NULL, NULL, "www.apache.org", NULL, "/", NULL, NULL, 0 + }, + { + "file:image.jpg", + 0, "file", NULL, NULL, NULL, NULL, NULL, "image.jpg", NULL, NULL, 0 + }, + { + "file:/image.jpg", + 0, "file", NULL, NULL, NULL, NULL, NULL, "/image.jpg", NULL, NULL, 0 + }, + { + "file:///image.jpg", + 0, "file", "", NULL, NULL, "", NULL, "/image.jpg", NULL, NULL, 0 + }, + { + "file:///tmp/photos/image.jpg", + 0, "file", "", NULL, NULL, "", NULL, "/tmp/photos/image.jpg", NULL, NULL, 0 + }, + { + "file:./image.jpg", + 0, "file", NULL, NULL, NULL, NULL, NULL, "./image.jpg", NULL, NULL, 0 + }, + { + "file:../photos/image.jpg", + 0, "file", NULL, NULL, NULL, NULL, NULL, "../photos/image.jpg", NULL, NULL, 0 + }, + { + "file+ssh-2:../photos/image.jpg", + 0, "file+ssh-2", NULL, NULL, NULL, NULL, NULL, "../photos/image.jpg", NULL, NULL, 0 + }, + { + "script/foo.js", + 0, NULL, NULL, NULL, NULL, NULL, NULL, "script/foo.js", NULL, NULL, 0 + }, + { + "../foo2.js", + 0, NULL, NULL, NULL, NULL, NULL, NULL, "../foo2.js", NULL, NULL, 0 + }, + { + "foo3.js", + 0, NULL, NULL, NULL, NULL, NULL, NULL, "foo3.js", NULL, NULL, 0 + }, + { + "_foo/bar", + 0, NULL, NULL, NULL, NULL, NULL, NULL, "_foo/bar", NULL, NULL, 0 + }, + { + "_foo:/bar", + APR_EGENERAL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0 + }, + { + "2foo:/bar", + APR_EGENERAL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0 + }, + { + ".foo:/bar", + APR_EGENERAL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0 + }, + { + "-foo:/bar", + APR_EGENERAL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0 + }, + { + "+foo:/bar", + APR_EGENERAL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0 + }, + { + "::/bar", + APR_EGENERAL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0 + }, + { + ":/bar", + APR_EGENERAL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0 + }, + { + ":foo", + APR_EGENERAL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0 + }, + { + ":", + APR_EGENERAL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0 + }, + { + "@localhost::8080", + APR_EGENERAL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0 + }, +}; + +struct uph_test { + const char *hostinfo; + apr_status_t rv; + const char *hostname; + const char *port_str; + apr_port_t port; +}; + +struct uph_test uph_tests[] = +{ + { + "www.ibm.com:443", + 0, "www.ibm.com", "443", 443 + }, + { + "[fe80::1]:443", + 0, "fe80::1", "443", 443 + }, + { + "127.0.0.1:443", + 0, "127.0.0.1", "443", 443 + }, + { + "127.0.0.1", + APR_EGENERAL, NULL, NULL, 0 + }, + { + "[fe80:80", + APR_EGENERAL, NULL, NULL, 0 + }, + { + "fe80::80]:443", + APR_EGENERAL, NULL, NULL, 0 + } +}; + +#if 0 +static void show_info(apr_status_t rv, apr_status_t expected, const apr_uri_t *info) +{ + if (rv != expected) { + fprintf(stderr, " actual rv: %d expected rv: %d\n", rv, expected); + } + else { + fprintf(stderr, + " scheme: %s\n" + " hostinfo: %s\n" + " user: %s\n" + " password: %s\n" + " hostname: %s\n" + " port_str: %s\n" + " path: %s\n" + " query: %s\n" + " fragment: %s\n" + " hostent: %p\n" + " port: %u\n" + " is_initialized: %u\n" + " dns_looked_up: %u\n" + " dns_resolved: %u\n", + info->scheme, info->hostinfo, info->user, info->password, + info->hostname, info->port_str, info->path, info->query, + info->fragment, info->hostent, info->port, info->is_initialized, + info->dns_looked_up, info->dns_resolved); + } +} +#endif + +static void test_aup(abts_case *tc, void *data) +{ + int i; + apr_status_t rv; + apr_uri_t info; + struct aup_test *t; + const char *s = NULL; + + for (i = 0; i < sizeof(aup_tests) / sizeof(aup_tests[0]); i++) { + char msg[256]; + + memset(&info, 0, sizeof(info)); + t = &aup_tests[i]; + rv = apr_uri_parse(p, t->uri, &info); + apr_snprintf(msg, sizeof msg, "uri '%s': rv=%d not %d", t->uri, + rv, t->rv); + ABTS_ASSERT(tc, msg, rv == t->rv); + if (t->rv == APR_SUCCESS) { + ABTS_STR_EQUAL(tc, t->scheme, info.scheme); + ABTS_STR_EQUAL(tc, t->hostinfo, info.hostinfo); + ABTS_STR_EQUAL(tc, t->user, info.user); + ABTS_STR_EQUAL(tc, t->password, info.password); + ABTS_STR_EQUAL(tc, t->hostname, info.hostname); + ABTS_STR_EQUAL(tc, t->port_str, info.port_str); + ABTS_STR_EQUAL(tc, t->path, info.path); + ABTS_STR_EQUAL(tc, t->query, info.query); + ABTS_STR_EQUAL(tc, t->user, info.user); + ABTS_INT_EQUAL(tc, t->port, info.port); + + s = apr_uri_unparse(p, &info, APR_URI_UNP_REVEALPASSWORD); + ABTS_STR_EQUAL(tc, t->uri, s); + + s = apr_uri_unparse(p, &info, APR_URI_UNP_OMITSITEPART); + rv = apr_uri_parse(p, s, &info); + ABTS_STR_EQUAL(tc, info.scheme, NULL); + ABTS_STR_EQUAL(tc, info.hostinfo, NULL); + ABTS_STR_EQUAL(tc, info.user, NULL); + ABTS_STR_EQUAL(tc, info.password, NULL); + ABTS_STR_EQUAL(tc, info.hostname, NULL); + ABTS_STR_EQUAL(tc, info.port_str, NULL); + ABTS_STR_EQUAL(tc, info.path, t->path); + ABTS_STR_EQUAL(tc, info.query, t->query); + ABTS_STR_EQUAL(tc, info.user, NULL); + ABTS_INT_EQUAL(tc, info.port, 0); + } + } +} + +static void test_uph(abts_case *tc, void *data) +{ + int i; + apr_status_t rv; + apr_uri_t info; + struct uph_test *t; + + for (i = 0; i < sizeof(uph_tests) / sizeof(uph_tests[0]); i++) { + memset(&info, 0, sizeof(info)); + t = &uph_tests[i]; + rv = apr_uri_parse_hostinfo(p, t->hostinfo, &info); + ABTS_INT_EQUAL(tc, t->rv, rv); + if (t->rv == APR_SUCCESS) { + ABTS_STR_EQUAL(tc, t->hostname, info.hostname); + ABTS_STR_EQUAL(tc, t->port_str, info.port_str); + ABTS_INT_EQUAL(tc, t->port, info.port); + } + } +} + +abts_suite *testuri(abts_suite *suite) +{ + suite = ADD_SUITE(suite); + + abts_run_test(suite, test_aup, NULL); + abts_run_test(suite, test_uph, NULL); + + return suite; +} + diff --git a/test/testuser.c b/test/testuser.c new file mode 100644 index 00000000000..e75782e902e --- /dev/null +++ b/test/testuser.c @@ -0,0 +1,174 @@ +/* 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 "testutil.h" +#include "apr_errno.h" +#include "apr_general.h" +#include "apr_user.h" + +#if APR_HAS_USER +static void uid_current(abts_case *tc, void *data) +{ + apr_uid_t uid; + apr_gid_t gid; + + APR_ASSERT_SUCCESS(tc, "apr_uid_current failed", + apr_uid_current(&uid, &gid, p)); +} + +static void username(abts_case *tc, void *data) +{ + apr_uid_t uid; + apr_gid_t gid; + apr_uid_t retreived_uid; + apr_gid_t retreived_gid; + char *uname = NULL; + + APR_ASSERT_SUCCESS(tc, "apr_uid_current failed", + apr_uid_current(&uid, &gid, p)); + + APR_ASSERT_SUCCESS(tc, "apr_uid_name_get failed", + apr_uid_name_get(&uname, uid, p)); + ABTS_PTR_NOTNULL(tc, uname); + + if (uname == NULL) + return; + + APR_ASSERT_SUCCESS(tc, "apr_uid_get failed", + apr_uid_get(&retreived_uid, &retreived_gid, uname, p)); + + APR_ASSERT_SUCCESS(tc, "apr_uid_compare failed", + apr_uid_compare(uid, retreived_uid)); +#ifdef WIN32 + /* ### this fudge was added for Win32 but makes the test return NotImpl + * on Unix if run as root, when !gid is also true. */ + if (!gid || !retreived_gid) { + /* The function had no way to recover the gid (this would have been + * an ENOTIMPL if apr_uid_ functions didn't try to double-up and + * also return apr_gid_t values, which was bogus. + */ + if (!gid) { + ABTS_NOT_IMPL(tc, "Groups from apr_uid_current"); + } + else { + ABTS_NOT_IMPL(tc, "Groups from apr_uid_get"); + } + } + else { +#endif + APR_ASSERT_SUCCESS(tc, "apr_gid_compare failed", + apr_gid_compare(gid, retreived_gid)); +#ifdef WIN32 + } +#endif +} + +static void groupname(abts_case *tc, void *data) +{ + apr_uid_t uid; + apr_gid_t gid; + apr_gid_t retreived_gid; + char *gname = NULL; + + APR_ASSERT_SUCCESS(tc, "apr_uid_current failed", + apr_uid_current(&uid, &gid, p)); + + APR_ASSERT_SUCCESS(tc, "apr_gid_name_get failed", + apr_gid_name_get(&gname, gid, p)); + ABTS_PTR_NOTNULL(tc, gname); + + if (gname == NULL) + return; + + APR_ASSERT_SUCCESS(tc, "apr_gid_get failed", + apr_gid_get(&retreived_gid, gname, p)); + + APR_ASSERT_SUCCESS(tc, "apr_gid_compare failed", + apr_gid_compare(gid, retreived_gid)); +} + +#ifdef APR_UID_GID_NUMERIC + +static void fail_userinfo(abts_case *tc, void *data) +{ + apr_uid_t uid; + apr_gid_t gid; + apr_status_t rv; + char *tmp; + + errno = 0; + gid = uid = 9999999; + tmp = NULL; + rv = apr_uid_name_get(&tmp, uid, p); + ABTS_ASSERT(tc, "apr_uid_name_get should fail or " + "return a user name", + rv != APR_SUCCESS || tmp != NULL); + + errno = 0; + tmp = NULL; + rv = apr_gid_name_get(&tmp, gid, p); + ABTS_ASSERT(tc, "apr_gid_name_get should fail or " + "return a group name", + rv != APR_SUCCESS || tmp != NULL); + + gid = 424242; + errno = 0; + rv = apr_gid_get(&gid, "I_AM_NOT_A_GROUP", p); + ABTS_ASSERT(tc, "apr_gid_get should fail or " + "set a group number", + rv != APR_SUCCESS || gid == 424242); + + gid = uid = 424242; + errno = 0; + rv = apr_uid_get(&uid, &gid, "I_AM_NOT_A_USER", p); + ABTS_ASSERT(tc, "apr_gid_get should fail or " + "set a user and group number", + rv != APR_SUCCESS || uid == 424242 || gid == 4242442); + + errno = 0; + tmp = NULL; + rv = apr_uid_homepath_get(&tmp, "I_AM_NOT_A_USER", p); + ABTS_ASSERT(tc, "apr_uid_homepath_get should fail or " + "set a path name", + rv != APR_SUCCESS || tmp != NULL); +} + +#endif + +#else +static void users_not_impl(abts_case *tc, void *data) +{ + ABTS_NOT_IMPL(tc, "Users not implemented on this platform"); +} +#endif + +abts_suite *testuser(abts_suite *suite) +{ + suite = ADD_SUITE(suite) + +#if !APR_HAS_USER + abts_run_test(suite, users_not_impl, NULL); +#else + abts_run_test(suite, uid_current, NULL); + abts_run_test(suite, username, NULL); + abts_run_test(suite, groupname, NULL); +#ifdef APR_UID_GID_NUMERIC + abts_run_test(suite, fail_userinfo, NULL); +#endif +#endif + + return suite; +} diff --git a/test/testutil.c b/test/testutil.c new file mode 100644 index 00000000000..d3c1ff8ac95 --- /dev/null +++ b/test/testutil.c @@ -0,0 +1,56 @@ +/* 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 <stdio.h> +#include <stdlib.h> + +#include "abts.h" +#include "testutil.h" +#include "apr_pools.h" + +apr_pool_t *p; + +void apr_assert_success(abts_case* tc, const char* context, apr_status_t rv, + int lineno) +{ + if (rv == APR_ENOTIMPL) { + abts_not_impl(tc, context, lineno); + } else if (rv != APR_SUCCESS) { + char buf[STRING_MAX], ebuf[128]; + sprintf(buf, "%s (%d): %s\n", context, rv, + apr_strerror(rv, ebuf, sizeof ebuf)); + abts_fail(tc, buf, lineno); + } +} + +void apr_assert_failure(abts_case* tc, const char* context, apr_status_t rv, + int lineno) +{ + if (rv == APR_ENOTIMPL) { + abts_not_impl(tc, context, lineno); + } else if (rv == APR_SUCCESS) { + char buf[STRING_MAX]; + sprintf(buf, "%s (%d): expected failure, got success\n", context, rv); + abts_fail(tc, buf, lineno); + } +} + +void initialize(void) { + apr_initialize(); + atexit(apr_terminate); + + apr_pool_create(&p, NULL); +} diff --git a/test/testutil.h b/test/testutil.h new file mode 100644 index 00000000000..f2a66b585ec --- /dev/null +++ b/test/testutil.h @@ -0,0 +1,137 @@ +/* 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_pools.h" +#include "apr_general.h" +#include "abts.h" + +#ifndef APR_TEST_UTIL +#define APR_TEST_UTIL + +/* XXX: FIXME - these all should become much more utilitarian + * and part of apr, itself + */ + +#ifdef WIN32 +#ifdef BINPATH +#define TESTBINPATH APR_STRINGIFY(BINPATH) "/" +#else +#define TESTBINPATH "" +#endif +#else +#define TESTBINPATH "./" +#endif + +#ifdef WIN32 +#define EXTENSION ".exe" +#elif NETWARE +#define EXTENSION ".nlm" +#else +#define EXTENSION +#endif + +#define STRING_MAX 8096 + +/* Some simple functions to make the test apps easier to write and + * a bit more consistent... + */ + +extern apr_pool_t *p; + +/* Assert that RV is an APR_SUCCESS value; else fail giving strerror + * for RV and CONTEXT message. */ +void apr_assert_success(abts_case* tc, const char *context, + apr_status_t rv, int lineno); +#define APR_ASSERT_SUCCESS(tc, ctxt, rv) \ + apr_assert_success(tc, ctxt, rv, __LINE__) + +void apr_assert_failure(abts_case* tc, const char *context, + apr_status_t rv, int lineno); +#define APR_ASSERT_FAILURE(tc, ctxt, rv) \ + apr_assert_failure(tc, ctxt, rv, __LINE__) + + +void initialize(void); + +abts_suite *testatomic(abts_suite *suite); +abts_suite *testdir(abts_suite *suite); +abts_suite *testdso(abts_suite *suite); +abts_suite *testdup(abts_suite *suite); +abts_suite *testenv(abts_suite *suite); +abts_suite *testfile(abts_suite *suite); +abts_suite *testfilecopy(abts_suite *suite); +abts_suite *testfileinfo(abts_suite *suite); +abts_suite *testflock(abts_suite *suite); +abts_suite *testfmt(abts_suite *suite); +abts_suite *testfnmatch(abts_suite *suite); +abts_suite *testgetopt(abts_suite *suite); +abts_suite *testglobalmutex(abts_suite *suite); +abts_suite *testhash(abts_suite *suite); +abts_suite *testhooks(abts_suite *suite); +abts_suite *testipsub(abts_suite *suite); +abts_suite *testlock(abts_suite *suite); +abts_suite *testcond(abts_suite *suite); +abts_suite *testlfs(abts_suite *suite); +abts_suite *testmmap(abts_suite *suite); +abts_suite *testnames(abts_suite *suite); +abts_suite *testoc(abts_suite *suite); +abts_suite *testpath(abts_suite *suite); +abts_suite *testpipe(abts_suite *suite); +abts_suite *testpoll(abts_suite *suite); +abts_suite *testpool(abts_suite *suite); +abts_suite *testproc(abts_suite *suite); +abts_suite *testprocmutex(abts_suite *suite); +abts_suite *testrand(abts_suite *suite); +abts_suite *testsleep(abts_suite *suite); +abts_suite *testshm(abts_suite *suite); +abts_suite *testsock(abts_suite *suite); +abts_suite *testsockets(abts_suite *suite); +abts_suite *testsockopt(abts_suite *suite); +abts_suite *teststr(abts_suite *suite); +abts_suite *teststrnatcmp(abts_suite *suite); +abts_suite *testtable(abts_suite *suite); +abts_suite *testtemp(abts_suite *suite); +abts_suite *testthread(abts_suite *suite); +abts_suite *testtime(abts_suite *suite); +abts_suite *testud(abts_suite *suite); +abts_suite *testuser(abts_suite *suite); +abts_suite *testvsn(abts_suite *suite); + +abts_suite *testescape(abts_suite *suite); +abts_suite *teststrmatch(abts_suite *suite); +abts_suite *testuri(abts_suite *suite); +abts_suite *testuuid(abts_suite *suite); +abts_suite *testbuckets(abts_suite *suite); +abts_suite *testpass(abts_suite *suite); +abts_suite *testbase64(abts_suite *suite); +abts_suite *testmd4(abts_suite *suite); +abts_suite *testmd5(abts_suite *suite); +abts_suite *testcrypto(abts_suite *suite); +abts_suite *testdbd(abts_suite *suite); +abts_suite *testdate(abts_suite *suite); +abts_suite *testmemcache(abts_suite *suite); +abts_suite *testredis(abts_suite *suite); +abts_suite *testreslist(abts_suite *suite); +abts_suite *testqueue(abts_suite *suite); +abts_suite *testxml(abts_suite *suite); +abts_suite *testxlate(abts_suite *suite); +abts_suite *testrmm(abts_suite *suite); +abts_suite *testdbm(abts_suite *suite); +abts_suite *testlfsabi(abts_suite *suite); +abts_suite *testskiplist(abts_suite *suite); +abts_suite *testsiphash(abts_suite *suite); + +#endif /* APR_TEST_INCLUDES */ diff --git a/test/testuuid.c b/test/testuuid.c new file mode 100644 index 00000000000..f33adde11f5 --- /dev/null +++ b/test/testuuid.c @@ -0,0 +1,56 @@ +/* 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 "testutil.h" +#include "apr_general.h" +#include "apr_uuid.h" + +static void test_uuid_parse(abts_case *tc, void *data) +{ + apr_uuid_t uuid; + apr_uuid_t uuid2; + char buf[APR_UUID_FORMATTED_LENGTH + 1]; + + apr_uuid_get(&uuid); + apr_uuid_format(buf, &uuid); + + apr_uuid_parse(&uuid2, buf); + ABTS_ASSERT(tc, "parse produced a different UUID", + memcmp(&uuid, &uuid2, sizeof(uuid)) == 0); +} + +static void test_gen2(abts_case *tc, void *data) +{ + apr_uuid_t uuid; + apr_uuid_t uuid2; + + /* generate two of them quickly */ + apr_uuid_get(&uuid); + apr_uuid_get(&uuid2); + + ABTS_ASSERT(tc, "generated the same UUID twice", + memcmp(&uuid, &uuid2, sizeof(uuid)) != 0); +} + +abts_suite *testuuid(abts_suite *suite) +{ + suite = ADD_SUITE(suite); + + abts_run_test(suite, test_uuid_parse, NULL); + abts_run_test(suite, test_gen2, NULL); + + return suite; +} diff --git a/test/testvsn.c b/test/testvsn.c new file mode 100644 index 00000000000..dbc218a13fe --- /dev/null +++ b/test/testvsn.c @@ -0,0 +1,56 @@ +/* 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 <stdio.h> + +#include "testutil.h" +#include "apr_version.h" +#include "apr_general.h" + + +static void test_strings(abts_case *tc, void *data) +{ + ABTS_STR_EQUAL(tc, APR_VERSION_STRING, apr_version_string()); +} + +#ifdef APR_IS_DEV_VERSION +# define IS_DEV 1 +#else +# define IS_DEV 0 +#endif + +static void test_ints(abts_case *tc, void *data) +{ + apr_version_t vsn; + + apr_version(&vsn); + + ABTS_INT_EQUAL(tc, APR_MAJOR_VERSION, vsn.major); + ABTS_INT_EQUAL(tc, APR_MINOR_VERSION, vsn.minor); + ABTS_INT_EQUAL(tc, APR_PATCH_VERSION, vsn.patch); + ABTS_INT_EQUAL(tc, IS_DEV, vsn.is_dev); +} + +abts_suite *testvsn(abts_suite *suite) +{ + suite = ADD_SUITE(suite) + + abts_run_test(suite, test_strings, NULL); + abts_run_test(suite, test_ints, NULL); + + return suite; +} + diff --git a/test/testxlate.c b/test/testxlate.c new file mode 100644 index 00000000000..e70196df6cc --- /dev/null +++ b/test/testxlate.c @@ -0,0 +1,126 @@ +/* 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_errno.h" +#include "apr_general.h" +#include "apr_strings.h" +#include "apr_xlate.h" +#include "abts.h" +#include "testutil.h" + +#if APR_HAS_XLATE + +static const char test_utf8[] = "Edelwei\xc3\x9f"; +static const char test_utf7[] = "Edelwei+AN8-"; +static const char test_latin1[] = "Edelwei\xdf"; +static const char test_latin2[] = "Edelwei\xdf"; + +static void test_conversion(abts_case *tc, apr_xlate_t *convset, + const char *inbuf, const char *expected) +{ + static char buf[1024]; + apr_size_t inbytes_left = strlen(inbuf); + apr_size_t outbytes_left = sizeof(buf) - 1; + apr_status_t rv; + + rv = apr_xlate_conv_buffer(convset, inbuf, &inbytes_left, buf, &outbytes_left); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + if (rv != APR_SUCCESS) + return; + + rv = apr_xlate_conv_buffer(convset, NULL, NULL, buf + sizeof(buf) - + outbytes_left - 1, &outbytes_left); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + buf[sizeof(buf) - outbytes_left - 1] = '\0'; + + ABTS_STR_EQUAL(tc, expected, buf); +} + +static void one_test(abts_case *tc, const char *cs1, const char *cs2, + const char *str1, const char *str2, + apr_pool_t *pool) +{ + apr_status_t rv; + apr_xlate_t *convset; + + rv = apr_xlate_open(&convset, cs2, cs1, pool); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + if (rv != APR_SUCCESS) + return; + + test_conversion(tc, convset, str1, str2); + + rv = apr_xlate_close(convset); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); +} + +/* some iconv implementations don't support all tested transforms; + * example: 8859-1 <-> 8859-2 using native Solaris iconv + */ +static int is_transform_supported(abts_case *tc, const char *cs1, + const char *cs2, apr_pool_t *pool) { + apr_status_t rv; + apr_xlate_t *convset; + + rv = apr_xlate_open(&convset, cs2, cs1, pool); + if (rv != APR_SUCCESS) { + return 0; + } + + rv = apr_xlate_close(convset); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + return 1; +} + +static void test_transformation(abts_case *tc, void *data) +{ + /* 1. Identity transformation: UTF-8 -> UTF-8 */ + one_test(tc, "UTF-8", "UTF-8", test_utf8, test_utf8, p); + + /* 2. UTF-8 <-> ISO-8859-1 */ + one_test(tc, "UTF-8", "ISO-8859-1", test_utf8, test_latin1, p); + one_test(tc, "ISO-8859-1", "UTF-8", test_latin1, test_utf8, p); + + /* 3. ISO-8859-1 <-> ISO-8859-2, identity */ + if (is_transform_supported(tc, "ISO-8859-1", "ISO-8859-2", p)) { + one_test(tc, "ISO-8859-1", "ISO-8859-2", test_latin1, test_latin2, p); + } + if (is_transform_supported(tc, "ISO-8859-2", "ISO-8859-1", p)) { + one_test(tc, "ISO-8859-2", "ISO-8859-1", test_latin2, test_latin1, p); + } + + /* 4. Transformation using charset aliases */ + one_test(tc, "UTF-8", "UTF-7", test_utf8, test_utf7, p); + one_test(tc, "UTF-7", "UTF-8", test_utf7, test_utf8, p); +} + +#endif /* APR_HAS_XLATE */ + +abts_suite *testxlate(abts_suite *suite) +{ + suite = ADD_SUITE(suite); + +#if APR_HAS_XLATE + abts_run_test(suite, test_transformation, NULL); +#endif + + return suite; +} diff --git a/test/testxml.c b/test/testxml.c new file mode 100644 index 00000000000..3d2542d4445 --- /dev/null +++ b/test/testxml.c @@ -0,0 +1,176 @@ +/* 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_xml.h" +#include "abts.h" +#include "testutil.h" + +static apr_status_t create_dummy_file_error(abts_case *tc, apr_pool_t *p, + apr_file_t **fd) +{ + int i; + apr_status_t rv; + apr_off_t off = 0L; + char template[] = "data/testxmldummyerrorXXXXXX"; + + rv = apr_file_mktemp(fd, template, APR_FOPEN_CREATE | APR_FOPEN_TRUNCATE | APR_FOPEN_DELONCLOSE | + APR_FOPEN_READ | APR_FOPEN_WRITE | APR_FOPEN_EXCL, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + if (rv != APR_SUCCESS) + return rv; + + rv = apr_file_puts("<?xml version=\"1.0\" ?>\n<maryx>" + "<had a=\"little\"/><lamb/>\n", *fd); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + for (i = 0; i < 5000; i++) { + rv = apr_file_puts("<hmm roast=\"lamb\" " + "for=\"dinner\">yummy</hmm>\n", *fd); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + } + + rv = apr_file_puts("</mary>\n", *fd); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + rv = apr_file_seek(*fd, APR_SET, &off); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + return rv; +} + +static apr_status_t create_dummy_file(abts_case *tc, apr_pool_t *p, + apr_file_t **fd) +{ + int i; + apr_status_t rv; + apr_off_t off = 0L; + char template[] = "data/testxmldummyXXXXXX"; + + rv = apr_file_mktemp(fd, template, APR_FOPEN_CREATE | APR_FOPEN_TRUNCATE | APR_FOPEN_DELONCLOSE | + APR_FOPEN_READ | APR_FOPEN_WRITE | APR_FOPEN_EXCL, p); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + if (rv != APR_SUCCESS) + return rv; + + rv = apr_file_puts("<?xml version=\"1.0\" ?>\n<mary>\n", *fd); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + for (i = 0; i < 5000; i++) { + rv = apr_file_puts("<hmm roast=\"lamb\" " + "for=\"dinner <>=\">yummy</hmm>\n", *fd); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + } + + rv = apr_file_puts("</mary>\n", *fd); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + rv = apr_file_seek(*fd, APR_SET, &off); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + return rv; +} + +static void dump_xml(abts_case *tc, apr_xml_elem *e, int level) +{ + apr_xml_attr *a; + apr_xml_elem *ec; + + if (level == 0) { + ABTS_STR_EQUAL(tc, "mary", e->name); + } else { + ABTS_STR_EQUAL(tc, "hmm", e->name); + } + + if (e->attr) { + a = e->attr; + ABTS_PTR_NOTNULL(tc, a); + ABTS_STR_EQUAL(tc, "for", a->name); + ABTS_STR_EQUAL(tc, "dinner <>=", a->value); + a = a->next; + ABTS_PTR_NOTNULL(tc, a); + ABTS_STR_EQUAL(tc, "roast", a->name); + ABTS_STR_EQUAL(tc, "lamb", a->value); + } + if (e->first_child) { + ec = e->first_child; + while (ec) { + dump_xml(tc, ec, level + 1); + ec = ec->next; + } + } +} + +static void test_xml_parser(abts_case *tc, void *data) +{ + apr_file_t *fd; + apr_xml_parser *parser; + apr_xml_doc *doc; + apr_status_t rv; + + rv = create_dummy_file(tc, p, &fd); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + if (rv != APR_SUCCESS) + return; + + rv = apr_xml_parse_file(p, &parser, &doc, fd, 2000); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + dump_xml(tc, doc->root, 0); + + rv = apr_file_close(fd); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + rv = create_dummy_file_error(tc, p, &fd); + ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); + + if (rv != APR_SUCCESS) + return; + + rv = apr_xml_parse_file(p, &parser, &doc, fd, 2000); + ABTS_TRUE(tc, rv != APR_SUCCESS); +} + +static void test_billion_laughs(abts_case *tc, void *data) +{ + apr_file_t *fd; + apr_xml_parser *parser; + apr_xml_doc *doc; + apr_status_t rv; + + rv = apr_file_open(&fd, "data/billion-laughs.xml", + APR_FOPEN_READ, 0, p); + APR_ASSERT_SUCCESS(tc, "open billion-laughs.xml", rv); + + rv = apr_xml_parse_file(p, &parser, &doc, fd, 2000); + ABTS_TRUE(tc, rv != APR_SUCCESS); + + apr_file_close(fd); +} + +abts_suite *testxml(abts_suite *suite) +{ + suite = ADD_SUITE(suite); + + abts_run_test(suite, test_xml_parser, NULL); + abts_run_test(suite, test_billion_laughs, NULL); + + return suite; +} diff --git a/test/timetest.dsp b/test/timetest.dsp deleted file mode 100644 index 007376cfd52..00000000000 --- a/test/timetest.dsp +++ /dev/null @@ -1,91 +0,0 @@ -# Microsoft Developer Studio Project File - Name="timetest" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 5.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Console Application" 0x0103 - -CFG=timetest - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "timetest.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "timetest.mak" CFG="timetest - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "timetest - Win32 Release" (based on\ - "Win32 (x86) Console Application") -!MESSAGE "timetest - Win32 Debug" (based on "Win32 (x86) Console Application") -!MESSAGE - -# Begin Project -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -RSC=rc.exe - -!IF "$(CFG)" == "timetest - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /W3 /GX /O2 /I "..\include" /I "..\..\include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD BASE RSC /l 0x409 /d "NDEBUG" -# ADD RSC /l 0x409 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 -# ADD LINK32 ..\Release\aprlib.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"..\Release\timetest.exe" - -!ELSEIF "$(CFG)" == "timetest - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "timetest" -# PROP BASE Intermediate_Dir "timetest" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "timetest" -# PROP Intermediate_Dir "timetest" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /I "..\include" /I "..\..\include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FD /c -# SUBTRACT CPP /YX /Yc /Yu -# ADD BASE RSC /l 0x409 /d "_DEBUG" -# ADD RSC /l 0x409 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept -# ADD LINK32 ..\Debug\aprlib.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"..\Debug\timetest.exe" /pdbtype:sept - -!ENDIF - -# Begin Target - -# Name "timetest - Win32 Release" -# Name "timetest - Win32 Debug" -# Begin Source File - -SOURCE=.\testtime.c -# End Source File -# End Target -# End Project diff --git a/test/tryread.c b/test/tryread.c new file mode 100644 index 00000000000..843abe70aac --- /dev/null +++ b/test/tryread.c @@ -0,0 +1,49 @@ +/* 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 "testflock.h" +#include "apr_pools.h" +#include "apr_file_io.h" +#include "apr_general.h" +#include "apr.h" + +#if APR_HAVE_STDLIB_H +#include <stdlib.h> +#endif + +int main(int argc, const char * const *argv) +{ + apr_file_t *file; + apr_status_t status; + apr_pool_t *p; + + apr_initialize(); + apr_pool_create(&p, NULL); + + if (apr_file_open(&file, TESTFILE, APR_FOPEN_WRITE, APR_FPROT_OS_DEFAULT, p) + != APR_SUCCESS) { + + exit(UNEXPECTED_ERROR); + } + status = apr_file_lock(file, APR_FLOCK_EXCLUSIVE | APR_FLOCK_NONBLOCK); + if (status == APR_SUCCESS) { + exit(SUCCESSFUL_READ); + } + if (APR_STATUS_IS_EAGAIN(status)) { + exit(FAILED_READ); + } + exit(UNEXPECTED_ERROR); +} diff --git a/threadproc/beos/Makefile.in b/threadproc/beos/Makefile.in deleted file mode 100644 index c2b8c6f1728..00000000000 --- a/threadproc/beos/Makefile.in +++ /dev/null @@ -1,96 +0,0 @@ -#CFLAGS=$(OPTIM) $(CFLAGS1) $(EXTRA_CFLAGS) -#LIBS=$(EXTRA_LIBS) $(LIBS1) -#INCLUDES=$(INCLUDES1) $(INCLUDES0) $(EXTRA_INCLUDES) -#LDFLAGS=$(LDFLAGS1) $(EXTRA_LDFLAGS) - -CC=@CC@ -RANLIB=@RANLIB@ -CFLAGS=@CFLAGS@ @OPTIM@ -LIBS=@LIBS@ -LDFLAGS=@LDFLAGS@ $(LIBS) -INCDIR=../../include -INCDIR1=../../file_io/unix -INCLUDES=-I$(INCDIR) -I$(INCDIR1) -I. - -LIB=libthreadproc.a - -OBJS=proc.o \ - thread.o \ - threadpriv.o \ - threadproc_common.o \ - procsup.o \ - apr_proc_stub - -.c.o: - $(CC) $(CFLAGS) -c $(INCLUDES) $< - -all: $(LIB) - -apr_proc_stub: - $(CC) apr_proc_stub.c \ - && cp apr_proc_stub /boot/home/config/bin - -clean: - $(RM) -f *.o *.a *.so /boot/home/config/bin/apr_proc_stub apr_proc_stub - -distclean: clean - -$(RM) -f Makefile - -$(OBJS): Makefile - -$(LIB): $(OBJS) - $(RM) -f $@ - $(AR) cr $@ $(OBJS) - $(RANLIB) $@ - -# -# We really don't expect end users to use this rule. It works only with -# gcc, and rebuilds Makefile.tmpl. You have to re-run Configure after -# using it. -# -depend: - cp Makefile.in Makefile.in.bak \ - && sed -ne '1,/^# DO NOT REMOVE/p' Makefile.in > Makefile.new \ - && gcc -MM $(INCLUDES) $(CFLAGS) *.c >> Makefile.new \ - && sed -e '1,$$s: $(INCDIR)/: $$(INCDIR)/:g' \ - -e '1,$$s: $(OSDIR)/: $$(OSDIR)/:g' Makefile.new \ - > Makefile.in \ - && rm Makefile.new - -# DO NOT REMOVE -apr_proc_stub.o: apr_proc_stub.c -proc.o: proc.c threadproc.h $(INCDIR)/apr_thread_proc.h \ - $(INCDIR)/apr_file_io.h $(INCDIR)/apr_general.h \ - $(INCDIR)/apr.h $(INCDIR)/apr_errno.h \ - $(INCDIR)/apr_time.h ../../file_io/unix/fileio.h \ - $(INCDIR)/apr_private.h $(INCDIR)/apr_lib.h \ - $(INCDIR)/apr_portable.h $(INCDIR)/apr_network_io.h \ - $(INCDIR)/apr_lock.h -procsup.o: procsup.c threadproc.h $(INCDIR)/apr_thread_proc.h \ - $(INCDIR)/apr_file_io.h $(INCDIR)/apr_general.h \ - $(INCDIR)/apr.h $(INCDIR)/apr_errno.h \ - $(INCDIR)/apr_time.h ../../file_io/unix/fileio.h \ - $(INCDIR)/apr_private.h $(INCDIR)/apr_lib.h \ - $(INCDIR)/apr_portable.h $(INCDIR)/apr_network_io.h \ - $(INCDIR)/apr_lock.h -signals.o: signals.c threadproc.h $(INCDIR)/apr_thread_proc.h \ - $(INCDIR)/apr_file_io.h $(INCDIR)/apr_general.h \ - $(INCDIR)/apr.h $(INCDIR)/apr_errno.h \ - $(INCDIR)/apr_time.h ../../file_io/unix/fileio.h \ - $(INCDIR)/apr_private.h $(INCDIR)/apr_lib.h \ - $(INCDIR)/apr_portable.h $(INCDIR)/apr_network_io.h \ - $(INCDIR)/apr_lock.h -thread.o: thread.c threadproc.h $(INCDIR)/apr_thread_proc.h \ - $(INCDIR)/apr_file_io.h $(INCDIR)/apr_general.h \ - $(INCDIR)/apr.h $(INCDIR)/apr_errno.h \ - $(INCDIR)/apr_time.h ../../file_io/unix/fileio.h \ - $(INCDIR)/apr_private.h $(INCDIR)/apr_lib.h \ - $(INCDIR)/apr_portable.h $(INCDIR)/apr_network_io.h \ - $(INCDIR)/apr_lock.h -threadpriv.o: threadpriv.c threadproc.h \ - $(INCDIR)/apr_thread_proc.h $(INCDIR)/apr_file_io.h \ - $(INCDIR)/apr_general.h $(INCDIR)/apr.h \ - $(INCDIR)/apr_errno.h $(INCDIR)/apr_time.h \ - ../../file_io/unix/fileio.h $(INCDIR)/apr_private.h \ - $(INCDIR)/apr_lib.h $(INCDIR)/apr_portable.h \ - $(INCDIR)/apr_network_io.h $(INCDIR)/apr_lock.h diff --git a/threadproc/beos/apr_proc_stub.c b/threadproc/beos/apr_proc_stub.c index ff2ea87cd1d..011d793e317 100644 --- a/threadproc/beos/apr_proc_stub.c +++ b/threadproc/beos/apr_proc_stub.c @@ -1,55 +1,17 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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 <kernel/OS.h> diff --git a/threadproc/beos/proc.c b/threadproc/beos/proc.c index adeb0db967e..e3698082f35 100644 --- a/threadproc/beos/proc.c +++ b/threadproc/beos/proc.c @@ -1,58 +1,26 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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 "threadproc.h" +#include "apr_arch_threadproc.h" +#include "apr_strings.h" + +/* Heavy on no'ops, here's what we want to pass if there is APR_NO_FILE + * requested for a specific child handle; + */ +static apr_file_t no_file = { NULL, -1, }; struct send_pipe { int in; @@ -60,15 +28,15 @@ struct send_pipe { int err; }; -ap_status_t ap_createprocattr_init(ap_procattr_t **new, ap_pool_t *cont) +APR_DECLARE(apr_status_t) apr_procattr_create(apr_procattr_t **new, apr_pool_t *pool) { - (*new) = (ap_procattr_t *)ap_palloc(cont, - sizeof(ap_procattr_t)); + (*new) = (apr_procattr_t *)apr_palloc(pool, + sizeof(apr_procattr_t)); if ((*new) == NULL) { return APR_ENOMEM; } - (*new)->cntxt = cont; + (*new)->pool = pool; (*new)->parent_in = NULL; (*new)->child_in = NULL; (*new)->parent_out = NULL; @@ -81,71 +49,67 @@ ap_status_t ap_createprocattr_init(ap_procattr_t **new, ap_pool_t *cont) return APR_SUCCESS; } -ap_status_t ap_setprocattr_io(ap_procattr_t *attr, ap_int32_t in, - ap_int32_t out, ap_int32_t err) +APR_DECLARE(apr_status_t) apr_procattr_io_set(apr_procattr_t *attr, + apr_int32_t in, + apr_int32_t out, + apr_int32_t err) { - ap_status_t status; - if (in != 0) { - if ((status = ap_create_pipe(&attr->child_in, &attr->parent_in, - attr->cntxt)) != APR_SUCCESS) { - return status; - } - switch (in) { - case APR_FULL_BLOCK: - ap_block_pipe(attr->child_in); - ap_block_pipe(attr->parent_in); - case APR_PARENT_BLOCK: - ap_block_pipe(attr->parent_in); - case APR_CHILD_BLOCK: - ap_block_pipe(attr->child_in); - } - } - if (out) { - if ((status = ap_create_pipe(&attr->parent_out, &attr->child_out, - attr->cntxt)) != APR_SUCCESS) { - return status; - } - switch (out) { - case APR_FULL_BLOCK: - ap_block_pipe(attr->child_out); - ap_block_pipe(attr->parent_out); - case APR_PARENT_BLOCK: - ap_block_pipe(attr->parent_out); - case APR_CHILD_BLOCK: - ap_block_pipe(attr->child_out); - } - } - if (err) { - if ((status = ap_create_pipe(&attr->parent_err, &attr->child_err, - attr->cntxt)) != APR_SUCCESS) { - return status; - } - switch (err) { - case APR_FULL_BLOCK: - ap_block_pipe(attr->child_err); - ap_block_pipe(attr->parent_err); - case APR_PARENT_BLOCK: - ap_block_pipe(attr->parent_err); - case APR_CHILD_BLOCK: - ap_block_pipe(attr->child_err); - } - } + apr_status_t rv; + + if ((in != APR_NO_PIPE) && (in != APR_NO_FILE)) { + /* APR_CHILD_BLOCK maps to APR_WRITE_BLOCK, while + * APR_PARENT_BLOCK maps to APR_READ_BLOCK, so transpose + * the CHILD/PARENT blocking flags for the stdin pipe. + * stdout/stderr map to the correct mode by default. + */ + if (in == APR_CHILD_BLOCK) + in = APR_READ_BLOCK; + else if (in == APR_PARENT_BLOCK) + in = APR_WRITE_BLOCK; + + if ((rv = apr_file_pipe_create_ex(&attr->child_in, &attr->parent_in, + in, attr->pool)) == APR_SUCCESS) + rv = apr_file_inherit_unset(attr->parent_in); + if (rv != APR_SUCCESS) + return rv; + } + else if (in == APR_NO_FILE) + attr->child_in = &no_file; + + if ((out != APR_NO_PIPE) && (out != APR_NO_FILE)) { + if ((rv = apr_file_pipe_create_ex(&attr->parent_out, &attr->child_out, + out, attr->pool)) == APR_SUCCESS) + rv = apr_file_inherit_unset(attr->parent_out); + if (rv != APR_SUCCESS) + return rv; + } + else if (out == APR_NO_FILE) + attr->child_out = &no_file; + + if ((err != APR_NO_PIPE) && (err != APR_NO_FILE)) { + if ((rv = apr_file_pipe_create_ex(&attr->parent_err, &attr->child_err, + err, attr->pool)) == APR_SUCCESS) + rv = apr_file_inherit_unset(attr->parent_err); + if (rv != APR_SUCCESS) + return rv; + } + else if (err == APR_NO_FILE) + attr->child_err = &no_file; + return APR_SUCCESS; } -ap_status_t ap_setprocattr_dir(ap_procattr_t *attr, - const char *dir) +APR_DECLARE(apr_status_t) apr_procattr_dir_set(apr_procattr_t *attr, + const char *dir) { char * cwd; - if (strncmp("/",dir,1) != 0 ) { + if (dir[0] != '/') { cwd = (char*)malloc(sizeof(char) * PATH_MAX); getcwd(cwd, PATH_MAX); - strncat(cwd,"/\0",2); - strcat(cwd,dir); - attr->currdir = (char *)ap_pstrdup(attr->cntxt, cwd); + attr->currdir = (char *)apr_pstrcat(attr->pool, cwd, "/", dir, NULL); free(cwd); } else { - attr->currdir = (char *)ap_pstrdup(attr->cntxt, dir); + attr->currdir = (char *)apr_pstrdup(attr->pool, dir); } if (attr->currdir) { return APR_SUCCESS; @@ -153,63 +117,113 @@ ap_status_t ap_setprocattr_dir(ap_procattr_t *attr, return APR_ENOMEM; } -ap_status_t ap_setprocattr_cmdtype(ap_procattr_t *attr, - ap_cmdtype_e cmd) +APR_DECLARE(apr_status_t) apr_procattr_cmdtype_set(apr_procattr_t *attr, + apr_cmdtype_e cmd) { attr->cmdtype = cmd; return APR_SUCCESS; } -ap_status_t ap_setprocattr_detach(ap_procattr_t *attr, ap_int32_t detach) +APR_DECLARE(apr_status_t) apr_procattr_detach_set(apr_procattr_t *attr, apr_int32_t detach) { attr->detached = detach; return APR_SUCCESS; } -ap_status_t ap_fork(ap_proc_t **proc, ap_pool_t *cont) +APR_DECLARE(apr_status_t) apr_proc_fork(apr_proc_t *proc, apr_pool_t *pool) { int pid; - (*proc) = (ap_proc_t *)ap_palloc(cont, sizeof(ap_proc_t)); - if ((pid = fork()) < 0) { return errno; } else if (pid == 0) { - (*proc)->pid = pid; - (*proc)->attr = NULL; + /* This is really ugly... + * The semantics of BeOS's fork() are that areas (used for shared + * memory) get COW'd :-( The only way we can make shared memory + * work across fork() is therefore to find any areas that have + * been created and then clone them into our address space. + * Thankfully only COW'd areas have the lock variable set at + * anything but 0, so we can use that to find the areas we need to + * copy. Of course what makes it even worse is that the loop through + * the area's will go into an infinite loop, eating memory and then + * eventually segfault unless we know when we reach then end of the + * "original" areas and stop. Why? Well, we delete the area and then + * add another to the end of the list... + */ + area_info ai; + int32 cookie = 0; + area_id highest = 0; + + while (get_next_area_info(0, &cookie, &ai) == B_OK) + if (ai.area > highest) + highest = ai.area; + cookie = 0; + while (get_next_area_info(0, &cookie, &ai) == B_OK) { + if (ai.area > highest) + break; + if (ai.lock > 0) { + area_id original = find_area(ai.name); + delete_area(ai.area); + clone_area(ai.name, &ai.address, B_CLONE_ADDRESS, + ai.protection, original); + } + } + + proc->pid = pid; + proc->in = NULL; + proc->out = NULL; + proc->err = NULL; return APR_INCHILD; } - (*proc)->pid = pid; - (*proc)->attr = NULL; + proc->pid = pid; + proc->in = NULL; + proc->out = NULL; + proc->err = NULL; return APR_INPARENT; } +APR_DECLARE(apr_status_t) apr_procattr_child_errfn_set(apr_procattr_t *attr, + apr_child_errfn_t *errfn) +{ + /* won't ever be called on this platform, so don't save the function pointer */ + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_procattr_error_check_set(apr_procattr_t *attr, + apr_int32_t chk) +{ + /* won't ever be used on this platform, so don't save the flag */ + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_procattr_addrspace_set(apr_procattr_t *attr, + apr_int32_t addrspace) +{ + /* won't ever be used on this platform, so don't save the flag */ + return APR_SUCCESS; +} -ap_status_t ap_create_process(ap_proc_t **new, const char *progname, - char *const args[], char **env, - ap_procattr_t *attr, ap_pool_t *cont) +APR_DECLARE(apr_status_t) apr_proc_create(apr_proc_t *new, const char *progname, + const char * const *args, + const char * const *env, + apr_procattr_t *attr, + apr_pool_t *pool) { int i=0,nargs=0; char **newargs = NULL; thread_id newproc, sender; - char * buffer = NULL; - size_t bufsize = 0; struct send_pipe *sp; - char * dir = NULL; + char * dir = NULL; - (*new) = (ap_proc_t *)ap_palloc(cont, sizeof(ap_proc_t)); - sp = (struct send_pipe *)ap_palloc(cont, sizeof(struct send_pipe)); - - if ((*new) == NULL){ - return APR_ENOMEM; - } - - (*new)->cntxt = cont; + sp = (struct send_pipe *)apr_palloc(pool, sizeof(struct send_pipe)); - sp->in = attr->child_in?attr->child_in->filedes:-1; - sp->out = attr->child_out?attr->child_out->filedes:-1; - sp->err = attr->child_err?attr->child_err->filedes:-1; + new->in = attr->parent_in; + new->err = attr->parent_err; + new->out = attr->parent_out; + sp->in = attr->child_in ? attr->child_in->filedes : FILENO_STDIN; + sp->out = attr->child_out ? attr->child_out->filedes : FILENO_STDOUT; + sp->err = attr->child_err ? attr->child_err->filedes : FILENO_STDERR; i = 0; while (args && args[i]) { @@ -236,148 +250,205 @@ ap_status_t ap_create_process(ap_proc_t **new, const char *progname, } newargs[nargs] = NULL; - newproc = load_image(nargs, newargs, env); + /* ### we should be looking at attr->cmdtype in here... */ + + newproc = load_image(nargs, (const char**)newargs, (const char**)env); /* load_image copies the data so now we can free it... */ while (--nargs >= 0) free (newargs[nargs]); free(newargs); - if ( newproc < B_NO_ERROR) { + if (newproc < B_NO_ERROR) { return errno; } + resume_thread(newproc); - if (attr->child_in) { - ap_close(attr->child_in); + if (attr->child_in && (attr->child_in->filedes != -1)) { + apr_file_close(attr->child_in); } - if (attr->child_out) { - ap_close(attr->child_out); + if (attr->child_out && (attr->child_in->filedes != -1)) { + apr_file_close(attr->child_out); } - if (attr->child_err) { - ap_close(attr->child_err); + if (attr->child_err && (attr->child_in->filedes != -1)) { + apr_file_close(attr->child_err); } send_data(newproc, 0, (void*)sp, sizeof(struct send_pipe)); - (*new)->pid = newproc; + new->pid = newproc; /* before we go charging on we need the new process to get to a * certain point. When it gets there it'll let us know and we * can carry on. */ receive_data(&sender, (void*)NULL,0); - (*new)->attr = attr; return APR_SUCCESS; } -ap_status_t ap_get_childin(ap_file_t **new, ap_proc_t *proc) +APR_DECLARE(apr_status_t) apr_proc_wait_all_procs(apr_proc_t *proc, + int *exitcode, + apr_exit_why_e *exitwhy, + apr_wait_how_e waithow, + apr_pool_t *p) { - (*new) = proc->attr->parent_in; - return APR_SUCCESS; -} + proc->pid = -1; + return apr_proc_wait(proc, exitcode, exitwhy, waithow); +} -ap_status_t ap_get_childout(ap_file_t **new, ap_proc_t *proc) +APR_DECLARE(apr_status_t) apr_proc_wait(apr_proc_t *proc, + int *exitcode, + apr_exit_why_e *exitwhy, + apr_wait_how_e waithow) { - (*new) = proc->attr->parent_out; - return APR_SUCCESS; -} + pid_t pstatus; + int waitpid_options = WUNTRACED; + int exit_int; + int ignore; + apr_exit_why_e ignorewhy; + + if (exitcode == NULL) { + exitcode = &ignore; + } + if (exitwhy == NULL) { + exitwhy = &ignorewhy; + } -ap_status_t ap_get_childerr(ap_file_t **new, ap_proc_t *proc) -{ - (*new) = proc->attr->parent_err; - return APR_SUCCESS; -} + if (waithow != APR_WAIT) { + waitpid_options |= WNOHANG; + } -ap_status_t ap_wait_proc(ap_proc_t *proc, - ap_wait_how_e wait) -{ - status_t exitval; - thread_info tinfo; - - if (!proc) - return APR_ENOPROC; - /* when we run processes we are actually running threads, so here - we'll wait on the thread dying... */ - if (wait == APR_WAIT) { - if (wait_for_thread(proc->pid, &exitval) == B_OK) { - return APR_CHILD_DONE; + if ((pstatus = waitpid(proc->pid, &exit_int, waitpid_options)) > 0) { + proc->pid = pstatus; + if (WIFEXITED(exit_int)) { + *exitwhy = APR_PROC_EXIT; + *exitcode = WEXITSTATUS(exit_int); + } + else if (WIFSIGNALED(exit_int)) { + *exitwhy = APR_PROC_SIGNAL; + *exitcode = WTERMSIG(exit_int); + } + else { + + /* unexpected condition */ + return APR_EGENERAL; } - return errno; - } - /* if the thread is still alive then it's not done... - this won't hang or holdup the thread checking... */ - if (get_thread_info(proc->pid, &tinfo) == B_BAD_VALUE) { return APR_CHILD_DONE; } - /* if we get this far it's still going... */ - return APR_CHILD_NOTDONE; + else if (pstatus == 0) { + return APR_CHILD_NOTDONE; + } + + return errno; } -ap_status_t ap_setprocattr_childin(ap_procattr_t *attr, ap_file_t *child_in, - ap_file_t *parent_in) +APR_DECLARE(apr_status_t) apr_procattr_child_in_set(apr_procattr_t *attr, apr_file_t *child_in, + apr_file_t *parent_in) { - if (attr->child_in == NULL && attr->parent_in == NULL) - ap_create_pipe(&attr->child_in, &attr->parent_in, attr->cntxt); - - if (child_in != NULL) - ap_dupfile(&attr->child_in, child_in, attr->cntxt); + apr_status_t rv; + + if (attr->child_in == NULL && attr->parent_in == NULL + && child_in == NULL && parent_in == NULL) + if ((rv = apr_file_pipe_create(&attr->child_in, &attr->parent_in, + attr->pool)) == APR_SUCCESS) + rv = apr_file_inherit_unset(attr->parent_in); + + if (child_in != NULL && rv == APR_SUCCESS) { + if (attr->child_in && (attr->child_in->filedes != -1)) + rv = apr_file_dup2(attr->child_in, child_in, attr->pool); + else { + attr->child_in = NULL; + if ((rv = apr_file_dup(&attr->child_in, child_in, attr->pool)) + == APR_SUCCESS) + rv = apr_file_inherit_set(attr->child_in); + } + } - if (parent_in != NULL) - ap_dupfile(&attr->parent_in, parent_in, attr->cntxt); + if (parent_in != NULL && rv == APR_SUCCESS) + rv = apr_file_dup(&attr->parent_in, parent_in, attr->pool); - return APR_SUCCESS; + return rv; } -ap_status_t ap_setprocattr_childout(ap_procattr_t *attr, ap_file_t *child_out, - ap_file_t *parent_out) +APR_DECLARE(apr_status_t) apr_procattr_child_out_set(apr_procattr_t *attr, apr_file_t *child_out, + apr_file_t *parent_out) { - if (attr->child_out == NULL && attr->parent_out == NULL) - ap_create_pipe(&attr->child_out, &attr->parent_out, attr->cntxt); - - if (child_out != NULL) - ap_dupfile(&attr->child_out, child_out, attr->cntxt); - - if (parent_out != NULL) - ap_dupfile(&attr->parent_out, parent_out, attr->cntxt); + apr_status_t rv; + + if (attr->child_out == NULL && attr->parent_out == NULL + && child_out == NULL && parent_out == NULL) + if ((rv = apr_file_pipe_create(&attr->parent_out, &attr->child_out, + attr->pool)) == APR_SUCCESS) + rv = apr_file_inherit_unset(attr->parent_out); + + if (child_out != NULL && rv == APR_SUCCESS) { + if (attr->child_out && (attr->child_out->filedes != -1)) + rv = apr_file_dup2(attr->child_out, child_out, attr->pool); + else { + attr->child_out = NULL; + if ((rv = apr_file_dup(&attr->child_out, child_out, attr->pool)) + == APR_SUCCESS) + rv = apr_file_inherit_set(attr->child_out); + } + } + + if (parent_out != NULL && rv == APR_SUCCESS) + rv = apr_file_dup(&attr->parent_out, parent_out, attr->pool); - return APR_SUCCESS; + return rv; } -ap_status_t ap_setprocattr_childerr(ap_procattr_t *attr, ap_file_t *child_err, - ap_file_t *parent_err) +APR_DECLARE(apr_status_t) apr_procattr_child_err_set(apr_procattr_t *attr, apr_file_t *child_err, + apr_file_t *parent_err) { - if (attr->child_err == NULL && attr->parent_err == NULL) - ap_create_pipe(&attr->child_err, &attr->parent_err, attr->cntxt); - - if (child_err != NULL) - ap_dupfile(&attr->child_err, child_err, attr->cntxt); + apr_status_t rv; + + if (attr->child_err == NULL && attr->parent_err == NULL + && child_err == NULL && parent_err == NULL) + if ((rv = apr_file_pipe_create(&attr->parent_err, &attr->child_err, + attr->pool)) == APR_SUCCESS) + rv = apr_file_inherit_unset(attr->parent_err); + + if (child_err != NULL && rv == APR_SUCCESS) { + if (attr->child_err && (attr->child_err->filedes != -1)) + rv = apr_file_dup2(attr->child_err, child_err, attr->pool); + else { + attr->child_err = NULL; + if ((rv = apr_file_dup(&attr->child_err, child_err, attr->pool)) + == APR_SUCCESS) + rv = apr_file_inherit_set(attr->child_err); + } + } + + if (parent_err != NULL && rv == APR_SUCCESS) + rv = apr_file_dup(&attr->parent_err, parent_err, attr->pool); - if (parent_err != NULL) - ap_dupfile(&attr->parent_err, parent_err, attr->cntxt); + return rv; +} - return APR_SUCCESS; +APR_DECLARE(apr_status_t) apr_procattr_limit_set(apr_procattr_t *attr, apr_int32_t what, + void *limit) +{ + return APR_ENOTIMPL; } -ap_status_t ap_get_os_proc(ap_os_proc_t *theproc, ap_proc_t *proc) +APR_DECLARE(apr_status_t) apr_procattr_user_set(apr_procattr_t *attr, + const char *username, + const char *password) { - if (proc == NULL) { - return APR_ENOPROC; - } - *theproc = proc->pid; - return APR_SUCCESS; + return APR_ENOTIMPL; } -ap_status_t ap_put_os_proc(ap_proc_t **proc, ap_os_proc_t *theproc, - ap_pool_t *cont) +APR_DECLARE(apr_status_t) apr_procattr_group_set(apr_procattr_t *attr, + const char *groupname) { - if (cont == NULL) { - return APR_ENOPOOL; - } - if ((*proc) == NULL) { - (*proc) = (ap_proc_t *)ap_palloc(cont, sizeof(ap_proc_t)); - (*proc)->cntxt = cont; - } - (*proc)->pid = *theproc; - return APR_SUCCESS; -} + return APR_ENOTIMPL; +} +APR_DECLARE(apr_status_t) apr_procattr_perms_set_register(apr_procattr_t *attr, + apr_perms_setfn_t *perms_set_fn, + void *data, + apr_fileperms_t perms) +{ + return APR_ENOTIMPL; +} diff --git a/threadproc/beos/procsup.c b/threadproc/beos/procsup.c deleted file mode 100644 index 0512855cd20..00000000000 --- a/threadproc/beos/procsup.c +++ /dev/null @@ -1,114 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#include "threadproc.h" - -ap_status_t ap_detach(ap_proc_t **new, ap_pool_t *cont) -{ - int x; - - (*new) = (ap_proc_t *)ap_palloc(cont, sizeof(ap_proc_t)); - (*new)->cntxt = cont; - (*new)->attr = NULL; - - chdir("/"); - - if (((*new)->pid = setsid()) == -1) { - return errno; - } - - /* close out the standard file descriptors */ - if (freopen("/dev/null", "r", stdin) == NULL) { - return errno; - /* continue anyhow -- note we can't close out descriptor 0 because we - * have nothing to replace it with, and if we didn't have a descriptor - * 0 the next file would be created with that value ... leading to - * havoc. - */ - } - if (freopen("/dev/null", "w", stdout) == NULL) { - return errno; - } - /* We are going to reopen this again in a little while to the error - * log file, but better to do it twice and suffer a small performance - * hit for consistancy than not reopen it here. - */ - if (freopen("/dev/null", "w", stderr) == NULL) { - return errno; - } -} - -ap_status_t ap_get_procdata(char *key, void *data, ap_proc_t *proc) -{ - if (proc != NULL) { - return ap_get_userdata(data, key, proc->cntxt); - } - else { - data = NULL; - return APR_ENOPROC; - } -} - -ap_status_t ap_set_procdata(void *data, char *key, - ap_status_t (*cleanup) (void *), - ap_proc_t *proc) -{ - if (proc != NULL) { - return ap_set_userdata(data, key, cleanup, proc->cntxt); - } - else { - data = NULL; - return APR_ENOPROC; - } -} diff --git a/threadproc/beos/thread.c b/threadproc/beos/thread.c index 85988eb93ae..01bc7a9732a 100644 --- a/threadproc/beos/thread.c +++ b/threadproc/beos/thread.c @@ -1,79 +1,38 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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 "threadproc.h" +#include "apr_arch_threadproc.h" +#include "apr_portable.h" -ap_status_t ap_create_threadattr(ap_threadattr_t **new, ap_pool_t *cont) +APR_DECLARE(apr_status_t) apr_threadattr_create(apr_threadattr_t **new, apr_pool_t *pool) { - ap_status_t stat; - - (*new) = (ap_threadattr_t *)ap_palloc(cont, - sizeof(ap_threadattr_t)); - (*new)->attr = (int32)ap_palloc(cont, - sizeof(int32)); + (*new) = (apr_threadattr_t *)apr_palloc(pool, + sizeof(apr_threadattr_t)); if ((*new) == NULL) { return APR_ENOMEM; } - (*new)->cntxt = cont; + (*new)->pool = pool; (*new)->attr = (int32)B_NORMAL_PRIORITY; return APR_SUCCESS; } -ap_status_t ap_setthreadattr_detach(ap_threadattr_t *attr, ap_int32_t on) +APR_DECLARE(apr_status_t) apr_threadattr_detach_set(apr_threadattr_t *attr, apr_int32_t on) { if (on == 1){ attr->detached = 1; @@ -83,7 +42,7 @@ ap_status_t ap_setthreadattr_detach(ap_threadattr_t *attr, ap_int32_t on) return APR_SUCCESS; } -ap_status_t ap_getthreadattr_detach(ap_threadattr_t *attr) +APR_DECLARE(apr_status_t) apr_threadattr_detach_get(apr_threadattr_t *attr) { if (attr->detached == 1){ return APR_DETACH; @@ -91,24 +50,44 @@ ap_status_t ap_getthreadattr_detach(ap_threadattr_t *attr) return APR_NOTDETACH; } -ap_status_t ap_create_thread(ap_thread_t **new, ap_threadattr_t *attr, - ap_thread_start_t func, void *data, - ap_pool_t *cont) +APR_DECLARE(apr_status_t) apr_threadattr_stacksize_set(apr_threadattr_t *attr, + apr_size_t stacksize) +{ + return APR_ENOTIMPL; +} + +APR_DECLARE(apr_status_t) apr_threadattr_guardsize_set(apr_threadattr_t *attr, + apr_size_t size) +{ + return APR_ENOTIMPL; +} + +static void *dummy_worker(void *opaque) +{ + apr_thread_t *thd = (apr_thread_t*)opaque; + void *ret; + + apr_pool_owner_set(thd->pool, 0); + ret = thd->func(thd, thd->data); + apr_pool_destroy(thd->pool); + return ret; +} + +APR_DECLARE(apr_status_t) apr_thread_create(apr_thread_t **new, apr_threadattr_t *attr, + apr_thread_start_t func, void *data, + apr_pool_t *pool) { int32 temp; - ap_status_t stat; + apr_status_t stat; - (*new) = (ap_thread_t *)ap_palloc(cont, sizeof(ap_thread_t)); + (*new) = (apr_thread_t *)apr_palloc(pool, sizeof(apr_thread_t)); if ((*new) == NULL) { return APR_ENOMEM; } - (*new)->td = (thread_id) ap_palloc(cont, sizeof(thread_id)); - if ((*new)->td == (thread_id)NULL) { - return APR_ENOMEM; - } - - (*new)->cntxt = cont; + (*new)->data = data; + (*new)->func = func; + (*new)->exitval = -1; /* First we create the new thread...*/ if (attr) @@ -116,12 +95,16 @@ ap_status_t ap_create_thread(ap_thread_t **new, ap_threadattr_t *attr, else temp = B_NORMAL_PRIORITY; - stat = ap_create_pool(&(*new)->cntxt, cont); + stat = apr_pool_create(&(*new)->pool, pool); if (stat != APR_SUCCESS) { return stat; } - (*new)->td = spawn_thread((thread_func)func, "apr thread", temp, data); + (*new)->td = spawn_thread((thread_func)dummy_worker, + "apr thread", + temp, + (*new)); + /* Now we try to run it...*/ if (resume_thread((*new)->td) == B_NO_ERROR) { return APR_SUCCESS; @@ -131,23 +114,46 @@ ap_status_t ap_create_thread(ap_thread_t **new, ap_threadattr_t *attr, } } -ap_status_t ap_thread_exit(ap_thread_t *thd, ap_status_t *retval) +APR_DECLARE(apr_os_thread_t) apr_os_thread_current(void) { - ap_destroy_pool(thd->cntxt); - exit_thread ((status_t)retval); + return find_thread(NULL); } -ap_status_t ap_thread_join(ap_status_t *retval, ap_thread_t *thd) +int apr_os_thread_equal(apr_os_thread_t tid1, apr_os_thread_t tid2) { - if (wait_for_thread(thd->td,(void *)&retval) == B_NO_ERROR) { + return tid1 == tid2; +} + +APR_DECLARE(apr_status_t) apr_thread_exit(apr_thread_t *thd, apr_status_t retval) +{ + apr_pool_destroy(thd->pool); + thd->exitval = retval; + exit_thread ((status_t)(retval)); + /* This will never be reached... */ + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_thread_join(apr_status_t *retval, apr_thread_t *thd) +{ + status_t rv = 0, ret; + ret = wait_for_thread(thd->td, &rv); + if (ret == B_NO_ERROR) { + *retval = rv; return APR_SUCCESS; } else { - return errno; + /* if we've missed the thread's death, did we set an exit value prior + * to it's demise? If we did return that. + */ + if (thd->exitval != -1) { + *retval = thd->exitval; + return APR_SUCCESS; + } else + return ret; } } -ap_status_t ap_thread_detach(ap_thread_t *thd) +APR_DECLARE(apr_status_t) apr_thread_detach(apr_thread_t *thd) { if (suspend_thread(thd->td) == B_NO_ERROR){ return APR_SUCCESS; @@ -156,3 +162,81 @@ ap_status_t ap_thread_detach(ap_thread_t *thd) return errno; } } + +void apr_thread_yield() +{ +} + +APR_DECLARE(apr_status_t) apr_thread_data_get(void **data, const char *key, apr_thread_t *thread) +{ + return apr_pool_userdata_get(data, key, thread->pool); +} + +APR_DECLARE(apr_status_t) apr_thread_data_set(void *data, const char *key, + apr_status_t (*cleanup) (void *), + apr_thread_t *thread) +{ + return apr_pool_userdata_set(data, key, cleanup, thread->pool); +} + +APR_DECLARE(apr_status_t) apr_os_thread_get(apr_os_thread_t **thethd, apr_thread_t *thd) +{ + *thethd = &thd->td; + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_os_thread_put(apr_thread_t **thd, apr_os_thread_t *thethd, + apr_pool_t *pool) +{ + if (pool == NULL) { + return APR_ENOPOOL; + } + if ((*thd) == NULL) { + (*thd) = (apr_thread_t *)apr_pcalloc(pool, sizeof(apr_thread_t)); + (*thd)->pool = pool; + } + (*thd)->td = *thethd; + return APR_SUCCESS; +} + +static apr_status_t thread_once_cleanup(void *vcontrol) +{ + apr_thread_once_t *control = (apr_thread_once_t *)vcontrol; + + if (control->sem) { + release_sem(control->sem); + delete_sem(control->sem); + } + + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_thread_once_init(apr_thread_once_t **control, + apr_pool_t *p) +{ + int rc; + *control = (apr_thread_once_t *)apr_pcalloc(p, sizeof(apr_thread_once_t)); + (*control)->hit = 0; /* we haven't done it yet... */ + rc = ((*control)->sem = create_sem(1, "thread_once")); + if (rc < 0) + return rc; + + apr_pool_cleanup_register(p, control, thread_once_cleanup, apr_pool_cleanup_null); + return APR_SUCCESS; +} + + + +APR_DECLARE(apr_status_t) apr_thread_once(apr_thread_once_t *control, + void (*func)(void)) +{ + if (!control->hit) { + if (acquire_sem(control->sem) == B_OK) { + control->hit = 1; + func(); + } + } + return APR_SUCCESS; +} + +APR_POOL_IMPLEMENT_ACCESSOR(thread) diff --git a/threadproc/beos/threadcancel.c b/threadproc/beos/threadcancel.c deleted file mode 100644 index 94a7e9407c4..00000000000 --- a/threadproc/beos/threadcancel.c +++ /dev/null @@ -1,88 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#include "threadproc.h" - - -ap_status_t ap_cancel_thread(ap_thread_t *thd) -{ - if (kill_thread(thd->td) == 0) { - return APR_SUCCESS; - } - else { - return errno; - } -} - - -ap_status_t ap_setcanceltype(ap_int32_t type, ap_pool_t *cont) -{ -/* if (pthread_setcanceltype(type, NULL) == 0) {*/ - return APR_SUCCESS; -/* } - else { - return APR_FAILURE; - }*/ -} - -ap_status_t ap_setcancelstate(ap_int32_t type, ap_pool_t *cont) -{ -/* if (pthread_setcanceltype(type, NULL) == 0) {*/ - return APR_SUCCESS; -/* } - else { - return APR_FAILURE; - }*/ -} - diff --git a/threadproc/beos/threadpriv.c b/threadproc/beos/threadpriv.c index bb81fe23e2c..442235f7dd6 100644 --- a/threadproc/beos/threadpriv.c +++ b/threadproc/beos/threadpriv.c @@ -1,72 +1,34 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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 "threadproc.h" +#include "apr_arch_threadproc.h" static struct beos_key key_table[BEOS_MAX_DATAKEYS]; static struct beos_private_data *beos_data[BEOS_MAX_DATAKEYS]; static sem_id lock; -ap_status_t ap_create_thread_private(ap_threadkey_t **key, - void (*dest)(void *), ap_pool_t *cont) +APR_DECLARE(apr_status_t) apr_threadkey_private_create(apr_threadkey_t **key, + void (*dest)(void *), apr_pool_t *pool) { - (*key) = (ap_threadkey_t *)ap_palloc(cont, sizeof(ap_threadkey_t)); + (*key) = (apr_threadkey_t *)apr_palloc(pool, sizeof(apr_threadkey_t)); if ((*key) == NULL) { return APR_ENOMEM; } - (*key)->cntxt = cont; + (*key)->pool = pool; acquire_sem(lock); for ((*key)->key=0; (*key)->key < BEOS_MAX_DATAKEYS; (*key)->key++){ @@ -82,7 +44,7 @@ ap_status_t ap_create_thread_private(ap_threadkey_t **key, return APR_ENOMEM; } -ap_status_t ap_get_thread_private(void **new, ap_threadkey_t *key) +APR_DECLARE(apr_status_t) apr_threadkey_private_get(void **new, apr_threadkey_t *key) { thread_id tid; int i, index=0; @@ -114,15 +76,15 @@ ap_status_t ap_get_thread_private(void **new, ap_threadkey_t *key) return APR_SUCCESS; } -ap_status_t ap_set_thread_private(void *priv, ap_threadkey_t *key) +APR_DECLARE(apr_status_t) apr_threadkey_private_set(void *priv, apr_threadkey_t *key) { thread_id tid; - int i,index = 0, ret; + int i,index = 0, ret = 0; tid = find_thread(NULL); for (i=0; i < BEOS_MAX_DATAKEYS; i++){ if (beos_data[i]->data){ - if (beos_data[i]->td = tid){index = i;} + if (beos_data[i]->td == tid){index = i;} } } if (index==0){ @@ -169,7 +131,7 @@ ap_status_t ap_set_thread_private(void *priv, ap_threadkey_t *key) return APR_ENOMEM; } -ap_status_t ap_delete_thread_private(ap_threadkey_t *key) +APR_DECLARE(apr_status_t) apr_threadkey_private_delete(apr_threadkey_t *key) { if (key->key < BEOS_MAX_DATAKEYS){ acquire_sem(key_table[key->key].lock); @@ -183,3 +145,36 @@ ap_status_t ap_delete_thread_private(ap_threadkey_t *key) } return APR_SUCCESS; } + +APR_DECLARE(apr_status_t) apr_threadkey_data_get(void **data, const char *key, + apr_threadkey_t *threadkey) +{ + return apr_pool_userdata_get(data, key, threadkey->pool); +} + +APR_DECLARE(apr_status_t) apr_threadkey_data_set(void *data, const char *key, + apr_status_t (*cleanup) (void *), + apr_threadkey_t *threadkey) +{ + return apr_pool_userdata_set(data, key, cleanup, threadkey->pool); +} + +APR_DECLARE(apr_status_t) apr_os_threadkey_get(apr_os_threadkey_t *thekey, apr_threadkey_t *key) +{ + *thekey = key->key; + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_os_threadkey_put(apr_threadkey_t **key, + apr_os_threadkey_t *thekey, apr_pool_t *pool) +{ + if (pool == NULL) { + return APR_ENOPOOL; + } + if ((*key) == NULL) { + (*key) = (apr_threadkey_t *)apr_pcalloc(pool, sizeof(apr_threadkey_t)); + (*key)->pool = pool; + } + (*key)->key = *thekey; + return APR_SUCCESS; +} diff --git a/threadproc/beos/threadproc.h b/threadproc/beos/threadproc.h deleted file mode 100644 index 4588105d15f..00000000000 --- a/threadproc/beos/threadproc.h +++ /dev/null @@ -1,134 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#include "apr_thread_proc.h" -#include "fileio.h" -#include "apr_file_io.h" -#include "apr_thread_proc.h" -#include "apr_file_io.h" -#include "apr_general.h" -#include "apr_portable.h" -#include <kernel/OS.h> -#include <signal.h> -#include <string.h> -#include <sys/wait.h> - -#ifndef THREAD_PROC_H -#define THREAD_PROC_H - -#define SHELL_PATH "/bin/sh" - -#define PTHREAD_CANCEL_AYNCHRONOUS CANCEL_ASYNCH; -#define PTHREAD_CANCEL_DEFERRED CANCEL_DEFER; - -#define PTHREAD_CANCEL_ENABLE CANCEL_ENABLE; -#define PTHREAD_CANCEL_DISABLE CANCEL_DISABLE; - -#define BEOS_MAX_DATAKEYS 128 - -struct ap_thread_t { - ap_pool_t *cntxt; - thread_id td; -}; - -struct ap_threadattr_t { - ap_pool_t *cntxt; - int32 attr; - int detached; - int joinable; -}; - -struct ap_threadkey_t { - ap_pool_t *cntxt; - int32 key; -}; - -struct beos_private_data { - const void ** data; - int count; - volatile thread_id td; -}; - -struct beos_key { - int assigned; - int count; - sem_id lock; - int32 ben_lock; - void (* destructor) (); -}; - -struct ap_procattr_t { - ap_pool_t *cntxt; - ap_file_t *parent_in; - ap_file_t *child_in; - ap_file_t *parent_out; - ap_file_t *child_out; - ap_file_t *parent_err; - ap_file_t *child_err; - char *currdir; - ap_int32_t cmdtype; - ap_int32_t detached; -}; - -struct ap_proc_t { - ap_pool_t *cntxt; - thread_id pid; - struct ap_procattr_t *attr; -}; - -/* we need a structure to pass off to the thread that will run any - * new process we create */ - -#endif /* ! THREAD_PROC_H */ - diff --git a/threadproc/beos/threadproc_common.c b/threadproc/beos/threadproc_common.c index 548344fd3bd..95e16254400 100644 --- a/threadproc/beos/threadproc_common.c +++ b/threadproc/beos/threadproc_common.c @@ -1,58 +1,21 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. +/* 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. */ /* As the signal code is identical, use the unix version to reduce code duplication */ - #include "../unix/signals.c" +#include "../unix/procsup.c" + diff --git a/threadproc/netware/proc.c b/threadproc/netware/proc.c new file mode 100644 index 00000000000..f5d24b21b5b --- /dev/null +++ b/threadproc/netware/proc.c @@ -0,0 +1,515 @@ +/* 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_threadproc.h" +#include "apr_arch_file_io.h" +#include "apr_strings.h" +#include "apr_portable.h" + +#include <proc.h> + +/* Heavy on no'ops, here's what we want to pass if there is APR_NO_FILE + * requested for a specific child handle; + */ +static apr_file_t no_file = { NULL, -1, }; + +static apr_status_t apr_netware_proc_cleanup(void *theproc) +{ + apr_proc_t *proc = theproc; + int exit_int; + int waitpid_options = WUNTRACED | WNOHANG; + + if (proc->pid > 0) { + waitpid(proc->pid, &exit_int, waitpid_options); + } + +/* NXVmDestroy(proc->pid); */ + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_procattr_create(apr_procattr_t **new,apr_pool_t *pool) +{ + (*new) = (apr_procattr_t *)apr_pcalloc(pool, sizeof(apr_procattr_t)); + + if ((*new) == NULL) { + return APR_ENOMEM; + } + (*new)->pool = pool; + (*new)->cmdtype = APR_PROGRAM; + /* Default to a current path since NetWare doesn't handle it very well */ + apr_filepath_get(&((*new)->currdir), APR_FILEPATH_NATIVE, pool); + (*new)->detached = 1; + return APR_SUCCESS; + +} + +APR_DECLARE(apr_status_t) apr_procattr_io_set(apr_procattr_t *attr, + apr_int32_t in, + apr_int32_t out, + apr_int32_t err) +{ + apr_status_t rv; + + if ((in != APR_NO_PIPE) && (in != APR_NO_FILE)) { + /* APR_CHILD_BLOCK maps to APR_WRITE_BLOCK, while + * APR_PARENT_BLOCK maps to APR_READ_BLOCK, so transpose + * the CHILD/PARENT blocking flags for the stdin pipe. + * stdout/stderr map to the correct mode by default. + */ + if (in == APR_CHILD_BLOCK) + in = APR_READ_BLOCK; + else if (in == APR_PARENT_BLOCK) + in = APR_WRITE_BLOCK; + + if ((rv = apr_file_pipe_create_ex(&attr->child_in, &attr->parent_in, + in, attr->pool)) == APR_SUCCESS) + rv = apr_file_inherit_unset(attr->parent_in); + if (rv != APR_SUCCESS) + return rv; + } + else if (in == APR_NO_FILE) + attr->child_in = &no_file; + + if ((out != APR_NO_PIPE) && (out != APR_NO_FILE)) { + if ((rv = apr_file_pipe_create_ex(&attr->parent_out, &attr->child_out, + out, attr->pool)) == APR_SUCCESS) + rv = apr_file_inherit_unset(attr->parent_out); + if (rv != APR_SUCCESS) + return rv; + } + else if (out == APR_NO_FILE) + attr->child_out = &no_file; + + if ((err != APR_NO_PIPE) && (err != APR_NO_FILE)) { + if ((rv = apr_file_pipe_create_ex(&attr->parent_err, &attr->child_err, + err, attr->pool)) == APR_SUCCESS) + rv = apr_file_inherit_unset(attr->parent_err); + if (rv != APR_SUCCESS) + return rv; + } + else if (err == APR_NO_FILE) + attr->child_err = &no_file; + + return APR_SUCCESS; +} + + +APR_DECLARE(apr_status_t) apr_procattr_child_in_set(apr_procattr_t *attr, apr_file_t *child_in, + apr_file_t *parent_in) +{ + apr_status_t rv = APR_SUCCESS; + + if (attr->child_in == NULL && attr->parent_in == NULL + && child_in == NULL && parent_in == NULL) + if ((rv = apr_file_pipe_create(&attr->child_in, &attr->parent_in, + attr->pool)) == APR_SUCCESS) + rv = apr_file_inherit_unset(attr->parent_in); + + if (child_in != NULL && rv == APR_SUCCESS) { + if (attr->child_in && (attr->child_in->filedes != -1)) + rv = apr_file_dup2(attr->child_in, child_in, attr->pool); + else { + attr->child_in = NULL; + if ((rv = apr_file_dup(&attr->child_in, child_in, attr->pool)) + == APR_SUCCESS) + rv = apr_file_inherit_set(attr->child_in); + } + } + + if (parent_in != NULL && rv == APR_SUCCESS) { + rv = apr_file_dup(&attr->parent_in, parent_in, attr->pool); + } + + return rv; +} + + +APR_DECLARE(apr_status_t) apr_procattr_child_out_set(apr_procattr_t *attr, apr_file_t *child_out, + apr_file_t *parent_out) +{ + apr_status_t rv = APR_SUCCESS; + + if (attr->child_out == NULL && attr->parent_out == NULL + && child_out == NULL && parent_out == NULL) + if ((rv = apr_file_pipe_create(&attr->parent_out, &attr->child_out, + attr->pool)) == APR_SUCCESS) + rv = apr_file_inherit_unset(attr->parent_out); + + if (child_out != NULL && rv == APR_SUCCESS) { + if (attr->child_out && (attr->child_out->filedes != -1)) + rv = apr_file_dup2(attr->child_out, child_out, attr->pool); + else { + attr->child_out = NULL; + if ((rv = apr_file_dup(&attr->child_out, child_out, attr->pool)) + == APR_SUCCESS) + rv = apr_file_inherit_set(attr->child_out); + } + } + + if (parent_out != NULL && rv == APR_SUCCESS) { + rv = apr_file_dup(&attr->parent_out, parent_out, attr->pool); + } + + return rv; +} + + +APR_DECLARE(apr_status_t) apr_procattr_child_err_set(apr_procattr_t *attr, apr_file_t *child_err, + apr_file_t *parent_err) +{ + apr_status_t rv = APR_SUCCESS; + + if (attr->child_err == NULL && attr->parent_err == NULL + && child_err == NULL && parent_err == NULL) + if ((rv = apr_file_pipe_create(&attr->parent_err, &attr->child_err, + attr->pool)) == APR_SUCCESS) + rv = apr_file_inherit_unset(attr->parent_err); + + if (child_err != NULL && rv == APR_SUCCESS) { + if (attr->child_err && (attr->child_err->filedes != -1)) + rv = apr_file_dup2(attr->child_err, child_err, attr->pool); + else { + attr->child_err = NULL; + if ((rv = apr_file_dup(&attr->child_err, child_err, attr->pool)) + == APR_SUCCESS) + rv = apr_file_inherit_set(attr->child_err); + } + } + + if (parent_err != NULL && rv == APR_SUCCESS) { + rv = apr_file_dup(&attr->parent_err, parent_err, attr->pool); + } + + return rv; +} + + +APR_DECLARE(apr_status_t) apr_procattr_dir_set(apr_procattr_t *attr, + const char *dir) +{ + return apr_filepath_merge(&attr->currdir, NULL, dir, + APR_FILEPATH_NATIVE, attr->pool); +} + +APR_DECLARE(apr_status_t) apr_procattr_cmdtype_set(apr_procattr_t *attr, + apr_cmdtype_e cmd) +{ + /* won't ever be called on this platform, so don't save the function pointer */ + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_procattr_detach_set(apr_procattr_t *attr, apr_int32_t detach) +{ + attr->detached = detach; + return APR_SUCCESS; +} + +#if APR_HAS_FORK +APR_DECLARE(apr_status_t) apr_proc_fork(apr_proc_t *proc, apr_pool_t *pool) +{ + int pid; + + if ((pid = fork()) < 0) { + return errno; + } + else if (pid == 0) { + proc->pid = pid; + proc->in = NULL; + proc->out = NULL; + proc->err = NULL; + return APR_INCHILD; + } + proc->pid = pid; + proc->in = NULL; + proc->out = NULL; + proc->err = NULL; + return APR_INPARENT; +} +#endif + +static apr_status_t limit_proc(apr_procattr_t *attr) +{ +#if APR_HAVE_STRUCT_RLIMIT && APR_HAVE_SETRLIMIT +#ifdef RLIMIT_CPU + if (attr->limit_cpu != NULL) { + if ((setrlimit(RLIMIT_CPU, attr->limit_cpu)) != 0) { + return errno; + } + } +#endif +#ifdef RLIMIT_NPROC + if (attr->limit_nproc != NULL) { + if ((setrlimit(RLIMIT_NPROC, attr->limit_nproc)) != 0) { + return errno; + } + } +#endif +#if defined(RLIMIT_AS) + if (attr->limit_mem != NULL) { + if ((setrlimit(RLIMIT_AS, attr->limit_mem)) != 0) { + return errno; + } + } +#elif defined(RLIMIT_DATA) + if (attr->limit_mem != NULL) { + if ((setrlimit(RLIMIT_DATA, attr->limit_mem)) != 0) { + return errno; + } + } +#elif defined(RLIMIT_VMEM) + if (attr->limit_mem != NULL) { + if ((setrlimit(RLIMIT_VMEM, attr->limit_mem)) != 0) { + return errno; + } + } +#endif +#else + /* + * Maybe make a note in error_log that setrlimit isn't supported?? + */ + +#endif + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_procattr_child_errfn_set(apr_procattr_t *attr, + apr_child_errfn_t *errfn) +{ + /* won't ever be called on this platform, so don't save the function pointer */ + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_procattr_error_check_set(apr_procattr_t *attr, + apr_int32_t chk) +{ + /* won't ever be used on this platform, so don't save the flag */ + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_procattr_addrspace_set(apr_procattr_t *attr, + apr_int32_t addrspace) +{ + attr->addrspace = addrspace; + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_proc_create(apr_proc_t *newproc, + const char *progname, + const char * const *args, + const char * const *env, + apr_procattr_t *attr, + apr_pool_t *pool) +{ + wiring_t wire; + int addr_space; + + wire.infd = attr->child_in + ? (attr->child_in->filedes != -1 ? attr->child_in->filedes + : FD_UNUSED) + : fileno(stdin); + wire.outfd = attr->child_out + ? (attr->child_out->filedes != -1 ? attr->child_out->filedes + : FD_UNUSED) + : fileno(stdout); + wire.errfd = attr->child_err + ? (attr->child_err->filedes != -1 ? attr->child_err->filedes + : FD_UNUSED) + : fileno(stderr); + + newproc->in = attr->parent_in; + newproc->out = attr->parent_out; + newproc->err = attr->parent_err; + + /* attr->detached and PROC_DETACHED do not mean the same thing. attr->detached means + * start the NLM in a separate address space. PROC_DETACHED means don't wait for the + * NLM to unload by calling wait() or waitpid(), just clean up */ + addr_space = PROC_LOAD_SILENT | (attr->addrspace ? 0 : PROC_CURRENT_SPACE); + addr_space |= (attr->detached ? PROC_DETACHED : 0); + + if (attr->currdir) { + char *fullpath = NULL; + apr_status_t rv; + + if ((rv = apr_filepath_merge(&fullpath, attr->currdir, progname, + APR_FILEPATH_NATIVE, pool)) != APR_SUCCESS) { + return rv; + } + progname = fullpath; + } + + if ((newproc->pid = procve(progname, addr_space, (const char**)env, &wire, + NULL, NULL, 0, NULL, (const char **)args)) == -1) { + return errno; + } + + if (attr->child_in && (attr->child_in->filedes != -1)) { + apr_pool_cleanup_kill(apr_file_pool_get(attr->child_in), + attr->child_in, apr_unix_file_cleanup); + apr_file_close(attr->child_in); + } + if (attr->child_out && (attr->child_out->filedes != -1)) { + apr_pool_cleanup_kill(apr_file_pool_get(attr->child_out), + attr->child_out, apr_unix_file_cleanup); + apr_file_close(attr->child_out); + } + if (attr->child_err && (attr->child_err->filedes != -1)) { + apr_pool_cleanup_kill(apr_file_pool_get(attr->child_err), + attr->child_err, apr_unix_file_cleanup); + apr_file_close(attr->child_err); + } + + apr_pool_cleanup_register(pool, (void *)newproc, apr_netware_proc_cleanup, + apr_pool_cleanup_null); + + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_proc_wait_all_procs(apr_proc_t *proc, + int *exitcode, + apr_exit_why_e *exitwhy, + apr_wait_how_e waithow, + apr_pool_t *p) +{ + proc->pid = -1; + return apr_proc_wait(proc, exitcode, exitwhy, waithow); +} + +APR_DECLARE(apr_status_t) apr_proc_wait(apr_proc_t *proc, + int *exitcode, apr_exit_why_e *exitwhy, + apr_wait_how_e waithow) +{ + pid_t pstatus; + int waitpid_options = WUNTRACED; + int exit_int; + int ignore; + apr_exit_why_e ignorewhy; + + if (exitcode == NULL) { + exitcode = &ignore; + } + + if (exitwhy == NULL) { + exitwhy = &ignorewhy; + } + + if (waithow != APR_WAIT) { + waitpid_options |= WNOHANG; + } + + /* If the pid is 0 then the process was started detached. There + is no need to wait since there is nothing to wait for on a + detached process. Starting a process as non-detached and + then calling wait or waitpid could cause the thread to hang. + The reason for this is because NetWare does not have a way + to kill or even signal a process to be killed. Starting + all processes as detached avoids the possibility of a + thread hanging. */ + if (proc->pid == 0) { + *exitwhy = APR_PROC_EXIT; + *exitcode = 0; + return APR_CHILD_DONE; + } + + if ((pstatus = waitpid(proc->pid, &exit_int, waitpid_options)) > 0) { + proc->pid = pstatus; + + if (WIFEXITED(exit_int)) { + *exitwhy = APR_PROC_EXIT; + *exitcode = WEXITSTATUS(exit_int); + } + else if (WIFSIGNALED(exit_int)) { + *exitwhy = APR_PROC_SIGNAL; + *exitcode = WIFTERMSIG(exit_int); + } + else { + /* unexpected condition */ + return APR_EGENERAL; + } + + return APR_CHILD_DONE; + } + else if (pstatus == 0) { + return APR_CHILD_NOTDONE; + } + + return errno; +} + +#if APR_HAVE_STRUCT_RLIMIT +APR_DECLARE(apr_status_t) apr_procattr_limit_set(apr_procattr_t *attr, + apr_int32_t what, + struct rlimit *limit) +{ + switch(what) { + case APR_LIMIT_CPU: +#ifdef RLIMIT_CPU + attr->limit_cpu = limit; + break; +#else + return APR_ENOTIMPL; +#endif + + case APR_LIMIT_MEM: +#if defined(RLIMIT_DATA) || defined(RLIMIT_VMEM) || defined(RLIMIT_AS) + attr->limit_mem = limit; + break; +#else + return APR_ENOTIMPL; +#endif + + case APR_LIMIT_NPROC: +#ifdef RLIMIT_NPROC + attr->limit_nproc = limit; + break; +#else + return APR_ENOTIMPL; +#endif + + case APR_LIMIT_NOFILE: +#ifdef RLIMIT_NOFILE + attr->limit_nofile = limit; + break; +#else + return APR_ENOTIMPL; +#endif + + } + return APR_SUCCESS; +} +#endif /* APR_HAVE_STRUCT_RLIMIT */ + +APR_DECLARE(apr_status_t) apr_procattr_user_set(apr_procattr_t *attr, + const char *username, + const char *password) +{ + /* Always return SUCCESS because NetWare threads don't run as a user */ + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_procattr_group_set(apr_procattr_t *attr, + const char *groupname) +{ + /* Always return SUCCESS because NetWare threads don't run within a group */ + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_procattr_perms_set_register(apr_procattr_t *attr, + apr_perms_setfn_t *perms_set_fn, + void *data, + apr_fileperms_t perms) +{ + return APR_ENOTIMPL; +} diff --git a/threadproc/netware/procsup.c b/threadproc/netware/procsup.c new file mode 100644 index 00000000000..72fa1d9764d --- /dev/null +++ b/threadproc/netware/procsup.c @@ -0,0 +1,102 @@ +/* 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_threadproc.h" + +apr_status_t apr_proc_detach(int daemonize) +{ +#if 0 + int x; + pid_t pgrp; + + chdir("/"); +#if !defined(MPE) && !defined(OS2) && !defined(TPF) && !defined(BEOS) +/* Don't detach for MPE because child processes can't survive the death of + the parent. */ + if ((x = fork()) > 0) + exit(0); + else if (x == -1) { + perror("fork"); + fprintf(stderr, "unable to fork new process\n"); + exit(1); /* we can't do anything here, so just exit. */ + } +/* RAISE_SIGSTOP(DETACH);*/ +#endif +#if APR_HAVE_SETSID + if ((pgrp = setsid()) == -1) { + return errno; + } +#elif defined(NEXT) || defined(NEWSOS) + if (setpgrp(0, getpid()) == -1 || (pgrp = getpgrp(0)) == -1) { + return errno; + } +#elif defined(OS2) || defined(TPF) + /* OS/2 don't support process group IDs */ + pgrp = getpid(); +#elif defined(MPE) + /* MPE uses negative pid for process group */ + pgrp = -getpid(); +#else + if ((pgrp = setpgid(0, 0)) == -1) { + return errno; + } +#endif + + /* close out the standard file descriptors */ + if (freopen("/dev/null", "r", stdin) == NULL) { + return errno; + /* continue anyhow -- note we can't close out descriptor 0 because we + * have nothing to replace it with, and if we didn't have a descriptor + * 0 the next file would be created with that value ... leading to + * havoc. + */ + } + if (freopen("/dev/null", "w", stdout) == NULL) { + return errno; + } + /* We are going to reopen this again in a little while to the error + * log file, but better to do it twice and suffer a small performance + * hit for consistancy than not reopen it here. + */ + if (freopen("/dev/null", "w", stderr) == NULL) { + return errno; + } +#endif + return APR_SUCCESS; +} + +#if 0 +#if (!HAVE_WAITPID) +/* From ikluft@amdahl.com + * this is not ideal but it works for SVR3 variants + * Modified by dwd@bell-labs.com to call wait3 instead of wait because + * apache started to use the WNOHANG option. + */ +int waitpid(pid_t pid, int *statusp, int options) +{ + int tmp_pid; + if (kill(pid, 0) == -1) { + errno = ECHILD; + return -1; + } + while (((tmp_pid = wait3(statusp, options, 0)) != pid) && + (tmp_pid != -1) && (tmp_pid != 0) && (pid != -1)) + ; + return tmp_pid; +} +#endif +#endif + diff --git a/threadproc/netware/signals.c b/threadproc/netware/signals.c new file mode 100644 index 00000000000..c744da5c512 --- /dev/null +++ b/threadproc/netware/signals.c @@ -0,0 +1,81 @@ +/* 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_threadproc.h" +#include "apr_private.h" +#include "apr_pools.h" +#include "apr_signal.h" +#include "apr_strings.h" + +#include <assert.h> +#if APR_HAS_THREADS && APR_HAVE_PTHREAD_H +#include <pthread.h> +#endif + +APR_DECLARE(apr_status_t) apr_proc_kill(apr_proc_t *proc, int signum) +{ + return APR_ENOTIMPL; +} + + +void apr_signal_init(apr_pool_t *pglobal) +{ +} + +const char *apr_signal_description_get(int signum) +{ + switch (signum) + { + case SIGABRT: + return "Abort"; + case SIGFPE: + return "Arithmetic exception"; + case SIGILL: + return "Illegal instruction"; + case SIGINT: + return "Interrupt"; + case SIGSEGV: + return "Segmentation fault"; + case SIGTERM: + return "Terminated"; + case SIGPOLL: + return "Pollable event occurred"; + default: + return "unknown signal (not supported)"; + } +} + +static void *signal_thread_func(void *signal_handler) +{ + return NULL; +} + +#if (APR_HAVE_SIGWAIT || APR_HAVE_SIGSUSPEND) +APR_DECLARE(apr_status_t) apr_setup_signal_thread(void) +{ + return 0; +} +#endif /* (APR_HAVE_SIGWAIT || APR_HAVE_SIGSUSPEND) */ + +APR_DECLARE(apr_status_t) apr_signal_block(int signum) +{ + return APR_ENOTIMPL; +} + +APR_DECLARE(apr_status_t) apr_signal_unblock(int signum) +{ + return APR_ENOTIMPL; +} diff --git a/threadproc/netware/thread.c b/threadproc/netware/thread.c new file mode 100644 index 00000000000..a37b107a02e --- /dev/null +++ b/threadproc/netware/thread.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_portable.h" +#include "apr_strings.h" +#include "apr_arch_threadproc.h" + +static int thread_count = 0; + +apr_status_t apr_threadattr_create(apr_threadattr_t **new, + apr_pool_t *pool) +{ + (*new) = (apr_threadattr_t *)apr_palloc(pool, + sizeof(apr_threadattr_t)); + + if ((*new) == NULL) { + return APR_ENOMEM; + } + + (*new)->pool = pool; + (*new)->stack_size = APR_DEFAULT_STACK_SIZE; + (*new)->detach = 0; + (*new)->thread_name = NULL; + return APR_SUCCESS; +} + +apr_status_t apr_threadattr_detach_set(apr_threadattr_t *attr,apr_int32_t on) +{ + attr->detach = on; + return APR_SUCCESS; +} + +apr_status_t apr_threadattr_detach_get(apr_threadattr_t *attr) +{ + if (attr->detach == 1) + return APR_DETACH; + return APR_NOTDETACH; +} + +APR_DECLARE(apr_status_t) apr_threadattr_stacksize_set(apr_threadattr_t *attr, + apr_size_t stacksize) +{ + attr->stack_size = stacksize; + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_threadattr_guardsize_set(apr_threadattr_t *attr, + apr_size_t size) +{ + return APR_ENOTIMPL; +} + +static void *dummy_worker(void *opaque) +{ + apr_thread_t *thd = (apr_thread_t *)opaque; + void *ret; + + apr_pool_owner_set(thd->pool, 0); + ret = thd->func(thd, thd->data); + apr_pool_destroy(thd->pool); + return ret; +} + +apr_status_t apr_thread_create(apr_thread_t **new, + apr_threadattr_t *attr, + apr_thread_start_t func, + void *data, + apr_pool_t *pool) +{ + apr_status_t stat; + unsigned long flags = NX_THR_BIND_CONTEXT; + char threadName[NX_MAX_OBJECT_NAME_LEN+1]; + size_t stack_size = APR_DEFAULT_STACK_SIZE; + + if (attr && attr->thread_name) { + strncpy (threadName, attr->thread_name, NX_MAX_OBJECT_NAME_LEN); + } + else { + sprintf(threadName, "APR_thread %04ld", ++thread_count); + } + + /* An original stack size of 0 will allow NXCreateThread() to + * assign a default system stack size. An original stack + * size of less than 0 will assign the APR default stack size. + * anything else will be taken as is. + */ + if (attr && (attr->stack_size >= 0)) { + stack_size = attr->stack_size; + } + + (*new) = (apr_thread_t *)apr_palloc(pool, sizeof(apr_thread_t)); + + if ((*new) == NULL) { + return APR_ENOMEM; + } + + (*new)->data = data; + (*new)->func = func; + (*new)->thread_name = (char*)apr_pstrdup(pool, threadName); + + stat = apr_pool_create(&(*new)->pool, pool); + if (stat != APR_SUCCESS) { + return stat; + } + + if (attr && attr->detach) { + flags |= NX_THR_DETACHED; + } + + (*new)->ctx = NXContextAlloc( + /* void(*start_routine)(void *arg) */ (void (*)(void *)) dummy_worker, + /* void *arg */ (*new), + /* int priority */ NX_PRIO_MED, + /* size_t stackSize */ stack_size, + /* unsigned long flags */ NX_CTX_NORMAL, + /* int *error */ &stat); + + stat = NXContextSetName( + /* NXContext_t ctx */ (*new)->ctx, + /* const char *name */ threadName); + + stat = NXThreadCreate( + /* NXContext_t context */ (*new)->ctx, + /* unsigned long flags */ flags, + /* NXThreadId_t *thread_id */ &(*new)->td); + + if (stat == 0) + return APR_SUCCESS; + + return(stat); /* if error */ +} + +apr_os_thread_t apr_os_thread_current() +{ + return NXThreadGetId(); +} + +int apr_os_thread_equal(apr_os_thread_t tid1, apr_os_thread_t tid2) +{ + return (tid1 == tid2); +} + +void apr_thread_yield() +{ + NXThreadYield(); +} + +apr_status_t apr_thread_exit(apr_thread_t *thd, + apr_status_t retval) +{ + thd->exitval = retval; + apr_pool_destroy(thd->pool); + NXThreadExit(NULL); + return APR_SUCCESS; +} + +apr_status_t apr_thread_join(apr_status_t *retval, + apr_thread_t *thd) +{ + apr_status_t stat; + NXThreadId_t dthr; + + if ((stat = NXThreadJoin(thd->td, &dthr, NULL)) == 0) { + *retval = thd->exitval; + return APR_SUCCESS; + } + else { + return stat; + } +} + +apr_status_t apr_thread_detach(apr_thread_t *thd) +{ + return APR_SUCCESS; +} + +apr_status_t apr_thread_data_get(void **data, const char *key, + apr_thread_t *thread) +{ + if (thread != NULL) { + return apr_pool_userdata_get(data, key, thread->pool); + } + else { + data = NULL; + return APR_ENOTHREAD; + } +} + +apr_status_t apr_thread_data_set(void *data, const char *key, + apr_status_t (*cleanup) (void *), + apr_thread_t *thread) +{ + if (thread != NULL) { + return apr_pool_userdata_set(data, key, cleanup, thread->pool); + } + else { + data = NULL; + return APR_ENOTHREAD; + } +} + +APR_DECLARE(apr_status_t) apr_os_thread_get(apr_os_thread_t **thethd, + apr_thread_t *thd) +{ + if (thd == NULL) { + return APR_ENOTHREAD; + } + *thethd = &(thd->td); + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_os_thread_put(apr_thread_t **thd, + apr_os_thread_t *thethd, + apr_pool_t *pool) +{ + if (pool == NULL) { + return APR_ENOPOOL; + } + if ((*thd) == NULL) { + (*thd) = (apr_thread_t *)apr_palloc(pool, sizeof(apr_thread_t)); + (*thd)->pool = pool; + } + (*thd)->td = *thethd; + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_thread_once_init(apr_thread_once_t **control, + apr_pool_t *p) +{ + (*control) = apr_pcalloc(p, sizeof(**control)); + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_thread_once(apr_thread_once_t *control, + void (*func)(void)) +{ + if (!atomic_xchg(&control->value, 1)) { + func(); + } + return APR_SUCCESS; +} + +APR_POOL_IMPLEMENT_ACCESSOR(thread) + + diff --git a/threadproc/netware/threadpriv.c b/threadproc/netware/threadpriv.c new file mode 100644 index 00000000000..54680a56342 --- /dev/null +++ b/threadproc/netware/threadpriv.c @@ -0,0 +1,102 @@ +/* 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_portable.h" +#include "apr_arch_threadproc.h" + +apr_status_t apr_threadkey_private_create(apr_threadkey_t **key, + void (*dest)(void *), apr_pool_t *pool) +{ + apr_status_t stat; + + (*key) = (apr_threadkey_t *)apr_palloc(pool, sizeof(apr_threadkey_t)); + if ((*key) == NULL) { + return APR_ENOMEM; + } + + (*key)->pool = pool; + + if ((stat = NXKeyCreate(NULL, dest, &(*key)->key)) == 0) { + return stat; + } + return stat; +} + +apr_status_t apr_threadkey_private_get(void **new, apr_threadkey_t *key) +{ + apr_status_t stat; + + if ((stat = NXKeyGetValue(key->key, new)) == 0) { + return APR_SUCCESS; + } + else { + return stat; + } +} + +apr_status_t apr_threadkey_private_set(void *priv, apr_threadkey_t *key) +{ + apr_status_t stat; + if ((stat = NXKeySetValue(key->key, priv)) == 0) { + return APR_SUCCESS; + } + else { + return stat; + } +} + +apr_status_t apr_threadkey_private_delete(apr_threadkey_t *key) +{ + apr_status_t stat; + if ((stat = NXKeyDelete(key->key)) == 0) { + return APR_SUCCESS; + } + return stat; +} + +apr_status_t apr_threadkey_data_get(void **data, const char *key, apr_threadkey_t *threadkey) +{ + return apr_pool_userdata_get(data, key, threadkey->pool); +} + +apr_status_t apr_threadkey_data_set(void *data, + const char *key, apr_status_t (*cleanup) (void *), + apr_threadkey_t *threadkey) +{ + return apr_pool_userdata_set(data, key, cleanup, threadkey->pool); +} + +apr_status_t apr_os_threadkey_get(apr_os_threadkey_t *thekey, + apr_threadkey_t *key) +{ + thekey = &(key->key); + return APR_SUCCESS; +} + +apr_status_t apr_os_threadkey_put(apr_threadkey_t **key, + apr_os_threadkey_t *thekey, apr_pool_t *pool) +{ + if (pool == NULL) { + return APR_ENOPOOL; + } + if ((*key) == NULL) { + (*key) = (apr_threadkey_t *)apr_palloc(pool, sizeof(apr_threadkey_t)); + (*key)->pool = pool; + } + (*key)->key = *thekey; + return APR_SUCCESS; +} + diff --git a/threadproc/os2/.cvsignore b/threadproc/os2/.cvsignore deleted file mode 100644 index f3c7a7c5da6..00000000000 --- a/threadproc/os2/.cvsignore +++ /dev/null @@ -1 +0,0 @@ -Makefile diff --git a/threadproc/os2/Makefile.in b/threadproc/os2/Makefile.in deleted file mode 100644 index 49fcb6b0281..00000000000 --- a/threadproc/os2/Makefile.in +++ /dev/null @@ -1,80 +0,0 @@ -#CFLAGS=$(OPTIM) $(CFLAGS1) $(EXTRA_CFLAGS) -#LIBS=$(EXTRA_LIBS) $(LIBS1) -#INCLUDES=$(INCLUDES1) $(INCLUDES0) $(EXTRA_INCLUDES) -#LDFLAGS=$(LDFLAGS1) $(EXTRA_LDFLAGS) - -CC=@CC@ -RANLIB=@RANLIB@ -CFLAGS=@CFLAGS@ @OPTIM@ -LIBS=@LIBS@ -LDFLAGS=@LDFLAGS@ $(LIBS) -INCDIR=../../inc -INCDIR1=../../include -INCDIR2=../../file_io/os2 -INCLUDES=-I$(INCDIR) -I$(INCDIR1) -I$(INCDIR2) -I. - -LIB=threadproc.a - -OBJS=proc.o \ - thread.o \ - threadpriv.o \ - signals.o - -.c.o: - $(CC) $(CFLAGS) -c $(INCLUDES) $< - -all: $(LIB) - -clean: - $(RM) -f *.o *.a *.so - -distclean: clean - -$(RM) -f Makefile - -$(OBJS): Makefile - -$(LIB): $(OBJS) - $(RM) -f $@ - $(AR) cr $@ $(OBJS) - $(RANLIB) $@ - -# -# We really don't expect end users to use this rule. It works only with -# gcc, and rebuilds Makefile.tmpl. You have to re-run Configure after -# using it. -# -depend: - cp Makefile.in Makefile.in.bak \ - && sed -ne '1,/^# DO NOT REMOVE/p' Makefile.in > Makefile.new \ - && gcc -MM $(INCLUDES) $(CFLAGS) *.c | sed -e "s%\\\\\(.\)%/\\1%g" >> Makefile.new \ - && sed -e '1,$$s: $(INCDIR)/: $$(INCDIR)/:g' \ - -e '1,$$s: $(INCDIR1)/: $$(INCDIR1)/:g' \ - -e '1,$$s: $(INCDIR2)/: $$(INCDIR2)/:g' \ - -e '1,$$s: $(OSDIR)/: $$(OSDIR)/:g' Makefile.new \ - > Makefile.in \ - && rm Makefile.new - -# DO NOT REMOVE -proc.o: proc.c threadproc.h $(INCDIR1)/apr_thread_proc.h \ - $(INCDIR1)/apr_file_io.h $(INCDIR1)/apr_general.h \ - $(INCDIR1)/apr.h $(INCDIR1)/apr_errno.h \ - $(INCDIR1)/apr_time.h $(INCDIR2)/fileio.h \ - $(INCDIR1)/apr_private.h $(INCDIR1)/apr_lib.h \ - $(INCDIR1)/apr_portable.h $(INCDIR1)/apr_network_io.h \ - $(INCDIR1)/apr_lock.h -signals.o: signals.c threadproc.h $(INCDIR1)/apr_thread_proc.h \ - $(INCDIR1)/apr_file_io.h $(INCDIR1)/apr_general.h \ - $(INCDIR1)/apr.h $(INCDIR1)/apr_errno.h \ - $(INCDIR1)/apr_time.h $(INCDIR2)/fileio.h \ - $(INCDIR1)/apr_private.h -thread.o: thread.c threadproc.h $(INCDIR1)/apr_thread_proc.h \ - $(INCDIR1)/apr_file_io.h $(INCDIR1)/apr_general.h \ - $(INCDIR1)/apr.h $(INCDIR1)/apr_errno.h \ - $(INCDIR1)/apr_time.h $(INCDIR1)/apr_lib.h \ - $(INCDIR2)/fileio.h $(INCDIR1)/apr_private.h -threadpriv.o: threadpriv.c threadproc.h \ - $(INCDIR1)/apr_thread_proc.h $(INCDIR1)/apr_file_io.h \ - $(INCDIR1)/apr_general.h $(INCDIR1)/apr.h \ - $(INCDIR1)/apr_errno.h $(INCDIR1)/apr_time.h \ - $(INCDIR1)/apr_lib.h $(INCDIR2)/fileio.h \ - $(INCDIR1)/apr_private.h diff --git a/threadproc/os2/proc.c b/threadproc/os2/proc.c index 6fc0f755a9c..cd750012966 100644 --- a/threadproc/os2/proc.c +++ b/threadproc/os2/proc.c @@ -1,85 +1,53 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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 INCL_DOS #define INCL_DOSERRORS -#include "threadproc.h" -#include "fileio.h" +#include "apr_arch_threadproc.h" +#include "apr_arch_file_io.h" #include "apr_private.h" #include "apr_thread_proc.h" #include "apr_file_io.h" #include "apr_general.h" #include "apr_lib.h" #include "apr_portable.h" +#include "apr_strings.h" +#include "apr_signal.h" #include <signal.h> #include <string.h> #include <sys/wait.h> #include <unistd.h> #include <process.h> #include <stdlib.h> -#include <os2.h> -ap_status_t ap_createprocattr_init(ap_procattr_t **new, ap_pool_t *cont) +/* Heavy on no'ops, here's what we want to pass if there is APR_NO_FILE + * requested for a specific child handle; + */ +static apr_file_t no_file = { NULL, -1, }; + +APR_DECLARE(apr_status_t) apr_procattr_create(apr_procattr_t **new, apr_pool_t *pool) { - (*new) = (ap_procattr_t *)ap_palloc(cont, - sizeof(ap_procattr_t)); + (*new) = (apr_procattr_t *)apr_palloc(pool, + sizeof(apr_procattr_t)); if ((*new) == NULL) { return APR_ENOMEM; } - (*new)->cntxt = cont; + (*new)->pool = pool; (*new)->parent_in = NULL; (*new)->child_in = NULL; (*new)->parent_out = NULL; @@ -92,98 +60,183 @@ ap_status_t ap_createprocattr_init(ap_procattr_t **new, ap_pool_t *cont) return APR_SUCCESS; } -ap_status_t ap_setprocattr_io(ap_procattr_t *attr, ap_int32_t in, - ap_int32_t out, ap_int32_t err) +APR_DECLARE(apr_status_t) apr_procattr_io_set(apr_procattr_t *attr, + apr_int32_t in, + apr_int32_t out, + apr_int32_t err) { - ap_status_t stat; - if (in) { - if ((stat = ap_create_pipe(&attr->child_in, &attr->parent_in, - attr->cntxt)) != APR_SUCCESS) { - return stat; - } - switch (in) { - case APR_FULL_BLOCK: - ap_block_pipe(attr->child_in); - ap_block_pipe(attr->parent_in); - case APR_PARENT_BLOCK: - ap_block_pipe(attr->parent_in); - case APR_CHILD_BLOCK: - ap_block_pipe(attr->child_in); - } - } - if (out) { - if ((stat = ap_create_pipe(&attr->parent_out, &attr->child_out, - attr->cntxt)) != APR_SUCCESS) { - return stat; - } - switch (out) { - case APR_FULL_BLOCK: - ap_block_pipe(attr->child_out); - ap_block_pipe(attr->parent_out); - case APR_PARENT_BLOCK: - ap_block_pipe(attr->parent_out); - case APR_CHILD_BLOCK: - ap_block_pipe(attr->child_out); + apr_status_t rv; + + if ((in != APR_NO_PIPE) && (in != APR_NO_FILE)) { + /* APR_CHILD_BLOCK maps to APR_WRITE_BLOCK, while + * APR_PARENT_BLOCK maps to APR_READ_BLOCK, so transpose + * the CHILD/PARENT blocking flags for the stdin pipe. + * stdout/stderr map to the correct mode by default. + */ + if (in == APR_CHILD_BLOCK) + in = APR_READ_BLOCK; + else if (in == APR_PARENT_BLOCK) + in = APR_WRITE_BLOCK; + + if ((rv = apr_file_pipe_create_ex(&attr->child_in, &attr->parent_in, + in, attr->pool)) == APR_SUCCESS) + rv = apr_file_inherit_unset(attr->parent_in); + if (rv != APR_SUCCESS) + return rv; + } + else if (in == APR_NO_FILE) + attr->child_in = &no_file; + + if ((out != APR_NO_PIPE) && (out != APR_NO_FILE)) { + if ((rv = apr_file_pipe_create_ex(&attr->parent_out, &attr->child_out, + out, attr->pool)) == APR_SUCCESS) + rv = apr_file_inherit_unset(attr->parent_out); + if (rv != APR_SUCCESS) + return rv; + } + else if (out == APR_NO_FILE) + attr->child_out = &no_file; + + if ((err != APR_NO_PIPE) && (err != APR_NO_FILE)) { + if ((rv = apr_file_pipe_create_ex(&attr->parent_err, &attr->child_err, + err, attr->pool)) == APR_SUCCESS) + rv = apr_file_inherit_unset(attr->parent_err); + if (rv != APR_SUCCESS) + return rv; + } + else if (err == APR_NO_FILE) + attr->child_err = &no_file; + + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_procattr_child_in_set(apr_procattr_t *attr, apr_file_t *child_in, + apr_file_t *parent_in) +{ + apr_status_t rv; + + if (attr->child_in == NULL && attr->parent_in == NULL + && child_in == NULL && parent_in == NULL) + if ((rv = apr_file_pipe_create(&attr->child_in, &attr->parent_in, + attr->pool)) == APR_SUCCESS) + rv = apr_file_inherit_unset(attr->parent_in); + + if (child_in != NULL && rv == APR_SUCCESS) { + if (attr->child_in && (attr->child_in->filedes != -1)) + rv = apr_file_dup2(attr->child_in, child_in, attr->pool); + else { + attr->child_in = NULL; + if ((rv = apr_file_dup(&attr->child_in, child_in, attr->pool)) + == APR_SUCCESS) + rv = apr_file_inherit_set(attr->child_in); } - } - if (err) { - if ((stat = ap_create_pipe(&attr->parent_err, &attr->child_err, - attr->cntxt)) != APR_SUCCESS) { - return stat; + } + + if (parent_in != NULL && rv == APR_SUCCESS) { + rv = apr_file_dup(&attr->parent_in, parent_in, attr->pool); + } + + return rv; +} + +APR_DECLARE(apr_status_t) apr_procattr_child_out_set(apr_procattr_t *attr, apr_file_t *child_out, + apr_file_t *parent_out) +{ + apr_status_t rv; + + if (attr->child_out == NULL && attr->parent_out == NULL + && child_out == NULL && parent_out == NULL) + if ((rv = apr_file_pipe_create(&attr->parent_out, &attr->child_out, + attr->pool)) == APR_SUCCESS) + rv = apr_file_inherit_unset(attr->parent_out); + + if (child_out != NULL && rv == APR_SUCCESS) { + if (attr->child_out && (attr->child_out->filedes != -1)) + rv = apr_file_dup2(attr->child_out, child_out, attr->pool); + else { + attr->child_out = NULL; + if ((rv = apr_file_dup(&attr->child_out, child_out, attr->pool)) + == APR_SUCCESS) + rv = apr_file_inherit_set(attr->child_out); } - switch (err) { - case APR_FULL_BLOCK: - ap_block_pipe(attr->child_err); - ap_block_pipe(attr->parent_err); - case APR_PARENT_BLOCK: - ap_block_pipe(attr->parent_err); - case APR_CHILD_BLOCK: - ap_block_pipe(attr->child_err); + } + + if (parent_out != NULL && rv == APR_SUCCESS) { + rv = apr_file_dup(&attr->parent_out, parent_out, attr->pool); + } + + return rv; +} + +APR_DECLARE(apr_status_t) apr_procattr_child_err_set(apr_procattr_t *attr, apr_file_t *child_err, + apr_file_t *parent_err) +{ + apr_status_t rv; + + if (attr->child_err == NULL && attr->parent_err == NULL + && child_err == NULL && parent_err == NULL) + if ((rv = apr_file_pipe_create(&attr->parent_err, &attr->child_err, + attr->pool)) == APR_SUCCESS) + rv = apr_file_inherit_unset(attr->parent_err); + + if (child_err != NULL && rv == APR_SUCCESS) { + if (attr->child_err && (attr->child_err->filedes != -1)) + rv = apr_file_dup2(attr->child_err, child_err, attr->pool); + else { + attr->child_err = NULL; + if ((rv = apr_file_dup(&attr->child_err, child_err, attr->pool)) + == APR_SUCCESS) + rv = apr_file_inherit_set(attr->child_err); } - } - return APR_SUCCESS; + } + + if (parent_err != NULL && rv == APR_SUCCESS) { + rv = apr_file_dup(&attr->parent_err, parent_err, attr->pool); + } + + return rv; } -ap_status_t ap_setprocattr_dir(ap_procattr_t *attr, const char *dir) +APR_DECLARE(apr_status_t) apr_procattr_dir_set(apr_procattr_t *attr, const char *dir) { - attr->currdir = ap_pstrdup(attr->cntxt, dir); + attr->currdir = apr_pstrdup(attr->pool, dir); if (attr->currdir) { return APR_SUCCESS; } return APR_ENOMEM; } -ap_status_t ap_setprocattr_cmdtype(ap_procattr_t *attr, - ap_cmdtype_e cmd) +APR_DECLARE(apr_status_t) apr_procattr_cmdtype_set(apr_procattr_t *attr, + apr_cmdtype_e cmd) { attr->cmdtype = cmd; return APR_SUCCESS; } -ap_status_t ap_setprocattr_detach(ap_procattr_t *attr, ap_int32_t detach) +APR_DECLARE(apr_status_t) apr_procattr_detach_set(apr_procattr_t *attr, apr_int32_t detach) { attr->detached = detach; return APR_SUCCESS; } -ap_status_t ap_fork(ap_proc_t **proc, ap_pool_t *cont) +APR_DECLARE(apr_status_t) apr_proc_fork(apr_proc_t *proc, apr_pool_t *pool) { int pid; - (*proc) = ap_palloc(cont, sizeof(ap_proc_t)); - if ((pid = fork()) < 0) { return errno; - } else if (pid == 0) { - (*proc)->pid = pid; - (*proc)->attr = NULL; - (*proc)->running = TRUE; + } + else if (pid == 0) { + proc->pid = pid; + proc->in = NULL; + proc->out = NULL; + proc->err = NULL; return APR_INCHILD; } - - (*proc)->pid = pid; - (*proc)->attr = NULL; - (*proc)->running = TRUE; + proc->pid = pid; + proc->in = NULL; + proc->out = NULL; + proc->err = NULL; return APR_INPARENT; } @@ -192,7 +245,7 @@ ap_status_t ap_fork(ap_proc_t **proc, ap_pool_t *cont) /* quotes in the string are doubled up. * Used to escape quotes in args passed to OS/2's cmd.exe */ -static char *double_quotes(ap_pool_t *cntxt, char *str) +static char *double_quotes(apr_pool_t *pool, const char *str) { int num_quotes = 0; int len = 0; @@ -202,7 +255,7 @@ static char *double_quotes(ap_pool_t *cntxt, char *str) num_quotes += str[len++] == '\"'; } - quote_doubled_str = ap_palloc(cntxt, len + num_quotes + 1); + quote_doubled_str = apr_palloc(pool, len + num_quotes + 1); dest = quote_doubled_str; while (*str) { @@ -217,32 +270,53 @@ static char *double_quotes(ap_pool_t *cntxt, char *str) -ap_status_t ap_create_process(ap_proc_t **new, const char *progname, - char *const args[], char **env, - ap_procattr_t *attr, ap_pool_t *cont) +APR_DECLARE(apr_status_t) apr_procattr_child_errfn_set(apr_procattr_t *attr, + apr_child_errfn_t *errfn) +{ + /* won't ever be called on this platform, so don't save the function pointer */ + return APR_SUCCESS; +} + + + +APR_DECLARE(apr_status_t) apr_procattr_error_check_set(apr_procattr_t *attr, + apr_int32_t chk) +{ + /* won't ever be used on this platform, so don't save the flag */ + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_procattr_addrspace_set(apr_procattr_t *attr, + apr_int32_t addrspace) +{ + /* won't ever be used on this platform, so don't save the flag */ + return APR_SUCCESS; +} + + + +APR_DECLARE(apr_status_t) apr_proc_create(apr_proc_t *proc, const char *progname, + const char * const *args, + const char * const *env, + apr_procattr_t *attr, apr_pool_t *pool) { int i, arg, numargs, cmdlen; - ap_status_t status; - char **newargs; + apr_status_t status; + const char **newargs; char savedir[300]; HFILE save_in, save_out, save_err, dup; int criticalsection = FALSE; char *extension, *newprogname, *extra_arg = NULL, *cmdline, *cmdline_pos; char interpreter[1024]; char error_object[260]; - ap_file_t *progfile; + apr_file_t *progfile; int env_len, e; char *env_block, *env_block_pos; RESULTCODES rescodes; - (*new) = (ap_proc_t *)ap_palloc(cont, sizeof(ap_proc_t)); - - if ((*new) == NULL) { - return APR_ENOMEM; - } - - (*new)->cntxt = cont; - (*new)->running = FALSE; + proc->in = attr->parent_in; + proc->err = attr->parent_err; + proc->out = attr->parent_out; /* Prevent other threads from running while these process-wide resources are modified */ if (attr->child_in || attr->child_out || attr->child_err || attr->currdir) { @@ -254,27 +328,33 @@ ap_status_t ap_create_process(ap_proc_t **new, const char *progname, save_in = -1; DosDupHandle(STDIN_FILENO, &save_in); dup = STDIN_FILENO; - DosDupHandle(attr->child_in->filedes, &dup); - DosSetFHState(attr->parent_in->filedes, OPEN_FLAGS_NOINHERIT); + if (attr->child_in->filedes == -1) + DosClose(dup); + else + DosDupHandle(attr->child_in->filedes, &dup); } if (attr->child_out) { save_out = -1; DosDupHandle(STDOUT_FILENO, &save_out); dup = STDOUT_FILENO; - DosDupHandle(attr->child_out->filedes, &dup); - DosSetFHState(attr->parent_out->filedes, OPEN_FLAGS_NOINHERIT); + if (attr->child_out->filedes == -1) + DosClose(dup); + else + DosDupHandle(attr->child_out->filedes, &dup); } if (attr->child_err) { save_err = -1; DosDupHandle(STDERR_FILENO, &save_err); dup = STDERR_FILENO; - DosDupHandle(attr->child_err->filedes, &dup); - DosSetFHState(attr->parent_err->filedes, OPEN_FLAGS_NOINHERIT); + if (attr->child_err->filedes == -1) + DosClose(dup); + else + DosDupHandle(attr->child_err->filedes, &dup); } - ap_signal(SIGCHLD, SIG_DFL); /*not sure if this is needed or not */ + apr_signal(SIGCHLD, SIG_DFL); /*not sure if this is needed or not */ if (attr->currdir != NULL) { _getcwd2(savedir, sizeof(savedir)); @@ -292,21 +372,34 @@ ap_status_t ap_create_process(ap_proc_t **new, const char *progname, if (extension == NULL || strchr(extension, '/') || strchr(extension, '\\')) extension = ""; - if (attr->cmdtype == APR_SHELLCMD || strcasecmp(extension, ".cmd") == 0) { + /* ### how to handle APR_PROGRAM_ENV and APR_PROGRAM_PATH? */ + + if (attr->cmdtype == APR_SHELLCMD || + attr->cmdtype == APR_SHELLCMD_ENV || + strcasecmp(extension, ".cmd") == 0) { strcpy(interpreter, "#!" SHELL_PATH); extra_arg = "/C"; } else if (stricmp(extension, ".exe") != 0) { - status = ap_open(&progfile, progname, APR_READ|APR_BUFFERED, 0, cont); + status = apr_file_open(&progfile, progname, + APR_FOPEN_READ|APR_FOPEN_BUFFERED, 0, pool); - if (status == APR_ENOENT) { - progname = ap_pstrcat(cont, progname, ".exe", NULL); + if (status != APR_SUCCESS && APR_STATUS_IS_ENOENT(status)) { + progname = apr_pstrcat(pool, progname, ".exe", NULL); } if (status == APR_SUCCESS) { - status = ap_fgets(interpreter, sizeof(interpreter), progfile); + status = apr_file_gets(interpreter, sizeof(interpreter), progfile); if (status == APR_SUCCESS) { if (interpreter[0] == '#' && interpreter[1] == '!') { + /* delete CR/LF & any other whitespace off the end */ + int end = strlen(interpreter) - 1; + + while (end >= 0 && apr_isspace(interpreter[end])) { + interpreter[end] = '\0'; + end--; + } + if (interpreter[2] != '/' && interpreter[2] != '\\' && interpreter[3] != ':') { char buffer[300]; @@ -323,8 +416,9 @@ ap_status_t ap_create_process(ap_proc_t **new, const char *progname, interpreter[0] = 0; } } + + apr_file_close(progfile); } - ap_close(progfile); } i = 0; @@ -333,7 +427,7 @@ ap_status_t ap_create_process(ap_proc_t **new, const char *progname, i++; } - newargs = (char **)ap_palloc(cont, sizeof (char *) * (i + 4)); + newargs = (const char **)apr_palloc(pool, sizeof (char *) * (i + 4)); numargs = 0; if (interpreter[0]) @@ -341,7 +435,7 @@ ap_status_t ap_create_process(ap_proc_t **new, const char *progname, if (extra_arg) newargs[numargs++] = "/c"; - newargs[numargs++] = newprogname = ap_pstrdup(cont, progname); + newargs[numargs++] = newprogname = apr_pstrdup(pool, progname); arg = 1; while (args && args[arg]) { @@ -359,16 +453,18 @@ ap_status_t ap_create_process(ap_proc_t **new, const char *progname, for (i=0; i<numargs; i++) cmdlen += strlen(newargs[i]) + 3; - cmdline = ap_pstrndup(cont, newargs[0], cmdlen + 2); - cmdline_pos = cmdline + strlen(cmdline); + cmdline = apr_palloc(pool, cmdlen + 2); + cmdline_pos = cmdline; - for (i=1; i<numargs; i++) { - char *a = newargs[i]; + for (i=0; i<numargs; i++) { + const char *a = newargs[i]; if (strpbrk(a, "&|<>\" ")) - a = ap_pstrcat(cont, "\"", double_quotes(cont, a), "\"", NULL); + a = apr_pstrcat(pool, "\"", double_quotes(pool, a), "\"", NULL); + + if (i) + *(cmdline_pos++) = ' '; - *(cmdline_pos++) = ' '; strcpy(cmdline_pos, a); cmdline_pos += strlen(cmdline_pos); } @@ -386,7 +482,7 @@ ap_status_t ap_create_process(ap_proc_t **new, const char *progname, for (env_len=1, e=0; env[e]; e++) env_len += strlen(env[e]) + 1; - env_block = ap_palloc(cont, env_len); + env_block = apr_palloc(pool, env_len); env_block_pos = env_block; for (e=0; env[e]; e++) { @@ -402,28 +498,37 @@ ap_status_t ap_create_process(ap_proc_t **new, const char *progname, attr->detached ? EXEC_BACKGROUND : EXEC_ASYNCRESULT, cmdline, env_block, &rescodes, cmdline); - (*new)->pid = rescodes.codeTerminate; + proc->pid = rescodes.codeTerminate; if (attr->currdir != NULL) { chdir(savedir); } if (attr->child_in) { - ap_close(attr->child_in); + if (attr->child_in->filedes != -1) { + apr_file_close(attr->child_in); + } + dup = STDIN_FILENO; DosDupHandle(save_in, &dup); DosClose(save_in); } if (attr->child_out) { - ap_close(attr->child_out); + if (attr->child_out->filedes != -1) { + apr_file_close(attr->child_out); + } + dup = STDOUT_FILENO; DosDupHandle(save_out, &dup); DosClose(save_out); } if (attr->child_err) { - ap_close(attr->child_err); + if (attr->child_err->filedes != -1) { + apr_file_close(attr->child_err); + } + dup = STDERR_FILENO; DosDupHandle(save_err, &dup); DosClose(save_err); @@ -432,63 +537,137 @@ ap_status_t ap_create_process(ap_proc_t **new, const char *progname, if (criticalsection) DosExitCritSec(); - (*new)->attr = attr; - (*new)->running = status == APR_SUCCESS; return status; } -ap_status_t ap_get_childin(ap_file_t **new, ap_proc_t *proc) +static void proces_result_codes(RESULTCODES codes, + int *exitcode, + apr_exit_why_e *exitwhy) { - (*new) = proc->attr->parent_in; - return APR_SUCCESS; -} + int result = 0; + apr_exit_why_e why = APR_PROC_EXIT; + + switch (codes.codeTerminate) { + case TC_EXIT: /* Normal exit */ + why = APR_PROC_EXIT; + result = codes.codeResult; + break; + + case TC_HARDERROR: /* Hard error halt */ + why = APR_PROC_SIGNAL; + result = SIGSYS; + break; + + case TC_KILLPROCESS: /* Was killed by a DosKillProcess() */ + why = APR_PROC_SIGNAL; + result = SIGKILL; + break; + + case TC_TRAP: /* TRAP in 16 bit code */ + case TC_EXCEPTION: /* Threw an exception (32 bit code) */ + why = APR_PROC_SIGNAL; + + switch (codes.codeResult | XCPT_FATAL_EXCEPTION) { + case XCPT_ACCESS_VIOLATION: + result = SIGSEGV; + break; + + case XCPT_ILLEGAL_INSTRUCTION: + result = SIGILL; + break; + + case XCPT_FLOAT_DIVIDE_BY_ZERO: + case XCPT_INTEGER_DIVIDE_BY_ZERO: + result = SIGFPE; + break; + + default: + result = codes.codeResult; + break; + } + } -ap_status_t ap_get_childout(ap_file_t **new, ap_proc_t *proc) -{ - (*new) = proc->attr->parent_out; - return APR_SUCCESS; + if (exitcode) { + *exitcode = result; + } + + if (exitwhy) { + *exitwhy = why; + } } -ap_status_t ap_get_childerr(ap_file_t **new, ap_proc_t *proc) -{ - (*new) = proc->attr->parent_err; - return APR_SUCCESS; -} -ap_status_t ap_wait_proc(ap_proc_t *proc, - ap_wait_how_e wait) + +APR_DECLARE(apr_status_t) apr_proc_wait_all_procs(apr_proc_t *proc, + int *exitcode, + apr_exit_why_e *exitwhy, + apr_wait_how_e waithow, + apr_pool_t *p) { RESULTCODES codes; ULONG rc; PID pid; - if (!proc) - return APR_ENOPROC; + rc = DosWaitChild(DCWA_PROCESSTREE, waithow == APR_WAIT ? DCWW_WAIT : DCWW_NOWAIT, &codes, &pid, 0); - if (!proc->running) + if (rc == 0) { + proc->pid = pid; + proces_result_codes(codes, exitcode, exitwhy); return APR_CHILD_DONE; + } else if (rc == ERROR_CHILD_NOT_COMPLETE) { + return APR_CHILD_NOTDONE; + } - rc = DosWaitChild(DCWA_PROCESS, wait == APR_WAIT ? DCWW_WAIT : DCWW_NOWAIT, &codes, &pid, proc->pid); + return APR_FROM_OS_ERROR(rc); +} + + + +APR_DECLARE(apr_status_t) apr_proc_wait(apr_proc_t *proc, + int *exitcode, apr_exit_why_e *exitwhy, + apr_wait_how_e waithow) +{ + RESULTCODES codes; + ULONG rc; + PID pid; + rc = DosWaitChild(DCWA_PROCESS, waithow == APR_WAIT ? DCWW_WAIT : DCWW_NOWAIT, &codes, &pid, proc->pid); if (rc == 0) { - proc->running = 0; + proces_result_codes(codes, exitcode, exitwhy); return APR_CHILD_DONE; } else if (rc == ERROR_CHILD_NOT_COMPLETE) { return APR_CHILD_NOTDONE; } - return APR_OS2_STATUS(rc); + return APR_FROM_OS_ERROR(rc); } -ap_status_t ap_get_os_proc(ap_os_proc_t *theproc, ap_proc_t *proc) +APR_DECLARE(apr_status_t) apr_proc_detach(int daemonize) { - if (proc == NULL) { - return APR_ENOPROC; - } - *theproc = proc->pid; - return APR_SUCCESS; + return APR_ENOTIMPL; +} + +APR_DECLARE(apr_status_t) apr_procattr_user_set(apr_procattr_t *attr, + const char *username, + const char *password) +{ + return APR_ENOTIMPL; +} + +APR_DECLARE(apr_status_t) apr_procattr_group_set(apr_procattr_t *attr, + const char *groupname) +{ + return APR_ENOTIMPL; +} + +APR_DECLARE(apr_status_t) apr_procattr_perms_set_register(apr_procattr_t *attr, + apr_perms_setfn_t *perms_set_fn, + void *data, + apr_fileperms_t perms) +{ + return APR_ENOTIMPL; } diff --git a/threadproc/os2/signals.c b/threadproc/os2/signals.c index 6ba71bada5b..cde3dedd713 100644 --- a/threadproc/os2/signals.c +++ b/threadproc/os2/signals.c @@ -1,81 +1,2 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#include "threadproc.h" -#include "fileio.h" -#include "apr_thread_proc.h" -#include "apr_file_io.h" -#include "apr_general.h" -#include <signal.h> -#include <string.h> -#include <sys/wait.h> -#define INCL_DOS -#include <os2.h> - -ap_status_t ap_kill(ap_proc_t *proc, int signal) -{ -/* SIGTERM's don't work too well in OS/2 (only affects other EMX programs). - CGIs may not be, esp. REXX scripts, so use a native call instead */ - - ap_status_t rc; - - if ( signal == SIGTERM ) { - rc = APR_OS2_STATUS(DosSendSignalException(proc->pid, XCPT_SIGNAL_BREAK)); - } else { - rc = kill(proc->pid, signal) < 0 ? errno : APR_SUCCESS; - } - - return rc; -} - +#define SIGPROCMASK_SETS_THREAD_MASK 1 +#include "../unix/signals.c" diff --git a/threadproc/os2/thread.c b/threadproc/os2/thread.c index dbfa3482550..9911034ae7c 100644 --- a/threadproc/os2/thread.c +++ b/threadproc/os2/thread.c @@ -1,83 +1,46 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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 INCL_DOSERRORS #define INCL_DOS -#include "threadproc.h" +#include "apr_arch_threadproc.h" #include "apr_thread_proc.h" #include "apr_general.h" #include "apr_lib.h" -#include "fileio.h" +#include "apr_portable.h" +#include "apr_arch_file_io.h" #include <stdlib.h> -#include <os2.h> -ap_status_t ap_create_threadattr(ap_threadattr_t **new, ap_pool_t *cont) +APR_DECLARE(apr_status_t) apr_threadattr_create(apr_threadattr_t **new, apr_pool_t *pool) { - (*new) = (ap_threadattr_t *)ap_palloc(cont, sizeof(ap_threadattr_t)); + (*new) = (apr_threadattr_t *)apr_palloc(pool, sizeof(apr_threadattr_t)); if ((*new) == NULL) { return APR_ENOMEM; } - (*new)->cntxt = cont; + (*new)->pool = pool; (*new)->attr = 0; + (*new)->stacksize = 0; return APR_SUCCESS; } -ap_status_t ap_setthreadattr_detach(ap_threadattr_t *attr, ap_int32_t on) +APR_DECLARE(apr_status_t) apr_threadattr_detach_set(apr_threadattr_t *attr, apr_int32_t on) { attr->attr |= APR_THREADATTR_DETACHED; return APR_SUCCESS; @@ -85,57 +48,69 @@ ap_status_t ap_setthreadattr_detach(ap_threadattr_t *attr, ap_int32_t on) -ap_status_t ap_getthreadattr_detach(ap_threadattr_t *attr) +APR_DECLARE(apr_status_t) apr_threadattr_detach_get(apr_threadattr_t *attr) { return (attr->attr & APR_THREADATTR_DETACHED) ? APR_DETACH : APR_NOTDETACH; } +APR_DECLARE(apr_status_t) apr_threadattr_stacksize_set(apr_threadattr_t *attr, + apr_size_t stacksize) +{ + attr->stacksize = stacksize; + return APR_SUCCESS; +} +APR_DECLARE(apr_status_t) apr_threadattr_guardsize_set(apr_threadattr_t *attr, + apr_size_t size) +{ + return APR_ENOTIMPL; +} -static void ap_thread_begin(void *arg) +static void apr_thread_begin(void *arg) { - ap_thread_t *thread = (ap_thread_t *)arg; - thread->rv = thread->func(thread->data); + apr_thread_t *thread = (apr_thread_t *)arg; + apr_pool_owner_set(thread->pool, 0); + thread->exitval = thread->func(thread, thread->data); + apr_pool_destroy(thread->pool); } -ap_status_t ap_create_thread(ap_thread_t **new, ap_threadattr_t *attr, - ap_thread_start_t func, void *data, - ap_pool_t *cont) +APR_DECLARE(apr_status_t) apr_thread_create(apr_thread_t **new, apr_threadattr_t *attr, + apr_thread_start_t func, void *data, + apr_pool_t *pool) { - ap_status_t stat; - ap_thread_t *thread; + apr_status_t stat; + apr_thread_t *thread; - thread = (ap_thread_t *)ap_palloc(cont, sizeof(ap_thread_t)); + thread = (apr_thread_t *)apr_palloc(pool, sizeof(apr_thread_t)); *new = thread; if (thread == NULL) { return APR_ENOMEM; } - thread->cntxt = cont; thread->attr = attr; thread->func = func; thread->data = data; - stat = ap_create_pool(&thread->cntxt, cont); + stat = apr_pool_create(&thread->pool, pool); if (stat != APR_SUCCESS) { return stat; } if (attr == NULL) { - stat = ap_create_threadattr(&thread->attr, thread->cntxt); + stat = apr_threadattr_create(&thread->attr, thread->pool); if (stat != APR_SUCCESS) { return stat; } } - - if (thread->attr->attr & APR_THREADATTR_DETACHED) - thread->tid = _beginthread((os2_thread_start_t)func, NULL, APR_THREAD_STACKSIZE, data); - else - thread->tid = _beginthread(ap_thread_begin, NULL, APR_THREAD_STACKSIZE, thread); + + thread->tid = _beginthread(apr_thread_begin, NULL, + thread->attr->stacksize > 0 ? + thread->attr->stacksize : APR_THREAD_STACKSIZE, + thread); if (thread->tid < 0) { return errno; @@ -146,16 +121,27 @@ ap_status_t ap_create_thread(ap_thread_t **new, ap_threadattr_t *attr, -ap_status_t ap_thread_exit(ap_thread_t *thd, ap_status_t *retval) +APR_DECLARE(apr_os_thread_t) apr_os_thread_current() +{ + PIB *ppib; + TIB *ptib; + DosGetInfoBlocks(&ptib, &ppib); + return ptib->tib_ptib2->tib2_ultid; +} + + + +APR_DECLARE(apr_status_t) apr_thread_exit(apr_thread_t *thd, apr_status_t retval) { - thd->rv = retval; + thd->exitval = retval; + apr_pool_destroy(thd->pool); _endthread(); return -1; /* If we get here something's wrong */ } -ap_status_t ap_thread_join(ap_status_t *retval, ap_thread_t *thd) +APR_DECLARE(apr_status_t) apr_thread_join(apr_status_t *retval, apr_thread_t *thd) { ULONG rc; TID waittid = thd->tid; @@ -168,16 +154,110 @@ ap_status_t ap_thread_join(ap_status_t *retval, ap_thread_t *thd) if (rc == ERROR_INVALID_THREADID) rc = 0; /* Thread had already terminated */ - *retval = (ap_status_t)thd->rv; - return APR_OS2_STATUS(rc); + *retval = thd->exitval; + return APR_FROM_OS_ERROR(rc); } -ap_status_t ap_thread_detach(ap_thread_t *thd) +APR_DECLARE(apr_status_t) apr_thread_detach(apr_thread_t *thd) { thd->attr->attr |= APR_THREADATTR_DETACHED; return APR_SUCCESS; } + +void apr_thread_yield() +{ + DosSleep(0); +} + + + +APR_DECLARE(apr_status_t) apr_os_thread_get(apr_os_thread_t **thethd, apr_thread_t *thd) +{ + *thethd = &thd->tid; + return APR_SUCCESS; +} + + + +APR_DECLARE(apr_status_t) apr_os_thread_put(apr_thread_t **thd, apr_os_thread_t *thethd, + apr_pool_t *pool) +{ + if ((*thd) == NULL) { + (*thd) = (apr_thread_t *)apr_pcalloc(pool, sizeof(apr_thread_t)); + (*thd)->pool = pool; + } + (*thd)->tid = *thethd; + return APR_SUCCESS; +} + + + +int apr_os_thread_equal(apr_os_thread_t tid1, apr_os_thread_t tid2) +{ + return tid1 == tid2; +} + + + +APR_DECLARE(apr_status_t) apr_thread_data_get(void **data, const char *key, apr_thread_t *thread) +{ + return apr_pool_userdata_get(data, key, thread->pool); +} + + + +APR_DECLARE(apr_status_t) apr_thread_data_set(void *data, const char *key, + apr_status_t (*cleanup) (void *), + apr_thread_t *thread) +{ + return apr_pool_userdata_set(data, key, cleanup, thread->pool); +} + +APR_POOL_IMPLEMENT_ACCESSOR(thread) + + + +static apr_status_t thread_once_cleanup(void *vcontrol) +{ + apr_thread_once_t *control = (apr_thread_once_t *)vcontrol; + + if (control->sem) { + DosCloseEventSem(control->sem); + } + + return APR_SUCCESS; +} + + + +APR_DECLARE(apr_status_t) apr_thread_once_init(apr_thread_once_t **control, + apr_pool_t *p) +{ + ULONG rc; + *control = (apr_thread_once_t *)apr_pcalloc(p, sizeof(apr_thread_once_t)); + rc = DosCreateEventSem(NULL, &(*control)->sem, 0, TRUE); + apr_pool_cleanup_register(p, control, thread_once_cleanup, apr_pool_cleanup_null); + return APR_FROM_OS_ERROR(rc); +} + + + +APR_DECLARE(apr_status_t) apr_thread_once(apr_thread_once_t *control, + void (*func)(void)) +{ + if (!control->hit) { + ULONG count, rc; + rc = DosResetEventSem(control->sem, &count); + + if (rc == 0 && count) { + control->hit = 1; + func(); + } + } + + return APR_SUCCESS; +} diff --git a/threadproc/os2/threadcancel.c b/threadproc/os2/threadcancel.c deleted file mode 100644 index ca7a187538e..00000000000 --- a/threadproc/os2/threadcancel.c +++ /dev/null @@ -1,85 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#include "threadproc.h" -#include "apr_thread_proc.h" -#include "apr_general.h" -#include "fileio.h" - -ap_status_t ap_cancel_thread(ap_thread_t *thd) -{ - return APR_OS2_STATUS(DosKillThread(thd->tid)); -} - - - -ap_status_t ap_setcanceltype(ap_int32_t type, ap_pool_t *cont) -{ - ULONG rc, nesting; - - if (type == APR_CANCEL_DEFER) - rc = DosEnterMustComplete(&nesting); - else - rc = DosExitMustComplete(&nesting); - - return APR_OS2_STATUS(rc); -} - - - -ap_status_t ap_setcancelstate(ap_int32_t type, ap_pool_t *cont) -{ -/* There's no way to ignore thread kills altogether in OS/2 (that I know of) */ - return APR_ENOTIMPL; -} diff --git a/threadproc/os2/threadpriv.c b/threadproc/os2/threadpriv.c index cf436d23708..c0f709c31c6 100644 --- a/threadproc/os2/threadpriv.c +++ b/threadproc/os2/threadpriv.c @@ -1,91 +1,88 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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 "threadproc.h" +#include "apr_arch_threadproc.h" #include "apr_thread_proc.h" +#include "apr_portable.h" #include "apr_general.h" #include "apr_errno.h" #include "apr_lib.h" -#include "fileio.h" +#include "apr_arch_file_io.h" -ap_status_t ap_create_thread_private(ap_threadkey_t **key, - void (*dest)(void *), ap_pool_t *cont) +APR_DECLARE(apr_status_t) apr_threadkey_private_create(apr_threadkey_t **key, + void (*dest)(void *), + apr_pool_t *pool) { - (*key) = (ap_threadkey_t *)ap_palloc(cont, sizeof(ap_threadkey_t)); + (*key) = (apr_threadkey_t *)apr_palloc(pool, sizeof(apr_threadkey_t)); if ((*key) == NULL) { return APR_ENOMEM; } - (*key)->cntxt = cont; - return APR_OS2_STATUS(DosAllocThreadLocalMemory(1, &((*key)->key))); + (*key)->pool = pool; + return APR_FROM_OS_ERROR(DosAllocThreadLocalMemory(1, &((*key)->key))); } -ap_status_t ap_get_thread_private(void **new, ap_threadkey_t *key) +APR_DECLARE(apr_status_t) apr_threadkey_private_get(void **new, apr_threadkey_t *key) { (*new) = (void *)*(key->key); return APR_SUCCESS; } -ap_status_t ap_set_thread_private(void *priv, ap_threadkey_t *key) +APR_DECLARE(apr_status_t) apr_threadkey_private_set(void *priv, apr_threadkey_t *key) { *(key->key) = (ULONG)priv; return APR_SUCCESS; } -ap_status_t ap_delete_thread_private(ap_threadkey_t *key) +APR_DECLARE(apr_status_t) apr_threadkey_private_delete(apr_threadkey_t *key) +{ + return APR_FROM_OS_ERROR(DosFreeThreadLocalMemory(key->key)); +} + +APR_DECLARE(apr_status_t) apr_threadkey_data_get(void **data, const char *key, + apr_threadkey_t *threadkey) +{ + return apr_pool_userdata_get(data, key, threadkey->pool); +} + +APR_DECLARE(apr_status_t) apr_threadkey_data_set(void *data, const char *key, + apr_status_t (*cleanup) (void *), + apr_threadkey_t *threadkey) +{ + return apr_pool_userdata_set(data, key, cleanup, threadkey->pool); +} + +APR_DECLARE(apr_status_t) apr_os_threadkey_get(apr_os_threadkey_t *thekey, apr_threadkey_t *key) { - return APR_OS2_STATUS(DosFreeThreadLocalMemory(key->key)); + *thekey = key->key; + return APR_SUCCESS; } +APR_DECLARE(apr_status_t) apr_os_threadkey_put(apr_threadkey_t **key, + apr_os_threadkey_t *thekey, + apr_pool_t *pool) +{ + if (pool == NULL) { + return APR_ENOPOOL; + } + if ((*key) == NULL) { + (*key) = (apr_threadkey_t *)apr_pcalloc(pool, sizeof(apr_threadkey_t)); + (*key)->pool = pool; + } + (*key)->key = *thekey; + return APR_SUCCESS; +} diff --git a/threadproc/os2/threadproc.h b/threadproc/os2/threadproc.h deleted file mode 100644 index cfcca8d621c..00000000000 --- a/threadproc/os2/threadproc.h +++ /dev/null @@ -1,108 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#include "apr_thread_proc.h" -#include "apr_file_io.h" - -#ifndef THREAD_PROC_H -#define THREAD_PROC_H - -#define APR_THREADATTR_DETACHED 1 - -#define SHELL_PATH "cmd.exe" -#define APR_THREAD_STACKSIZE 65536 - -struct ap_threadattr_t { - ap_pool_t *cntxt; - unsigned long attr; -}; - -struct ap_thread_t { - ap_pool_t *cntxt; - struct ap_threadattr_t *attr; - unsigned long tid; - ap_thread_start_t func; - void *data; - void *rv; -}; - -struct ap_threadkey_t { - ap_pool_t *cntxt; - unsigned long *key; -}; - -struct ap_procattr_t { - ap_pool_t *cntxt; - ap_file_t *parent_in; - ap_file_t *child_in; - ap_file_t *parent_out; - ap_file_t *child_out; - ap_file_t *parent_err; - ap_file_t *child_err; - char *currdir; - ap_int32_t cmdtype; - ap_int32_t detached; -}; - -struct ap_proc_t { - ap_pool_t *cntxt; - pid_t pid; - struct ap_procattr_t *attr; - int running; -}; - -typedef void (*os2_thread_start_t)(void *); - -#endif /* ! THREAD_PROC_H */ - diff --git a/threadproc/unix/.cvsignore b/threadproc/unix/.cvsignore deleted file mode 100644 index f3c7a7c5da6..00000000000 --- a/threadproc/unix/.cvsignore +++ /dev/null @@ -1 +0,0 @@ -Makefile diff --git a/threadproc/unix/Makefile.in b/threadproc/unix/Makefile.in deleted file mode 100644 index 016f07a49c7..00000000000 --- a/threadproc/unix/Makefile.in +++ /dev/null @@ -1,93 +0,0 @@ -#CFLAGS=$(OPTIM) $(CFLAGS1) $(EXTRA_CFLAGS) -#LIBS=$(EXTRA_LIBS) $(LIBS1) -#INCLUDES=$(INCLUDES1) $(INCLUDES0) $(EXTRA_INCLUDES) -#LDFLAGS=$(LDFLAGS1) $(EXTRA_LDFLAGS) - -RM=@RM@ -CC=@CC@ -RANLIB=@RANLIB@ -CFLAGS=@CFLAGS@ @OPTIM@ -LIBS=@LIBS@ -LDFLAGS=@LDFLAGS@ $(LIBS) -INCDIR=../../include -INCDIR1=../../file_io/unix -INCLUDES=-I$(INCDIR) -I$(INCDIR1) -I. - -LIB=libthreadproc.a - -OBJS=proc.o \ - procsup.o \ - thread.o \ - threadpriv.o \ - signals.o - -.c.o: - $(CC) $(CFLAGS) -c $(INCLUDES) $< - -all: $(OBJS) - -clean: - $(RM) -f *.o *.a *.so - -distclean: clean - -$(RM) -f Makefile - -$(OBJS): Makefile - -#$(LIB): $(OBJS) -# $(RM) -f $@ -# $(AR) cr $@ $(OBJS) -# $(RANLIB) $@ - -# -# We really don't expect end users to use this rule. It works only with -# gcc, and rebuilds Makefile.tmpl. You have to re-run Configure after -# using it. -# -depend: - cp Makefile.in Makefile.in.bak \ - && sed -ne '1,/^# DO NOT REMOVE/p' Makefile.in > Makefile.new \ - && gcc -MM $(INCLUDES) $(CFLAGS) *.c >> Makefile.new \ - && sed -e '1,$$s: $(INCDIR)/: $$(INCDIR)/:g' \ - -e '1,$$s: $(OSDIR)/: $$(OSDIR)/:g' Makefile.new \ - > Makefile.in \ - && rm Makefile.new - -# DO NOT REMOVE -proc.o: proc.c threadproc.h $(INCDIR)/apr_private.h \ - $(INCDIR)/apr_thread_proc.h $(INCDIR)/apr_file_io.h \ - $(INCDIR)/apr_general.h $(INCDIR)/apr.h \ - $(INCDIR)/apr_errno.h $(INCDIR)/apr_time.h \ - ../../file_io/unix/fileio.h $(INCDIR)/apr_lib.h \ - $(INCDIR)/apr_portable.h $(INCDIR)/apr_network_io.h \ - $(INCDIR)/apr_lock.h -procsup.o: procsup.c threadproc.h $(INCDIR)/apr_private.h \ - $(INCDIR)/apr_thread_proc.h $(INCDIR)/apr_file_io.h \ - $(INCDIR)/apr_general.h $(INCDIR)/apr.h \ - $(INCDIR)/apr_errno.h $(INCDIR)/apr_time.h \ - ../../file_io/unix/fileio.h $(INCDIR)/apr_lib.h -signals.o: signals.c threadproc.h $(INCDIR)/apr_private.h \ - $(INCDIR)/apr_thread_proc.h $(INCDIR)/apr_file_io.h \ - $(INCDIR)/apr_general.h $(INCDIR)/apr.h \ - $(INCDIR)/apr_errno.h $(INCDIR)/apr_time.h \ - ../../file_io/unix/fileio.h $(INCDIR)/apr_lib.h -thread.o: thread.c threadproc.h $(INCDIR)/apr_private.h \ - $(INCDIR)/apr_thread_proc.h $(INCDIR)/apr_file_io.h \ - $(INCDIR)/apr_general.h $(INCDIR)/apr.h \ - $(INCDIR)/apr_errno.h $(INCDIR)/apr_time.h \ - ../../file_io/unix/fileio.h $(INCDIR)/apr_lib.h \ - $(INCDIR)/apr_portable.h $(INCDIR)/apr_network_io.h \ - $(INCDIR)/apr_lock.h -threadcancel.o: threadcancel.c threadproc.h \ - $(INCDIR)/apr_private.h $(INCDIR)/apr_thread_proc.h \ - $(INCDIR)/apr_file_io.h $(INCDIR)/apr_general.h \ - $(INCDIR)/apr.h $(INCDIR)/apr_errno.h \ - $(INCDIR)/apr_time.h ../../file_io/unix/fileio.h \ - $(INCDIR)/apr_lib.h -threadpriv.o: threadpriv.c threadproc.h $(INCDIR)/apr_private.h \ - $(INCDIR)/apr_thread_proc.h $(INCDIR)/apr_file_io.h \ - $(INCDIR)/apr_general.h $(INCDIR)/apr.h \ - $(INCDIR)/apr_errno.h $(INCDIR)/apr_time.h \ - ../../file_io/unix/fileio.h $(INCDIR)/apr_lib.h \ - $(INCDIR)/apr_portable.h $(INCDIR)/apr_network_io.h \ - $(INCDIR)/apr_lock.h diff --git a/threadproc/unix/proc.c b/threadproc/unix/proc.c index 0d951f8527d..004772ff88e 100644 --- a/threadproc/unix/proc.c +++ b/threadproc/unix/proc.c @@ -1,378 +1,739 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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 "threadproc.h" +#include "apr_arch_threadproc.h" +#include "apr_strings.h" #include "apr_portable.h" +#include "apr_signal.h" +#include "apr_random.h" + +/* Heavy on no'ops, here's what we want to pass if there is APR_NO_FILE + * requested for a specific child handle; + */ +static apr_file_t no_file = { NULL, -1, }; -ap_status_t ap_createprocattr_init(ap_procattr_t **new, ap_pool_t *cont) +APR_DECLARE(apr_status_t) apr_procattr_create(apr_procattr_t **new, + apr_pool_t *pool) { - (*new) = (ap_procattr_t *)ap_palloc(cont, - sizeof(ap_procattr_t)); + (*new) = (apr_procattr_t *)apr_pcalloc(pool, sizeof(apr_procattr_t)); if ((*new) == NULL) { return APR_ENOMEM; } - (*new)->cntxt = cont; - (*new)->parent_in = NULL; - (*new)->child_in = NULL; - (*new)->parent_out = NULL; - (*new)->child_out = NULL; - (*new)->parent_err = NULL; - (*new)->child_err = NULL; - (*new)->currdir = NULL; + (*new)->pool = pool; (*new)->cmdtype = APR_PROGRAM; - (*new)->detached = 0; + (*new)->uid = (*new)->gid = -1; return APR_SUCCESS; } -ap_status_t ap_setprocattr_io(ap_procattr_t *attr, ap_int32_t in, - ap_int32_t out, ap_int32_t err) +APR_DECLARE(apr_status_t) apr_procattr_io_set(apr_procattr_t *attr, + apr_int32_t in, + apr_int32_t out, + apr_int32_t err) { - ap_status_t status; - if (in != 0) { - if ((status = ap_create_pipe(&attr->child_in, &attr->parent_in, - attr->cntxt)) != APR_SUCCESS) { - return status; - } - switch (in) { - case APR_FULL_BLOCK: - ap_block_pipe(attr->child_in); - ap_block_pipe(attr->parent_in); - case APR_PARENT_BLOCK: - ap_block_pipe(attr->parent_in); - case APR_CHILD_BLOCK: - ap_block_pipe(attr->child_in); - } - } - if (out) { - if ((status = ap_create_pipe(&attr->parent_out, &attr->child_out, - attr->cntxt)) != APR_SUCCESS) { - return status; - } - switch (out) { - case APR_FULL_BLOCK: - ap_block_pipe(attr->child_out); - ap_block_pipe(attr->parent_out); - case APR_PARENT_BLOCK: - ap_block_pipe(attr->parent_out); - case APR_CHILD_BLOCK: - ap_block_pipe(attr->child_out); - } - } - if (err) { - if ((status = ap_create_pipe(&attr->parent_err, &attr->child_err, - attr->cntxt)) != APR_SUCCESS) { - return status; - } - switch (err) { - case APR_FULL_BLOCK: - ap_block_pipe(attr->child_err); - ap_block_pipe(attr->parent_err); - case APR_PARENT_BLOCK: - ap_block_pipe(attr->parent_err); - case APR_CHILD_BLOCK: - ap_block_pipe(attr->child_err); - } - } + apr_status_t rv; + + if ((in != APR_NO_PIPE) && (in != APR_NO_FILE)) { + /* APR_CHILD_BLOCK maps to APR_WRITE_BLOCK, while + * APR_PARENT_BLOCK maps to APR_READ_BLOCK, so transpose + * the CHILD/PARENT blocking flags for the stdin pipe. + * stdout/stderr map to the correct mode by default. + */ + if (in == APR_CHILD_BLOCK) + in = APR_READ_BLOCK; + else if (in == APR_PARENT_BLOCK) + in = APR_WRITE_BLOCK; + + if ((rv = apr_file_pipe_create_ex(&attr->child_in, &attr->parent_in, + in, attr->pool)) == APR_SUCCESS) + rv = apr_file_inherit_unset(attr->parent_in); + if (rv != APR_SUCCESS) + return rv; + } + else if (in == APR_NO_FILE) + attr->child_in = &no_file; + + if ((out != APR_NO_PIPE) && (out != APR_NO_FILE)) { + if ((rv = apr_file_pipe_create_ex(&attr->parent_out, &attr->child_out, + out, attr->pool)) == APR_SUCCESS) + rv = apr_file_inherit_unset(attr->parent_out); + if (rv != APR_SUCCESS) + return rv; + } + else if (out == APR_NO_FILE) + attr->child_out = &no_file; + + if ((err != APR_NO_PIPE) && (err != APR_NO_FILE)) { + if ((rv = apr_file_pipe_create_ex(&attr->parent_err, &attr->child_err, + err, attr->pool)) == APR_SUCCESS) + rv = apr_file_inherit_unset(attr->parent_err); + if (rv != APR_SUCCESS) + return rv; + } + else if (err == APR_NO_FILE) + attr->child_err = &no_file; + return APR_SUCCESS; } -ap_status_t ap_setprocattr_childin(ap_procattr_t *attr, ap_file_t *child_in, - ap_file_t *parent_in) +APR_DECLARE(apr_status_t) apr_procattr_child_in_set(apr_procattr_t *attr, + apr_file_t *child_in, + apr_file_t *parent_in) { - if (attr->child_in == NULL && attr->parent_in == NULL) - ap_create_pipe(&attr->child_in, &attr->parent_in, attr->cntxt); + apr_status_t rv = APR_SUCCESS; - if (child_in != NULL) - ap_dupfile(&attr->child_in, child_in, attr->cntxt); + if (attr->child_in == NULL && attr->parent_in == NULL + && child_in == NULL && parent_in == NULL) + if ((rv = apr_file_pipe_create(&attr->child_in, &attr->parent_in, + attr->pool)) == APR_SUCCESS) + rv = apr_file_inherit_unset(attr->parent_in); - if (parent_in != NULL) - ap_dupfile(&attr->parent_in, parent_in, attr->cntxt); + if (child_in != NULL && rv == APR_SUCCESS) { + if (attr->child_in && (attr->child_in->filedes != -1)) + rv = apr_file_dup2(attr->child_in, child_in, attr->pool); + else { + attr->child_in = NULL; + if ((rv = apr_file_dup(&attr->child_in, child_in, attr->pool)) + == APR_SUCCESS) + rv = apr_file_inherit_set(attr->child_in); + } + } - return APR_SUCCESS; + if (parent_in != NULL && rv == APR_SUCCESS) { + if (attr->parent_in) + rv = apr_file_dup2(attr->parent_in, parent_in, attr->pool); + else + rv = apr_file_dup(&attr->parent_in, parent_in, attr->pool); + } + + return rv; } -ap_status_t ap_setprocattr_childout(ap_procattr_t *attr, ap_file_t *child_out, - ap_file_t *parent_out) +APR_DECLARE(apr_status_t) apr_procattr_child_out_set(apr_procattr_t *attr, + apr_file_t *child_out, + apr_file_t *parent_out) { - if (attr->child_out == NULL && attr->parent_out == NULL) - ap_create_pipe(&attr->child_out, &attr->parent_out, attr->cntxt); + apr_status_t rv = APR_SUCCESS; + + if (attr->child_out == NULL && attr->parent_out == NULL + && child_out == NULL && parent_out == NULL) + if ((rv = apr_file_pipe_create(&attr->parent_out, &attr->child_out, + attr->pool)) == APR_SUCCESS) + rv = apr_file_inherit_unset(attr->parent_out); - if (child_out != NULL) - ap_dupfile(&attr->child_out, child_out, attr->cntxt); + if (child_out != NULL && rv == APR_SUCCESS) { + if (attr->child_out && (attr->child_out->filedes != -1)) + rv = apr_file_dup2(attr->child_out, child_out, attr->pool); + else { + attr->child_out = NULL; + if ((rv = apr_file_dup(&attr->child_out, child_out, attr->pool)) + == APR_SUCCESS) + rv = apr_file_inherit_set(attr->child_out); + } + } - if (parent_out != NULL) - ap_dupfile(&attr->parent_out, parent_out, attr->cntxt); + if (parent_out != NULL && rv == APR_SUCCESS) { + if (attr->parent_out) + rv = apr_file_dup2(attr->parent_out, parent_out, attr->pool); + else + rv = apr_file_dup(&attr->parent_out, parent_out, attr->pool); + } - return APR_SUCCESS; + return rv; } -ap_status_t ap_setprocattr_childerr(ap_procattr_t *attr, ap_file_t *child_err, - ap_file_t *parent_err) +APR_DECLARE(apr_status_t) apr_procattr_child_err_set(apr_procattr_t *attr, + apr_file_t *child_err, + apr_file_t *parent_err) { - if (attr->child_err == NULL && attr->parent_err == NULL) - ap_create_pipe(&attr->child_err, &attr->parent_err, attr->cntxt); + apr_status_t rv = APR_SUCCESS; - if (child_err != NULL) - ap_dupfile(&attr->child_err, child_err, attr->cntxt); + if (attr->child_err == NULL && attr->parent_err == NULL + && child_err == NULL && parent_err == NULL) + if ((rv = apr_file_pipe_create(&attr->parent_err, &attr->child_err, + attr->pool)) == APR_SUCCESS) + rv = apr_file_inherit_unset(attr->parent_err); - if (parent_err != NULL) - ap_dupfile(&attr->parent_err, parent_err, attr->cntxt); + if (child_err != NULL && rv == APR_SUCCESS) { + if (attr->child_err && (attr->child_err->filedes != -1)) + rv = apr_file_dup2(attr->child_err, child_err, attr->pool); + else { + attr->child_err = NULL; + if ((rv = apr_file_dup(&attr->child_err, child_err, attr->pool)) + == APR_SUCCESS) + rv = apr_file_inherit_set(attr->child_err); + } + } + if (parent_err != NULL && rv == APR_SUCCESS) { + if (attr->parent_err) + rv = apr_file_dup2(attr->parent_err, parent_err, attr->pool); + else + rv = apr_file_dup(&attr->parent_err, parent_err, attr->pool); + } - return APR_SUCCESS; + return rv; } -ap_status_t ap_setprocattr_dir(ap_procattr_t *attr, - const char *dir) +APR_DECLARE(apr_status_t) apr_procattr_dir_set(apr_procattr_t *attr, + const char *dir) { - attr->currdir = ap_pstrdup(attr->cntxt, dir); + attr->currdir = apr_pstrdup(attr->pool, dir); if (attr->currdir) { return APR_SUCCESS; } + return APR_ENOMEM; } -ap_status_t ap_setprocattr_cmdtype(ap_procattr_t *attr, - ap_cmdtype_e cmd) +APR_DECLARE(apr_status_t) apr_procattr_cmdtype_set(apr_procattr_t *attr, + apr_cmdtype_e cmd) { attr->cmdtype = cmd; return APR_SUCCESS; } -ap_status_t ap_setprocattr_detach(ap_procattr_t *attr, ap_int32_t detach) +APR_DECLARE(apr_status_t) apr_procattr_detach_set(apr_procattr_t *attr, + apr_int32_t detach) { attr->detached = detach; return APR_SUCCESS; } -ap_status_t ap_fork(ap_proc_t **proc, ap_pool_t *cont) +APR_DECLARE(apr_status_t) apr_proc_fork(apr_proc_t *proc, apr_pool_t *pool) { int pid; - (*proc) = ap_palloc(cont, sizeof(ap_proc_t)); + memset(proc, 0, sizeof(apr_proc_t)); if ((pid = fork()) < 0) { return errno; } else if (pid == 0) { - (*proc)->pid = pid; - (*proc)->attr = NULL; + proc->pid = getpid(); + + apr_random_after_fork(proc); + return APR_INCHILD; } - (*proc)->pid = pid; - (*proc)->attr = NULL; + + proc->pid = pid; + return APR_INPARENT; } -ap_status_t ap_create_process(ap_proc_t **new, const char *progname, - char *const args[], char **env, - ap_procattr_t *attr, ap_pool_t *cont) +static apr_status_t limit_proc(apr_procattr_t *attr) { - int i; - typedef const char *my_stupid_string; - my_stupid_string *newargs; - ap_proc_t *pgrp; +#if APR_HAVE_STRUCT_RLIMIT && APR_HAVE_SETRLIMIT +#ifdef RLIMIT_CPU + if (attr->limit_cpu != NULL) { + if ((setrlimit(RLIMIT_CPU, attr->limit_cpu)) != 0) { + return errno; + } + } +#endif +#ifdef RLIMIT_NPROC + if (attr->limit_nproc != NULL) { + if ((setrlimit(RLIMIT_NPROC, attr->limit_nproc)) != 0) { + return errno; + } + } +#endif +#ifdef RLIMIT_NOFILE + if (attr->limit_nofile != NULL) { + if ((setrlimit(RLIMIT_NOFILE, attr->limit_nofile)) != 0) { + return errno; + } + } +#endif +#if defined(RLIMIT_AS) + if (attr->limit_mem != NULL) { + if ((setrlimit(RLIMIT_AS, attr->limit_mem)) != 0) { + return errno; + } + } +#elif defined(RLIMIT_DATA) + if (attr->limit_mem != NULL) { + if ((setrlimit(RLIMIT_DATA, attr->limit_mem)) != 0) { + return errno; + } + } +#elif defined(RLIMIT_VMEM) + if (attr->limit_mem != NULL) { + if ((setrlimit(RLIMIT_VMEM, attr->limit_mem)) != 0) { + return errno; + } + } +#endif +#else + /* + * Maybe make a note in error_log that setrlimit isn't supported?? + */ - (*new) = (ap_proc_t *)ap_palloc(cont, sizeof(ap_proc_t)); +#endif + return APR_SUCCESS; +} - if ((*new) == NULL) { - return APR_ENOMEM; +APR_DECLARE(apr_status_t) apr_procattr_child_errfn_set(apr_procattr_t *attr, + apr_child_errfn_t *errfn) +{ + attr->errfn = errfn; + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_procattr_error_check_set(apr_procattr_t *attr, + apr_int32_t chk) +{ + attr->errchk = chk; + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_procattr_addrspace_set(apr_procattr_t *attr, + apr_int32_t addrspace) +{ + /* won't ever be used on this platform, so don't save the flag */ + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_procattr_user_set(apr_procattr_t *attr, + const char *username, + const char *password) +{ + apr_status_t rv; + apr_gid_t gid; + + if ((rv = apr_uid_get(&attr->uid, &gid, username, + attr->pool)) != APR_SUCCESS) { + attr->uid = -1; + return rv; } + + /* Use default user group if not already set */ + if (attr->gid == -1) { + attr->gid = gid; + } + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_procattr_group_set(apr_procattr_t *attr, + const char *groupname) +{ + apr_status_t rv; + + if ((rv = apr_gid_get(&attr->gid, groupname, attr->pool)) != APR_SUCCESS) + attr->gid = -1; + return rv; +} + +APR_DECLARE(apr_status_t) apr_proc_create(apr_proc_t *new, + const char *progname, + const char * const *args, + const char * const *env, + apr_procattr_t *attr, + apr_pool_t *pool) +{ + int i; + const char * const empty_envp[] = {NULL}; - (*new)->cntxt = cont; + if (!env) { /* Specs require an empty array instead of NULL; + * Purify will trigger a failure, even if many + * implementations don't. + */ + env = empty_envp; + } + + new->in = attr->parent_in; + new->err = attr->parent_err; + new->out = attr->parent_out; + + if (attr->errchk) { + if (attr->currdir) { + if (access(attr->currdir, X_OK) == -1) { + /* chdir() in child wouldn't have worked */ + return errno; + } + } + + if (attr->cmdtype == APR_PROGRAM || + attr->cmdtype == APR_PROGRAM_ENV || + *progname == '/') { + /* for both of these values of cmdtype, caller must pass + * full path, so it is easy to check; + * caller can choose to pass full path for other + * values of cmdtype + */ + if (access(progname, X_OK) == -1) { + /* exec*() in child wouldn't have worked */ + return errno; + } + } + else { + /* todo: search PATH for progname then try to access it */ + } + } - if (((*new)->pid = fork()) < 0) { + if ((new->pid = fork()) < 0) { return errno; } - else if ((*new)->pid == 0) { + else if (new->pid == 0) { /* child process */ + + /* + * If we do exec cleanup before the dup2() calls to set up pipes + * on 0-2, we accidentally close the pipes used by programs like + * mod_cgid. + * + * If we do exec cleanup after the dup2() calls, cleanup can accidentally + * close our pipes which replaced any files which previously had + * descriptors 0-2. + * + * The solution is to kill the cleanup for the pipes, then do + * exec cleanup, then do the dup2() calls. + */ + if (attr->child_in) { - ap_close(attr->parent_in); - dup2(attr->child_in->filedes, STDIN_FILENO); - ap_close(attr->child_in); + apr_pool_cleanup_kill(apr_file_pool_get(attr->child_in), + attr->child_in, apr_unix_file_cleanup); } + if (attr->child_out) { - ap_close(attr->parent_out); - dup2(attr->child_out->filedes, STDOUT_FILENO); - ap_close(attr->child_out); + apr_pool_cleanup_kill(apr_file_pool_get(attr->child_out), + attr->child_out, apr_unix_file_cleanup); } + if (attr->child_err) { - ap_close(attr->parent_err); + apr_pool_cleanup_kill(apr_file_pool_get(attr->child_err), + attr->child_err, apr_unix_file_cleanup); + } + + apr_pool_cleanup_for_exec(); + + if ((attr->child_in) && (attr->child_in->filedes == -1)) { + close(STDIN_FILENO); + } + else if (attr->child_in && + attr->child_in->filedes != STDIN_FILENO) { + dup2(attr->child_in->filedes, STDIN_FILENO); + apr_file_close(attr->child_in); + } + + if ((attr->child_out) && (attr->child_out->filedes == -1)) { + close(STDOUT_FILENO); + } + else if (attr->child_out && + attr->child_out->filedes != STDOUT_FILENO) { + dup2(attr->child_out->filedes, STDOUT_FILENO); + apr_file_close(attr->child_out); + } + + if ((attr->child_err) && (attr->child_err->filedes == -1)) { + close(STDERR_FILENO); + } + else if (attr->child_err && + attr->child_err->filedes != STDERR_FILENO) { dup2(attr->child_err->filedes, STDERR_FILENO); - ap_close(attr->child_err); + apr_file_close(attr->child_err); } - - ap_signal(SIGCHLD, SIG_DFL); /*not sure if this is needed or not */ + + apr_signal(SIGCHLD, SIG_DFL); /* not sure if this is needed or not */ if (attr->currdir != NULL) { if (chdir(attr->currdir) == -1) { - exit(-1); /* We have big problems, the child should exit. */ + if (attr->errfn) { + attr->errfn(pool, errno, "change of working directory failed"); + } + _exit(-1); /* We have big problems, the child should exit. */ + } + } + if (!geteuid()) { + apr_procattr_pscb_t *c = attr->perms_set_callbacks; + + while (c) { + apr_status_t r; + r = (*c->perms_set_fn)((void *)c->data, c->perms, + attr->uid, attr->gid); + if (r != APR_SUCCESS && r != APR_ENOTIMPL) { + _exit(-1); + } + c = c->next; + } + } + /* Only try to switch if we are running as root */ + if (attr->gid != -1 && !geteuid()) { + if (setgid(attr->gid)) { + if (attr->errfn) { + attr->errfn(pool, errno, "setting of group failed"); + } + _exit(-1); /* We have big problems, the child should exit. */ } } - ap_cleanup_for_exec(); + if (attr->uid != -1 && !geteuid()) { + if (setuid(attr->uid)) { + if (attr->errfn) { + attr->errfn(pool, errno, "setting of user failed"); + } + _exit(-1); /* We have big problems, the child should exit. */ + } + } - if (attr->cmdtype == APR_SHELLCMD) { - i = 0; - while (args[i]) { - i++; + if (limit_proc(attr) != APR_SUCCESS) { + if (attr->errfn) { + attr->errfn(pool, errno, "setting of resource limits failed"); } - newargs = - (my_stupid_string *) ap_palloc(cont, sizeof (char *) * (i + 3)); + _exit(-1); /* We have big problems, the child should exit. */ + } + + if (attr->cmdtype == APR_SHELLCMD || + attr->cmdtype == APR_SHELLCMD_ENV) { + int onearg_len = 0; + const char *newargs[4]; + newargs[0] = SHELL_PATH; newargs[1] = "-c"; + i = 0; while (args[i]) { - newargs[i + 2] = args[i]; + onearg_len += strlen(args[i]); + onearg_len++; /* for space delimiter */ i++; } - newargs[i + 3] = NULL; + + switch(i) { + case 0: + /* bad parameters; we're doomed */ + break; + case 1: + /* no args, or caller already built a single string from + * progname and args + */ + newargs[2] = args[0]; + break; + default: + { + char *ch, *onearg; + + ch = onearg = apr_palloc(pool, onearg_len); + i = 0; + while (args[i]) { + size_t len = strlen(args[i]); + + memcpy(ch, args[i], len); + ch += len; + *ch = ' '; + ++ch; + ++i; + } + --ch; /* back up to trailing blank */ + *ch = '\0'; + newargs[2] = onearg; + } + } + + newargs[3] = NULL; + if (attr->detached) { - ap_detach(&pgrp, attr->cntxt); + apr_proc_detach(APR_PROC_DETACH_DAEMONIZE); + } + + if (attr->cmdtype == APR_SHELLCMD) { + execve(SHELL_PATH, (char * const *) newargs, (char * const *)env); + } + else { + execv(SHELL_PATH, (char * const *)newargs); } - execve(SHELL_PATH, (char **) newargs, env); + } + else if (attr->cmdtype == APR_PROGRAM) { + if (attr->detached) { + apr_proc_detach(APR_PROC_DETACH_DAEMONIZE); + } + + execve(progname, (char * const *)args, (char * const *)env); + } + else if (attr->cmdtype == APR_PROGRAM_ENV) { + if (attr->detached) { + apr_proc_detach(APR_PROC_DETACH_DAEMONIZE); + } + + execv(progname, (char * const *)args); } else { + /* APR_PROGRAM_PATH */ if (attr->detached) { - ap_detach(&pgrp, attr->cntxt); + apr_proc_detach(APR_PROC_DETACH_DAEMONIZE); } - execve(progname, args, env); + + execvp(progname, (char * const *)args); } - exit(-1); /* if we get here, there is a problem, so exit with an */ - /* error code. */ + if (attr->errfn) { + char *desc; + + desc = apr_psprintf(pool, "exec of '%s' failed", + progname); + attr->errfn(pool, errno, desc); + } + + _exit(-1); /* if we get here, there is a problem, so exit with an + * error code. */ } + /* Parent process */ - if (attr->child_in) { - ap_close(attr->child_in); + if (attr->child_in && (attr->child_in->filedes != -1)) { + apr_file_close(attr->child_in); } - if (attr->child_out) { - ap_close(attr->child_out); + + if (attr->child_out && (attr->child_out->filedes != -1)) { + apr_file_close(attr->child_out); } - if (attr->child_err) { - ap_close(attr->child_err); + + if (attr->child_err && (attr->child_err->filedes != -1)) { + apr_file_close(attr->child_err); } - - (*new)->attr = attr; + return APR_SUCCESS; } -ap_status_t ap_get_childin(ap_file_t **new, ap_proc_t *proc) +APR_DECLARE(apr_status_t) apr_proc_wait_all_procs(apr_proc_t *proc, + int *exitcode, + apr_exit_why_e *exitwhy, + apr_wait_how_e waithow, + apr_pool_t *p) { - (*new) = proc->attr->parent_in; - return APR_SUCCESS; + proc->pid = -1; + return apr_proc_wait(proc, exitcode, exitwhy, waithow); } -ap_status_t ap_get_childout(ap_file_t **new, ap_proc_t *proc) +APR_DECLARE(apr_status_t) apr_proc_wait(apr_proc_t *proc, + int *exitcode, apr_exit_why_e *exitwhy, + apr_wait_how_e waithow) { - (*new) = proc->attr->parent_out; - return APR_SUCCESS; -} + pid_t pstatus; + int waitpid_options = WUNTRACED; + int exit_int; + int ignore; + apr_exit_why_e ignorewhy; + + if (exitcode == NULL) { + exitcode = &ignore; + } -ap_status_t ap_get_childerr(ap_file_t **new, ap_proc_t *proc) -{ - (*new) = proc->attr->parent_err; - return APR_SUCCESS; -} + if (exitwhy == NULL) { + exitwhy = &ignorewhy; + } -ap_status_t ap_wait_proc(ap_proc_t *proc, - ap_wait_how_e waithow) -{ - pid_t status; - if (!proc) - return APR_ENOPROC; - if (waithow == APR_WAIT) { - if ((status = waitpid(proc->pid, NULL, WUNTRACED)) > 0) { - return APR_CHILD_DONE; + if (waithow != APR_WAIT) { + waitpid_options |= WNOHANG; + } + + do { + pstatus = waitpid(proc->pid, &exit_int, waitpid_options); + } while (pstatus < 0 && errno == EINTR); + + if (pstatus > 0) { + proc->pid = pstatus; + + if (WIFEXITED(exit_int)) { + *exitwhy = APR_PROC_EXIT; + *exitcode = WEXITSTATUS(exit_int); } - else if (status == 0) { - return APR_CHILD_NOTDONE; + else if (WIFSIGNALED(exit_int)) { + *exitwhy = APR_PROC_SIGNAL; + +#ifdef WCOREDUMP + if (WCOREDUMP(exit_int)) { + *exitwhy |= APR_PROC_SIGNAL_CORE; + } +#endif + + *exitcode = WTERMSIG(exit_int); } - return errno; - } - if ((status = waitpid(proc->pid, NULL, WUNTRACED | WNOHANG)) > 0) { + else { + /* unexpected condition */ + return APR_EGENERAL; + } + return APR_CHILD_DONE; } - else if (status == 0) { + else if (pstatus == 0) { return APR_CHILD_NOTDONE; } + return errno; -} +} -ap_status_t ap_get_os_proc(ap_os_proc_t *theproc, ap_proc_t *proc) +#if APR_HAVE_STRUCT_RLIMIT +APR_DECLARE(apr_status_t) apr_procattr_limit_set(apr_procattr_t *attr, + apr_int32_t what, + struct rlimit *limit) { - if (proc == NULL) { - return APR_ENOPROC; + switch(what) { + case APR_LIMIT_CPU: +#ifdef RLIMIT_CPU + attr->limit_cpu = limit; + break; +#else + return APR_ENOTIMPL; +#endif + + case APR_LIMIT_MEM: +#if defined(RLIMIT_DATA) || defined(RLIMIT_VMEM) || defined(RLIMIT_AS) + attr->limit_mem = limit; + break; +#else + return APR_ENOTIMPL; +#endif + + case APR_LIMIT_NPROC: +#ifdef RLIMIT_NPROC + attr->limit_nproc = limit; + break; +#else + return APR_ENOTIMPL; +#endif + + case APR_LIMIT_NOFILE: +#ifdef RLIMIT_NOFILE + attr->limit_nofile = limit; + break; +#else + return APR_ENOTIMPL; +#endif + } - *theproc = proc->pid; + return APR_SUCCESS; } +#endif /* APR_HAVE_STRUCT_RLIMIT */ -ap_status_t ap_put_os_proc(ap_proc_t **proc, ap_os_proc_t *theproc, - ap_pool_t *cont) +APR_DECLARE(apr_status_t) apr_procattr_perms_set_register(apr_procattr_t *attr, + apr_perms_setfn_t *perms_set_fn, + void *data, + apr_fileperms_t perms) { - if (cont == NULL) { - return APR_ENOPOOL; - } - if ((*proc) == NULL) { - (*proc) = (ap_proc_t *)ap_palloc(cont, sizeof(ap_proc_t)); - (*proc)->cntxt = cont; - } - (*proc)->pid = *theproc; - return APR_SUCCESS; -} + apr_procattr_pscb_t *c; + + c = apr_palloc(attr->pool, sizeof(apr_procattr_pscb_t)); + c->data = data; + c->perms = perms; + c->perms_set_fn = perms_set_fn; + c->next = attr->perms_set_callbacks; + attr->perms_set_callbacks = c; + return APR_SUCCESS; +} diff --git a/threadproc/unix/procsup.c b/threadproc/unix/procsup.c index a2bdf38f1e5..94177f92a65 100644 --- a/threadproc/unix/procsup.c +++ b/threadproc/unix/procsup.c @@ -1,96 +1,61 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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 "threadproc.h" +#include "apr_arch_threadproc.h" -ap_status_t ap_detach(ap_proc_t **new, ap_pool_t *cont) +APR_DECLARE(apr_status_t) apr_proc_detach(int daemonize) { - int x; + if (chdir("/") == -1) { + return errno; + } - (*new) = (ap_proc_t *)ap_palloc(cont, sizeof(ap_proc_t)); - (*new)->cntxt = cont; - (*new)->attr = NULL; +#if !defined(MPE) && !defined(OS2) && !defined(TPF) && !defined(BEOS) + /* Don't detach for MPE because child processes can't survive the death of + * the parent. */ + if (daemonize) { + int x; - chdir("/"); -#if !defined(MPE) && !defined(OS2) && !defined(TPF) -/* Don't detach for MPE because child processes can't survive the death of - the parent. */ - if ((x = fork()) > 0) - exit(0); - else if (x == -1) { - perror("fork"); - fprintf(stderr, "unable to fork new process\n"); - exit(1); /* we can't do anything here, so just exit. */ + if ((x = fork()) > 0) { + exit(0); + } + else if (x == -1) { + perror("fork"); + fprintf(stderr, "unable to fork new process\n"); + exit(1); /* we can't do anything here, so just exit. */ + } + /* RAISE_SIGSTOP(DETACH); */ } -/* RAISE_SIGSTOP(DETACH);*/ #endif -#if HAVE_SETSID - if (((*new)->pid = setsid()) == -1) { + +#ifdef HAVE_SETSID + /* A setsid() failure is not fatal if we didn't just fork(). + * The calling process may be the process group leader, in + * which case setsid() will fail with EPERM. + */ + if (setsid() == -1 && daemonize) { return errno; } #elif defined(NEXT) || defined(NEWSOS) - if (setpgrp(0, getpid()) == -1 || ((*new)->pid = getpgrp(0)) == -1) { + if (setpgrp(0, getpid()) == -1) { return errno; } -#elif defined(OS2) || defined(TPF) - /* OS/2 don't support process group IDs */ - (*new)->pid = getpid(); -#elif defined(MPE) - /* MPE uses negative pid for process group */ - (*new)->pid = -getpid(); +#elif defined(OS2) || defined(TPF) || defined(MPE) + /* do nothing */ #else - if (((*new)->pid = setpgrp(getpid(), 0)) == -1) { + if (setpgid(0, 0) == -1) { return errno; } #endif @@ -114,31 +79,26 @@ ap_status_t ap_detach(ap_proc_t **new, ap_pool_t *cont) if (freopen("/dev/null", "w", stderr) == NULL) { return errno; } - return APR_SUCCESS; } -ap_status_t ap_get_procdata(char *key, void *data, ap_proc_t *proc) -{ - if (proc != NULL) { - return ap_get_userdata(data, key, proc->cntxt); - } - else { - data = NULL; - return APR_ENOPROC; - } -} - -ap_status_t ap_set_procdata(void *data, char *key, - ap_status_t (*cleanup) (void *), - ap_proc_t *proc) +#if (!HAVE_WAITPID) +/* From ikluft@amdahl.com + * this is not ideal but it works for SVR3 variants + * Modified by dwd@bell-labs.com to call wait3 instead of wait because + * apache started to use the WNOHANG option. + */ +int waitpid(pid_t pid, int *statusp, int options) { - if (proc != NULL) { - return ap_set_userdata(data, key, cleanup, proc->cntxt); - } - else { - data = NULL; - return APR_ENOPROC; + int tmp_pid; + if (kill(pid, 0) == -1) { + errno = ECHILD; + return -1; } + while (((tmp_pid = wait3(statusp, options, 0)) != pid) && + (tmp_pid != -1) && (tmp_pid != 0) && (pid != -1)) + ; + return tmp_pid; } +#endif diff --git a/threadproc/unix/signals.c b/threadproc/unix/signals.c index d31edd324b7..361d68acbd9 100644 --- a/threadproc/unix/signals.c +++ b/threadproc/unix/signals.c @@ -1,68 +1,487 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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. */ -#ifndef BEOS -#include "threadproc.h" +#define INCL_DOSEXCEPTIONS /* for OS2 */ +#include "apr_arch_threadproc.h" +#include "apr_private.h" +#include "apr_pools.h" +#include "apr_signal.h" +#include "apr_strings.h" + +#include <assert.h> +#if APR_HAS_THREADS && APR_HAVE_PTHREAD_H +#include <pthread.h> +#endif + +#ifdef SIGWAIT_TAKES_ONE_ARG +#define apr_sigwait(a,b) ((*(b)=sigwait((a)))<0?-1:0) #else -#include "../beos/threadproc.h" +#define apr_sigwait(a,b) sigwait((a),(b)) #endif -ap_status_t ap_kill(ap_proc_t *proc, int sig) +APR_DECLARE(apr_status_t) apr_proc_kill(apr_proc_t *proc, int signum) { - if (kill(proc->pid, sig) == -1) { +#ifdef OS2 + /* SIGTERM's don't work too well in OS/2 (only affects other EMX + * programs). CGIs may not be, esp. REXX scripts, so use a native + * call instead + */ + if (signum == SIGTERM) { + return APR_FROM_OS_ERROR(DosSendSignalException(proc->pid, + XCPT_SIGNAL_BREAK)); + } +#endif /* OS2 */ + + if (kill(proc->pid, signum) == -1) { return errno; } + return APR_SUCCESS; } + +#if APR_HAVE_SIGACTION + +#if defined(__NetBSD__) || defined(DARWIN) +static void avoid_zombies(int signo) +{ + int exit_status; + + while (waitpid(-1, &exit_status, WNOHANG) > 0) { + /* do nothing */ + } +} +#endif /* DARWIN */ + +/* + * Replace standard signal() with the more reliable sigaction equivalent + * from W. Richard Stevens' "Advanced Programming in the UNIX Environment" + * (the version that does not automatically restart system calls). + */ +APR_DECLARE(apr_sigfunc_t *) apr_signal(int signo, apr_sigfunc_t * func) +{ + struct sigaction act, oact; + + act.sa_handler = func; + sigemptyset(&act.sa_mask); + act.sa_flags = 0; +#ifdef SA_INTERRUPT /* SunOS */ + act.sa_flags |= SA_INTERRUPT; +#endif +#if defined(__osf__) && defined(__alpha) + /* XXX jeff thinks this should be enabled whenever SA_NOCLDWAIT is defined */ + + /* this is required on Tru64 to cause child processes to + * disappear gracefully - XPG4 compatible + */ + if ((signo == SIGCHLD) && (func == SIG_IGN)) { + act.sa_flags |= SA_NOCLDWAIT; + } +#endif +#if defined(__NetBSD__) || defined(DARWIN) + /* ignoring SIGCHLD or leaving the default disposition doesn't avoid zombies, + * and there is no SA_NOCLDWAIT flag, so catch the signal and reap status in + * the handler to avoid zombies + */ + if ((signo == SIGCHLD) && (func == SIG_IGN)) { + act.sa_handler = avoid_zombies; + } +#endif + if (sigaction(signo, &act, &oact) < 0) + return SIG_ERR; + return oact.sa_handler; +} + +#endif /* HAVE_SIGACTION */ + +/* AC_DECL_SYS_SIGLIST defines either of these symbols depending + * on the version of autoconf used. */ +#if defined(SYS_SIGLIST_DECLARED) || HAVE_DECL_SYS_SIGLIST + +void apr_signal_init(apr_pool_t *pglobal) +{ +} +const char *apr_signal_description_get(int signum) +{ + return (signum >= 0) ? sys_siglist[signum] : "unknown signal (number)"; +} + +#else /* !(SYS_SIGLIST_DECLARED || HAVE_DECL_SYS_SIGLIST) */ + +/* we need to roll our own signal description stuff */ + +#if defined(NSIG) +#define APR_NUMSIG NSIG +#elif defined(_NSIG) +#define APR_NUMSIG _NSIG +#elif defined(__NSIG) +#define APR_NUMSIG __NSIG +#else +#define APR_NUMSIG 33 /* breaks on OS/390 with < 33; 32 is o.k. for most */ +#endif + +static const char *signal_description[APR_NUMSIG]; + +#define store_desc(index, string) \ + do { \ + if (index >= APR_NUMSIG) { \ + assert(index < APR_NUMSIG); \ + } \ + else { \ + signal_description[index] = string; \ + } \ + } while (0) + +void apr_signal_init(apr_pool_t *pglobal) +{ + int sig; + + store_desc(0, "Signal 0"); + +#ifdef SIGHUP + store_desc(SIGHUP, "Hangup"); +#endif +#ifdef SIGINT + store_desc(SIGINT, "Interrupt"); +#endif +#ifdef SIGQUIT + store_desc(SIGQUIT, "Quit"); +#endif +#ifdef SIGILL + store_desc(SIGILL, "Illegal instruction"); +#endif +#ifdef SIGTRAP + store_desc(SIGTRAP, "Trace/BPT trap"); +#endif +#ifdef SIGIOT + store_desc(SIGIOT, "IOT instruction"); +#endif +#ifdef SIGABRT + store_desc(SIGABRT, "Abort"); +#endif +#ifdef SIGEMT + store_desc(SIGEMT, "Emulator trap"); +#endif +#ifdef SIGFPE + store_desc(SIGFPE, "Arithmetic exception"); +#endif +#ifdef SIGKILL + store_desc(SIGKILL, "Killed"); +#endif +#ifdef SIGBUS + store_desc(SIGBUS, "Bus error"); +#endif +#ifdef SIGSEGV + store_desc(SIGSEGV, "Segmentation fault"); +#endif +#ifdef SIGSYS + store_desc(SIGSYS, "Bad system call"); +#endif +#ifdef SIGPIPE + store_desc(SIGPIPE, "Broken pipe"); +#endif +#ifdef SIGALRM + store_desc(SIGALRM, "Alarm clock"); +#endif +#ifdef SIGTERM + store_desc(SIGTERM, "Terminated"); +#endif +#ifdef SIGUSR1 + store_desc(SIGUSR1, "User defined signal 1"); +#endif +#ifdef SIGUSR2 + store_desc(SIGUSR2, "User defined signal 2"); +#endif +#ifdef SIGCLD + store_desc(SIGCLD, "Child status change"); +#endif +#ifdef SIGCHLD + store_desc(SIGCHLD, "Child status change"); +#endif +#ifdef SIGPWR + store_desc(SIGPWR, "Power-fail restart"); +#endif +#ifdef SIGWINCH + store_desc(SIGWINCH, "Window changed"); +#endif +#ifdef SIGURG + store_desc(SIGURG, "urgent socket condition"); +#endif +#ifdef SIGPOLL + store_desc(SIGPOLL, "Pollable event occurred"); +#endif +#ifdef SIGIO + store_desc(SIGIO, "socket I/O possible"); +#endif +#ifdef SIGSTOP + store_desc(SIGSTOP, "Stopped (signal)"); +#endif +#ifdef SIGTSTP + store_desc(SIGTSTP, "Stopped"); +#endif +#ifdef SIGCONT + store_desc(SIGCONT, "Continued"); +#endif +#ifdef SIGTTIN + store_desc(SIGTTIN, "Stopped (tty input)"); +#endif +#ifdef SIGTTOU + store_desc(SIGTTOU, "Stopped (tty output)"); +#endif +#ifdef SIGVTALRM + store_desc(SIGVTALRM, "virtual timer expired"); +#endif +#ifdef SIGPROF + store_desc(SIGPROF, "profiling timer expired"); +#endif +#ifdef SIGXCPU + store_desc(SIGXCPU, "exceeded cpu limit"); +#endif +#ifdef SIGXFSZ + store_desc(SIGXFSZ, "exceeded file size limit"); +#endif + + for (sig = 0; sig < APR_NUMSIG; ++sig) + if (signal_description[sig] == NULL) + signal_description[sig] = apr_psprintf(pglobal, "signal #%d", sig); +} + +const char *apr_signal_description_get(int signum) +{ + return + (signum >= 0 && signum < APR_NUMSIG) + ? signal_description[signum] + : "unknown signal (number)"; +} + +#endif /* SYS_SIGLIST_DECLARED || HAVE_DECL_SYS_SIGLIST */ + +#if APR_HAS_THREADS && (HAVE_SIGSUSPEND || APR_HAVE_SIGWAIT) && !defined(OS2) + +static void remove_sync_sigs(sigset_t *sig_mask) +{ +#ifdef SIGABRT + sigdelset(sig_mask, SIGABRT); +#endif +#ifdef SIGBUS + sigdelset(sig_mask, SIGBUS); +#endif +#ifdef SIGEMT + sigdelset(sig_mask, SIGEMT); +#endif +#ifdef SIGFPE + sigdelset(sig_mask, SIGFPE); +#endif +#ifdef SIGILL + sigdelset(sig_mask, SIGILL); +#endif +#ifdef SIGIOT + sigdelset(sig_mask, SIGIOT); +#endif +#ifdef SIGPIPE + sigdelset(sig_mask, SIGPIPE); +#endif +#ifdef SIGSEGV + sigdelset(sig_mask, SIGSEGV); +#endif +#ifdef SIGSYS + sigdelset(sig_mask, SIGSYS); +#endif +#ifdef SIGTRAP + sigdelset(sig_mask, SIGTRAP); +#endif + +/* the rest of the signals removed from the mask in this function + * absolutely must be removed; you cannot block synchronous signals + * (requirement of pthreads API) + * + * SIGUSR2 is being removed from the mask for the convenience of + * Purify users (Solaris, HP-UX, SGI) since Purify uses SIGUSR2 + */ +#ifdef SIGUSR2 + sigdelset(sig_mask, SIGUSR2); +#endif +} + +APR_DECLARE(apr_status_t) apr_signal_thread(int(*signal_handler)(int signum)) +{ + sigset_t sig_mask; +#if APR_HAVE_SIGWAIT + int (*sig_func)(int signum) = (int (*)(int))signal_handler; +#endif + + /* This thread will be the one responsible for handling signals */ + sigfillset(&sig_mask); + + /* On certain platforms, sigwait() returns EINVAL if any of various + * unblockable signals are included in the mask. This was first + * observed on AIX and Tru64. + */ +#ifdef SIGKILL + sigdelset(&sig_mask, SIGKILL); +#endif +#ifdef SIGSTOP + sigdelset(&sig_mask, SIGSTOP); +#endif +#ifdef SIGCONT + sigdelset(&sig_mask, SIGCONT); +#endif +#ifdef SIGWAITING + sigdelset(&sig_mask, SIGWAITING); +#endif + + /* no synchronous signals should be in the mask passed to sigwait() */ + remove_sync_sigs(&sig_mask); + + /* On AIX (4.3.3, at least), sigwait() won't wake up if the high- + * order bit of the second word of flags is turned on. sigdelset() + * returns an error when trying to turn this off, so we'll turn it + * off manually. + * + * Note that the private fields differ between 32-bit and 64-bit + * and even between _ALL_SOURCE and !_ALL_SOURCE. Except that on + * AIX 4.3 32-bit builds and 64-bit builds use the same definition. + * + * Applicable AIX fixes such that this is no longer needed: + * + * APAR IY23096 for AIX 51B, fix included in AIX 51C, and + * APAR IY24162 for 43X. + */ +#if defined(_AIX) +#if defined(__64BIT__) && defined(_AIXVERSION_510) +#ifdef _ALL_SOURCE + sig_mask.ss_set[3] &= 0x7FFFFFFF; +#else /* not _ALL_SOURCE */ + sig_mask.__ss_set[3] &= 0x7FFFFFFF; +#endif +#else /* not 64-bit build, or 64-bit build on 4.3 */ +#ifdef _ALL_SOURCE + sig_mask.hisigs &= 0x7FFFFFFF; +#else /* not _ALL_SOURCE */ + sig_mask.__hisigs &= 0x7FFFFFFF; +#endif +#endif +#endif /* _AIX */ + + while (1) { +#if APR_HAVE_SIGWAIT + int signal_received; + + if (apr_sigwait(&sig_mask, &signal_received) != 0) + { + /* handle sigwait() error here */ + } + + if (sig_func(signal_received) == 1) { + return APR_SUCCESS; + } +#elif HAVE_SIGSUSPEND + sigsuspend(&sig_mask); +#else +#error No apr_sigwait() and no sigsuspend() +#endif + } +} + +APR_DECLARE(apr_status_t) apr_setup_signal_thread(void) +{ + sigset_t sig_mask; + int rv; + + /* All threads should mask out signals to be handled by + * the thread doing sigwait(). + * + * No thread should ever block synchronous signals. + * See the Solaris man page for pthread_sigmask() for + * some information. Solaris chooses to knock out such + * processes when a blocked synchronous signal is + * delivered, skipping any registered signal handler. + * AIX doesn't call a signal handler either. At least + * one level of linux+glibc does call the handler even + * when the synchronous signal is blocked. + */ + sigfillset(&sig_mask); + remove_sync_sigs(&sig_mask); + +#if defined(SIGPROCMASK_SETS_THREAD_MASK) || ! APR_HAS_THREADS + if ((rv = sigprocmask(SIG_SETMASK, &sig_mask, NULL)) != 0) { + rv = errno; + } +#else + if ((rv = pthread_sigmask(SIG_SETMASK, &sig_mask, NULL)) != 0) { +#ifdef HAVE_ZOS_PTHREADS + rv = errno; +#endif + } +#endif + return rv; +} + +#endif /* APR_HAS_THREADS && ... */ + +APR_DECLARE(apr_status_t) apr_signal_block(int signum) +{ +#if APR_HAVE_SIGACTION + sigset_t sig_mask; + int rv; + + sigemptyset(&sig_mask); + + sigaddset(&sig_mask, signum); + +#if defined(SIGPROCMASK_SETS_THREAD_MASK) || ! APR_HAS_THREADS + if ((rv = sigprocmask(SIG_BLOCK, &sig_mask, NULL)) != 0) { + rv = errno; + } +#else + if ((rv = pthread_sigmask(SIG_BLOCK, &sig_mask, NULL)) != 0) { +#ifdef HAVE_ZOS_PTHREADS + rv = errno; +#endif + } +#endif + return rv; +#else + return APR_ENOTIMPL; +#endif +} + +APR_DECLARE(apr_status_t) apr_signal_unblock(int signum) +{ +#if APR_HAVE_SIGACTION + sigset_t sig_mask; + int rv; + + sigemptyset(&sig_mask); + + sigaddset(&sig_mask, signum); + +#if defined(SIGPROCMASK_SETS_THREAD_MASK) || ! APR_HAS_THREADS + if ((rv = sigprocmask(SIG_UNBLOCK, &sig_mask, NULL)) != 0) { + rv = errno; + } +#else + if ((rv = pthread_sigmask(SIG_UNBLOCK, &sig_mask, NULL)) != 0) { +#ifdef HAVE_ZOS_PTHREADS + rv = errno; +#endif + } +#endif + return rv; +#else + return APR_ENOTIMPL; +#endif +} diff --git a/threadproc/unix/thread.c b/threadproc/unix/thread.c index 300818e0fa6..dcef500e9f7 100644 --- a/threadproc/unix/thread.c +++ b/threadproc/unix/thread.c @@ -1,222 +1,339 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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 "threadproc.h" +#include "apr.h" #include "apr_portable.h" +#include "apr_arch_threadproc.h" #if APR_HAS_THREADS -#ifdef HAVE_PTHREAD_H -ap_status_t ap_create_threadattr(ap_threadattr_t **new, ap_pool_t *cont) +#if APR_HAVE_PTHREAD_H + +/* Destroy the threadattr object */ +static apr_status_t threadattr_cleanup(void *data) { - ap_status_t stat; - - (*new) = (ap_threadattr_t *)ap_palloc(cont, - sizeof(ap_threadattr_t)); - (*new)->attr = (pthread_attr_t *)ap_palloc(cont, - sizeof(pthread_attr_t)); + apr_threadattr_t *attr = data; + apr_status_t rv; - if ((*new) == NULL || (*new)->attr == NULL) { - return APR_ENOMEM; + rv = pthread_attr_destroy(&attr->attr); +#ifdef HAVE_ZOS_PTHREADS + if (rv) { + rv = errno; } +#endif + return rv; +} - (*new)->cntxt = cont; - stat = pthread_attr_init((*new)->attr); +APR_DECLARE(apr_status_t) apr_threadattr_create(apr_threadattr_t **new, + apr_pool_t *pool) +{ + apr_status_t stat; + + (*new) = apr_palloc(pool, sizeof(apr_threadattr_t)); + (*new)->pool = pool; + stat = pthread_attr_init(&(*new)->attr); if (stat == 0) { + apr_pool_cleanup_register(pool, *new, threadattr_cleanup, + apr_pool_cleanup_null); return APR_SUCCESS; } +#ifdef HAVE_ZOS_PTHREADS + stat = errno; +#endif + return stat; } -ap_status_t ap_setthreadattr_detach(ap_threadattr_t *attr, ap_int32_t on) +#if defined(PTHREAD_CREATE_DETACHED) +#define DETACH_ARG(v) ((v) ? PTHREAD_CREATE_DETACHED : PTHREAD_CREATE_JOINABLE) +#else +#define DETACH_ARG(v) ((v) ? 1 : 0) +#endif + +APR_DECLARE(apr_status_t) apr_threadattr_detach_set(apr_threadattr_t *attr, + apr_int32_t on) { - ap_status_t stat; - if ((stat = pthread_attr_setdetachstate(attr->attr, on)) == 0) { + apr_status_t stat; +#ifdef HAVE_ZOS_PTHREADS + int arg = DETACH_ARG(on); + + if ((stat = pthread_attr_setdetachstate(&attr->attr, &arg)) == 0) { +#else + if ((stat = pthread_attr_setdetachstate(&attr->attr, + DETACH_ARG(on))) == 0) { +#endif return APR_SUCCESS; } else { +#ifdef HAVE_ZOS_PTHREADS + stat = errno; +#endif + return stat; } } -ap_status_t ap_getthreadattr_detach(ap_threadattr_t *attr) +APR_DECLARE(apr_status_t) apr_threadattr_detach_get(apr_threadattr_t *attr) { int state; - pthread_attr_getdetachstate(attr->attr, &state); - if (state == 1) +#ifdef PTHREAD_ATTR_GETDETACHSTATE_TAKES_ONE_ARG + state = pthread_attr_getdetachstate(&attr->attr); +#else + pthread_attr_getdetachstate(&attr->attr, &state); +#endif + if (state == DETACH_ARG(1)) return APR_DETACH; return APR_NOTDETACH; } -ap_status_t ap_create_thread(ap_thread_t **new, ap_threadattr_t *attr, - ap_thread_start_t func, void *data, - ap_pool_t *cont) +APR_DECLARE(apr_status_t) apr_threadattr_stacksize_set(apr_threadattr_t *attr, + apr_size_t stacksize) +{ + int stat; + + stat = pthread_attr_setstacksize(&attr->attr, stacksize); + if (stat == 0) { + return APR_SUCCESS; + } +#ifdef HAVE_ZOS_PTHREADS + stat = errno; +#endif + + return stat; +} + +APR_DECLARE(apr_status_t) apr_threadattr_guardsize_set(apr_threadattr_t *attr, + apr_size_t size) { - ap_status_t stat; +#ifdef HAVE_PTHREAD_ATTR_SETGUARDSIZE + apr_status_t rv; + + rv = pthread_attr_setguardsize(&attr->attr, size); + if (rv == 0) { + return APR_SUCCESS; + } +#ifdef HAVE_ZOS_PTHREADS + rv = errno; +#endif + return rv; +#else + return APR_ENOTIMPL; +#endif +} + +static void *dummy_worker(void *opaque) +{ + apr_thread_t *thread = (apr_thread_t*)opaque; + void *ret; + + apr_pool_owner_set(thread->pool, 0); + ret = thread->func(thread, thread->data); + apr_pool_destroy(thread->pool); + return ret; +} + +APR_DECLARE(apr_status_t) apr_thread_create(apr_thread_t **new, + apr_threadattr_t *attr, + apr_thread_start_t func, + void *data, + apr_pool_t *pool) +{ + apr_status_t stat; pthread_attr_t *temp; - - (*new) = (ap_thread_t *)ap_palloc(cont, sizeof(ap_thread_t)); + + (*new) = (apr_thread_t *)apr_pcalloc(pool, sizeof(apr_thread_t)); if ((*new) == NULL) { return APR_ENOMEM; } - (*new)->td = (pthread_t *)ap_palloc(cont, sizeof(pthread_t)); + (*new)->td = (pthread_t *)apr_pcalloc(pool, sizeof(pthread_t)); if ((*new)->td == NULL) { return APR_ENOMEM; } - (*new)->cntxt = cont; + (*new)->data = data; + (*new)->func = func; if (attr) - temp = attr->attr; + temp = &attr->attr; else temp = NULL; - - stat = ap_create_pool(&(*new)->cntxt, cont); + + stat = apr_pool_create(&(*new)->pool, pool); if (stat != APR_SUCCESS) { return stat; } - if ((stat = pthread_create((*new)->td, temp, func, data)) == 0) { + if ((stat = pthread_create((*new)->td, temp, dummy_worker, (*new))) == 0) { return APR_SUCCESS; } else { +#ifdef HAVE_ZOS_PTHREADS + stat = errno; +#endif + return stat; - } + } +} + +APR_DECLARE(apr_os_thread_t) apr_os_thread_current(void) +{ + return pthread_self(); +} + +APR_DECLARE(int) apr_os_thread_equal(apr_os_thread_t tid1, + apr_os_thread_t tid2) +{ + return pthread_equal(tid1, tid2); } -ap_status_t ap_thread_exit(ap_thread_t *thd, ap_status_t *retval) +APR_DECLARE(apr_status_t) apr_thread_exit(apr_thread_t *thd, + apr_status_t retval) { - ap_destroy_pool(thd->cntxt); - pthread_exit(retval); + thd->exitval = retval; + apr_pool_destroy(thd->pool); + pthread_exit(NULL); return APR_SUCCESS; } -ap_status_t ap_thread_join(ap_status_t *retval, ap_thread_t *thd) +APR_DECLARE(apr_status_t) apr_thread_join(apr_status_t *retval, + apr_thread_t *thd) { - ap_status_t stat; + apr_status_t stat; + apr_status_t *thread_stat; - if ((stat = pthread_join(*thd->td,(void *)&retval)) == 0) { + if ((stat = pthread_join(*thd->td,(void *)&thread_stat)) == 0) { + *retval = thd->exitval; return APR_SUCCESS; } else { +#ifdef HAVE_ZOS_PTHREADS + stat = errno; +#endif + return stat; } } -ap_status_t ap_thread_detach(ap_thread_t *thd) +APR_DECLARE(apr_status_t) apr_thread_detach(apr_thread_t *thd) { - ap_status_t stat; + apr_status_t stat; +#ifdef HAVE_ZOS_PTHREADS + if ((stat = pthread_detach(thd->td)) == 0) { +#else if ((stat = pthread_detach(*thd->td)) == 0) { +#endif + return APR_SUCCESS; } else { +#ifdef HAVE_ZOS_PTHREADS + stat = errno; +#endif + return stat; } } -ap_status_t ap_get_threaddata(void **data, char *key, ap_thread_t *thread) +APR_DECLARE(void) apr_thread_yield(void) { - if (thread != NULL) { - return ap_get_userdata(data, key, thread->cntxt); - } - else { - data = NULL; - return APR_ENOTHREAD; - } +#ifdef HAVE_PTHREAD_YIELD +#ifdef HAVE_ZOS_PTHREADS + pthread_yield(NULL); +#else + pthread_yield(); +#endif /* HAVE_ZOS_PTHREADS */ +#else +#ifdef HAVE_SCHED_YIELD + sched_yield(); +#endif +#endif } -ap_status_t ap_set_threaddata(void *data, char *key, - ap_status_t (*cleanup) (void *), - ap_thread_t *thread) +APR_DECLARE(apr_status_t) apr_thread_data_get(void **data, const char *key, + apr_thread_t *thread) { - if (thread != NULL) { - return ap_set_userdata(data, key, cleanup, thread->cntxt); - } - else { - data = NULL; - return APR_ENOTHREAD; - } + return apr_pool_userdata_get(data, key, thread->pool); } -ap_status_t ap_get_os_thread(ap_os_thread_t *thethd, ap_thread_t *thd) +APR_DECLARE(apr_status_t) apr_thread_data_set(void *data, const char *key, + apr_status_t (*cleanup)(void *), + apr_thread_t *thread) { - if (thd == NULL) { - return APR_ENOTHREAD; - } - thethd = thd->td; + return apr_pool_userdata_set(data, key, cleanup, thread->pool); +} + +APR_DECLARE(apr_status_t) apr_os_thread_get(apr_os_thread_t **thethd, + apr_thread_t *thd) +{ + *thethd = thd->td; return APR_SUCCESS; } -ap_status_t ap_put_os_thread(ap_thread_t **thd, ap_os_thread_t *thethd, - ap_pool_t *cont) +APR_DECLARE(apr_status_t) apr_os_thread_put(apr_thread_t **thd, + apr_os_thread_t *thethd, + apr_pool_t *pool) { - if (cont == NULL) { + if (pool == NULL) { return APR_ENOPOOL; } + if ((*thd) == NULL) { - (*thd) = (ap_thread_t *)ap_palloc(cont, sizeof(ap_thread_t)); - (*thd)->cntxt = cont; + (*thd) = (apr_thread_t *)apr_pcalloc(pool, sizeof(apr_thread_t)); + (*thd)->pool = pool; } + (*thd)->td = thethd; return APR_SUCCESS; } + +APR_DECLARE(apr_status_t) apr_thread_once_init(apr_thread_once_t **control, + apr_pool_t *p) +{ + static const pthread_once_t once_init = PTHREAD_ONCE_INIT; + + *control = apr_palloc(p, sizeof(**control)); + (*control)->once = once_init; + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_thread_once(apr_thread_once_t *control, + void (*func)(void)) +{ + return pthread_once(&control->once, func); +} + +APR_POOL_IMPLEMENT_ACCESSOR(thread) + #endif /* HAVE_PTHREAD_H */ #endif /* APR_HAS_THREADS */ +#if !APR_HAS_THREADS + +/* avoid warning for no prototype */ +APR_DECLARE(apr_status_t) apr_os_thread_get(void); + +APR_DECLARE(apr_status_t) apr_os_thread_get(void) +{ + return APR_ENOTIMPL; +} + +#endif diff --git a/threadproc/unix/threadcancel.c b/threadproc/unix/threadcancel.c deleted file mode 100644 index 81e3d3e7cd5..00000000000 --- a/threadproc/unix/threadcancel.c +++ /dev/null @@ -1,114 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#include "threadproc.h" -#if APR_HAS_THREADS - -#ifdef HAVE_PTHREAD_H - -#if 0 /* some platforms, e.g. FreeBSD 2.2.8, do not have pthread_cancel (they do have an undocumented pthread_kill, though) */ -/* ***APRDOC******************************************************** - * ap_status_t ap_cancel_thread(ap_thread_t *thd) - * Asynchronously kill a thread - * arg 1) The thread to kill. - */ -ap_status_t ap_cancel_thread(ap_thread_t *thd) -{ - ap_status_t stat; - if ((stat = pthread_cancel(*thd->td)) == 0) { - return APR_SUCCESS; - } - else { - return stat; - } -} -#endif - -/* ***APRDOC******************************************************** - * ap_status_t ap_setcanceltype(ap_int32_t type, ap_pool_t *cont) - * Determine how threads are cancelable. - * arg 1) how are threads cancelable. One of: - * APR_CANCEL_ASYNCH -- cancel it no matter where it is - * APR_CANCEL_DEFER -- only cancel the thread if it is safe. - * arg 2) The context to operate on - */ -ap_status_t ap_setcanceltype(ap_int32_t type, ap_pool_t *cont) -{ - ap_status_t stat; - if ((stat = pthread_setcanceltype(type, NULL)) == 0) { - return APR_SUCCESS; - } - else { - return stat; - } -} - -/* ***APRDOC******************************************************** - * ap_status_t ap_setcancelstate(ap_int32_t type, ap_pool_t *cont) - * Determine if threads will be cancelable. - * arg 1) Are threads cancelable. - * arg 2) The context to operate on - */ -ap_status_t ap_setcancelstate(ap_int32_t type, ap_pool_t *cont) -{ - ap_status_t stat; - if ((stat = pthread_setcanceltype(type, NULL)) == 0) { - return APR_SUCCESS; - } - else { - return stat; - } -} -#endif -#endif diff --git a/threadproc/unix/threadpriv.c b/threadproc/unix/threadpriv.c index 9d82395a6e9..c2785203801 100644 --- a/threadproc/unix/threadpriv.c +++ b/threadproc/unix/threadpriv.c @@ -1,90 +1,59 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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 "threadproc.h" +#include "apr.h" #include "apr_portable.h" +#include "apr_arch_threadproc.h" #if APR_HAS_THREADS -#ifdef HAVE_PTHREAD_H -ap_status_t ap_create_thread_private(ap_threadkey_t **key, - void (*dest)(void *), ap_pool_t *cont) +#if APR_HAVE_PTHREAD_H +APR_DECLARE(apr_status_t) apr_threadkey_private_create(apr_threadkey_t **key, + void (*dest)(void *), + apr_pool_t *pool) { - ap_status_t stat; - (*key) = (ap_threadkey_t *)ap_palloc(cont, sizeof(ap_threadkey_t)); + (*key) = (apr_threadkey_t *)apr_pcalloc(pool, sizeof(apr_threadkey_t)); if ((*key) == NULL) { return APR_ENOMEM; } - (*key)->cntxt = cont; + (*key)->pool = pool; + + return pthread_key_create(&(*key)->key, dest); - if ((stat = pthread_key_create(&(*key)->key, dest)) == 0) { - return stat; - } - return stat; } -ap_status_t ap_get_thread_private(void **new, ap_threadkey_t *key) +APR_DECLARE(apr_status_t) apr_threadkey_private_get(void **new, + apr_threadkey_t *key) { +#ifdef PTHREAD_GETSPECIFIC_TAKES_TWO_ARGS + if (pthread_getspecific(key->key,new)) + *new = NULL; +#else (*new) = pthread_getspecific(key->key); +#endif return APR_SUCCESS; } -ap_status_t ap_set_thread_private(void *priv, ap_threadkey_t *key) +APR_DECLARE(apr_status_t) apr_threadkey_private_set(void *priv, + apr_threadkey_t *key) { - ap_status_t stat; + apr_status_t stat; + if ((stat = pthread_setspecific(key->key, priv)) == 0) { return APR_SUCCESS; } @@ -93,60 +62,68 @@ ap_status_t ap_set_thread_private(void *priv, ap_threadkey_t *key) } } -ap_status_t ap_delete_thread_private(ap_threadkey_t *key) +APR_DECLARE(apr_status_t) apr_threadkey_private_delete(apr_threadkey_t *key) { - ap_status_t stat; +#ifdef HAVE_PTHREAD_KEY_DELETE + apr_status_t stat; + if ((stat = pthread_key_delete(key->key)) == 0) { - return APR_SUCCESS; + return APR_SUCCESS; } + return stat; +#else + return APR_ENOTIMPL; +#endif } -ap_status_t ap_get_threadkeydata(void **data, char *key, ap_threadkey_t *threadkey) +APR_DECLARE(apr_status_t) apr_threadkey_data_get(void **data, const char *key, + apr_threadkey_t *threadkey) { - if (threadkey != NULL) { - return ap_get_userdata(data, key, threadkey->cntxt); - } - else { - data = NULL; - return APR_ENOTHDKEY; - } + return apr_pool_userdata_get(data, key, threadkey->pool); } -ap_status_t ap_set_threadkeydata(void *data, - char *key, ap_status_t (*cleanup) (void *), - ap_threadkey_t *threadkey) +APR_DECLARE(apr_status_t) apr_threadkey_data_set(void *data, const char *key, + apr_status_t (*cleanup)(void *), + apr_threadkey_t *threadkey) { - if (threadkey != NULL) { - return ap_set_userdata(data, key, cleanup, threadkey->cntxt); - } - else { - data = NULL; - return APR_ENOTHDKEY; - } + return apr_pool_userdata_set(data, key, cleanup, threadkey->pool); } -ap_status_t ap_get_os_threadkey(ap_os_threadkey_t *thekey, ap_threadkey_t *key) +APR_DECLARE(apr_status_t) apr_os_threadkey_get(apr_os_threadkey_t *thekey, + apr_threadkey_t *key) { - if (key == NULL) { - return APR_ENOFILE; - } - thekey = &(key->key); + *thekey = key->key; return APR_SUCCESS; } -ap_status_t ap_put_os_threadkey(ap_threadkey_t **key, - ap_os_threadkey_t *thekey, ap_pool_t *cont) +APR_DECLARE(apr_status_t) apr_os_threadkey_put(apr_threadkey_t **key, + apr_os_threadkey_t *thekey, + apr_pool_t *pool) { - if (cont == NULL) { + if (pool == NULL) { return APR_ENOPOOL; } + if ((*key) == NULL) { - (*key) = (ap_threadkey_t *)ap_palloc(cont, sizeof(ap_threadkey_t)); - (*key)->cntxt = cont; + (*key) = (apr_threadkey_t *)apr_pcalloc(pool, sizeof(apr_threadkey_t)); + (*key)->pool = pool; } + (*key)->key = *thekey; return APR_SUCCESS; -} -#endif +} +#endif /* APR_HAVE_PTHREAD_H */ +#endif /* APR_HAS_THREADS */ + +#if !APR_HAS_THREADS + +/* avoid warning for no prototype */ +APR_DECLARE(apr_status_t) apr_os_threadkey_get(void); + +APR_DECLARE(apr_status_t) apr_os_threadkey_get(void) +{ + return APR_ENOTIMPL; +} + #endif diff --git a/threadproc/unix/threadproc.h b/threadproc/unix/threadproc.h deleted file mode 100644 index ea4c8289db7..00000000000 --- a/threadproc/unix/threadproc.h +++ /dev/null @@ -1,126 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#include "apr_private.h" -#include "apr_thread_proc.h" -#include "apr_file_io.h" -#include "fileio.h" - -/* System headers required for thread/process library */ -#if HAVE_PTHREAD_H -#include <pthread.h> -#endif -#if HAVE_SIGNAL_H -#include <signal.h> -#endif -#if HAVE_STRING_H -#include <string.h> -#endif -#if HAVE_SYS_WAIT_H -#include <sys/wait.h> -#endif -#if HAVE_STRING_H -#include <string.h> -#endif -/* End System Headers */ - - -#ifndef THREAD_PROC_H -#define THREAD_PROC_H - -#define SHELL_PATH "/bin/sh" - -#if APR_HAS_THREADS -struct ap_thread_t { - ap_pool_t *cntxt; - pthread_t *td; -}; - -struct ap_threadattr_t { - ap_pool_t *cntxt; - pthread_attr_t *attr; -}; - -struct ap_threadkey_t { - ap_pool_t *cntxt; - pthread_key_t key; -}; -#endif - -struct ap_procattr_t { - ap_pool_t *cntxt; - ap_file_t *parent_in; - ap_file_t *child_in; - ap_file_t *parent_out; - ap_file_t *child_out; - ap_file_t *parent_err; - ap_file_t *child_err; - char *currdir; - ap_int32_t cmdtype; - ap_int32_t detached; -}; - -struct ap_proc_t { - ap_pool_t *cntxt; - pid_t pid; - struct ap_procattr_t *attr; -}; - -/*This will move to ap_threadproc.h in time, but I need to figure it out - * on windows first. :) - */ -ap_status_t ap_detach(struct ap_proc_t **, ap_pool_t *); - -#endif /* ! THREAD_PROC_H */ - diff --git a/threadproc/win32/proc.c b/threadproc/win32/proc.c index b516a2cdcb5..0357b0bd87d 100644 --- a/threadproc/win32/proc.c +++ b/threadproc/win32/proc.c @@ -1,322 +1,654 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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 "threadproc.h" -#include "fileio.h" +#include "apr_arch_threadproc.h" +#include "apr_arch_file_io.h" #include "apr_thread_proc.h" #include "apr_file_io.h" #include "apr_general.h" -#include "apr_lib.h" +#include "apr_strings.h" #include "apr_portable.h" +#include "apr_lib.h" #include <stdlib.h> +#if APR_HAVE_SIGNAL_H #include <signal.h> +#endif #include <string.h> +#ifdef HAVE_PROCESS_H #include <process.h> +#endif -ap_status_t ap_createprocattr_init(ap_procattr_t **new, ap_pool_t *cont) -{ - (*new) = (ap_procattr_t *)ap_palloc(cont, - sizeof(ap_procattr_t)); +/* Heavy on no'ops, here's what we want to pass if there is APR_NO_FILE + * requested for a specific child handle; + */ +static apr_file_t no_file = { NULL, INVALID_HANDLE_VALUE, }; - if ((*new) == NULL) { - return APR_ENOMEM; - } - (*new)->cntxt = cont; - (*new)->parent_in = NULL; - (*new)->child_in = NULL; - (*new)->parent_out = NULL; - (*new)->child_out = NULL; - (*new)->parent_err = NULL; - (*new)->child_err = NULL; - (*new)->currdir = NULL; - (*new)->cmdtype = APR_PROGRAM; - (*new)->detached = TRUE; +/* We have very carefully excluded volumes of definitions from the + * Microsoft Platform SDK, which kill the build time performance. + * These the sole constants we borrow from WinBase.h and WinUser.h + */ +#ifndef LOGON32_LOGON_NETWORK +#define LOGON32_LOGON_NETWORK 3 +#endif - memset(&(*new)->si, 0, sizeof((*new)->si)); +#ifdef _WIN32_WCE +#ifndef DETACHED_PROCESS +#define DETACHED_PROCESS 0 +#endif +#ifndef CREATE_UNICODE_ENVIRONMENT +#define CREATE_UNICODE_ENVIRONMENT 0 +#endif +#ifndef STARTF_USESHOWWINDOW +#define STARTF_USESHOWWINDOW 0 +#endif +#ifndef SW_HIDE +#define SW_HIDE 0 +#endif +#endif +/* + * some of the ideas expressed herein are based off of Microsoft + * Knowledge Base article: Q190351 + * + */ +APR_DECLARE(apr_status_t) apr_procattr_create(apr_procattr_t **new, + apr_pool_t *pool) +{ + (*new) = (apr_procattr_t *)apr_pcalloc(pool, sizeof(apr_procattr_t)); + (*new)->pool = pool; + (*new)->cmdtype = APR_PROGRAM; return APR_SUCCESS; } -ap_status_t ap_setprocattr_io(ap_procattr_t *attr, ap_int32_t in, - ap_int32_t out, ap_int32_t err) +APR_DECLARE(apr_status_t) apr_procattr_io_set(apr_procattr_t *attr, + apr_int32_t in, + apr_int32_t out, + apr_int32_t err) { - ap_status_t stat; + apr_status_t stat = APR_SUCCESS; + if (in) { - if ((stat = ap_create_pipe(&attr->child_in, &attr->parent_in, - attr->cntxt)) != APR_SUCCESS) { - return stat; + /* APR_CHILD_BLOCK maps to APR_WRITE_BLOCK, while + * APR_PARENT_BLOCK maps to APR_READ_BLOCK, so transpose + * the CHILD/PARENT blocking flags for the stdin pipe. + * stdout/stderr map to the correct mode by default. + */ + if (in == APR_CHILD_BLOCK) + in = APR_READ_BLOCK; + else if (in == APR_PARENT_BLOCK) + in = APR_WRITE_BLOCK; + + if (in == APR_NO_FILE) + attr->child_in = &no_file; + else { + stat = apr_file_pipe_create_ex(&attr->child_in, &attr->parent_in, + in, attr->pool); } + if (stat == APR_SUCCESS) + stat = apr_file_inherit_unset(attr->parent_in); } - if (out) { - if ((stat = ap_create_pipe(&attr->parent_out, &attr->child_out, - attr->cntxt)) != APR_SUCCESS) { - return stat; + if (out && stat == APR_SUCCESS) { + if (out == APR_NO_FILE) + attr->child_out = &no_file; + else { + stat = apr_file_pipe_create_ex(&attr->parent_out, &attr->child_out, + out, attr->pool); } + if (stat == APR_SUCCESS) + stat = apr_file_inherit_unset(attr->parent_out); } - if (err) { - if ((stat = ap_create_pipe(&attr->parent_err, &attr->child_err, - attr->cntxt)) != APR_SUCCESS) { - return stat; + if (err && stat == APR_SUCCESS) { + if (err == APR_NO_FILE) + attr->child_err = &no_file; + else { + stat = apr_file_pipe_create_ex(&attr->parent_err, &attr->child_err, + err, attr->pool); } - } - return APR_SUCCESS; + if (stat == APR_SUCCESS) + stat = apr_file_inherit_unset(attr->parent_err); + } + return stat; +} + +APR_DECLARE(apr_status_t) apr_procattr_child_in_set(apr_procattr_t *attr, + apr_file_t *child_in, + apr_file_t *parent_in) +{ + apr_status_t rv = APR_SUCCESS; + + if (child_in) { + if ((attr->child_in == NULL) || (attr->child_in == &no_file)) + rv = apr_file_dup(&attr->child_in, child_in, attr->pool); + else + rv = apr_file_dup2(attr->child_in, child_in, attr->pool); + + if (rv == APR_SUCCESS) + rv = apr_file_inherit_set(attr->child_in); + } + + if (parent_in && rv == APR_SUCCESS) { + if (attr->parent_in == NULL) + rv = apr_file_dup(&attr->parent_in, parent_in, attr->pool); + else + rv = apr_file_dup2(attr->parent_in, parent_in, attr->pool); + } + + return rv; } -#if 0 -ap_status_t ap_setprocattr_childin(ap_procattr_t *attr, ap_file_t *child_in, - ap_file_t *parent_in) + +APR_DECLARE(apr_status_t) apr_procattr_child_out_set(apr_procattr_t *attr, + apr_file_t *child_out, + apr_file_t *parent_out) { + apr_status_t rv = APR_SUCCESS; + + if (child_out) { + if ((attr->child_out == NULL) || (attr->child_out == &no_file)) + rv = apr_file_dup(&attr->child_out, child_out, attr->pool); + else + rv = apr_file_dup2(attr->child_out, child_out, attr->pool); + + if (rv == APR_SUCCESS) + rv = apr_file_inherit_set(attr->child_out); + } + + if (parent_out && rv == APR_SUCCESS) { + if (attr->parent_out == NULL) + rv = apr_file_dup(&attr->parent_out, parent_out, attr->pool); + else + rv = apr_file_dup2(attr->parent_out, parent_out, attr->pool); + } + + return rv; } -ap_status_t ap_setprocattr_childout(ap_procattr_t *attr, ap_file_t *child_out, - ap_file_t *parent_out) + +APR_DECLARE(apr_status_t) apr_procattr_child_err_set(apr_procattr_t *attr, + apr_file_t *child_err, + apr_file_t *parent_err) { - if (attr->child_out == NULL && attr->parent_out == NULL) - ap_create_pipe(&attr->child_out, &attr->parent_out, attr->cntxt); + apr_status_t rv = APR_SUCCESS; - if (child_out != NULL) - ap_dupfile(&attr->child_out, child_out, attr->cntxt); + if (child_err) { + if ((attr->child_err == NULL) || (attr->child_err == &no_file)) + rv = apr_file_dup(&attr->child_err, child_err, attr->pool); + else + rv = apr_file_dup2(attr->child_err, child_err, attr->pool); - if (parent_out != NULL) - ap_dupfile(&attr->parent_out, parent_out, attr->cntxt); + if (rv == APR_SUCCESS) + rv = apr_file_inherit_set(attr->child_err); + } - return APR_SUCCESS; + if (parent_err && rv == APR_SUCCESS) { + if (attr->parent_err == NULL) + rv = apr_file_dup(&attr->parent_err, parent_err, attr->pool); + else + rv = apr_file_dup2(attr->parent_err, parent_err, attr->pool); + } + + return rv; +} + +APR_DECLARE(apr_status_t) apr_procattr_dir_set(apr_procattr_t *attr, + const char *dir) +{ + /* curr dir must be in native format, there are all sorts of bugs in + * the NT library loading code that flunk the '/' parsing test. + */ + return apr_filepath_merge(&attr->currdir, NULL, dir, + APR_FILEPATH_NATIVE, attr->pool); } -ap_status_t ap_setprocattr_childerr(ap_procattr_t *attr, ap_file_t *child_err, - ap_file_t *parent_err) + +APR_DECLARE(apr_status_t) apr_procattr_cmdtype_set(apr_procattr_t *attr, + apr_cmdtype_e cmd) { - if (attr->child_err == NULL && attr->parent_err == NULL) - ap_create_pipe(&attr->child_err, &attr->parent_err, attr->cntxt); + attr->cmdtype = cmd; + return APR_SUCCESS; +} - if (child_err != NULL) - ap_dupfile(&attr->child_err, child_err, attr->cntxt); +APR_DECLARE(apr_status_t) apr_procattr_detach_set(apr_procattr_t *attr, + apr_int32_t det) +{ + attr->detached = det; + return APR_SUCCESS; +} - if (parent_err != NULL) - ap_dupfile(&attr->parent_err, parent_err, attr->cntxt); +#ifndef _WIN32_WCE +static apr_status_t attr_cleanup(void *theattr) +{ + apr_procattr_t *attr = (apr_procattr_t *)theattr; + if (attr->user_token) + CloseHandle(attr->user_token); + attr->user_token = NULL; return APR_SUCCESS; } #endif -ap_status_t ap_setprocattr_dir(ap_procattr_t *attr, - const char *dir) + +APR_DECLARE(apr_status_t) apr_procattr_user_set(apr_procattr_t *attr, + const char *username, + const char *password) { - char path[MAX_PATH]; - int length; +#ifdef _WIN32_WCE + return APR_ENOTIMPL; +#else + HANDLE user; + apr_wchar_t *wusername = NULL; + apr_wchar_t *wpassword = NULL; + apr_status_t rv; + apr_size_t len, wlen; - if (dir[0] != '\\' && dir[0] != '/' && dir[1] != ':') { - length = GetCurrentDirectory(MAX_PATH, path); + if (apr_os_level >= APR_WIN_NT_4) + { + if (attr->user_token) { + /* Cannot set that twice */ + if (attr->errfn) { + attr->errfn(attr->pool, 0, + apr_pstrcat(attr->pool, + "function called twice" + " on username: ", username, NULL)); + } + return APR_EINVAL; + } + len = strlen(username) + 1; + wlen = len; + wusername = apr_palloc(attr->pool, wlen * sizeof(apr_wchar_t)); + if ((rv = apr_conv_utf8_to_ucs2(username, &len, wusername, &wlen)) + != APR_SUCCESS) { + if (attr->errfn) { + attr->errfn(attr->pool, rv, + apr_pstrcat(attr->pool, + "utf8 to ucs2 conversion failed" + " on username: ", username, NULL)); + } + return rv; + } + if (password) { + len = strlen(password) + 1; + wlen = len; + wpassword = apr_palloc(attr->pool, wlen * sizeof(apr_wchar_t)); + if ((rv = apr_conv_utf8_to_ucs2(password, &len, wpassword, &wlen)) + != APR_SUCCESS) { + if (attr->errfn) { + attr->errfn(attr->pool, rv, + apr_pstrcat(attr->pool, + "utf8 to ucs2 conversion failed" + " on password: ", password, NULL)); + } + return rv; + } + } + if (!LogonUserW(wusername, + NULL, + wpassword ? wpassword : L"", + LOGON32_LOGON_NETWORK, + LOGON32_PROVIDER_DEFAULT, + &user)) { + /* Logon Failed */ + return apr_get_os_error(); + } + if (wpassword) + memset(wpassword, 0, wlen * sizeof(apr_wchar_t)); + /* Get the primary token for user */ + if (!DuplicateTokenEx(user, + TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY, + NULL, + SecurityImpersonation, + TokenPrimary, + &(attr->user_token))) { + /* Failed to duplicate the user token */ + rv = apr_get_os_error(); + CloseHandle(user); + return rv; + } + CloseHandle(user); - if (length == 0 || length + strlen(dir) + 1 >= MAX_PATH) - return APR_ENOMEM; + attr->sd = apr_pcalloc(attr->pool, SECURITY_DESCRIPTOR_MIN_LENGTH); + InitializeSecurityDescriptor(attr->sd, SECURITY_DESCRIPTOR_REVISION); + SetSecurityDescriptorDacl(attr->sd, -1, 0, 0); + attr->sa = apr_palloc(attr->pool, sizeof(SECURITY_ATTRIBUTES)); + attr->sa->nLength = sizeof (SECURITY_ATTRIBUTES); + attr->sa->lpSecurityDescriptor = attr->sd; + attr->sa->bInheritHandle = FALSE; - attr->currdir = ap_pstrcat(attr->cntxt, path, "\\", dir, NULL); + /* register the cleanup */ + apr_pool_cleanup_register(attr->pool, (void *)attr, + attr_cleanup, + apr_pool_cleanup_null); + return APR_SUCCESS; } - else { - attr->currdir = ap_pstrdup(attr->cntxt, dir); + else + return APR_ENOTIMPL; +#endif +} + +APR_DECLARE(apr_status_t) apr_procattr_group_set(apr_procattr_t *attr, + const char *groupname) +{ + /* Always return SUCCESS cause groups are irrelevant */ + return APR_SUCCESS; +} + +static const char* has_space(const char *str) +{ + const char *ch; + for (ch = str; *ch; ++ch) { + if (apr_isspace(*ch)) { + return ch; + } } + return NULL; +} - if (attr->currdir) { - return APR_SUCCESS; +static char *apr_caret_escape_args(apr_pool_t *p, const char *str) +{ + char *cmd; + unsigned char *d; + const unsigned char *s; + + cmd = apr_palloc(p, 2 * strlen(str) + 1); /* Be safe */ + d = (unsigned char *)cmd; + s = (const unsigned char *)str; + for (; *s; ++s) { + + /* + * Newlines to Win32/OS2 CreateProcess() are ill advised. + * Convert them to spaces since they are effectively white + * space to most applications + */ + if (*s == '\r' || *s == '\n') { + *d++ = ' '; + continue; + } + + if (IS_SHCHAR(*s)) { + *d++ = '^'; + } + *d++ = *s; } - return APR_ENOMEM; + *d = '\0'; + + return cmd; } -ap_status_t ap_setprocattr_cmdtype(ap_procattr_t *attr, - ap_cmdtype_e cmd) +APR_DECLARE(apr_status_t) apr_procattr_child_errfn_set(apr_procattr_t *attr, + apr_child_errfn_t *errfn) { - attr->cmdtype = cmd; + attr->errfn = errfn; return APR_SUCCESS; } -ap_status_t ap_setprocattr_detach(ap_procattr_t *attr, ap_int32_t det) +APR_DECLARE(apr_status_t) apr_procattr_error_check_set(apr_procattr_t *attr, + apr_int32_t chk) { - attr->detached = det; + attr->errchk = chk; return APR_SUCCESS; } -ap_status_t ap_create_process(ap_proc_t **new, const char *progname, - char *const args[], char **env, - ap_procattr_t *attr, ap_pool_t *cont) +APR_DECLARE(apr_status_t) apr_procattr_addrspace_set(apr_procattr_t *attr, + apr_int32_t addrspace) { - int i, iEnvBlockLen; - char *cmdline; - HANDLE hCurrentProcess; - HANDLE hParentindup, hParentoutdup,hParenterrdup; - char ppid[20]; - char *envstr; - char *pEnvBlock, *pNext; + /* won't ever be used on this platform, so don't save the flag */ + return APR_SUCCESS; +} - (*new) = (ap_proc_t *)ap_palloc(cont, sizeof(ap_proc_t)); +#if APR_HAS_UNICODE_FS && !defined(_WIN32_WCE) - if ((*new) == NULL) { - return APR_ENOMEM; +/* Used only for the NT code path, a critical section is the fastest + * implementation available. + */ +static CRITICAL_SECTION proc_lock; + +static apr_status_t threadproc_global_cleanup(void *ignored) +{ + DeleteCriticalSection(&proc_lock); + return APR_SUCCESS; +} + +/* Called from apr_initialize, we need a critical section to handle + * the pipe inheritance on win32. This will mutex any process create + * so as we change our inherited pipes, we prevent another process from + * also inheriting those alternate handles, and prevent the other process + * from failing to inherit our standard handles. + */ +apr_status_t apr_threadproc_init(apr_pool_t *pool) +{ + IF_WIN_OS_IS_UNICODE + { + InitializeCriticalSection(&proc_lock); + /* register the cleanup */ + apr_pool_cleanup_register(pool, &proc_lock, + threadproc_global_cleanup, + apr_pool_cleanup_null); } + return APR_SUCCESS; +} + +#else /* !APR_HAS_UNICODE_FS || defined(_WIN32_WCE) */ + +apr_status_t apr_threadproc_init(apr_pool_t *pool) +{ + return APR_SUCCESS; +} - (*new)->cntxt = cont; - (*new)->attr = attr; +#endif + +APR_DECLARE(apr_status_t) apr_proc_create(apr_proc_t *new, + const char *progname, + const char * const *args, + const char * const *env, + apr_procattr_t *attr, + apr_pool_t *pool) +{ + apr_status_t rv; + apr_size_t i; + const char *argv0; + char *cmdline; + char *pEnvBlock; + PROCESS_INFORMATION pi; + DWORD dwCreationFlags = 0; + + new->in = attr->parent_in; + new->out = attr->parent_out; + new->err = attr->parent_err; - attr->si.cb = sizeof(attr->si); if (attr->detached) { - /* If we are creating ourselves detached, Then we should hide the - * window we are starting in. And we had better redfine our - * handles for STDIN, STDOUT, and STDERR. + /* If we are creating ourselves detached, then we should hide the + * window we are starting in. And we had better redefine our + * handles for STDIN, STDOUT, and STDERR. Do not set the + * detached attribute for Win9x. We have found that Win9x does + * not manage the stdio handles properly when running old 16 + * bit executables if the detached attribute is set. */ - attr->si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES; - attr->si.wShowWindow = SW_HIDE; - - if (attr->child_in) { - attr->si.hStdInput = attr->child_in->filehand; + if (apr_os_level >= APR_WIN_NT) { + /* + * XXX DETACHED_PROCESS won't on Win9x at all; on NT/W2K + * 16 bit executables fail (MS KB: Q150956) + */ + dwCreationFlags |= DETACHED_PROCESS; } + } - if (attr->child_out) { - attr->si.hStdOutput = attr->child_out->filehand; - } + /* progname must be unquoted, in native format, as there are all sorts + * of bugs in the NT library loader code that fault when parsing '/'. + * XXX progname must be NULL if this is a 16 bit app running in WOW + */ + if (progname[0] == '\"') { + progname = apr_pstrmemdup(pool, progname + 1, strlen(progname) - 2); + } - if (attr->child_err) { - attr->si.hStdError = attr->child_err->filehand; + if (attr->cmdtype == APR_PROGRAM || attr->cmdtype == APR_PROGRAM_ENV) { + char *fullpath = NULL; + if ((rv = apr_filepath_merge(&fullpath, attr->currdir, progname, + APR_FILEPATH_NATIVE, pool)) != APR_SUCCESS) { + if (attr->errfn) { + attr->errfn(pool, rv, + apr_pstrcat(pool, "filepath_merge failed.", + " currdir: ", attr->currdir, + " progname: ", progname, NULL)); + } + return rv; } + progname = fullpath; + } + else { + /* Do not fail if the path isn't parseable for APR_PROGRAM_PATH + * or APR_SHELLCMD. We only invoke apr_filepath_merge (with no + * left hand side expression) in order to correct the path slash + * delimiters. But the filename doesn't need to be in the CWD, + * nor does it need to be a filename at all (it could be a + * built-in shell command.) + */ + char *fullpath = NULL; + if ((rv = apr_filepath_merge(&fullpath, "", progname, + APR_FILEPATH_NATIVE, pool)) == APR_SUCCESS) { + progname = fullpath; + } } - if (attr->cmdtype == APR_PROGRAM) { - const char *ptr = progname; + if (has_space(progname)) { + argv0 = apr_pstrcat(pool, "\"", progname, "\"", NULL); + } + else { + argv0 = progname; + } - if (*ptr =='"') { - ptr++; + /* Handle the args, seperate from argv0 */ + cmdline = ""; + for (i = 1; args && args[i]; ++i) { + if (has_space(args[i]) || !args[i][0]) { + cmdline = apr_pstrcat(pool, cmdline, " \"", args[i], "\"", NULL); } + else { + cmdline = apr_pstrcat(pool, cmdline, " ", args[i], NULL); + } + } - if (*ptr == '\\' || *++ptr == ':') { - cmdline = ap_pstrdup(cont, progname); +#ifndef _WIN32_WCE + if (attr->cmdtype == APR_SHELLCMD || attr->cmdtype == APR_SHELLCMD_ENV) { + char *shellcmd = getenv("COMSPEC"); + if (!shellcmd) { + if (attr->errfn) { + attr->errfn(pool, APR_EINVAL, "COMSPEC envar is not set"); + } + return APR_EINVAL; } - else if (attr->currdir == NULL) { - cmdline = ap_pstrdup(cont, progname); + if (shellcmd[0] == '"') { + progname = apr_pstrmemdup(pool, shellcmd + 1, strlen(shellcmd) - 2); } else { - char lastchar = attr->currdir[strlen(attr->currdir)-1]; - if ( lastchar == '\\' || lastchar == '/') { - cmdline = ap_pstrcat(cont, attr->currdir, progname, NULL); + progname = shellcmd; + if (has_space(shellcmd)) { + shellcmd = apr_pstrcat(pool, "\"", shellcmd, "\"", NULL); + } + } + /* Command.com does not support a quoted command, while cmd.exe demands one. + */ + i = strlen(progname); + if (i >= 11 && strcasecmp(progname + i - 11, "command.com") == 0) { + cmdline = apr_pstrcat(pool, shellcmd, " /C ", argv0, cmdline, NULL); + } + else { + cmdline = apr_pstrcat(pool, shellcmd, " /C \"", argv0, cmdline, "\"", NULL); + } + } + else +#endif + { +#if defined(_WIN32_WCE) + { +#else + /* Win32 is _different_ than unix. While unix will find the given + * program since it's already chdir'ed, Win32 cannot since the parent + * attempts to open the program with it's own path. + * ###: This solution isn't much better - it may defeat path searching + * when the path search was desired. Open to further discussion. + */ + i = strlen(progname); + if (i >= 4 && (strcasecmp(progname + i - 4, ".bat") == 0 + || strcasecmp(progname + i - 4, ".cmd") == 0)) + { + char *shellcmd = getenv("COMSPEC"); + if (!shellcmd) { + if (attr->errfn) { + attr->errfn(pool, APR_EINVAL, "COMSPEC envar is not set"); + } + return APR_EINVAL; + } + if (shellcmd[0] == '"') { + progname = apr_pstrmemdup(pool, shellcmd + 1, strlen(shellcmd) - 2); } else { - cmdline = ap_pstrcat(cont, attr->currdir, "\\", progname, NULL); + progname = shellcmd; + if (has_space(shellcmd)) { + shellcmd = apr_pstrcat(pool, "\"", shellcmd, "\"", NULL); + } + } + i = strlen(progname); + if (i >= 11 && strcasecmp(progname + i - 11, "command.com") == 0) { + /* XXX: Still insecure - need doubled-quotes on each individual + * arg of cmdline. Suspect we need to postpone cmdline parsing + * until this moment in all four code paths, with some flags + * to toggle 'which flavor' is needed. + */ + cmdline = apr_pstrcat(pool, shellcmd, " /C ", argv0, cmdline, NULL); + } + else { + /* We must protect the cmdline args from any interpolation - this + * is not a shellcmd, and the source of argv[] is untrusted. + * Notice we escape ALL the cmdline args, including the quotes + * around the individual args themselves. No sense in allowing + * the shift-state to be toggled, and the application will + * not see the caret escapes. + */ + cmdline = apr_caret_escape_args(pool, cmdline); + /* + * Our app name must always be quoted so the quotes surrounding + * the entire /c "command args" are unambigious. + */ + if (*argv0 != '"') { + cmdline = apr_pstrcat(pool, shellcmd, " /C \"\"", argv0, "\"", cmdline, "\"", NULL); + } + else { + cmdline = apr_pstrcat(pool, shellcmd, " /C \"", argv0, cmdline, "\"", NULL); + } } } - } - else { - char * shell_cmd = getenv("COMSPEC"); - if (!shell_cmd) - shell_cmd = SHELL_PATH; - shell_cmd = ap_pstrdup(cont, shell_cmd); - cmdline = ap_pstrcat(cont, shell_cmd, " /C ", progname, NULL); - } + else { +#endif + /* A simple command we are directly invoking. Do not pass + * the first arg to CreateProc() for APR_PROGRAM_PATH + * invocation, since it would need to be a literal and + * complete file path. That is; "c:\bin\aprtest.exe" + * would succeed, but "c:\bin\aprtest" or "aprtest.exe" + * can fail. + */ + cmdline = apr_pstrcat(pool, argv0, cmdline, NULL); - i = 1; - while (args && args[i]) { - cmdline = ap_pstrcat(cont, cmdline, " ", args[i], NULL); - i++; - } - /* - * When the pipe handles are created, the security descriptor - * indicates that the handle can be inherited. However, we do not - * want the server side handles to the pipe to be inherited by the - * child CGI process. If the child CGI does inherit the server - * side handles, then the child may be left around if the server - * closes its handles (e.g. if the http connection is aborted), - * because the child will have a valid copy of handles to both - * sides of the pipes, and no I/O error will occur. Microsoft - * recommends using DuplicateHandle to turn off the inherit bit - * under NT and Win95. - */ - hCurrentProcess = GetCurrentProcess(); - if ((attr->child_in && !DuplicateHandle(hCurrentProcess, attr->parent_in->filehand, - hCurrentProcess, - &hParentindup, 0, FALSE, - DUPLICATE_SAME_ACCESS)) - || (attr->child_out && !DuplicateHandle(hCurrentProcess, attr->parent_out->filehand, - hCurrentProcess, &hParentoutdup, - 0, FALSE, DUPLICATE_SAME_ACCESS)) - || (attr->child_err && !DuplicateHandle(hCurrentProcess, attr->parent_err->filehand, - hCurrentProcess, &hParenterrdup, - 0, FALSE, DUPLICATE_SAME_ACCESS))) { - if (attr->child_in) { - ap_close(attr->child_in); - ap_close(attr->parent_in); - } - if (attr->child_out) { - ap_close(attr->child_out); - ap_close(attr->parent_out); - } - if (attr->child_err) { - ap_close(attr->child_err); - ap_close(attr->parent_err); - } - return APR_EEXIST; - } - else { - if (attr->child_in) { - ap_close(attr->parent_in); - attr->parent_in->filehand = hParentindup; - } - if (attr->child_out) { - ap_close(attr->parent_out); - attr->parent_out->filehand = hParentoutdup; - } - if (attr->child_err) { - ap_close(attr->parent_err); - attr->parent_err->filehand = hParenterrdup; + if (attr->cmdtype == APR_PROGRAM_PATH) { + progname = NULL; + } } } - _itoa(_getpid(), ppid, 10); - if (env) { - envstr = ap_pstrcat(cont, "parentpid=", ppid, NULL); + if (!env || attr->cmdtype == APR_PROGRAM_ENV || + attr->cmdtype == APR_SHELLCMD_ENV) { + pEnvBlock = NULL; + } + else { + apr_size_t iEnvBlockLen; /* * Win32's CreateProcess call requires that the environment * be passed in an environment block, a null terminated block of @@ -328,127 +660,499 @@ ap_status_t ap_create_process(ap_proc_t **new, const char *progname, iEnvBlockLen += strlen(env[i]) + 1; i++; } - - pEnvBlock = (char *)ap_pcalloc(cont, iEnvBlockLen + strlen(envstr)); + if (!i) + ++iEnvBlockLen; + +#if APR_HAS_UNICODE_FS + IF_WIN_OS_IS_UNICODE + { + apr_wchar_t *pNext; + pEnvBlock = (char *)apr_palloc(pool, iEnvBlockLen * 2); + dwCreationFlags |= CREATE_UNICODE_ENVIRONMENT; + + i = 0; + pNext = (apr_wchar_t*)pEnvBlock; + while (env[i]) { + apr_size_t in = strlen(env[i]) + 1; + if ((rv = apr_conv_utf8_to_ucs2(env[i], &in, + pNext, &iEnvBlockLen)) + != APR_SUCCESS) { + if (attr->errfn) { + attr->errfn(pool, rv, + apr_pstrcat(pool, + "utf8 to ucs2 conversion failed" + " on this string: ", env[i], NULL)); + } + return rv; + } + pNext = wcschr(pNext, L'\0') + 1; + i++; + } + if (!i) + *(pNext++) = L'\0'; + *pNext = L'\0'; + } +#endif /* APR_HAS_UNICODE_FS */ +#if APR_HAS_ANSI_FS + ELSE_WIN_OS_IS_ANSI + { + char *pNext; + pEnvBlock = (char *)apr_palloc(pool, iEnvBlockLen); - i = 0; - pNext = pEnvBlock; - while (env[i]) { - strcpy(pNext, env[i]); - pNext = pNext + strlen(pNext) + 1; - i++; + i = 0; + pNext = pEnvBlock; + while (env[i]) { + strcpy(pNext, env[i]); + pNext = strchr(pNext, '\0') + 1; + i++; + } + if (!i) + *(pNext++) = '\0'; + *pNext = '\0'; } - strcpy(pNext, envstr); - } - else { - SetEnvironmentVariable("parentpid", ppid); - pEnvBlock = NULL; +#endif /* APR_HAS_ANSI_FS */ } - - if (CreateProcess(NULL, cmdline, NULL, NULL, TRUE, 0, pEnvBlock, attr->currdir, - &attr->si, &(*new)->pi)) { - if (attr->child_in) { - ap_close(attr->child_in); + new->invoked = cmdline; + +#if APR_HAS_UNICODE_FS + IF_WIN_OS_IS_UNICODE + { + STARTUPINFOW si; + DWORD stdin_reset = 0; + DWORD stdout_reset = 0; + DWORD stderr_reset = 0; + apr_wchar_t *wprg = NULL; + apr_wchar_t *wcmd = NULL; + apr_wchar_t *wcwd = NULL; + + if (progname) { + apr_size_t nprg = strlen(progname) + 1; + apr_size_t nwprg = nprg + 6; + wprg = apr_palloc(pool, nwprg * sizeof(wprg[0])); + if ((rv = apr_conv_utf8_to_ucs2(progname, &nprg, wprg, &nwprg)) + != APR_SUCCESS) { + if (attr->errfn) { + attr->errfn(pool, rv, + apr_pstrcat(pool, + "utf8 to ucs2 conversion failed" + " on progname: ", progname, NULL)); + } + return rv; + } } - if (attr->child_out) { - ap_close(attr->child_out); + + if (cmdline) { + apr_size_t ncmd = strlen(cmdline) + 1; + apr_size_t nwcmd = ncmd; + wcmd = apr_palloc(pool, nwcmd * sizeof(wcmd[0])); + if ((rv = apr_conv_utf8_to_ucs2(cmdline, &ncmd, wcmd, &nwcmd)) + != APR_SUCCESS) { + if (attr->errfn) { + attr->errfn(pool, rv, + apr_pstrcat(pool, + "utf8 to ucs2 conversion failed" + " on cmdline: ", cmdline, NULL)); + } + return rv; + } } - if (attr->child_err) { - ap_close(attr->child_err); + + if (attr->currdir) + { + apr_size_t ncwd = strlen(attr->currdir) + 1; + apr_size_t nwcwd = ncwd; + wcwd = apr_palloc(pool, ncwd * sizeof(wcwd[0])); + if ((rv = apr_conv_utf8_to_ucs2(attr->currdir, &ncwd, + wcwd, &nwcwd)) + != APR_SUCCESS) { + if (attr->errfn) { + attr->errfn(pool, rv, + apr_pstrcat(pool, + "utf8 to ucs2 conversion failed" + " on currdir: ", attr->currdir, NULL)); + } + return rv; + } } - CloseHandle((*new)->pi.hThread); - return APR_SUCCESS; - } - return GetLastError(); -} + memset(&si, 0, sizeof(si)); + si.cb = sizeof(si); -ap_status_t ap_get_childin(ap_file_t **new, ap_proc_t *proc) -{ - (*new) = proc->attr->parent_in; - return APR_SUCCESS; -} + if (attr->detached) { + si.dwFlags |= STARTF_USESHOWWINDOW; + si.wShowWindow = SW_HIDE; + } -ap_status_t ap_get_childout(ap_file_t **new, ap_proc_t *proc) -{ - (*new) = proc->attr->parent_out; - return APR_SUCCESS; -} +#ifndef _WIN32_WCE + /* LOCK CRITICAL SECTION + * before we begin to manipulate the inherited handles + */ + EnterCriticalSection(&proc_lock); -ap_status_t ap_get_childerr(ap_file_t **new, ap_proc_t *proc) -{ - (*new) = proc->attr->parent_err; - return APR_SUCCESS; -} + if ((attr->child_in && attr->child_in->filehand) + || (attr->child_out && attr->child_out->filehand) + || (attr->child_err && attr->child_err->filehand)) + { + si.dwFlags |= STARTF_USESTDHANDLES; -ap_status_t ap_wait_proc(ap_proc_t *proc, - ap_wait_how_e wait) -{ - DWORD stat; - if (!proc) - return APR_ENOPROC; - if (wait == APR_WAIT) { - if ((stat = WaitForSingleObject(proc->pi.hProcess, INFINITE)) == WAIT_OBJECT_0) { - return APR_CHILD_DONE; + si.hStdInput = GetStdHandle(STD_INPUT_HANDLE); + if (attr->child_in && attr->child_in->filehand) + { + if (GetHandleInformation(si.hStdInput, + &stdin_reset) + && (stdin_reset &= HANDLE_FLAG_INHERIT)) + SetHandleInformation(si.hStdInput, + HANDLE_FLAG_INHERIT, 0); + + if ( (si.hStdInput = attr->child_in->filehand) + != INVALID_HANDLE_VALUE ) + SetHandleInformation(si.hStdInput, HANDLE_FLAG_INHERIT, + HANDLE_FLAG_INHERIT); + } + + si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); + if (attr->child_out && attr->child_out->filehand) + { + if (GetHandleInformation(si.hStdOutput, + &stdout_reset) + && (stdout_reset &= HANDLE_FLAG_INHERIT)) + SetHandleInformation(si.hStdOutput, + HANDLE_FLAG_INHERIT, 0); + + if ( (si.hStdOutput = attr->child_out->filehand) + != INVALID_HANDLE_VALUE ) + SetHandleInformation(si.hStdOutput, HANDLE_FLAG_INHERIT, + HANDLE_FLAG_INHERIT); + } + + si.hStdError = GetStdHandle(STD_ERROR_HANDLE); + if (attr->child_err && attr->child_err->filehand) + { + if (GetHandleInformation(si.hStdError, + &stderr_reset) + && (stderr_reset &= HANDLE_FLAG_INHERIT)) + SetHandleInformation(si.hStdError, + HANDLE_FLAG_INHERIT, 0); + + if ( (si.hStdError = attr->child_err->filehand) + != INVALID_HANDLE_VALUE ) + SetHandleInformation(si.hStdError, HANDLE_FLAG_INHERIT, + HANDLE_FLAG_INHERIT); + } } - else if (stat == WAIT_TIMEOUT) { - return APR_CHILD_NOTDONE; + if (attr->user_token) { + /* XXX: for terminal services, handles can't be cannot be + * inherited across sessions. This process must be created + * in our existing session. lpDesktop assignment appears + * to be wrong according to these rules. + */ + si.lpDesktop = L"Winsta0\\Default"; + if (!ImpersonateLoggedOnUser(attr->user_token)) { + /* failed to impersonate the logged user */ + rv = apr_get_os_error(); + CloseHandle(attr->user_token); + attr->user_token = NULL; + LeaveCriticalSection(&proc_lock); + return rv; + } + rv = CreateProcessAsUserW(attr->user_token, + wprg, wcmd, + attr->sa, + NULL, + TRUE, + dwCreationFlags, + pEnvBlock, + wcwd, + &si, &pi); + + RevertToSelf(); } - return GetLastError(); + else { + rv = CreateProcessW(wprg, wcmd, /* Executable & Command line */ + NULL, NULL, /* Proc & thread security attributes */ + TRUE, /* Inherit handles */ + dwCreationFlags, /* Creation flags */ + pEnvBlock, /* Environment block */ + wcwd, /* Current directory name */ + &si, &pi); + } + + if ((attr->child_in && attr->child_in->filehand) + || (attr->child_out && attr->child_out->filehand) + || (attr->child_err && attr->child_err->filehand)) + { + if (stdin_reset) + SetHandleInformation(GetStdHandle(STD_INPUT_HANDLE), + stdin_reset, stdin_reset); + + if (stdout_reset) + SetHandleInformation(GetStdHandle(STD_OUTPUT_HANDLE), + stdout_reset, stdout_reset); + + if (stderr_reset) + SetHandleInformation(GetStdHandle(STD_ERROR_HANDLE), + stderr_reset, stderr_reset); + } + /* RELEASE CRITICAL SECTION + * The state of the inherited handles has been restored. + */ + LeaveCriticalSection(&proc_lock); + +#else /* defined(_WIN32_WCE) */ + rv = CreateProcessW(wprg, wcmd, /* Executable & Command line */ + NULL, NULL, /* Proc & thread security attributes */ + FALSE, /* must be 0 */ + dwCreationFlags, /* Creation flags */ + NULL, /* Environment block must be NULL */ + NULL, /* Current directory name must be NULL*/ + NULL, /* STARTUPINFO not supported */ + &pi); +#endif } - if ((stat = WaitForSingleObject(proc->pi.hProcess, 0)) == WAIT_OBJECT_0) { - return APR_CHILD_DONE; +#endif /* APR_HAS_UNICODE_FS */ +#if APR_HAS_ANSI_FS + ELSE_WIN_OS_IS_ANSI + { + STARTUPINFOA si; + memset(&si, 0, sizeof(si)); + si.cb = sizeof(si); + + if (attr->detached) { + si.dwFlags |= STARTF_USESHOWWINDOW; + si.wShowWindow = SW_HIDE; + } + + if ((attr->child_in && attr->child_in->filehand) + || (attr->child_out && attr->child_out->filehand) + || (attr->child_err && attr->child_err->filehand)) + { + si.dwFlags |= STARTF_USESTDHANDLES; + + si.hStdInput = (attr->child_in) + ? attr->child_in->filehand + : GetStdHandle(STD_INPUT_HANDLE); + + si.hStdOutput = (attr->child_out) + ? attr->child_out->filehand + : GetStdHandle(STD_OUTPUT_HANDLE); + + si.hStdError = (attr->child_err) + ? attr->child_err->filehand + : GetStdHandle(STD_ERROR_HANDLE); + } + + rv = CreateProcessA(progname, cmdline, /* Command line */ + NULL, NULL, /* Proc & thread security attributes */ + TRUE, /* Inherit handles */ + dwCreationFlags, /* Creation flags */ + pEnvBlock, /* Environment block */ + attr->currdir, /* Current directory name */ + &si, &pi); } - else if (stat == WAIT_TIMEOUT) { - return APR_CHILD_NOTDONE; +#endif /* APR_HAS_ANSI_FS */ + + /* Check CreateProcess result + */ + if (!rv) + return apr_get_os_error(); + + /* XXX Orphaned handle warning - no fix due to broken apr_proc_t api. + */ + new->hproc = pi.hProcess; + new->pid = pi.dwProcessId; + + if ((attr->child_in) && (attr->child_in != &no_file)) { + apr_file_close(attr->child_in); + } + if ((attr->child_out) && (attr->child_out != &no_file)) { + apr_file_close(attr->child_out); } - return GetLastError(); + if ((attr->child_err) && (attr->child_err != &no_file)) { + apr_file_close(attr->child_err); + } + CloseHandle(pi.hThread); + + return APR_SUCCESS; +} + +static apr_exit_why_e why_from_exit_code(DWORD exit) { + /* See WinNT.h STATUS_ACCESS_VIOLATION and family for how + * this class of failures was determined + */ + if (((exit & 0xC0000000) == 0xC0000000) + && !(exit & 0x3FFF0000)) + return APR_PROC_SIGNAL; + else + return APR_PROC_EXIT; + + /* ### No way to tell if Dr Watson grabbed a core, AFAICT. */ } -ap_status_t ap_get_procdata(char *key, void *data, ap_proc_t *proc) +APR_DECLARE(apr_status_t) apr_proc_wait_all_procs(apr_proc_t *proc, + int *exitcode, + apr_exit_why_e *exitwhy, + apr_wait_how_e waithow, + apr_pool_t *p) { - if (proc != NULL) { - return ap_get_userdata(data, key, proc->cntxt); - } - else { - data = NULL; - return APR_ENOPROC; +#if APR_HAS_UNICODE_FS +#ifndef _WIN32_WCE + IF_WIN_OS_IS_UNICODE + { + DWORD dwId = GetCurrentProcessId(); + DWORD i; + DWORD nChilds = 0; + DWORD nActive = 0; + HANDLE ps32; + PROCESSENTRY32W pe32; + BOOL bHasMore = FALSE; + DWORD dwFlags = PROCESS_QUERY_INFORMATION; + apr_status_t rv = APR_EGENERAL; + + if (waithow == APR_WAIT) + dwFlags |= SYNCHRONIZE; + if (!(ps32 = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0))) { + return apr_get_os_error(); + } + pe32.dwSize = sizeof(PROCESSENTRY32W); + if (!Process32FirstW(ps32, &pe32)) { + if (GetLastError() == ERROR_NO_MORE_FILES) + return APR_EOF; + else + return apr_get_os_error(); + } + do { + DWORD dwRetval = 0; + DWORD nHandles = 0; + HANDLE hProcess = NULL; + HANDLE pHandles[MAXIMUM_WAIT_OBJECTS]; + do { + if (pe32.th32ParentProcessID == dwId) { + nChilds++; + if ((hProcess = OpenProcess(dwFlags, FALSE, + pe32.th32ProcessID)) != NULL) { + if (GetExitCodeProcess(hProcess, &dwRetval)) { + if (dwRetval == STILL_ACTIVE) { + nActive++; + if (waithow == APR_WAIT) + pHandles[nHandles++] = hProcess; + else + CloseHandle(hProcess); + } + else { + /* Process has exited. + * No need to wait for its termination. + */ + CloseHandle(hProcess); + if (exitcode) + *exitcode = dwRetval; + if (exitwhy) + *exitwhy = why_from_exit_code(dwRetval); + proc->pid = pe32.th32ProcessID; + } + } + else { + /* Unexpected error code. + * Cleanup and return; + */ + rv = apr_get_os_error(); + CloseHandle(hProcess); + for (i = 0; i < nHandles; i++) + CloseHandle(pHandles[i]); + return rv; + } + } + else { + /* This is our child, so it shouldn't happen + * that we cannot open our child's process handle. + * However if the child process increased the + * security token it might fail. + */ + } + } + } while ((bHasMore = Process32NextW(ps32, &pe32)) && + nHandles < MAXIMUM_WAIT_OBJECTS); + if (nHandles) { + /* Wait for all collected processes to finish */ + DWORD waitStatus = WaitForMultipleObjects(nHandles, pHandles, + TRUE, INFINITE); + for (i = 0; i < nHandles; i++) + CloseHandle(pHandles[i]); + if (waitStatus == WAIT_OBJECT_0) { + /* Decrease active count by the number of awaited + * processes. + */ + nActive -= nHandles; + } + else { + /* Broken from the infinite loop */ + break; + } + } + } while (bHasMore); + CloseHandle(ps32); + if (waithow != APR_WAIT) { + if (nChilds && nChilds == nActive) { + /* All child processes are running */ + rv = APR_CHILD_NOTDONE; + proc->pid = -1; + } + else { + /* proc->pid contains the pid of the + * exited processes + */ + rv = APR_CHILD_DONE; + } + } + if (nActive == 0) { + rv = APR_CHILD_DONE; + proc->pid = -1; + } + return rv; } +#endif /* _WIN32_WCE */ +#endif /* APR_HAS_UNICODE_FS */ + return APR_ENOTIMPL; } -ap_status_t ap_set_procdata(void *data, char *key, - ap_status_t (*cleanup) (void *), - ap_proc_t *proc) +APR_DECLARE(apr_status_t) apr_proc_wait(apr_proc_t *proc, + int *exitcode, apr_exit_why_e *exitwhy, + apr_wait_how_e waithow) { - if (proc != NULL) { - return ap_set_userdata(data, key, cleanup, proc->cntxt); + DWORD stat; + DWORD time; + + if (waithow == APR_WAIT) + time = INFINITE; + else + time = 0; + + if ((stat = WaitForSingleObject(proc->hproc, time)) == WAIT_OBJECT_0) { + if (GetExitCodeProcess(proc->hproc, &stat)) { + if (exitcode) + *exitcode = stat; + if (exitwhy) + *exitwhy = why_from_exit_code(stat); + CloseHandle(proc->hproc); + proc->hproc = NULL; + return APR_CHILD_DONE; + } } - else { - data = NULL; - return APR_ENOPROC; + else if (stat == WAIT_TIMEOUT) { + return APR_CHILD_NOTDONE; } + return apr_get_os_error(); } -ap_status_t ap_get_os_proc(ap_os_proc_t *theproc, ap_proc_t *proc) +APR_DECLARE(apr_status_t) apr_proc_detach(int daemonize) { - if (proc == NULL) { - return APR_ENOPROC; - } - *theproc = proc->pi; - return APR_SUCCESS; + return APR_ENOTIMPL; } -ap_status_t ap_put_os_proc(ap_proc_t **proc, ap_os_proc_t *theproc, - ap_pool_t *cont) +APR_DECLARE(apr_status_t) apr_procattr_perms_set_register(apr_procattr_t *attr, + apr_perms_setfn_t *perms_set_fn, + void *data, + apr_fileperms_t perms) { - if (cont == NULL) { - return APR_ENOPOOL; - } - if ((*proc) == NULL) { - (*proc) = (ap_proc_t *)ap_palloc(cont, sizeof(ap_proc_t)); - (*proc)->cntxt = cont; - } - (*proc)->pi = *theproc; - return APR_SUCCESS; -} + return APR_ENOTIMPL; +} diff --git a/threadproc/win32/signals.c b/threadproc/win32/signals.c index 08119b78d05..48676d856ca 100644 --- a/threadproc/win32/signals.c +++ b/threadproc/win32/signals.c @@ -1,74 +1,67 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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 "threadproc.h" -#include "fileio.h" +#include "apr_arch_threadproc.h" +#include "apr_arch_file_io.h" #include "apr_thread_proc.h" +#include "apr_signal.h" #include "apr_file_io.h" #include "apr_general.h" +#if APR_HAVE_SIGNAL_H #include <signal.h> +#endif #include <string.h> -#ifdef HAVE_SYS_WAIT +#if APR_HAVE_SYS_WAIT #include <sys/wait.h> #endif -/* Windows only really support killing process, but that will do for now. */ -ap_status_t ap_kill(ap_proc_t *proc, int signal) +/* Windows only really support killing process, but that will do for now. + * + * ### Actually, closing the input handle to the proc should also do fine + * for most console apps. This definitely needs improvement... + */ +APR_DECLARE(apr_status_t) apr_proc_kill(apr_proc_t *proc, int signal) { - if (TerminateProcess(proc->pi.hProcess, signal) == 0) { - return errno; + if (proc->hproc != NULL) { + if (TerminateProcess(proc->hproc, signal) == 0) { + return apr_get_os_error(); + } + /* On unix, SIGKILL leaves a apr_proc_wait()able pid lying around, + * so we will leave hproc alone until the app calls apr_proc_wait(). + */ + return APR_SUCCESS; } - return APR_SUCCESS; + return APR_EPROC_UNKNOWN; } +void apr_signal_init(apr_pool_t *pglobal) +{ +} + +APR_DECLARE(const char *) apr_signal_description_get(int signum) +{ + return "unknown signal (not supported)"; +} + +APR_DECLARE(apr_status_t) apr_signal_block(int signum) +{ + return APR_ENOTIMPL; +} + +APR_DECLARE(apr_status_t) apr_signal_unblock(int signum) +{ + return APR_ENOTIMPL; +} diff --git a/threadproc/win32/thread.c b/threadproc/win32/thread.c index 5e38f066c07..c713e1444f3 100644 --- a/threadproc/win32/thread.c +++ b/threadproc/win32/thread.c @@ -1,205 +1,286 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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 "threadproc.h" +#include "apr_arch_threadproc.h" #include "apr_thread_proc.h" #include "apr_general.h" #include "apr_lib.h" #include "apr_portable.h" +#ifdef HAVE_PROCESS_H #include <process.h> +#endif +#include "apr_arch_misc.h" +/* Chosen for us by apr_initialize */ +DWORD tls_apr_thread = 0; -ap_status_t ap_create_threadattr(ap_threadattr_t **new, ap_pool_t *cont) +APR_DECLARE(apr_status_t) apr_threadattr_create(apr_threadattr_t **new, + apr_pool_t *pool) { - (*new) = (ap_threadattr_t *)ap_palloc(cont, - sizeof(ap_threadattr_t)); + (*new) = (apr_threadattr_t *)apr_palloc(pool, + sizeof(apr_threadattr_t)); if ((*new) == NULL) { return APR_ENOMEM; } - (*new)->cntxt = cont; + (*new)->pool = pool; + (*new)->detach = 0; + (*new)->stacksize = 0; + return APR_SUCCESS; } -ap_status_t ap_setthreadattr_detach(ap_threadattr_t *attr, ap_int32_t on) +APR_DECLARE(apr_status_t) apr_threadattr_detach_set(apr_threadattr_t *attr, + apr_int32_t on) { attr->detach = on; - return APR_SUCCESS; + return APR_SUCCESS; } -ap_status_t ap_getthreadattr_detach(ap_threadattr_t *attr) +APR_DECLARE(apr_status_t) apr_threadattr_detach_get(apr_threadattr_t *attr) { if (attr->detach == 1) return APR_DETACH; return APR_NOTDETACH; } -ap_status_t ap_create_thread(ap_thread_t **new, ap_threadattr_t *attr, - ap_thread_start_t func, void *data, - ap_pool_t *cont) +APR_DECLARE(apr_status_t) apr_threadattr_stacksize_set(apr_threadattr_t *attr, + apr_size_t stacksize) +{ + attr->stacksize = stacksize; + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_threadattr_guardsize_set(apr_threadattr_t *attr, + apr_size_t size) +{ + return APR_ENOTIMPL; +} + +static void *dummy_worker(void *opaque) +{ + apr_thread_t *thd = (apr_thread_t *)opaque; + void *ret; + + TlsSetValue(tls_apr_thread, thd->td); + apr_pool_owner_set(thd->pool, 0); + ret = thd->func(thd, thd->data); + apr_pool_destroy(thd->pool); + return ret; +} + +APR_DECLARE(apr_status_t) apr_thread_create(apr_thread_t **new, + apr_threadattr_t *attr, + apr_thread_start_t func, + void *data, apr_pool_t *pool) { - ap_status_t stat; + apr_status_t stat; unsigned temp; - int lasterror; - - (*new) = (ap_thread_t *)ap_palloc(cont, sizeof(ap_thread_t)); + HANDLE handle; + + (*new) = (apr_thread_t *)apr_palloc(pool, sizeof(apr_thread_t)); if ((*new) == NULL) { return APR_ENOMEM; } - (*new)->cntxt = cont; - - stat = ap_create_pool(&(*new)->cntxt, cont); + (*new)->data = data; + (*new)->func = func; + (*new)->td = NULL; + stat = apr_pool_create(&(*new)->pool, pool); if (stat != APR_SUCCESS) { return stat; } - /* Use 0 for Thread Stack Size, because that will default the stack to the - * same size as the calling thread. - */ - if (((*new)->td = (HANDLE *)_beginthreadex(NULL, 0, (unsigned int (API_THREAD_FUNC *)(void *))func, - data, 0, &temp)) == 0) { - lasterror = GetLastError(); - return APR_EEXIST; + /* Use 0 for default Thread Stack Size, because that will + * default the stack to the same size as the calling thread. + */ +#ifndef _WIN32_WCE + if ((handle = (HANDLE)_beginthreadex(NULL, + (DWORD) (attr ? attr->stacksize : 0), + (unsigned int (APR_THREAD_FUNC *)(void *))dummy_worker, + (*new), 0, &temp)) == 0) { + return APR_FROM_OS_ERROR(_doserrno); } +#else + if ((handle = CreateThread(NULL, + attr && attr->stacksize > 0 ? attr->stacksize : 0, + (unsigned int (APR_THREAD_FUNC *)(void *))dummy_worker, + (*new), 0, &temp)) == 0) { + return apr_get_os_error(); + } +#endif + if (attr && attr->detach) { + CloseHandle(handle); + } + else + (*new)->td = handle; - if (attr && attr->detach) { - CloseHandle((*new)->td); - } - - return APR_SUCCESS; + return APR_SUCCESS; } -ap_status_t ap_thread_exit(ap_thread_t *thd, ap_status_t *retval) +APR_DECLARE(apr_status_t) apr_thread_exit(apr_thread_t *thd, + apr_status_t retval) { - ap_destroy_pool(thd->cntxt); - _endthreadex(*retval); - return APR_SUCCESS; + thd->exitval = retval; + apr_pool_destroy(thd->pool); + thd->pool = NULL; +#ifndef _WIN32_WCE + _endthreadex(0); +#else + ExitThread(0); +#endif + return APR_SUCCESS; } -ap_status_t ap_thread_join(ap_status_t *retval, ap_thread_t *thd) +APR_DECLARE(apr_status_t) apr_thread_join(apr_status_t *retval, + apr_thread_t *thd) { - ap_status_t stat; - - if ((stat = WaitForSingleObject(thd->td, INFINITE)) == WAIT_OBJECT_0) { - if (GetExitCodeThread(thd->td, retval) == 0) { - return APR_SUCCESS; - } - return APR_EEXIST; + apr_status_t rv = APR_SUCCESS; + + if (!thd->td) { + /* Can not join on detached threads */ + return APR_DETACH; } - else { - return stat; + rv = WaitForSingleObject(thd->td, INFINITE); + if ( rv == WAIT_OBJECT_0 || rv == WAIT_ABANDONED) { + /* If the thread_exit has been called */ + if (!thd->pool) + *retval = thd->exitval; + else + rv = APR_INCOMPLETE; } + else + rv = apr_get_os_error(); + CloseHandle(thd->td); + thd->td = NULL; + + return rv; } -ap_status_t ap_thread_detach(ap_thread_t *thd) +APR_DECLARE(apr_status_t) apr_thread_detach(apr_thread_t *thd) { - if (CloseHandle(thd->td)) { + if (thd->td && CloseHandle(thd->td)) { + thd->td = NULL; return APR_SUCCESS; } else { - return APR_EEXIST; + return apr_get_os_error(); } } -ap_status_t ap_get_threaddata(void **data, char *key, ap_thread_t *thread) +APR_DECLARE(void) apr_thread_yield() { - if (thread != NULL) { - return ap_get_userdata(data, key, thread->cntxt); - } - else { - data = NULL; - return APR_ENOTHREAD; + /* SwitchToThread is not supported on Win9x, but since it's + * primarily a noop (entering time consuming code, therefore + * providing more critical threads a bit larger timeslice) + * we won't worry too much if it's not available. + */ +#ifndef _WIN32_WCE + if (apr_os_level >= APR_WIN_NT) { + SwitchToThread(); } +#endif } -ap_status_t ap_set_threaddata(void *data, char *key, - ap_status_t (*cleanup) (void *), - ap_thread_t *thread) +APR_DECLARE(apr_status_t) apr_thread_data_get(void **data, const char *key, + apr_thread_t *thread) { - if (thread != NULL) { - return ap_set_userdata(data, key, cleanup, thread->cntxt); + return apr_pool_userdata_get(data, key, thread->pool); +} + +APR_DECLARE(apr_status_t) apr_thread_data_set(void *data, const char *key, + apr_status_t (*cleanup) (void *), + apr_thread_t *thread) +{ + return apr_pool_userdata_set(data, key, cleanup, thread->pool); +} + + +APR_DECLARE(apr_os_thread_t) apr_os_thread_current(void) +{ + HANDLE hthread = (HANDLE)TlsGetValue(tls_apr_thread); + HANDLE hproc; + + if (hthread) { + return hthread; } - else { - data = NULL; - return APR_ENOTHREAD; + + hproc = GetCurrentProcess(); + hthread = GetCurrentThread(); + if (!DuplicateHandle(hproc, hthread, + hproc, &hthread, 0, FALSE, + DUPLICATE_SAME_ACCESS)) { + return NULL; } + TlsSetValue(tls_apr_thread, hthread); + return hthread; } -ap_status_t ap_get_os_thread(ap_os_thread_t *thethd, ap_thread_t *thd) +APR_DECLARE(apr_status_t) apr_os_thread_get(apr_os_thread_t **thethd, + apr_thread_t *thd) { if (thd == NULL) { return APR_ENOTHREAD; } - thethd = thd->td; + *thethd = thd->td; return APR_SUCCESS; } -ap_status_t ap_put_os_thread(ap_thread_t **thd, ap_os_thread_t *thethd, - ap_pool_t *cont) +APR_DECLARE(apr_status_t) apr_os_thread_put(apr_thread_t **thd, + apr_os_thread_t *thethd, + apr_pool_t *pool) { - if (cont == NULL) { + if (pool == NULL) { return APR_ENOPOOL; } if ((*thd) == NULL) { - (*thd) = (ap_thread_t *)ap_palloc(cont, sizeof(ap_thread_t)); - (*thd)->cntxt = cont; + (*thd) = (apr_thread_t *)apr_palloc(pool, sizeof(apr_thread_t)); + (*thd)->pool = pool; } (*thd)->td = thethd; return APR_SUCCESS; } +APR_DECLARE(apr_status_t) apr_thread_once_init(apr_thread_once_t **control, + apr_pool_t *p) +{ + (*control) = apr_pcalloc(p, sizeof(**control)); + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_thread_once(apr_thread_once_t *control, + void (*func)(void)) +{ + if (!InterlockedExchange(&control->value, 1)) { + func(); + } + return APR_SUCCESS; +} + +APR_DECLARE(int) apr_os_thread_equal(apr_os_thread_t tid1, + apr_os_thread_t tid2) +{ + /* Since the only tid's we support our are own, and + * apr_os_thread_current returns the identical handle + * to the one we created initially, the test is simple. + */ + return (tid1 == tid2); +} + +APR_POOL_IMPLEMENT_ACCESSOR(thread) diff --git a/threadproc/win32/threadcancel.c b/threadproc/win32/threadcancel.c deleted file mode 100644 index 3a509202b6e..00000000000 --- a/threadproc/win32/threadcancel.c +++ /dev/null @@ -1,86 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#include "threadproc.h" -#include "apr_thread_proc.h" -#include "apr_general.h" - - -ap_status_t ap_cancel_thread(ap_thread_t *thd) -{ - if (TerminateThread(thd->td, APR_SUCCESS) == 0) { - return APR_EEXIST; - } - else { - return APR_SUCCESS; - } -} - -/* Not sure of the best way to do this just yet. -ap_status_t ap_setcanceltype(ap_int32_t type, ap_pool_t *cont) -{ - -} - -ap_status_t ap_setcancelstate(ap_int32_t type, ap_pool_t *cont) -{ - ap_status_t stat; - if ((stat = pthread_setcanceltype(type, NULL)) == 0) { - return APR_SUCCESS; - } - else { - return stat; - } -} -*/ diff --git a/threadproc/win32/threadpriv.c b/threadproc/win32/threadpriv.c index c556be1926f..787c142c49d 100644 --- a/threadproc/win32/threadpriv.c +++ b/threadproc/win32/threadpriv.c @@ -1,136 +1,99 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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 "threadproc.h" +#include "apr_arch_threadproc.h" #include "apr_thread_proc.h" #include "apr_general.h" #include "apr_lib.h" #include "apr_errno.h" #include "apr_portable.h" -ap_status_t ap_create_thread_private(ap_threadkey_t **key, - void (*dest)(void *), ap_pool_t *cont) +APR_DECLARE(apr_status_t) apr_threadkey_private_create(apr_threadkey_t **key, + void (*dest)(void *), + apr_pool_t *pool) { - (*key)->key = TlsAlloc(); - return APR_SUCCESS; + (*key) = (apr_threadkey_t *)apr_palloc(pool, sizeof(apr_threadkey_t)); + if ((*key) == NULL) { + return APR_ENOMEM; + } + + (*key)->pool = pool; + + if (((*key)->key = TlsAlloc()) != 0xFFFFFFFF) { + return APR_SUCCESS; + } + return apr_get_os_error(); } -ap_status_t ap_get_thread_private(void **new, ap_threadkey_t *key) +APR_DECLARE(apr_status_t) apr_threadkey_private_get(void **new, + apr_threadkey_t *key) { - if ((*new) = TlsGetValue(key->key)) { + if (((*new) = TlsGetValue(key->key))) { return APR_SUCCESS; } - return APR_EEXIST; + return apr_get_os_error(); } -ap_status_t ap_set_thread_private(void *priv, ap_threadkey_t *key) +APR_DECLARE(apr_status_t) apr_threadkey_private_set(void *priv, + apr_threadkey_t *key) { if (TlsSetValue(key->key, priv)) { return APR_SUCCESS; } - return APR_EEXIST; + return apr_get_os_error(); } -ap_status_t ap_delete_thread_private(ap_threadkey_t *key) +APR_DECLARE(apr_status_t) apr_threadkey_private_delete(apr_threadkey_t *key) { if (TlsFree(key->key)) { return APR_SUCCESS; } - return APR_EEXIST; + return apr_get_os_error(); } -ap_status_t ap_get_threadkeydata(void **data, char *key, ap_threadkey_t *threadkey) +APR_DECLARE(apr_status_t) apr_threadkey_data_get(void **data, const char *key, + apr_threadkey_t *threadkey) { - if (threadkey != NULL) { - return ap_get_userdata(data, key, threadkey->cntxt); - } - else { - data = NULL; - return APR_ENOTHDKEY; - } + return apr_pool_userdata_get(data, key, threadkey->pool); } -ap_status_t ap_set_threadkeydata(void *data, char *key, ap_status_t (*cleanup) (void *), - ap_threadkey_t *threadkey) +APR_DECLARE(apr_status_t) apr_threadkey_data_set(void *data, const char *key, + apr_status_t (*cleanup)(void *), + apr_threadkey_t *threadkey) { - if (threadkey != NULL) { - return ap_set_userdata(data, key, cleanup, threadkey->cntxt); - } - else { - data = NULL; - return APR_ENOTHDKEY; - } + return apr_pool_userdata_set(data, key, cleanup, threadkey->pool); } -ap_status_t ap_get_os_threadkey(ap_os_threadkey_t *thekey, ap_threadkey_t *key) +APR_DECLARE(apr_status_t) apr_os_threadkey_get(apr_os_threadkey_t *thekey, + apr_threadkey_t *key) { - if (key == NULL) { - return APR_ENOFILE; - } - thekey = &(key->key); + *thekey = key->key; return APR_SUCCESS; } -ap_status_t ap_put_os_threadkey(ap_threadkey_t **key, - ap_os_threadkey_t *thekey, ap_pool_t *cont) +APR_DECLARE(apr_status_t) apr_os_threadkey_put(apr_threadkey_t **key, + apr_os_threadkey_t *thekey, + apr_pool_t *pool) { - if (cont == NULL) { + if (pool == NULL) { return APR_ENOPOOL; } if ((*key) == NULL) { - (*key) = (ap_threadkey_t *)ap_palloc(cont, sizeof(ap_threadkey_t)); - (*key)->cntxt = cont; + (*key) = (apr_threadkey_t *)apr_palloc(pool, sizeof(apr_threadkey_t)); + (*key)->pool = pool; } (*key)->key = *thekey; return APR_SUCCESS; diff --git a/threadproc/win32/threadproc.h b/threadproc/win32/threadproc.h deleted file mode 100644 index 16667de67e7..00000000000 --- a/threadproc/win32/threadproc.h +++ /dev/null @@ -1,103 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#include "apr_private.h" -#include "apr_thread_proc.h" -#include "apr_file_io.h" -#include <windows.h> - -#ifndef THREAD_PROC_H -#define THREAD_PROC_H - -#define SHELL_PATH "cmd.exe" - -struct ap_thread_t { - ap_pool_t *cntxt; - HANDLE td; - ap_int32_t cancel; - ap_int32_t cancel_how; -}; - -struct ap_threadattr_t { - ap_pool_t *cntxt; - ap_int32_t detach; -}; - -struct ap_threadkey_t { - ap_pool_t *cntxt; - DWORD key; -}; - -struct ap_procattr_t { - ap_pool_t *cntxt; - STARTUPINFO si; - ap_file_t *parent_in; - ap_file_t *child_in; - ap_file_t *parent_out; - ap_file_t *child_out; - ap_file_t *parent_err; - ap_file_t *child_err; - char *currdir; - ap_int32_t cmdtype; - ap_int32_t detached; -}; - -struct ap_proc_t { - ap_pool_t *cntxt; - PROCESS_INFORMATION pi; - struct ap_procattr_t *attr; -}; - -#endif /* ! THREAD_PROC_H */ - diff --git a/threads.m4 b/threads.m4 deleted file mode 100644 index 04207aa79bc..00000000000 --- a/threads.m4 +++ /dev/null @@ -1,93 +0,0 @@ -dnl -dnl REENTRANCY_FLAGS -dnl -dnl Set some magic defines -dnl -AC_DEFUN(REENTRANCY_FLAGS,[ - case "`uname -sr`" in - "SunOS 5"*) - CFLAGS="$CFLAGS -D_POSIX_PTHREAD_SEMANTICS";; - esac - -dnl This works for now.. - CFLAGS="$CFLAGS -D_REENTRANT" -])dnl -dnl -dnl PTHREADS_CHECK_COMPILE -dnl -dnl Check whether the current setup can use POSIX threads calls -dnl -AC_DEFUN(PTHREADS_CHECK_COMPILE, [ -AC_TRY_RUN( [ -#include <pthread.h> -#include <stddef.h> - -void *thread_routine(void *data) { - return data; -} - -int main() { - pthread_t thd; - pthread_mutexattr_t mattr; - int data = 1; - pthread_mutexattr_init(&mattr); - return pthread_create(&thd, NULL, thread_routine, &data); -} ], [ - pthreads_working="yes" - ], [ - pthreads_working="no" - ], pthreads_working="no" ) ] )dnl -dnl -dnl PTHREADS_CHECK() -dnl -dnl Try to find a way to enable POSIX threads -dnl -AC_DEFUN(PTHREADS_CHECK,[ -if test -n "$ac_cv_pthreads_lib"; then - LIBS="$LIBS -l$ac_cv_pthreads_lib" -fi - -if test -n "$ac_cv_pthreads_cflags"; then - CFLAGS="$CFLAGS $ac_cv_pthreads_cflags" -fi - -PTHREADS_CHECK_COMPILE - -AC_CACHE_CHECK(for pthreads_cflags,ac_cv_pthreads_cflags,[ -ac_cv_pthreads_cflags="" -if test "$pthreads_working" != "yes"; then - for flag in -pthreads -pthread -mthreads; do - ac_save="$CFLAGS" - CFLAGS="$CFLAGS $flag" - PTHREADS_CHECK_COMPILE - if test "$pthreads_working" = "yes"; then - ac_cv_pthreads_cflags="$flag" - break - fi - CFLAGS="$ac_save" - done -fi -]) - -AC_CACHE_CHECK(for pthreads_lib, ac_cv_pthreads_lib,[ -ac_cv_pthreads_lib="" -if test "$pthreads_working" != "yes"; then - for lib in pthread pthreads c_r; do - ac_save="$LIBS" - LIBS="$LIBS -l$lib" - PTHREADS_CHECK_COMPILE - if test "$pthreads_working" = "yes"; then - ac_cv_pthreads_lib="$lib" - break - fi - LIBS="$ac_save" - done -fi -]) - -if test "$pthreads_working" = "yes"; then - threads_result="POSIX Threads found" -else - threads_result="POSIX Threads not found" -fi -])dnl diff --git a/time/unix/.cvsignore b/time/unix/.cvsignore deleted file mode 100644 index f3c7a7c5da6..00000000000 --- a/time/unix/.cvsignore +++ /dev/null @@ -1 +0,0 @@ -Makefile diff --git a/time/unix/Makefile.in b/time/unix/Makefile.in deleted file mode 100644 index 352364d25da..00000000000 --- a/time/unix/Makefile.in +++ /dev/null @@ -1,64 +0,0 @@ -#CFLAGS=$(OPTIM) $(CFLAGS1) $(EXTRA_CFLAGS) -#LIBS=$(EXTRA_LIBS) $(LIBS1) -#INCLUDES=$(INCLUDES1) $(INCLUDES0) $(EXTRA_INCLUDES) -#LDFLAGS=$(LDFLAGS1) $(EXTRA_LDFLAGS) - -RM=@RM@ -CC=@CC@ -RANLIB=@RANLIB@ -CFLAGS=@CFLAGS@ @OPTIM@ -LIBS=@LIBS@ -LDFLAGS=@LDFLAGS@ $(LIBS) -INCDIR=../../include -INCLUDES=-I$(INCDIR) -I. - -#LIB=libtime.a - -OBJS=time.o \ - timestr.o - -.c.o: - $(CC) $(CFLAGS) -c $(INCLUDES) $< - -all: $(OBJS) - -clean: - $(RM) -f *.o *.a *.so - -distclean: clean - -$(RM) -f Makefile - -$(OBJS): Makefile - -#$(LIB): $(OBJS) -# $(RM) -f $@ -# $(AR) cr $@ $(OBJS) -# $(RANLIB) $@ - -# -# We really don't expect end users to use this rule. It works only with -# gcc, and rebuilds Makefile.tmpl. You have to re-run Configure after -# using it. -# -depend: - cp Makefile.in Makefile.in.bak \ - && sed -ne '1,/^# DO NOT REMOVE/p' Makefile.in > Makefile.new \ - && gcc -MM $(INCLUDES) $(CFLAGS) *.c >> Makefile.new \ - && sed -e '1,$$s: $(INCDIR)/: $$(INCDIR)/:g' \ - -e '1,$$s: $(OSDIR)/: $$(OSDIR)/:g' Makefile.new \ - > Makefile.in \ - && rm Makefile.new - -# DO NOT REMOVE -time.o: time.c atime.h $(INCDIR)/apr_private.h \ - $(INCDIR)/apr_time.h $(INCDIR)/apr_general.h \ - $(INCDIR)/apr.h $(INCDIR)/apr_errno.h $(INCDIR)/apr_lib.h \ - $(INCDIR)/apr_file_io.h $(INCDIR)/apr_thread_proc.h \ - $(INCDIR)/apr_portable.h $(INCDIR)/apr_network_io.h \ - $(INCDIR)/apr_lock.h -timestr.o: timestr.c atime.h $(INCDIR)/apr_private.h \ - $(INCDIR)/apr_time.h $(INCDIR)/apr_general.h \ - $(INCDIR)/apr.h $(INCDIR)/apr_errno.h $(INCDIR)/apr_lib.h \ - $(INCDIR)/apr_file_io.h $(INCDIR)/apr_thread_proc.h \ - $(INCDIR)/apr_portable.h $(INCDIR)/apr_network_io.h \ - $(INCDIR)/apr_lock.h diff --git a/time/unix/atime.h b/time/unix/atime.h deleted file mode 100644 index f22167486e5..00000000000 --- a/time/unix/atime.h +++ /dev/null @@ -1,80 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#ifndef ATIME_H -#define ATIME_H - -#include "apr_private.h" -#include "apr_time.h" -#include "apr_lib.h" - -/* System Headers required for time library */ -#if HAVE_SYS_TIME_H -#include <sys/time.h> -#endif -#if HAVE_TIME_H -#include <time.h> -#endif -/* End System Headers */ - -struct atime_t { - ap_pool_t *cntxt; - struct timeval *currtime; - struct tm *explodedtime; - int time_ex; /* have we already exploded the time? */ -}; - - -#endif /* ! ATIME_H */ - diff --git a/time/unix/time.c b/time/unix/time.c index bbd0dd31261..7f095819276 100644 --- a/time/unix/time.c +++ b/time/unix/time.c @@ -1,177 +1,149 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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 "atime.h" #include "apr_portable.h" +#include "apr_time.h" +#include "apr_lib.h" +#include "apr_private.h" +#include "apr_strings.h" -ap_status_t ap_ansi_time_to_ap_time(ap_time_t *result, time_t input) -{ - *result = (ap_time_t)input * AP_USEC_PER_SEC; - return APR_SUCCESS; -} +/* private APR headers */ +#include "apr_arch_internal_time.h" +/* System Headers required for time library */ +#if APR_HAVE_SYS_TIME_H +#include <sys/time.h> +#endif +#if APR_HAVE_UNISTD_H +#include <unistd.h> +#endif +#ifdef HAVE_TIME_H +#include <time.h> +#endif +/* End System Headers */ + +#if !defined(HAVE_STRUCT_TM_TM_GMTOFF) && !defined(HAVE_STRUCT_TM___TM_GMTOFF) +static apr_int32_t server_gmt_offset; +#define NO_GMTOFF_IN_STRUCT_TM +#endif -ap_time_t ap_now(void) +static apr_int32_t get_offset(struct tm *tm) { - struct timeval tv; - gettimeofday(&tv, NULL); - return tv.tv_sec * AP_USEC_PER_SEC + tv.tv_usec; +#if defined(HAVE_STRUCT_TM_TM_GMTOFF) + return tm->tm_gmtoff; +#elif defined(HAVE_STRUCT_TM___TM_GMTOFF) + return tm->__tm_gmtoff; +#else +#ifdef NETWARE + /* Need to adjust the global variable each time otherwise + the web server would have to be restarted when daylight + savings changes. + */ + if (daylightOnOff) { + return server_gmt_offset + daylightOffset; + } +#else + if (tm->tm_isdst) + return server_gmt_offset + 3600; +#endif + return server_gmt_offset; +#endif } - -static void tm_to_exp(ap_exploded_time_t *xt, struct tm *tm) +APR_DECLARE(apr_status_t) apr_time_ansi_put(apr_time_t *result, + time_t input) { - xt->tm_sec = tm->tm_sec; - xt->tm_min = tm->tm_min; - xt->tm_hour = tm->tm_hour; - xt->tm_mday = tm->tm_mday; - xt->tm_mon = tm->tm_mon; - xt->tm_year = tm->tm_year; - xt->tm_wday = tm->tm_wday; - xt->tm_yday = tm->tm_yday; - xt->tm_isdst = tm->tm_isdst; + *result = (apr_time_t)input * APR_USEC_PER_SEC; + return APR_SUCCESS; } +/* NB NB NB NB This returns GMT!!!!!!!!!! */ +APR_DECLARE(apr_time_t) apr_time_now(void) +{ + struct timeval tv; + gettimeofday(&tv, NULL); + return tv.tv_sec * APR_USEC_PER_SEC + tv.tv_usec; +} -ap_status_t ap_explode_gmt(ap_exploded_time_t *result, ap_time_t input) +static void explode_time(apr_time_exp_t *xt, apr_time_t t, + apr_int32_t offset, int use_localtime) { - time_t t = input / AP_USEC_PER_SEC; -#if APR_HAS_THREADS && defined(_POSIX_THREAD_SAFE_FUNCTIONS) - struct tm banana; + struct tm tm; + time_t tt = (t / APR_USEC_PER_SEC) + offset; + xt->tm_usec = t % APR_USEC_PER_SEC; + +#if APR_HAS_THREADS && defined (_POSIX_THREAD_SAFE_FUNCTIONS) + if (use_localtime) + localtime_r(&tt, &tm); + else + gmtime_r(&tt, &tm); +#else + if (use_localtime) + tm = *localtime(&tt); + else + tm = *gmtime(&tt); #endif - result->tm_usec = input % AP_USEC_PER_SEC; + xt->tm_sec = tm.tm_sec; + xt->tm_min = tm.tm_min; + xt->tm_hour = tm.tm_hour; + xt->tm_mday = tm.tm_mday; + xt->tm_mon = tm.tm_mon; + xt->tm_year = tm.tm_year; + xt->tm_wday = tm.tm_wday; + xt->tm_yday = tm.tm_yday; + xt->tm_isdst = tm.tm_isdst; + xt->tm_gmtoff = get_offset(&tm); +} -#if APR_HAS_THREADS && defined(_POSIX_THREAD_SAFE_FUNCTIONS) - gmtime_r(&t, &banana); - tm_to_exp(result, &banana); -#else - tm_to_exp(result, gmtime(&t)); -#endif - result->tm_gmtoff = 0; +APR_DECLARE(apr_status_t) apr_time_exp_tz(apr_time_exp_t *result, + apr_time_t input, apr_int32_t offs) +{ + explode_time(result, input, offs, 0); + result->tm_gmtoff = offs; return APR_SUCCESS; } -ap_status_t ap_explode_localtime(ap_exploded_time_t *result, ap_time_t input) +APR_DECLARE(apr_status_t) apr_time_exp_gmt(apr_time_exp_t *result, + apr_time_t input) { -#if APR_HAS_THREADS && defined(_POSIX_THREAD_SAFE_FUNCTIONS) - time_t t = input / AP_USEC_PER_SEC; - struct tm apricot; - - result->tm_usec = input % AP_USEC_PER_SEC; - - localtime_r(&t, &apricot); - tm_to_exp(result, &apricot); -#if defined(HAVE_GMTOFF) - result->tm_gmtoff = apricot.tm_gmtoff; -#elif defined(HAVE___GMTOFF) - result->tm_gmtoff = apricot.__tm_gmtoff; -#else - /* solaris is backwards enough to have pthreads but no tm_gmtoff, feh */ - { - int days, hours, minutes; - - gmtime_r(&t, &apricot); - days = result->tm_yday - apricot.tm_yday; - hours = ((days < -1 ? 24 : 1 < days ? -24 : days * 24) - + result->tm_hour - apricot.tm_hour); - minutes = hours * 60 + result->tm_min - apricot.tm_min; - result->tm_gmtoff = minutes * 60; - } -#endif -#else - time_t t = input / AP_USEC_PER_SEC; - struct tm *tmx; - - result->tm_usec = input % AP_USEC_PER_SEC; + return apr_time_exp_tz(result, input, 0); +} - tmx = localtime(&t); - tm_to_exp(result, tmx); -#if defined(HAVE_GMTOFF) - result->tm_gmtoff = tmx->tm_gmtoff; -#elif defined(HAVE___GMTOFF) - result->tm_gmtoff = tmx->__tm_gmtoff; +APR_DECLARE(apr_status_t) apr_time_exp_lt(apr_time_exp_t *result, + apr_time_t input) +{ +#if defined(__EMX__) + /* EMX gcc (OS/2) has a timezone global we can use */ + return apr_time_exp_tz(result, input, -timezone); #else - /* need to create tm_gmtoff... assume we are never more than 24 hours away */ - { - int days, hours, minutes; - - tmx = gmtime(&t); - days = result->tm_yday - tmx->tm_yday; - hours = ((days < -1 ? 24 : 1 < days ? -24 : days * 24) - + result->tm_hour - tmx->tm_hour); - minutes = hours * 60 + result->tm_min - tmx->tm_min; - result->tm_gmtoff = minutes * 60; - } -#endif -#endif + explode_time(result, input, 0, 1); return APR_SUCCESS; +#endif /* __EMX__ */ } - -ap_status_t ap_implode_time(ap_time_t *t, ap_exploded_time_t *xt) +APR_DECLARE(apr_status_t) apr_time_exp_get(apr_time_t *t, apr_time_exp_t *xt) { - int year; - time_t days; + apr_time_t year = xt->tm_year; + apr_time_t days; static const int dayoffset[12] = {306, 337, 0, 31, 61, 92, 122, 153, 184, 214, 245, 275}; - year = xt->tm_year; - - if (year < 70 || ((sizeof(time_t) <= 4) && (year >= 138))) { + if (xt->tm_mon < 0 || xt->tm_mon >= 12) return APR_EBADDATE; - } /* shift new year to 1st March in order to make leap year calc easy */ @@ -183,25 +155,34 @@ ap_status_t ap_implode_time(ap_time_t *t, ap_exploded_time_t *xt) days = year * 365 + year / 4 - year / 100 + (year / 100 + 3) / 4; days += dayoffset[xt->tm_mon] + xt->tm_mday - 1; days -= 25508; /* 1 jan 1970 is 25508 days since 1 mar 1900 */ - days = ((days * 24 + xt->tm_hour) * 60 + xt->tm_min) * 60 + xt->tm_sec; if (days < 0) { return APR_EBADDATE; } - days -= xt->tm_gmtoff; - *t = days * AP_USEC_PER_SEC + xt->tm_usec; + *t = days * APR_USEC_PER_SEC + xt->tm_usec; return APR_SUCCESS; } -ap_status_t ap_get_os_imp_time(ap_os_imp_time_t **ostime, ap_time_t *aprtime) +APR_DECLARE(apr_status_t) apr_time_exp_gmt_get(apr_time_t *t, + apr_time_exp_t *xt) { - (*ostime)->tv_usec = *aprtime % AP_USEC_PER_SEC; - (*ostime)->tv_sec = *aprtime / AP_USEC_PER_SEC; + apr_status_t status = apr_time_exp_get(t, xt); + if (status == APR_SUCCESS) + *t -= (apr_time_t) xt->tm_gmtoff * APR_USEC_PER_SEC; + return status; +} + +APR_DECLARE(apr_status_t) apr_os_imp_time_get(apr_os_imp_time_t **ostime, + apr_time_t *aprtime) +{ + (*ostime)->tv_usec = *aprtime % APR_USEC_PER_SEC; + (*ostime)->tv_sec = *aprtime / APR_USEC_PER_SEC; return APR_SUCCESS; } -ap_status_t ap_get_os_exp_time(ap_os_exp_time_t **ostime, ap_exploded_time_t *aprtime) +APR_DECLARE(apr_status_t) apr_os_exp_time_get(apr_os_exp_time_t **ostime, + apr_time_exp_t *aprtime) { (*ostime)->tm_sec = aprtime->tm_sec; (*ostime)->tm_min = aprtime->tm_min; @@ -212,18 +193,27 @@ ap_status_t ap_get_os_exp_time(ap_os_exp_time_t **ostime, ap_exploded_time_t *ap (*ostime)->tm_wday = aprtime->tm_wday; (*ostime)->tm_yday = aprtime->tm_yday; (*ostime)->tm_isdst = aprtime->tm_isdst; + +#if defined(HAVE_STRUCT_TM_TM_GMTOFF) + (*ostime)->tm_gmtoff = aprtime->tm_gmtoff; +#elif defined(HAVE_STRUCT_TM___TM_GMTOFF) + (*ostime)->__tm_gmtoff = aprtime->tm_gmtoff; +#endif + return APR_SUCCESS; } -ap_status_t ap_put_os_imp_time(ap_time_t *aprtime, ap_os_imp_time_t **ostime, - ap_pool_t *cont) +APR_DECLARE(apr_status_t) apr_os_imp_time_put(apr_time_t *aprtime, + apr_os_imp_time_t **ostime, + apr_pool_t *cont) { - *aprtime = (*ostime)->tv_sec * AP_USEC_PER_SEC + (*ostime)->tv_usec; + *aprtime = (*ostime)->tv_sec * APR_USEC_PER_SEC + (*ostime)->tv_usec; return APR_SUCCESS; } -ap_status_t ap_put_os_exp_time(ap_exploded_time_t *aprtime, - ap_os_exp_time_t **ostime, ap_pool_t *cont) +APR_DECLARE(apr_status_t) apr_os_exp_time_put(apr_time_exp_t *aprtime, + apr_os_exp_time_t **ostime, + apr_pool_t *cont) { aprtime->tm_sec = (*ostime)->tm_sec; aprtime->tm_min = (*ostime)->tm_min; @@ -234,16 +224,36 @@ ap_status_t ap_put_os_exp_time(ap_exploded_time_t *aprtime, aprtime->tm_wday = (*ostime)->tm_wday; aprtime->tm_yday = (*ostime)->tm_yday; aprtime->tm_isdst = (*ostime)->tm_isdst; - return APR_SUCCESS; -} +#if defined(HAVE_STRUCT_TM_TM_GMTOFF) + aprtime->tm_gmtoff = (*ostime)->tm_gmtoff; +#elif defined(HAVE_STRUCT_TM___TM_GMTOFF) + aprtime->tm_gmtoff = (*ostime)->__tm_gmtoff; +#endif + return APR_SUCCESS; +} +APR_DECLARE(void) apr_sleep(apr_interval_time_t t) +{ #ifdef OS2 -#define INCL_DOS -#include <os2.h> + DosSleep(t/1000); +#elif defined(BEOS) + snooze(t); +#elif defined(NETWARE) + delay(t/1000); +#else + struct timeval tv; + tv.tv_usec = t % APR_USEC_PER_SEC; + tv.tv_sec = t / APR_USEC_PER_SEC; + select(0, NULL, NULL, NULL, &tv); +#endif +} -ap_status_t ap_os2_time_to_ap_time(ap_time_t *result, FDATE os2date, FTIME os2time) +#ifdef OS2 +APR_DECLARE(apr_status_t) apr_os2_time_to_apr_time(apr_time_t *result, + FDATE os2date, + FTIME os2time) { struct tm tmpdate; @@ -257,7 +267,86 @@ ap_status_t ap_os2_time_to_ap_time(ap_time_t *result, FDATE os2date, FTIME os2ti tmpdate.tm_year = os2date.year + 80; tmpdate.tm_isdst = -1; - *result = mktime(&tmpdate) * AP_USEC_PER_SEC; + *result = mktime(&tmpdate) * APR_USEC_PER_SEC; return APR_SUCCESS; } + +APR_DECLARE(apr_status_t) apr_apr_time_to_os2_time(FDATE *os2date, + FTIME *os2time, + apr_time_t aprtime) +{ + time_t ansitime = aprtime / APR_USEC_PER_SEC; + struct tm *lt; + lt = localtime(&ansitime); + os2time->hours = lt->tm_hour; + os2time->minutes = lt->tm_min; + os2time->twosecs = lt->tm_sec / 2; + + os2date->day = lt->tm_mday; + os2date->month = lt->tm_mon + 1; + os2date->year = lt->tm_year - 80; + return APR_SUCCESS; +} +#endif + +#ifdef NETWARE +APR_DECLARE(void) apr_netware_setup_time(void) +{ + tzset(); + server_gmt_offset = -TZONE; +} +#else +APR_DECLARE(void) apr_unix_setup_time(void) +{ +#ifdef NO_GMTOFF_IN_STRUCT_TM + /* Precompute the offset from GMT on systems where it's not + in struct tm. + + Note: This offset is normalized to be independent of daylight + savings time; if the calculation happens to be done in a + time/place where a daylight savings adjustment is in effect, + the returned offset has the same value that it would have + in the same location if daylight savings were not in effect. + The reason for this is that the returned offset can be + applied to a past or future timestamp in explode_time(), + so the DST adjustment obtained from the current time won't + necessarily be applicable. + + mktime() is the inverse of localtime(); so, presumably, + passing in a struct tm made by gmtime() let's us calculate + the true GMT offset. However, there's a catch: if daylight + savings is in effect, gmtime()will set the tm_isdst field + and confuse mktime() into returning a time that's offset + by one hour. In that case, we must adjust the calculated GMT + offset. + + */ + + struct timeval now; + time_t t1, t2; + struct tm t; + + gettimeofday(&now, NULL); + t1 = now.tv_sec; + t2 = 0; + +#if APR_HAS_THREADS && defined(_POSIX_THREAD_SAFE_FUNCTIONS) + gmtime_r(&t1, &t); +#else + t = *gmtime(&t1); +#endif + t.tm_isdst = 0; /* we know this GMT time isn't daylight-savings */ + t2 = mktime(&t); + server_gmt_offset = (apr_int32_t) difftime(t1, t2); +#endif /* NO_GMTOFF_IN_STRUCT_TM */ +} + #endif + +/* A noop on all known Unix implementations */ +APR_DECLARE(void) apr_time_clock_hires(apr_pool_t *p) +{ + return; +} + + diff --git a/time/unix/timestr.c b/time/unix/timestr.c index 889f4799734..f74febac192 100644 --- a/time/unix/timestr.c +++ b/time/unix/timestr.c @@ -1,83 +1,56 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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 "atime.h" #include "apr_portable.h" - +#include "apr_time.h" +#include "apr_lib.h" +#include "apr_private.h" +/* System Headers required for time library */ +#if APR_HAVE_SYS_TIME_H +#include <sys/time.h> +#endif +#ifdef HAVE_TIME_H +#include <time.h> +#endif +#if APR_HAVE_STRING_H #include <string.h> +#endif +/* End System Headers */ -API_VAR_EXPORT const char ap_month_snames[12][4] = +APR_DECLARE_DATA const char apr_month_snames[12][4] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; -API_VAR_EXPORT const char ap_day_snames[7][4] = +APR_DECLARE_DATA const char apr_day_snames[7][4] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; -ap_status_t ap_rfc822_date(char *date_str, ap_time_t t) +apr_status_t apr_rfc822_date(char *date_str, apr_time_t t) { - ap_exploded_time_t xt; + apr_time_exp_t xt; const char *s; int real_year; - ap_explode_gmt(&xt, t); + apr_time_exp_gmt(&xt, t); /* example: "Sat, 08 Jan 2000 18:31:41 GMT" */ /* 12345678901234567890123456789 */ - s = &ap_day_snames[xt.tm_wday][0]; + s = &apr_day_snames[xt.tm_wday][0]; *date_str++ = *s++; *date_str++ = *s++; *date_str++ = *s++; @@ -86,7 +59,7 @@ ap_status_t ap_rfc822_date(char *date_str, ap_time_t t) *date_str++ = xt.tm_mday / 10 + '0'; *date_str++ = xt.tm_mday % 10 + '0'; *date_str++ = ' '; - s = &ap_month_snames[xt.tm_mon][0]; + s = &apr_month_snames[xt.tm_mon][0]; *date_str++ = *s++; *date_str++ = *s++; *date_str++ = *s++; @@ -114,22 +87,22 @@ ap_status_t ap_rfc822_date(char *date_str, ap_time_t t) return APR_SUCCESS; } -ap_status_t ap_ctime(char *date_str, ap_time_t t) +apr_status_t apr_ctime(char *date_str, apr_time_t t) { - ap_exploded_time_t xt; + apr_time_exp_t xt; const char *s; int real_year; /* example: "Wed Jun 30 21:49:08 1993" */ /* 123456789012345678901234 */ - ap_explode_localtime(&xt, t); - s = &ap_day_snames[xt.tm_wday][0]; + apr_time_exp_lt(&xt, t); + s = &apr_day_snames[xt.tm_wday][0]; *date_str++ = *s++; *date_str++ = *s++; *date_str++ = *s++; *date_str++ = ' '; - s = &ap_month_snames[xt.tm_mon][0]; + s = &apr_month_snames[xt.tm_mon][0]; *date_str++ = *s++; *date_str++ = *s++; *date_str++ = *s++; @@ -156,11 +129,10 @@ ap_status_t ap_ctime(char *date_str, ap_time_t t) return APR_SUCCESS; } -ap_status_t ap_strftime(char *s, ap_size_t *retsize, ap_size_t max, - const char *format, ap_exploded_time_t *xt) +apr_status_t apr_strftime(char *s, apr_size_t *retsize, apr_size_t max, + const char *format, apr_time_exp_t *xt) { struct tm tm; - memset(&tm, 0, sizeof tm); tm.tm_sec = xt->tm_sec; tm.tm_min = xt->tm_min; @@ -171,6 +143,11 @@ ap_status_t ap_strftime(char *s, ap_size_t *retsize, ap_size_t max, tm.tm_wday = xt->tm_wday; tm.tm_yday = xt->tm_yday; tm.tm_isdst = xt->tm_isdst; +#if defined(HAVE_STRUCT_TM_TM_GMTOFF) + tm.tm_gmtoff = xt->tm_gmtoff; +#elif defined(HAVE_STRUCT_TM___TM_GMTOFF) + tm.__tm_gmtoff = xt->tm_gmtoff; +#endif (*retsize) = strftime(s, max, format, &tm); return APR_SUCCESS; } diff --git a/time/win32/access.c b/time/win32/access.c deleted file mode 100644 index 7ec0e4ec7d2..00000000000 --- a/time/win32/access.c +++ /dev/null @@ -1,267 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#include "atime.h" -#include "apr_time.h" -#include "apr_general.h" -#include "apr_lib.h" - -ap_status_t ap_get_curtime(struct atime_t *time, ap_time_t *rv) -{ - if (time) { - (*rv) = time->currtime; - return APR_SUCCESS; - } - return APR_ENOTIME; -} - -ap_status_t ap_get_sec(struct atime_t *time, ap_int32_t *rv) -{ - if (time) { - (*rv) = time->explodedtime->wSecond; - return APR_SUCCESS; - } - return APR_ENOTIME; -} - -ap_status_t ap_get_min(struct atime_t *time, ap_int32_t *rv) -{ - if (time) { - (*rv) = time->explodedtime->wMinute; - return APR_SUCCESS; - } - return APR_ENOTIME; -} - -ap_status_t ap_get_hour(struct atime_t *time, ap_int32_t *rv) -{ - if (time) { - (*rv) = time->explodedtime->wHour; - return APR_SUCCESS; - } - return APR_ENOTIME; -} - -ap_status_t ap_get_mday(struct atime_t *time, ap_int32_t *rv) -{ - if (time) { - (*rv) = time->explodedtime->wDay; - return APR_SUCCESS; - } - return APR_ENOTIME; -} - -ap_status_t ap_get_mon(struct atime_t *time, ap_int32_t *rv) -{ - if (time) { - (*rv) = time->explodedtime->wMonth; - return APR_SUCCESS; - } - return APR_ENOTIME; -} - -ap_status_t ap_get_year(struct atime_t *time, ap_int32_t *rv) -{ - if (time) { - (*rv) = time->explodedtime->wYear; - return APR_SUCCESS; - } - return APR_ENOTIME; -} - -ap_status_t ap_get_wday(struct atime_t *time, ap_int32_t *rv) -{ - if (time) { - (*rv) = time->explodedtime->wDayOfWeek; - return APR_SUCCESS; - } - return APR_ENOTIME; -} - -ap_status_t ap_set_sec(struct atime_t *time, ap_int32_t value) -{ - if (!time) { - return APR_ENOTIME; - } - if (time->explodedtime == NULL) { - time->explodedtime = (SYSTEMTIME *)ap_pcalloc(time->cntxt, - sizeof(SYSTEMTIME)); - } - if (time->explodedtime == NULL) { - return APR_ENOMEM; - } - time->explodedtime->wSecond = value; - return APR_SUCCESS; -} - -ap_status_t ap_set_min(struct atime_t *time, ap_int32_t value) -{ - if (!time) { - return APR_ENOTIME; - } - if (time->explodedtime == NULL) { - time->explodedtime = (SYSTEMTIME *)ap_pcalloc(time->cntxt, - sizeof(SYSTEMTIME)); - } - if (time->explodedtime == NULL) { - return APR_ENOMEM; - } - time->explodedtime->wMinute = value; - return APR_SUCCESS; -} - -ap_status_t ap_set_hour(struct atime_t *time, ap_int32_t value) -{ - if (!time) { - return APR_ENOTIME; - } - if (time->explodedtime == NULL) { - time->explodedtime = (SYSTEMTIME *)ap_pcalloc(time->cntxt, - sizeof(SYSTEMTIME)); - } - if (time->explodedtime == NULL) { - return APR_ENOMEM; - } - time->explodedtime->wHour = value; - return APR_SUCCESS; -} - -ap_status_t ap_set_mday(struct atime_t *time, ap_int32_t value) -{ - if (!time) { - return APR_ENOTIME; - } - if (time->explodedtime == NULL) { - time->explodedtime = (SYSTEMTIME *)ap_pcalloc(time->cntxt, - sizeof(SYSTEMTIME)); - } - if (time->explodedtime == NULL) { - return APR_ENOMEM; - } - time->explodedtime->wDay = value; - return APR_SUCCESS; -} - -ap_status_t ap_set_mon(struct atime_t *time, ap_int32_t value) -{ - if (!time) { - return APR_ENOTIME; - } - if (time->explodedtime == NULL) { - time->explodedtime = (SYSTEMTIME *)ap_pcalloc(time->cntxt, - sizeof(SYSTEMTIME)); - } - if (time->explodedtime == NULL) { - return APR_ENOMEM; - } - time->explodedtime->wMonth = value; - return APR_SUCCESS; -} - -ap_status_t ap_set_year(struct atime_t *time, ap_int32_t value) -{ - if (!time) { - return APR_ENOTIME; - } - if (time->explodedtime == NULL) { - time->explodedtime = (SYSTEMTIME *)ap_pcalloc(time->cntxt, - sizeof(SYSTEMTIME)); - } - if (time->explodedtime == NULL) { - return APR_ENOMEM; - } - time->explodedtime->wYear = value; - return APR_SUCCESS; -} - -ap_status_t ap_set_wday(struct atime_t *time, ap_int32_t value) -{ - if (!time) { - return APR_ENOTIME; - } - if (time->explodedtime == NULL) { - time->explodedtime = (SYSTEMTIME *)ap_pcalloc(time->cntxt, - sizeof(SYSTEMTIME)); - } - if (time->explodedtime == NULL) { - return APR_ENOMEM; - } - time->explodedtime->wDayOfWeek = value; - return APR_SUCCESS; -} - -ap_status_t ap_get_timedata(struct atime_t *atime, char *key, void *data) -{ - if (atime != NULL) { - return ap_get_userdata(data, key, atime->cntxt); - } - else { - data = NULL; - return APR_ENOTIME; - } -} - -ap_status_t ap_set_timedata(struct atime_t *atime, void *data, char *key, - ap_status_t (*cleanup) (void *)) -{ - if (atime != NULL) { - return ap_set_userdata(data, key, cleanup, atime->cntxt); - } - else { - data = NULL; - return APR_ENOTIME; - } -} - - diff --git a/time/win32/atime.h b/time/win32/atime.h deleted file mode 100644 index cf5ab487386..00000000000 --- a/time/win32/atime.h +++ /dev/null @@ -1,72 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#ifndef ATIME_H -#define ATIME_H - -#include "apr_private.h" -#include "apr_time.h" -#include <time.h> - -struct atime_t { - ap_pool_t *cntxt; - ap_time_t currtime; - SYSTEMTIME *explodedtime; -}; - -void FileTimeToAprTime(ap_time_t *atime, FILETIME *ft); -void AprTimeToFileTime(LPFILETIME pft, ap_time_t t); - -#endif /* ! ATIME_H */ - diff --git a/time/win32/time.c b/time/win32/time.c index 76d62de33e1..1a705443b2b 100644 --- a/time/win32/time.c +++ b/time/win32/time.c @@ -1,94 +1,65 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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 "atime.h" +#include "apr_arch_atime.h" #include "apr_time.h" #include "apr_general.h" #include "apr_lib.h" #include "apr_portable.h" +#if APR_HAVE_TIME_H #include <time.h> +#endif +#if APR_HAVE_ERRNO_H #include <errno.h> +#endif #include <string.h> #include <winbase.h> +#include "apr_arch_misc.h" -/* Number of micro-seconds between the beginning of the Windows epoch - * (Jan. 1, 1601) and the Unix epoch (Jan. 1, 1970) +/* Leap year is any year divisible by four, but not by 100 unless also + * divisible by 400 */ -#define AP_DELTA_EPOCH_IN_USEC 11644473600000000; +#define IsLeapYear(y) ((!(y % 4)) ? (((y % 400) && !(y % 100)) ? 0 : 1) : 0) -void FileTimeToAprTime(ap_time_t *result, FILETIME *input) +static DWORD get_local_timezone(TIME_ZONE_INFORMATION **tzresult) { - /* Convert FILETIME one 64 bit number so we can work with it. */ - *result = input->dwHighDateTime; - *result = (*result) << 32; - *result |= input->dwLowDateTime; - *result /= 10; /* Convert from 100 nano-sec periods to micro-seconds. */ - *result -= AP_DELTA_EPOCH_IN_USEC; /* Convert from Windows epoch to Unix epoch */ - return; -} -void AprTimeToFileTime(LPFILETIME pft, ap_time_t t) -{ - LONGLONG ll; - t += AP_DELTA_EPOCH_IN_USEC; - ll = t * 10; - pft->dwLowDateTime = (DWORD)ll; - pft->dwHighDateTime = (DWORD) (ll >> 32); - return; + static TIME_ZONE_INFORMATION tz; + static DWORD result; + static int init = 0; + + if (!init) { + result = GetTimeZoneInformation(&tz); + init = 1; + } + + *tzresult = &tz; + return result; } -void SystemTimeToAprExpTime(ap_exploded_time_t *xt, SYSTEMTIME *tm) +static void SystemTimeToAprExpTime(apr_time_exp_t *xt, SYSTEMTIME *tm) { + static const int dayoffset[12] = + {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}; + + if (tm->wMonth < 1 || tm->wMonth > 12) + return APR_EBADDATE; + + /* Note; the caller is responsible for filling in detailed tm_usec, + * tm_gmtoff and tm_isdst data when applicable. + */ xt->tm_usec = tm->wMilliseconds * 1000; xt->tm_sec = tm->wSecond; xt->tm_min = tm->wMinute; @@ -97,63 +68,167 @@ void SystemTimeToAprExpTime(ap_exploded_time_t *xt, SYSTEMTIME *tm) xt->tm_mon = tm->wMonth - 1; xt->tm_year = tm->wYear - 1900; xt->tm_wday = tm->wDayOfWeek; - xt->tm_yday = 0; /* ToDo: need to compute this */ - xt->tm_isdst = 0; /* ToDo: need to compute this */ - xt->tm_gmtoff = 0; /* ToDo: maybe the caller should set this explicitly */ - return; + xt->tm_yday = dayoffset[xt->tm_mon] + (tm->wDay - 1); + xt->tm_isdst = 0; + xt->tm_gmtoff = 0; + + /* If this is a leap year, and we're past the 28th of Feb. (the + * 58th day after Jan. 1), we'll increment our tm_yday by one. + */ + if (IsLeapYear(tm->wYear) && (xt->tm_yday > 58)) + xt->tm_yday++; } -ap_status_t ap_ansi_time_to_ap_time(ap_time_t *result, time_t input) +APR_DECLARE(apr_status_t) apr_time_ansi_put(apr_time_t *result, + time_t input) { - *result = (ap_time_t) input * AP_USEC_PER_SEC; + *result = (apr_time_t) input * APR_USEC_PER_SEC; return APR_SUCCESS; } -/* Return micro-seconds since the Unix epoch (jan. 1, 1970) */ -ap_time_t ap_now(void) +/* Return micro-seconds since the Unix epoch (jan. 1, 1970) UTC */ +APR_DECLARE(apr_time_t) apr_time_now(void) { LONGLONG aprtime = 0; FILETIME time; +#ifndef _WIN32_WCE GetSystemTimeAsFileTime(&time); +#else + SYSTEMTIME st; + GetSystemTime(&st); + SystemTimeToFileTime(&st, &time); +#endif FileTimeToAprTime(&aprtime, &time); return aprtime; } -ap_status_t ap_explode_gmt(ap_exploded_time_t *result, ap_time_t input) +APR_DECLARE(apr_status_t) apr_time_exp_gmt(apr_time_exp_t *result, + apr_time_t input) { FILETIME ft; SYSTEMTIME st; AprTimeToFileTime(&ft, input); FileTimeToSystemTime(&ft, &st); + /* The Platform SDK documents that SYSTEMTIME/FILETIME are + * generally UTC, so no timezone info needed + */ SystemTimeToAprExpTime(result, &st); - result->tm_gmtoff = 0; + result->tm_usec = (apr_int32_t) (input % APR_USEC_PER_SEC); return APR_SUCCESS; } -ap_status_t ap_explode_localtime(ap_exploded_time_t *result, ap_time_t input) +APR_DECLARE(apr_status_t) apr_time_exp_tz(apr_time_exp_t *result, + apr_time_t input, + apr_int32_t offs) +{ + FILETIME ft; + SYSTEMTIME st; + AprTimeToFileTime(&ft, input + (offs * APR_USEC_PER_SEC)); + FileTimeToSystemTime(&ft, &st); + /* The Platform SDK documents that SYSTEMTIME/FILETIME are + * generally UTC, so we will simply note the offs used. + */ + SystemTimeToAprExpTime(result, &st); + result->tm_usec = (apr_int32_t) (input % APR_USEC_PER_SEC); + result->tm_gmtoff = offs; + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_time_exp_lt(apr_time_exp_t *result, + apr_time_t input) { SYSTEMTIME st; FILETIME ft, localft; AprTimeToFileTime(&ft, input); - FileTimeToLocalFileTime(&ft, &localft); - FileTimeToSystemTime(&localft, &st); - SystemTimeToAprExpTime(result, &st); + +#if APR_HAS_UNICODE_FS && !defined(_WIN32_WCE) + IF_WIN_OS_IS_UNICODE + { + TIME_ZONE_INFORMATION *tz; + SYSTEMTIME localst; + apr_time_t localtime; + + get_local_timezone(&tz); + + FileTimeToSystemTime(&ft, &st); + + /* The Platform SDK documents that SYSTEMTIME/FILETIME are + * generally UTC. We use SystemTimeToTzSpecificLocalTime + * because FileTimeToLocalFileFime is documented that the + * resulting time local file time would have DST relative + * to the *present* date, not the date converted. + */ + SystemTimeToTzSpecificLocalTime(tz, &st, &localst); + SystemTimeToAprExpTime(result, &localst); + result->tm_usec = (apr_int32_t) (input % APR_USEC_PER_SEC); + + + /* Recover the resulting time as an apr time and use the + * delta for gmtoff in seconds (and ignore msec rounding) + */ + SystemTimeToFileTime(&localst, &localft); + FileTimeToAprTime(&localtime, &localft); + result->tm_gmtoff = (int)apr_time_sec(localtime) + - (int)apr_time_sec(input); + + /* To compute the dst flag, we compare the expected + * local (standard) timezone bias to the delta. + * [Note, in war time or double daylight time the + * resulting tm_isdst is, desireably, 2 hours] + */ + result->tm_isdst = (result->tm_gmtoff / 3600) + - (-(tz->Bias + tz->StandardBias) / 60); + } +#endif +#if APR_HAS_ANSI_FS || defined(_WIN32_WCE) + ELSE_WIN_OS_IS_ANSI + { + TIME_ZONE_INFORMATION tz; + /* XXX: This code is simply *wrong*. The time converted will always + * map to the *now current* status of daylight savings time. + */ + + FileTimeToLocalFileTime(&ft, &localft); + FileTimeToSystemTime(&localft, &st); + SystemTimeToAprExpTime(result, &st); + result->tm_usec = (apr_int32_t) (input % APR_USEC_PER_SEC); + + switch (GetTimeZoneInformation(&tz)) { + case TIME_ZONE_ID_UNKNOWN: + result->tm_isdst = 0; + /* Bias = UTC - local time in minutes + * tm_gmtoff is seconds east of UTC + */ + result->tm_gmtoff = tz.Bias * -60; + break; + case TIME_ZONE_ID_STANDARD: + result->tm_isdst = 0; + result->tm_gmtoff = (tz.Bias + tz.StandardBias) * -60; + break; + case TIME_ZONE_ID_DAYLIGHT: + result->tm_isdst = 1; + result->tm_gmtoff = (tz.Bias + tz.DaylightBias) * -60; + break; + default: + /* noop */; + } + } +#endif + return APR_SUCCESS; } -ap_status_t ap_implode_time(ap_time_t *t, ap_exploded_time_t *xt) +APR_DECLARE(apr_status_t) apr_time_exp_get(apr_time_t *t, + apr_time_exp_t *xt) { - int year; - time_t days; + apr_time_t year = xt->tm_year; + apr_time_t days; static const int dayoffset[12] = {306, 337, 0, 31, 61, 92, 122, 153, 184, 214, 245, 275}; - year = xt->tm_year; - - if (year < 70 || ((sizeof(time_t) <= 4) && (year >= 138))) { + if (xt->tm_mon < 0 || xt->tm_mon >= 12) return APR_EBADDATE; - } /* shift new year to 1st March in order to make leap year calc easy */ @@ -171,19 +246,29 @@ ap_status_t ap_implode_time(ap_time_t *t, ap_exploded_time_t *xt) if (days < 0) { return APR_EBADDATE; } - days -= xt->tm_gmtoff; - *t = days * AP_USEC_PER_SEC + xt->tm_usec; + *t = days * APR_USEC_PER_SEC + xt->tm_usec; return APR_SUCCESS; } -ap_status_t ap_get_os_imp_time(ap_os_imp_time_t **ostime, ap_time_t *aprtime) +APR_DECLARE(apr_status_t) apr_time_exp_gmt_get(apr_time_t *t, + apr_time_exp_t *xt) +{ + apr_status_t status = apr_time_exp_get(t, xt); + if (status == APR_SUCCESS) + *t -= (apr_time_t) xt->tm_gmtoff * APR_USEC_PER_SEC; + return status; +} + +APR_DECLARE(apr_status_t) apr_os_imp_time_get(apr_os_imp_time_t **ostime, + apr_time_t *aprtime) { - /* TODO: Consider not passing in pointer to ap_time_t (e.g., call by value) */ + /* TODO: Consider not passing in pointer to apr_time_t (e.g., call by value) */ AprTimeToFileTime(*ostime, *aprtime); return APR_SUCCESS; } -ap_status_t ap_get_os_exp_time(ap_os_exp_time_t **ostime, ap_exploded_time_t *aprexptime) +APR_DECLARE(apr_status_t) apr_os_exp_time_get(apr_os_exp_time_t **ostime, + apr_time_exp_t *aprexptime) { (*ostime)->wYear = aprexptime->tm_year + 1900; (*ostime)->wMonth = aprexptime->tm_mon + 1; @@ -196,17 +281,59 @@ ap_status_t ap_get_os_exp_time(ap_os_exp_time_t **ostime, ap_exploded_time_t *ap return APR_SUCCESS; } -ap_status_t ap_put_os_imp_time(ap_time_t *aprtime, ap_os_imp_time_t **ostime, - ap_pool_t *cont) +APR_DECLARE(apr_status_t) apr_os_imp_time_put(apr_time_t *aprtime, + apr_os_imp_time_t **ostime, + apr_pool_t *cont) { + /* XXX: sanity failure, what is file time, gmt or local ? + */ FileTimeToAprTime(aprtime, *ostime); return APR_SUCCESS; } -ap_status_t ap_put_os_exp_time(ap_exploded_time_t *aprtime, - ap_os_exp_time_t **ostime, ap_pool_t *cont) +APR_DECLARE(apr_status_t) apr_os_exp_time_put(apr_time_exp_t *aprtime, + apr_os_exp_time_t **ostime, + apr_pool_t *cont) { + /* The Platform SDK documents that SYSTEMTIME/FILETIME are + * generally UTC, so no timezone info needed + */ SystemTimeToAprExpTime(aprtime, *ostime); return APR_SUCCESS; } +APR_DECLARE(void) apr_sleep(apr_interval_time_t t) +{ + /* One of the few sane situations for a cast, Sleep + * is in ms, not us, and passed as a DWORD value + */ + Sleep((DWORD)(t / 1000)); +} + +#if defined(_WIN32_WCE) +/* A noop on WinCE, like Unix implementation */ +APR_DECLARE(void) apr_time_clock_hires(apr_pool_t *p) +{ + return; +} +#else +static apr_status_t clock_restore(void *unsetres) +{ + ULONG newRes; + SetTimerResolution((ULONG)(apr_ssize_t)unsetres, FALSE, &newRes); + return APR_SUCCESS; +} + +APR_DECLARE(void) apr_time_clock_hires(apr_pool_t *p) +{ + ULONG newRes; + /* Timer resolution is stated in 100ns units. Note that TRUE requests the + * new clock resolution, FALSE above releases the request. + */ + if (SetTimerResolution(10000, TRUE, &newRes) == 0 /* STATUS_SUCCESS */) { + /* register the cleanup... */ + apr_pool_cleanup_register(p, (void*)10000, clock_restore, + apr_pool_cleanup_null); + } +} +#endif diff --git a/time/win32/timestr.c b/time/win32/timestr.c index 099fc1448a4..13841235218 100644 --- a/time/win32/timestr.c +++ b/time/win32/timestr.c @@ -1,81 +1,48 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 +/* 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 * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. + * 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 "atime.h" +#include "apr_arch_atime.h" #include "apr_portable.h" +#include "apr_strings.h" + +#if APR_HAVE_STDLIB_H +#include <stdlib.h> +#endif -API_VAR_EXPORT const char ap_month_snames[12][4] = +APR_DECLARE_DATA const char apr_month_snames[12][4] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; -API_VAR_EXPORT const char ap_day_snames[7][4] = +APR_DECLARE_DATA const char apr_day_snames[7][4] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; -ap_status_t ap_rfc822_date(char *date_str, ap_time_t t) +APR_DECLARE(apr_status_t) apr_rfc822_date(char *date_str, apr_time_t t) { - ap_exploded_time_t xt; + apr_time_exp_t xt; const char *s; int real_year; - ap_explode_gmt(&xt, t); + apr_time_exp_gmt(&xt, t); /* example: "Sat, 08 Jan 2000 18:31:41 GMT" */ /* 12345678901234567890123456789 */ - s = &ap_day_snames[xt.tm_wday][0]; + s = &apr_day_snames[xt.tm_wday][0]; *date_str++ = *s++; *date_str++ = *s++; *date_str++ = *s++; @@ -84,7 +51,7 @@ ap_status_t ap_rfc822_date(char *date_str, ap_time_t t) *date_str++ = xt.tm_mday / 10 + '0'; *date_str++ = xt.tm_mday % 10 + '0'; *date_str++ = ' '; - s = &ap_month_snames[xt.tm_mon][0]; + s = &apr_month_snames[xt.tm_mon][0]; *date_str++ = *s++; *date_str++ = *s++; *date_str++ = *s++; @@ -112,22 +79,22 @@ ap_status_t ap_rfc822_date(char *date_str, ap_time_t t) return APR_SUCCESS; } -ap_status_t ap_ctime(char *date_str, ap_time_t t) +APR_DECLARE(apr_status_t) apr_ctime(char *date_str, apr_time_t t) { - ap_exploded_time_t xt; + apr_time_exp_t xt; const char *s; int real_year; /* example: "Wed Jun 30 21:49:08 1993" */ /* 123456789012345678901234 */ - ap_explode_localtime(&xt, t); - s = &ap_day_snames[xt.tm_wday][0]; + apr_time_exp_lt(&xt, t); + s = &apr_day_snames[xt.tm_wday][0]; *date_str++ = *s++; *date_str++ = *s++; *date_str++ = *s++; *date_str++ = ' '; - s = &ap_month_snames[xt.tm_mon][0]; + s = &apr_month_snames[xt.tm_mon][0]; *date_str++ = *s++; *date_str++ = *s++; *date_str++ = *s++; @@ -154,9 +121,88 @@ ap_status_t ap_ctime(char *date_str, ap_time_t t) return APR_SUCCESS; } -ap_status_t ap_strftime(char *s, ap_size_t *retsize, ap_size_t max, - const char *format, ap_exploded_time_t *xt) + +#ifndef _WIN32_WCE + +static apr_size_t win32_strftime_extra(char *s, size_t max, const char *format, + const struct tm *tm) +{ + /* If the new format string is bigger than max, the result string won't fit + * anyway. If format strings are added, made sure the padding below is + * enough */ + char *new_format = (char *) malloc(max + 11); + size_t i, j, format_length = strlen(format); + apr_size_t return_value; + int length_written; + + for (i = 0, j = 0; (i < format_length && j < max);) { + if (format[i] != '%') { + new_format[j++] = format[i++]; + continue; + } + switch (format[i+1]) { + case 'C': + length_written = apr_snprintf(new_format + j, max - j, "%2d", + (tm->tm_year + 1970)/100); + j = (length_written == -1) ? max : (j + length_written); + i += 2; + break; + case 'D': + /* Is this locale dependent? Shouldn't be... + Also note the year 2000 exposure here */ + memcpy(new_format + j, "%m/%d/%y", 8); + i += 2; + j += 8; + break; + case 'r': + memcpy(new_format + j, "%I:%M:%S %p", 11); + i += 2; + j += 11; + break; + case 'R': + memcpy(new_format + j, "%H:%M", 5); + i += 2; + j += 5; + break; + case 'T': + memcpy(new_format + j, "%H:%M:%S", 8); + i += 2; + j += 8; + break; + case 'e': + length_written = apr_snprintf(new_format + j, max - j, "%2d", + tm->tm_mday); + j = (length_written == -1) ? max : (j + length_written); + i += 2; + break; + default: + /* We know we can advance two characters forward here. Also + * makes sure that %% is preserved. */ + new_format[j++] = format[i++]; + new_format[j++] = format[i++]; + } + } + if (j >= max) { + *s = '\0'; /* Defensive programming, okay since output is undefined*/ + return_value = 0; + } else { + new_format[j] = '\0'; + return_value = strftime(s, max, new_format, tm); + } + free(new_format); + return return_value; +} + +#endif + + +APR_DECLARE(apr_status_t) apr_strftime(char *s, apr_size_t *retsize, + apr_size_t max, const char *format, + apr_time_exp_t *xt) { +#ifdef _WIN32_WCE + return APR_ENOTIMPL; +#else struct tm tm; memset(&tm, 0, sizeof tm); tm.tm_sec = xt->tm_sec; @@ -168,6 +214,7 @@ ap_status_t ap_strftime(char *s, ap_size_t *retsize, ap_size_t max, tm.tm_wday = xt->tm_wday; tm.tm_yday = xt->tm_yday; tm.tm_isdst = xt->tm_isdst; - (*retsize) = strftime(s, max, format, &tm); + (*retsize) = win32_strftime_extra(s, max, format, &tm); return APR_SUCCESS; +#endif } diff --git a/tools/gen_test_char.c b/tools/gen_test_char.c new file mode 100644 index 00000000000..c48d2cbe743 --- /dev/null +++ b/tools/gen_test_char.c @@ -0,0 +1,131 @@ +/* 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. + */ + +#if defined(WIN32) || defined(OS2) +#define NEED_ENHANCED_ESCAPES +#endif + +#include <stdio.h> +#include <string.h> +#include <stdio.h> +#include <ctype.h> + +/* A bunch of functions in util.c scan strings looking for certain characters. + * To make that more efficient we encode a lookup table. + */ +#define T_ESCAPE_SHELL_CMD (0x01) +#define T_ESCAPE_PATH_SEGMENT (0x02) +#define T_OS_ESCAPE_PATH (0x04) +#define T_ESCAPE_ECHO (0x08) +#define T_ESCAPE_URLENCODED (0x10) +#define T_ESCAPE_XML (0x20) +#define T_ESCAPE_LDAP_DN (0x40) +#define T_ESCAPE_LDAP_FILTER (0x80) + +int main(int argc, char *argv[]) +{ + unsigned c; + unsigned char flags; + + printf("/* this file is automatically generated by gen_test_char, " + "do not edit. \"make include/private/apr_escape_test_char.h\" to regenerate. */\n" + "#define T_ESCAPE_SHELL_CMD (%u)\n" + "#define T_ESCAPE_PATH_SEGMENT (%u)\n" + "#define T_OS_ESCAPE_PATH (%u)\n" + "#define T_ESCAPE_ECHO (%u)\n" + "#define T_ESCAPE_URLENCODED (%u)\n" + "#define T_ESCAPE_XML (%u)\n" + "#define T_ESCAPE_LDAP_DN (%u)\n" + "#define T_ESCAPE_LDAP_FILTER (%u)\n" + "\n" + "static const unsigned char test_char_table[256] = {", + T_ESCAPE_SHELL_CMD, + T_ESCAPE_PATH_SEGMENT, + T_OS_ESCAPE_PATH, + T_ESCAPE_ECHO, + T_ESCAPE_URLENCODED, + T_ESCAPE_XML, + T_ESCAPE_LDAP_DN, + T_ESCAPE_LDAP_FILTER); + + for (c = 0; c < 256; ++c) { + flags = 0; + if (c % 20 == 0) + printf("\n "); + + /* escape_shell_cmd */ +#ifdef NEED_ENHANCED_ESCAPES + /* Win32/OS2 have many of the same vulnerable characters + * as Unix sh, plus the carriage return and percent char. + * The proper escaping of these characters varies from unix + * since Win32/OS2 use carets or doubled-double quotes, + * and neither lf nor cr can be escaped. We escape unix + * specific as well, to assure that cross-compiled unix + * applications behave similiarly when invoked on win32/os2. + * + * Rem please keep in-sync with apr's list in win32/filesys.c + */ + if (c && strchr("&;`'\"|*?~<>^()[]{}$\\\n\r%", c)) { + flags |= T_ESCAPE_SHELL_CMD; + } +#else + if (c && strchr("&;`'\"|*?~<>^()[]{}$\\\n", c)) { + flags |= T_ESCAPE_SHELL_CMD; + } +#endif + + if (!isalnum(c) && !strchr("$-_.+!*'(),:@&=~", c)) { + flags |= T_ESCAPE_PATH_SEGMENT; + } + + if (!isalnum(c) && !strchr("$-_.+!*'(),:@&=/~", c)) { + flags |= T_OS_ESCAPE_PATH; + } + + if (!isalnum(c) && !strchr(".-*_ ", c)) { + flags |= T_ESCAPE_URLENCODED; + } + + /* For logging, escape all control characters, + * double quotes (because they delimit the request in the log file) + * backslashes (because we use backslash for escaping) + * and 8-bit chars with the high bit set + */ + if (c && (!isprint(c) || c == '"' || c == '\\' || iscntrl(c))) { + flags |= T_ESCAPE_ECHO; + } + + if (strchr("<>&\"", c)) { + flags |= T_ESCAPE_XML; + } + + /* LDAP DN escaping (RFC4514) */ + if (!isprint(c) || strchr("\"+,;<>\\", c)) { + flags |= T_ESCAPE_LDAP_DN; + } + + /* LDAP filter escaping (RFC4515) */ + if (!isprint(c) || strchr("*()\\", c)) { + flags |= T_ESCAPE_LDAP_FILTER; + } + + printf("%u%c", flags, (c < 255) ? ',' : ' '); + } + + printf("\n};\n"); + + return 0; +} diff --git a/uri/apr_uri.c b/uri/apr_uri.c new file mode 100644 index 00000000000..8b22d462f9f --- /dev/null +++ b/uri/apr_uri.c @@ -0,0 +1,962 @@ +/* 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. + */ + +/* + * apr_uri.c: URI related utility things + * + */ + +#include <stdlib.h> + +#include "apu.h" +#include "apr.h" +#include "apr_general.h" +#include "apr_strings.h" + +#define APR_WANT_STRFUNC +#include "apr_want.h" + +#include "apr_uri.h" + +typedef struct schemes_t schemes_t; + +/** Structure to store various schemes and their default ports */ +struct schemes_t { + /** The name of the scheme */ + const char *name; + /** The default port for the scheme */ + apr_port_t default_port; +}; + +/* Some WWW schemes and their default ports; this is basically /etc/services */ +/* This will become global when the protocol abstraction comes */ +/* As the schemes are searched by a linear search, */ +/* they are sorted by their expected frequency */ +static schemes_t schemes[] = +{ + {"http", APR_URI_HTTP_DEFAULT_PORT}, + {"ftp", APR_URI_FTP_DEFAULT_PORT}, + {"https", APR_URI_HTTPS_DEFAULT_PORT}, + {"gopher", APR_URI_GOPHER_DEFAULT_PORT}, + {"ldap", APR_URI_LDAP_DEFAULT_PORT}, + {"nntp", APR_URI_NNTP_DEFAULT_PORT}, + {"snews", APR_URI_SNEWS_DEFAULT_PORT}, + {"imap", APR_URI_IMAP_DEFAULT_PORT}, + {"pop", APR_URI_POP_DEFAULT_PORT}, + {"sip", APR_URI_SIP_DEFAULT_PORT}, + {"rtsp", APR_URI_RTSP_DEFAULT_PORT}, + {"wais", APR_URI_WAIS_DEFAULT_PORT}, + {"z39.50r", APR_URI_WAIS_DEFAULT_PORT}, + {"z39.50s", APR_URI_WAIS_DEFAULT_PORT}, + {"prospero", APR_URI_PROSPERO_DEFAULT_PORT}, + {"nfs", APR_URI_NFS_DEFAULT_PORT}, + {"tip", APR_URI_TIP_DEFAULT_PORT}, + {"acap", APR_URI_ACAP_DEFAULT_PORT}, + {"telnet", APR_URI_TELNET_DEFAULT_PORT}, + {"ssh", APR_URI_SSH_DEFAULT_PORT}, + { NULL, 0xFFFF } /* unknown port */ +}; + +APR_DECLARE(apr_port_t) apr_uri_port_of_scheme(const char *scheme_str) +{ + schemes_t *scheme; + + if (scheme_str) { + for (scheme = schemes; scheme->name != NULL; ++scheme) { + if (strcasecmp(scheme_str, scheme->name) == 0) { + return scheme->default_port; + } + } + } + return 0; +} + +/* Unparse a apr_uri_t structure to an URI string. + * Optionally suppress the password for security reasons. + */ +APR_DECLARE(char *) apr_uri_unparse(apr_pool_t *p, + const apr_uri_t *uptr, + unsigned flags) +{ + char *ret = ""; + + /* If suppressing the site part, omit both user name & scheme://hostname */ + if (!(flags & APR_URI_UNP_OMITSITEPART)) { + + /* Construct a "user:password@" string, honoring the passed + * APR_URI_UNP_ flags: */ + if (uptr->user || uptr->password) { + ret = apr_pstrcat(p, + (uptr->user && !(flags & APR_URI_UNP_OMITUSER)) + ? uptr->user : "", + (uptr->password && !(flags & APR_URI_UNP_OMITPASSWORD)) + ? ":" : "", + (uptr->password && !(flags & APR_URI_UNP_OMITPASSWORD)) + ? ((flags & APR_URI_UNP_REVEALPASSWORD) + ? uptr->password : "XXXXXXXX") + : "", + ((uptr->user && !(flags & APR_URI_UNP_OMITUSER)) || + (uptr->password && !(flags & APR_URI_UNP_OMITPASSWORD))) + ? "@" : "", + NULL); + } + + /* Construct scheme://site string */ + if (uptr->hostname) { + int is_default_port; + const char *lbrk = "", *rbrk = ""; + + if (strchr(uptr->hostname, ':')) { /* v6 literal */ + lbrk = "["; + rbrk = "]"; + } + + is_default_port = + (uptr->port_str == NULL || + uptr->port == 0 || + uptr->port == apr_uri_port_of_scheme(uptr->scheme)); + + ret = apr_pstrcat(p, "//", ret, lbrk, uptr->hostname, rbrk, + is_default_port ? "" : ":", + is_default_port ? "" : uptr->port_str, + NULL); + } + if (uptr->scheme) { + ret = apr_pstrcat(p, uptr->scheme, ":", ret, NULL); + } + } + + /* Should we suppress all path info? */ + if (!(flags & APR_URI_UNP_OMITPATHINFO)) { + /* Append path, query and fragment strings: */ + ret = apr_pstrcat(p, + ret, + (uptr->path) + ? uptr->path : "", + (uptr->query && !(flags & APR_URI_UNP_OMITQUERY)) + ? "?" : "", + (uptr->query && !(flags & APR_URI_UNP_OMITQUERY)) + ? uptr->query : "", + (uptr->fragment && !(flags & APR_URI_UNP_OMITQUERY)) + ? "#" : NULL, + (uptr->fragment && !(flags & APR_URI_UNP_OMITQUERY)) + ? uptr->fragment : NULL, + NULL); + } + return ret; +} + +/* Here is the hand-optimized parse_uri_components(). There are some wild + * tricks we could pull in assembly language that we don't pull here... like we + * can do word-at-time scans for delimiter characters using the same technique + * that fast memchr()s use. But that would be way non-portable. -djg + */ + +/* We have a apr_table_t that we can index by character and it tells us if the + * character is one of the interesting delimiters. Note that we even get + * compares for NUL for free -- it's just another delimiter. + */ + +#define T_SLASH 0x01 /* '/' */ +#define T_QUESTION 0x02 /* '?' */ +#define T_HASH 0x04 /* '#' */ +#define T_ALPHA 0x08 /* 'A' ... 'Z', 'a' ... 'z' */ +#define T_SCHEME 0x10 /* '0' ... '9', '-', '+', '.' + * (allowed in scheme except first char) + */ +#define T_NUL 0x80 /* '\0' */ + +#if APR_CHARSET_EBCDIC +/* Delimiter table for the EBCDIC character set */ +static const unsigned char uri_delims[256] = { + T_NUL, /* 0x00 */ + 0, /* 0x01 */ + 0, /* 0x02 */ + 0, /* 0x03 */ + 0, /* 0x04 */ + 0, /* 0x05 */ + 0, /* 0x06 */ + 0, /* 0x07 */ + 0, /* 0x08 */ + 0, /* 0x09 */ + 0, /* 0x0a */ + 0, /* 0x0b */ + 0, /* 0x0c */ + 0, /* 0x0d */ + 0, /* 0x0e */ + 0, /* 0x0f */ + 0, /* 0x10 */ + 0, /* 0x11 */ + 0, /* 0x12 */ + 0, /* 0x13 */ + 0, /* 0x14 */ + 0, /* 0x15 */ + 0, /* 0x16 */ + 0, /* 0x17 */ + 0, /* 0x18 */ + 0, /* 0x19 */ + 0, /* 0x1a */ + 0, /* 0x1b */ + 0, /* 0x1c */ + 0, /* 0x1d */ + 0, /* 0x1e */ + 0, /* 0x1f */ + 0, /* 0x20 */ + 0, /* 0x21 */ + 0, /* 0x22 */ + 0, /* 0x23 */ + 0, /* 0x24 */ + 0, /* 0x25 */ + 0, /* 0x26 */ + 0, /* 0x27 */ + 0, /* 0x28 */ + 0, /* 0x29 */ + 0, /* 0x2a */ + 0, /* 0x2b */ + 0, /* 0x2c */ + 0, /* 0x2d */ + 0, /* 0x2e */ + 0, /* 0x2f */ + 0, /* 0x30 */ + 0, /* 0x31 */ + 0, /* 0x32 */ + 0, /* 0x33 */ + 0, /* 0x34 */ + 0, /* 0x35 */ + 0, /* 0x36 */ + 0, /* 0x37 */ + 0, /* 0x38 */ + 0, /* 0x39 */ + 0, /* 0x3a */ + 0, /* 0x3b */ + 0, /* 0x3c */ + 0, /* 0x3d */ + 0, /* 0x3e */ + 0, /* 0x3f */ + 0, /* 0x40 ' ' */ + 0, /* 0x41 */ + 0, /* 0x42 */ + 0, /* 0x43 */ + 0, /* 0x44 */ + 0, /* 0x45 */ + 0, /* 0x46 */ + 0, /* 0x47 */ + 0, /* 0x48 */ + 0, /* 0x49 */ + 0, /* 0x4a '[' */ + T_SCHEME, /* 0x4b '.' */ + 0, /* 0x4c '<' */ + 0, /* 0x4d '(' */ + T_SCHEME, /* 0x4e '+' */ + 0, /* 0x4f '!' */ + 0, /* 0x50 '&' */ + 0, /* 0x51 */ + 0, /* 0x52 */ + 0, /* 0x53 */ + 0, /* 0x54 */ + 0, /* 0x55 */ + 0, /* 0x56 */ + 0, /* 0x57 */ + 0, /* 0x58 */ + 0, /* 0x59 */ + 0, /* 0x5a ']' */ + 0, /* 0x5b '$' */ + 0, /* 0x5c '*' */ + 0, /* 0x5d ')' */ + 0, /* 0x5e ';' */ + 0, /* 0x5f '^' */ + T_SCHEME, /* 0x60 '-' */ + T_SLASH, /* 0x61 '/' */ + 0, /* 0x62 */ + 0, /* 0x63 */ + 0, /* 0x64 */ + 0, /* 0x65 */ + 0, /* 0x66 */ + 0, /* 0x67 */ + 0, /* 0x68 */ + 0, /* 0x69 */ + 0, /* 0x6a '|' */ + 0, /* 0x6b ',' */ + 0, /* 0x6c '%' */ + 0, /* 0x6d '_' */ + 0, /* 0x6e '>' */ + T_QUESTION, /* 0x6f '?' */ + 0, /* 0x70 */ + 0, /* 0x71 */ + 0, /* 0x72 */ + 0, /* 0x73 */ + 0, /* 0x74 */ + 0, /* 0x75 */ + 0, /* 0x76 */ + 0, /* 0x77 */ + 0, /* 0x78 */ + 0, /* 0x79 '`' */ + 0, /* 0x7a ':' */ + T_HASH, /* 0x7b '#' */ + 0, /* 0x7c '@' */ + 0, /* 0x7d ''' */ + 0, /* 0x7e '=' */ + 0, /* 0x7f '"' */ + 0, /* 0x80 */ + T_ALPHA, /* 0x81 'a' */ + T_ALPHA, /* 0x82 'b' */ + T_ALPHA, /* 0x83 'c' */ + T_ALPHA, /* 0x84 'd' */ + T_ALPHA, /* 0x85 'e' */ + T_ALPHA, /* 0x86 'f' */ + T_ALPHA, /* 0x87 'g' */ + T_ALPHA, /* 0x88 'h' */ + T_ALPHA, /* 0x89 'i' */ + 0, /* 0x8a */ + 0, /* 0x8b */ + 0, /* 0x8c */ + 0, /* 0x8d */ + 0, /* 0x8e */ + 0, /* 0x8f */ + 0, /* 0x90 */ + T_ALPHA, /* 0x91 'j' */ + T_ALPHA, /* 0x92 'k' */ + T_ALPHA, /* 0x93 'l' */ + T_ALPHA, /* 0x94 'm' */ + T_ALPHA, /* 0x95 'n' */ + T_ALPHA, /* 0x96 'o' */ + T_ALPHA, /* 0x97 'p' */ + T_ALPHA, /* 0x98 'q' */ + T_ALPHA, /* 0x99 'r' */ + 0, /* 0x9a */ + 0, /* 0x9b */ + 0, /* 0x9c */ + 0, /* 0x9d */ + 0, /* 0x9e */ + 0, /* 0x9f */ + 0, /* 0xa0 */ + 0, /* 0xa1 '~' */ + T_ALPHA, /* 0xa2 's' */ + T_ALPHA, /* 0xa3 't' */ + T_ALPHA, /* 0xa4 'u' */ + T_ALPHA, /* 0xa5 'v' */ + T_ALPHA, /* 0xa6 'w' */ + T_ALPHA, /* 0xa7 'x' */ + T_ALPHA, /* 0xa8 'y' */ + T_ALPHA, /* 0xa9 'z' */ + 0, /* 0xaa */ + 0, /* 0xab */ + 0, /* 0xac */ + 0, /* 0xad */ + 0, /* 0xae */ + 0, /* 0xaf */ + 0, /* 0xb0 */ + 0, /* 0xb1 */ + 0, /* 0xb2 */ + 0, /* 0xb3 */ + 0, /* 0xb4 */ + 0, /* 0xb5 */ + 0, /* 0xb6 */ + 0, /* 0xb7 */ + 0, /* 0xb8 */ + 0, /* 0xb9 */ + 0, /* 0xba */ + 0, /* 0xbb */ + 0, /* 0xbc */ + 0, /* 0xbd */ + 0, /* 0xbe */ + 0, /* 0xbf */ + 0, /* 0xc0 '{' */ + T_ALPHA, /* 0xc1 'A' */ + T_ALPHA, /* 0xc2 'B' */ + T_ALPHA, /* 0xc3 'C' */ + T_ALPHA, /* 0xc4 'D' */ + T_ALPHA, /* 0xc5 'E' */ + T_ALPHA, /* 0xc6 'F' */ + T_ALPHA, /* 0xc7 'G' */ + T_ALPHA, /* 0xc8 'H' */ + T_ALPHA, /* 0xc9 'I' */ + 0, /* 0xca */ + 0, /* 0xcb */ + 0, /* 0xcc */ + 0, /* 0xcd */ + 0, /* 0xce */ + 0, /* 0xcf */ + 0, /* 0xd0 '}' */ + T_ALPHA, /* 0xd1 'J' */ + T_ALPHA, /* 0xd2 'K' */ + T_ALPHA, /* 0xd3 'L' */ + T_ALPHA, /* 0xd4 'M' */ + T_ALPHA, /* 0xd5 'N' */ + T_ALPHA, /* 0xd6 'O' */ + T_ALPHA, /* 0xd7 'P' */ + T_ALPHA, /* 0xd8 'Q' */ + T_ALPHA, /* 0xd9 'R' */ + 0, /* 0xda */ + 0, /* 0xdb */ + 0, /* 0xdc */ + 0, /* 0xdd */ + 0, /* 0xde */ + 0, /* 0xdf */ + 0, /* 0xe0 '\' */ + 0, /* 0xe1 */ + T_ALPHA, /* 0xe2 'S' */ + T_ALPHA, /* 0xe3 'T' */ + T_ALPHA, /* 0xe4 'U' */ + T_ALPHA, /* 0xe5 'V' */ + T_ALPHA, /* 0xe6 'W' */ + T_ALPHA, /* 0xe7 'X' */ + T_ALPHA, /* 0xe8 'Y' */ + T_ALPHA, /* 0xe9 'Z' */ + 0, /* 0xea */ + 0, /* 0xeb */ + 0, /* 0xec */ + 0, /* 0xed */ + 0, /* 0xee */ + 0, /* 0xef */ + T_SCHEME, /* 0xf0 '0' */ + T_SCHEME, /* 0xf1 '1' */ + T_SCHEME, /* 0xf2 '2' */ + T_SCHEME, /* 0xf3 '3' */ + T_SCHEME, /* 0xf4 '4' */ + T_SCHEME, /* 0xf5 '5' */ + T_SCHEME, /* 0xf6 '6' */ + T_SCHEME, /* 0xf7 '7' */ + T_SCHEME, /* 0xf8 '8' */ + T_SCHEME, /* 0xf9 '9' */ + 0, /* 0xfa */ + 0, /* 0xfb */ + 0, /* 0xfc */ + 0, /* 0xfd */ + 0, /* 0xfe */ + 0 /* 0xff */ +}; +#else +/* Delimiter table for the ASCII character set */ +static const unsigned char uri_delims[256] = { + T_NUL, /* 0x00 */ + 0, /* 0x01 */ + 0, /* 0x02 */ + 0, /* 0x03 */ + 0, /* 0x04 */ + 0, /* 0x05 */ + 0, /* 0x06 */ + 0, /* 0x07 */ + 0, /* 0x08 */ + 0, /* 0x09 */ + 0, /* 0x0a */ + 0, /* 0x0b */ + 0, /* 0x0c */ + 0, /* 0x0d */ + 0, /* 0x0e */ + 0, /* 0x0f */ + 0, /* 0x10 */ + 0, /* 0x11 */ + 0, /* 0x12 */ + 0, /* 0x13 */ + 0, /* 0x14 */ + 0, /* 0x15 */ + 0, /* 0x16 */ + 0, /* 0x17 */ + 0, /* 0x18 */ + 0, /* 0x19 */ + 0, /* 0x1a */ + 0, /* 0x1b */ + 0, /* 0x1c */ + 0, /* 0x1d */ + 0, /* 0x1e */ + 0, /* 0x1f */ + 0, /* 0x20 ' ' */ + 0, /* 0x21 '!' */ + 0, /* 0x22 '"' */ + T_HASH, /* 0x23 '#' */ + 0, /* 0x24 '$' */ + 0, /* 0x25 '%' */ + 0, /* 0x26 '&' */ + 0, /* 0x27 ''' */ + 0, /* 0x28 '(' */ + 0, /* 0x29 ')' */ + 0, /* 0x2a '*' */ + T_SCHEME, /* 0x2b '+' */ + 0, /* 0x2c ',' */ + T_SCHEME, /* 0x2d '-' */ + T_SCHEME, /* 0x2e '.' */ + T_SLASH, /* 0x2f '/' */ + T_SCHEME, /* 0x30 '0' */ + T_SCHEME, /* 0x31 '1' */ + T_SCHEME, /* 0x32 '2' */ + T_SCHEME, /* 0x33 '3' */ + T_SCHEME, /* 0x34 '4' */ + T_SCHEME, /* 0x35 '5' */ + T_SCHEME, /* 0x36 '6' */ + T_SCHEME, /* 0x37 '7' */ + T_SCHEME, /* 0x38 '8' */ + T_SCHEME, /* 0x39 '9' */ + 0, /* 0x3a ':' */ + 0, /* 0x3b ';' */ + 0, /* 0x3c '<' */ + 0, /* 0x3d '=' */ + 0, /* 0x3e '>' */ + T_QUESTION, /* 0x3f '?' */ + 0, /* 0x40 '@' */ + T_ALPHA, /* 0x41 'A' */ + T_ALPHA, /* 0x42 'B' */ + T_ALPHA, /* 0x43 'C' */ + T_ALPHA, /* 0x44 'D' */ + T_ALPHA, /* 0x45 'E' */ + T_ALPHA, /* 0x46 'F' */ + T_ALPHA, /* 0x47 'G' */ + T_ALPHA, /* 0x48 'H' */ + T_ALPHA, /* 0x49 'I' */ + T_ALPHA, /* 0x4a 'J' */ + T_ALPHA, /* 0x4b 'K' */ + T_ALPHA, /* 0x4c 'L' */ + T_ALPHA, /* 0x4d 'M' */ + T_ALPHA, /* 0x4e 'N' */ + T_ALPHA, /* 0x4f 'O' */ + T_ALPHA, /* 0x50 'P' */ + T_ALPHA, /* 0x51 'Q' */ + T_ALPHA, /* 0x52 'R' */ + T_ALPHA, /* 0x53 'S' */ + T_ALPHA, /* 0x54 'T' */ + T_ALPHA, /* 0x55 'U' */ + T_ALPHA, /* 0x56 'V' */ + T_ALPHA, /* 0x57 'W' */ + T_ALPHA, /* 0x58 'X' */ + T_ALPHA, /* 0x59 'Y' */ + T_ALPHA, /* 0x5a 'Z' */ + 0, /* 0x5b '[' */ + 0, /* 0x5c '\' */ + 0, /* 0x5d ']' */ + 0, /* 0x5e '^' */ + 0, /* 0x5f '_' */ + 0, /* 0x60 '`' */ + T_ALPHA, /* 0x61 'a' */ + T_ALPHA, /* 0x62 'b' */ + T_ALPHA, /* 0x63 'c' */ + T_ALPHA, /* 0x64 'd' */ + T_ALPHA, /* 0x65 'e' */ + T_ALPHA, /* 0x66 'f' */ + T_ALPHA, /* 0x67 'g' */ + T_ALPHA, /* 0x68 'h' */ + T_ALPHA, /* 0x69 'i' */ + T_ALPHA, /* 0x6a 'j' */ + T_ALPHA, /* 0x6b 'k' */ + T_ALPHA, /* 0x6c 'l' */ + T_ALPHA, /* 0x6d 'm' */ + T_ALPHA, /* 0x6e 'n' */ + T_ALPHA, /* 0x6f 'o' */ + T_ALPHA, /* 0x70 'p' */ + T_ALPHA, /* 0x71 'q' */ + T_ALPHA, /* 0x72 'r' */ + T_ALPHA, /* 0x73 's' */ + T_ALPHA, /* 0x74 't' */ + T_ALPHA, /* 0x75 'u' */ + T_ALPHA, /* 0x76 'v' */ + T_ALPHA, /* 0x77 'w' */ + T_ALPHA, /* 0x78 'x' */ + T_ALPHA, /* 0x79 'y' */ + T_ALPHA, /* 0x7a 'z' */ + 0, /* 0x7b '{' */ + 0, /* 0x7c '|' */ + 0, /* 0x7d '}' */ + 0, /* 0x7e '~' */ + 0, /* 0x7f */ + 0, /* 0x80 */ + 0, /* 0x81 */ + 0, /* 0x82 */ + 0, /* 0x83 */ + 0, /* 0x84 */ + 0, /* 0x85 */ + 0, /* 0x86 */ + 0, /* 0x87 */ + 0, /* 0x88 */ + 0, /* 0x89 */ + 0, /* 0x8a */ + 0, /* 0x8b */ + 0, /* 0x8c */ + 0, /* 0x8d */ + 0, /* 0x8e */ + 0, /* 0x8f */ + 0, /* 0x90 */ + 0, /* 0x91 */ + 0, /* 0x92 */ + 0, /* 0x93 */ + 0, /* 0x94 */ + 0, /* 0x95 */ + 0, /* 0x96 */ + 0, /* 0x97 */ + 0, /* 0x98 */ + 0, /* 0x99 */ + 0, /* 0x9a */ + 0, /* 0x9b */ + 0, /* 0x9c */ + 0, /* 0x9d */ + 0, /* 0x9e */ + 0, /* 0x9f */ + 0, /* 0xa0 */ + 0, /* 0xa1 */ + 0, /* 0xa2 */ + 0, /* 0xa3 */ + 0, /* 0xa4 */ + 0, /* 0xa5 */ + 0, /* 0xa6 */ + 0, /* 0xa7 */ + 0, /* 0xa8 */ + 0, /* 0xa9 */ + 0, /* 0xaa */ + 0, /* 0xab */ + 0, /* 0xac */ + 0, /* 0xad */ + 0, /* 0xae */ + 0, /* 0xaf */ + 0, /* 0xb0 */ + 0, /* 0xb1 */ + 0, /* 0xb2 */ + 0, /* 0xb3 */ + 0, /* 0xb4 */ + 0, /* 0xb5 */ + 0, /* 0xb6 */ + 0, /* 0xb7 */ + 0, /* 0xb8 */ + 0, /* 0xb9 */ + 0, /* 0xba */ + 0, /* 0xbb */ + 0, /* 0xbc */ + 0, /* 0xbd */ + 0, /* 0xbe */ + 0, /* 0xbf */ + 0, /* 0xc0 */ + 0, /* 0xc1 */ + 0, /* 0xc2 */ + 0, /* 0xc3 */ + 0, /* 0xc4 */ + 0, /* 0xc5 */ + 0, /* 0xc6 */ + 0, /* 0xc7 */ + 0, /* 0xc8 */ + 0, /* 0xc9 */ + 0, /* 0xca */ + 0, /* 0xcb */ + 0, /* 0xcc */ + 0, /* 0xcd */ + 0, /* 0xce */ + 0, /* 0xcf */ + 0, /* 0xd0 */ + 0, /* 0xd1 */ + 0, /* 0xd2 */ + 0, /* 0xd3 */ + 0, /* 0xd4 */ + 0, /* 0xd5 */ + 0, /* 0xd6 */ + 0, /* 0xd7 */ + 0, /* 0xd8 */ + 0, /* 0xd9 */ + 0, /* 0xda */ + 0, /* 0xdb */ + 0, /* 0xdc */ + 0, /* 0xdd */ + 0, /* 0xde */ + 0, /* 0xdf */ + 0, /* 0xe0 */ + 0, /* 0xe1 */ + 0, /* 0xe2 */ + 0, /* 0xe3 */ + 0, /* 0xe4 */ + 0, /* 0xe5 */ + 0, /* 0xe6 */ + 0, /* 0xe7 */ + 0, /* 0xe8 */ + 0, /* 0xe9 */ + 0, /* 0xea */ + 0, /* 0xeb */ + 0, /* 0xec */ + 0, /* 0xed */ + 0, /* 0xee */ + 0, /* 0xef */ + 0, /* 0xf0 */ + 0, /* 0xf1 */ + 0, /* 0xf2 */ + 0, /* 0xf3 */ + 0, /* 0xf4 */ + 0, /* 0xf5 */ + 0, /* 0xf6 */ + 0, /* 0xf7 */ + 0, /* 0xf8 */ + 0, /* 0xf9 */ + 0, /* 0xfa */ + 0, /* 0xfb */ + 0, /* 0xfc */ + 0, /* 0xfd */ + 0, /* 0xfe */ + 0 /* 0xff */ +}; +#endif + + +/* it works like this: + if (uri_delims[ch] & NOTEND_foobar) { + then we're not at a delimiter for foobar + } +*/ + +#define NOTEND_HOSTINFO (T_SLASH | T_QUESTION | T_HASH | T_NUL) +#define NOTEND_PATH (T_QUESTION | T_HASH | T_NUL) + +/* parse_uri_components(): + * Parse a given URI, fill in all supplied fields of a uri_components + * structure. This eliminates the necessity of extracting host, port, + * path, query info repeatedly in the modules. + * Side effects: + * - fills in fields of uri_components *uptr + * - none on any of the r->* fields + */ +APR_DECLARE(apr_status_t) apr_uri_parse(apr_pool_t *p, const char *uri, + apr_uri_t *uptr) +{ + const char *s; + const char *s1; + const char *hostinfo; + char *endstr; + int port; + int v6_offset1 = 0, v6_offset2 = 0; + + /* Initialize the structure. parse_uri() and parse_uri_components() + * can be called more than once per request. + */ + memset (uptr, '\0', sizeof(*uptr)); + uptr->is_initialized = 1; + + /* We assume the processor has a branch predictor like most -- + * it assumes forward branches are untaken and backwards are taken. That's + * the reason for the gotos. -djg + */ + if (uri[0] == '/') { + /* RFC2396 #4.3 says that two leading slashes mean we have an + * authority component, not a path! Fixing this looks scary + * with the gotos here. But if the existing logic is valid, + * then presumably a goto pointing to deal_with_authority works. + * + * RFC2396 describes this as resolving an ambiguity. In the + * case of three or more slashes there would seem to be no + * ambiguity, so it is a path after all. + */ + if (uri[1] == '/' && uri[2] != '/') { + s = uri + 2 ; + goto deal_with_authority ; + } + +deal_with_path: + /* we expect uri to point to first character of path ... remember + * that the path could be empty -- http://foobar?query for example + */ + s = uri; + while ((uri_delims[*(unsigned char *)s] & NOTEND_PATH) == 0) { + ++s; + } + if (s != uri) { + uptr->path = apr_pstrmemdup(p, uri, s - uri); + } + if (*s == 0) { + return APR_SUCCESS; + } + if (*s == '?') { + ++s; + s1 = strchr(s, '#'); + if (s1) { + uptr->fragment = apr_pstrdup(p, s1 + 1); + uptr->query = apr_pstrmemdup(p, s, s1 - s); + } + else { + uptr->query = apr_pstrdup(p, s); + } + return APR_SUCCESS; + } + /* otherwise it's a fragment */ + uptr->fragment = apr_pstrdup(p, s + 1); + return APR_SUCCESS; + } + + /* find the scheme: */ + s = uri; + /* first char must be letter */ + if (uri_delims[*(unsigned char *)s] & T_ALPHA) { + ++s; + while ((uri_delims[*(unsigned char *)s] & (T_ALPHA|T_SCHEME))) + ++s; + } + /* scheme must be non-empty and followed by : */ + if (s != uri && s[0] == ':') { + uptr->scheme = apr_pstrmemdup(p, uri, s - uri); + s++; + } + else { + /* No valid scheme, restart from the beginning */ + s = uri; + } + + if (s[0] != '/' || s[1] != '/') { + if (uri == s) { + /* + * RFC 3986 3.3: If we have no scheme and no authority, + * the leading segment of a relative path must not contain a ':'. + */ + char *first_slash = strchr(uri, '/'); + if (first_slash) { + while (s < first_slash) { + if (s[0] == ':') + return APR_EGENERAL; + ++s; + } + /* no scheme but relative path, e.g. '../image.jpg' */ + } + else { + if (strchr(uri, ':') != NULL) + return APR_EGENERAL; + /* no scheme, no slash, but relative path, e.g. 'image.jpg' */ + } + goto deal_with_path; + } + /* scheme and relative path */ + uri = s; + goto deal_with_path; + } + + s += 2; + +deal_with_authority: + hostinfo = s; + while ((uri_delims[*(unsigned char *)s] & NOTEND_HOSTINFO) == 0) { + ++s; + } + uri = s; /* whatever follows hostinfo is start of uri */ + uptr->hostinfo = apr_pstrmemdup(p, hostinfo, uri - hostinfo); + + /* If there's a username:password@host:port, the @ we want is the last @... + * too bad there's no memrchr()... For the C purists, note that hostinfo + * is definitely not the first character of the original uri so therefore + * &hostinfo[-1] < &hostinfo[0] ... and this loop is valid C. + */ + do { + --s; + } while (s >= hostinfo && *s != '@'); + if (s < hostinfo) { + /* again we want the common case to be fall through */ +deal_with_host: + /* We expect hostinfo to point to the first character of + * the hostname. If there's a port it is the first colon, + * except with IPv6. + */ + if (*hostinfo == '[') { + v6_offset1 = 1; + v6_offset2 = 2; + s = memchr(hostinfo, ']', uri - hostinfo); + if (s == NULL) { + return APR_EGENERAL; + } + if (*++s != ':') { + s = NULL; /* no port */ + } + } + else { + s = memchr(hostinfo, ':', uri - hostinfo); + } + if (s == NULL) { + /* we expect the common case to have no port */ + uptr->hostname = apr_pstrmemdup(p, + hostinfo + v6_offset1, + uri - hostinfo - v6_offset2); + goto deal_with_path; + } + uptr->hostname = apr_pstrmemdup(p, + hostinfo + v6_offset1, + s - hostinfo - v6_offset2); + ++s; + uptr->port_str = apr_pstrmemdup(p, s, uri - s); + if (uri != s) { + port = strtol(uptr->port_str, &endstr, 10); + uptr->port = port; + if (*endstr == '\0') { + goto deal_with_path; + } + /* Invalid characters after ':' found */ + return APR_EGENERAL; + } + uptr->port = apr_uri_port_of_scheme(uptr->scheme); + goto deal_with_path; + } + + /* first colon delimits username:password */ + s1 = memchr(hostinfo, ':', s - hostinfo); + if (s1) { + uptr->user = apr_pstrmemdup(p, hostinfo, s1 - hostinfo); + ++s1; + uptr->password = apr_pstrmemdup(p, s1, s - s1); + } + else { + uptr->user = apr_pstrmemdup(p, hostinfo, s - hostinfo); + } + hostinfo = s + 1; + goto deal_with_host; +} + +/* Special case for CONNECT parsing: it comes with the hostinfo part only */ +/* See the INTERNET-DRAFT document "Tunneling SSL Through a WWW Proxy" + * currently at http://www.mcom.com/newsref/std/tunneling_ssl.html + * for the format of the "CONNECT host:port HTTP/1.0" request + */ +APR_DECLARE(apr_status_t) apr_uri_parse_hostinfo(apr_pool_t *p, + const char *hostinfo, + apr_uri_t *uptr) +{ + const char *s; + char *endstr; + const char *rsb; + int v6_offset1 = 0; + + /* Initialize the structure. parse_uri() and parse_uri_components() + * can be called more than once per request. + */ + memset(uptr, '\0', sizeof(*uptr)); + uptr->is_initialized = 1; + uptr->hostinfo = apr_pstrdup(p, hostinfo); + + /* We expect hostinfo to point to the first character of + * the hostname. There must be a port, separated by a colon + */ + if (*hostinfo == '[') { + if ((rsb = strchr(hostinfo, ']')) == NULL || + *(rsb + 1) != ':') { + return APR_EGENERAL; + } + /* literal IPv6 address */ + s = rsb + 1; + ++hostinfo; + v6_offset1 = 1; + } + else { + s = strchr(hostinfo, ':'); + } + if (s == NULL) { + return APR_EGENERAL; + } + uptr->hostname = apr_pstrndup(p, hostinfo, s - hostinfo - v6_offset1); + ++s; + uptr->port_str = apr_pstrdup(p, s); + if (*s != '\0') { + uptr->port = (unsigned short) strtol(uptr->port_str, &endstr, 10); + if (*endstr == '\0') { + return APR_SUCCESS; + } + /* Invalid characters after ':' found */ + } + return APR_EGENERAL; +} diff --git a/user/netware/groupinfo.c b/user/netware/groupinfo.c new file mode 100644 index 00000000000..e7cfd9b2677 --- /dev/null +++ b/user/netware/groupinfo.c @@ -0,0 +1,41 @@ +/* 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_strings.h" +#include "apr_portable.h" +#include "apr_user.h" +#include "apr_private.h" +#ifdef HAVE_GRP_H +#include <grp.h> +#endif +#if APR_HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#if APR_HAVE_UNISTD_H +#include <unistd.h> /* for _POSIX_THREAD_SAFE_FUNCTIONS */ +#endif + +APR_DECLARE(apr_status_t) apr_gid_name_get(char **groupname, apr_gid_t groupid, + apr_pool_t *p) +{ + return APR_ENOTIMPL; +} + +APR_DECLARE(apr_status_t) apr_gid_get(apr_gid_t *groupid, + const char *groupname, apr_pool_t *p) +{ + return APR_ENOTIMPL; +} diff --git a/user/netware/userinfo.c b/user/netware/userinfo.c new file mode 100644 index 00000000000..b58991b8ea5 --- /dev/null +++ b/user/netware/userinfo.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. + */ + +#include "apr_strings.h" +#include "apr_portable.h" +#include "apr_user.h" +#include "apr_private.h" +#ifdef HAVE_PWD_H +#include <pwd.h> +#endif +#if APR_HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#if APR_HAVE_UNISTD_H +#include <unistd.h> /* for _POSIX_THREAD_SAFE_FUNCTIONS */ +#endif + +#define PWBUF_SIZE 512 + +static apr_status_t getpwnam_safe(const char *username, + struct passwd *pw, + char pwbuf[PWBUF_SIZE]) +{ + return APR_ENOTIMPL; +} + +APR_DECLARE(apr_status_t) apr_uid_homepath_get(char **dirname, + const char *username, + apr_pool_t *p) +{ + return APR_ENOTIMPL; +} + + + +APR_DECLARE(apr_status_t) apr_uid_current(apr_uid_t *uid, + apr_gid_t *gid, + apr_pool_t *p) +{ + return APR_ENOTIMPL; +} + + + + +APR_DECLARE(apr_status_t) apr_uid_get(apr_uid_t *uid, apr_gid_t *gid, + const char *username, apr_pool_t *p) +{ + return APR_ENOTIMPL; +} + +APR_DECLARE(apr_status_t) apr_uid_name_get(char **username, apr_uid_t userid, + apr_pool_t *p) +{ + return APR_ENOTIMPL; +} + diff --git a/user/unix/groupinfo.c b/user/unix/groupinfo.c new file mode 100644 index 00000000000..7967219f8fb --- /dev/null +++ b/user/unix/groupinfo.c @@ -0,0 +1,87 @@ +/* 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_strings.h" +#include "apr_portable.h" +#include "apr_user.h" +#include "apr_private.h" +#ifdef HAVE_GRP_H +#include <grp.h> +#endif +#if APR_HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#if APR_HAVE_UNISTD_H +#include <unistd.h> /* for _POSIX_THREAD_SAFE_FUNCTIONS */ +#endif + +#define GRBUF_SIZE 8192 + +APR_DECLARE(apr_status_t) apr_gid_name_get(char **groupname, apr_gid_t groupid, + apr_pool_t *p) +{ + struct group *gr; + +#if APR_HAS_THREADS && defined(_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETGRGID_R) + struct group grp; + char grbuf[GRBUF_SIZE]; + apr_status_t rv; + + /* See comment in getpwnam_safe on error handling. */ + rv = getgrgid_r(groupid, &grp, grbuf, sizeof(grbuf), &gr); + if (rv) { + return rv; + } + if (gr == NULL) { + return APR_ENOENT; + } +#else + errno = 0; + if ((gr = getgrgid(groupid)) == NULL) { + return errno ? errno : APR_ENOENT; + } +#endif + *groupname = apr_pstrdup(p, gr->gr_name); + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_gid_get(apr_gid_t *groupid, + const char *groupname, apr_pool_t *p) +{ + struct group *gr; + +#if APR_HAS_THREADS && defined(_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETGRNAM_R) + struct group grp; + char grbuf[GRBUF_SIZE]; + apr_status_t rv; + + /* See comment in getpwnam_safe on error handling. */ + rv = getgrnam_r(groupname, &grp, grbuf, sizeof(grbuf), &gr); + if (rv) { + return rv; + } + if (gr == NULL) { + return APR_ENOENT; + } +#else + errno = 0; + if ((gr = getgrnam(groupname)) == NULL) { + return errno ? errno : APR_ENOENT; + } +#endif + *groupid = gr->gr_gid; + return APR_SUCCESS; +} diff --git a/user/unix/userinfo.c b/user/unix/userinfo.c new file mode 100644 index 00000000000..516445b56d5 --- /dev/null +++ b/user/unix/userinfo.c @@ -0,0 +1,146 @@ +/* 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_strings.h" +#include "apr_portable.h" +#include "apr_user.h" +#include "apr_private.h" +#ifdef HAVE_PWD_H +#include <pwd.h> +#endif +#if APR_HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#if APR_HAVE_UNISTD_H +#include <unistd.h> /* for _POSIX_THREAD_SAFE_FUNCTIONS */ +#endif +#define APR_WANT_MEMFUNC +#include "apr_want.h" + +#define PWBUF_SIZE 2048 + +static apr_status_t getpwnam_safe(const char *username, + struct passwd *pw, + char pwbuf[PWBUF_SIZE]) +{ + struct passwd *pwptr; +#if APR_HAS_THREADS && defined(_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R) + apr_status_t rv; + + /* POSIX defines getpwnam_r() et al to return the error number + * rather than set errno, and requires pwptr to be set to NULL if + * the entry is not found, imply that "not found" is not an error + * condition; some implementations do return 0 with pwptr set to + * NULL. */ + rv = getpwnam_r(username, pw, pwbuf, PWBUF_SIZE, &pwptr); + if (rv) { + return rv; + } + if (pwptr == NULL) { + return APR_ENOENT; + } +#else + /* Some platforms (e.g. FreeBSD 4.x) do not set errno on NULL "not + * found" return values for the non-threadsafe function either. */ + errno = 0; + if ((pwptr = getpwnam(username)) != NULL) { + memcpy(pw, pwptr, sizeof *pw); + } + else { + return errno ? errno : APR_ENOENT; + } +#endif + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_uid_homepath_get(char **dirname, + const char *username, + apr_pool_t *p) +{ + struct passwd pw; + char pwbuf[PWBUF_SIZE]; + apr_status_t rv; + + if ((rv = getpwnam_safe(username, &pw, pwbuf)) != APR_SUCCESS) + return rv; + +#ifdef OS2 + /* Need to manually add user name for OS/2 */ + *dirname = apr_pstrcat(p, pw.pw_dir, pw.pw_name, NULL); +#else + *dirname = apr_pstrdup(p, pw.pw_dir); +#endif + return APR_SUCCESS; +} + + + +APR_DECLARE(apr_status_t) apr_uid_current(apr_uid_t *uid, + apr_gid_t *gid, + apr_pool_t *p) +{ + *uid = getuid(); + *gid = getgid(); + + return APR_SUCCESS; +} + + + + +APR_DECLARE(apr_status_t) apr_uid_get(apr_uid_t *uid, apr_gid_t *gid, + const char *username, apr_pool_t *p) +{ + struct passwd pw; + char pwbuf[PWBUF_SIZE]; + apr_status_t rv; + + if ((rv = getpwnam_safe(username, &pw, pwbuf)) != APR_SUCCESS) + return rv; + + *uid = pw.pw_uid; + *gid = pw.pw_gid; + + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_uid_name_get(char **username, apr_uid_t userid, + apr_pool_t *p) +{ + struct passwd *pw; +#if APR_HAS_THREADS && defined(_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWUID_R) + struct passwd pwd; + char pwbuf[PWBUF_SIZE]; + apr_status_t rv; + + rv = getpwuid_r(userid, &pwd, pwbuf, sizeof(pwbuf), &pw); + if (rv) { + return rv; + } + + if (pw == NULL) { + return APR_ENOENT; + } + +#else + errno = 0; + if ((pw = getpwuid(userid)) == NULL) { + return errno ? errno : APR_ENOENT; + } +#endif + *username = apr_pstrdup(p, pw->pw_name); + return APR_SUCCESS; +} diff --git a/user/win32/groupinfo.c b/user/win32/groupinfo.c new file mode 100644 index 00000000000..b53656962a2 --- /dev/null +++ b/user/win32/groupinfo.c @@ -0,0 +1,100 @@ +/* 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_strings.h" +#include "apr_portable.h" +#include "apr_user.h" +#include "apr_private.h" +#if APR_HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif + +APR_DECLARE(apr_status_t) apr_gid_get(apr_gid_t *gid, + const char *groupname, apr_pool_t *p) +{ +#ifdef _WIN32_WCE + return APR_ENOTIMPL; +#else + SID_NAME_USE sidtype; + char anydomain[256]; + char *domain; + DWORD sidlen = 0; + DWORD domlen = sizeof(anydomain); + DWORD rv; + char *pos; + + if ((pos = strchr(groupname, '/'))) { + domain = apr_pstrmemdup(p, groupname, pos - groupname); + groupname = pos + 1; + } + else if ((pos = strchr(groupname, '\\'))) { + domain = apr_pstrmemdup(p, groupname, pos - groupname); + groupname = pos + 1; + } + else { + domain = NULL; + } + /* Get nothing on the first pass ... need to size the sid buffer + */ + rv = LookupAccountName(domain, groupname, domain, &sidlen, + anydomain, &domlen, &sidtype); + if (sidlen) { + /* Give it back on the second pass + */ + *gid = apr_palloc(p, sidlen); + domlen = sizeof(anydomain); + rv = LookupAccountName(domain, groupname, *gid, &sidlen, + anydomain, &domlen, &sidtype); + } + if (!sidlen || !rv) { + return apr_get_os_error(); + } + return APR_SUCCESS; +#endif +} + +APR_DECLARE(apr_status_t) apr_gid_name_get(char **groupname, apr_gid_t groupid, apr_pool_t *p) +{ +#ifdef _WIN32_WCE + *groupname = apr_pstrdup(p, "Administrators"); +#else + SID_NAME_USE type; + char name[MAX_PATH], domain[MAX_PATH]; + DWORD cbname = sizeof(name), cbdomain = sizeof(domain); + if (!groupid) + return APR_EINVAL; + if (!LookupAccountSid(NULL, groupid, name, &cbname, domain, &cbdomain, &type)) + return apr_get_os_error(); + if (type != SidTypeGroup && type != SidTypeWellKnownGroup + && type != SidTypeAlias) + return APR_EINVAL; + *groupname = apr_pstrdup(p, name); +#endif + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_gid_compare(apr_gid_t left, apr_gid_t right) +{ + if (!left || !right) + return APR_EINVAL; +#ifndef _WIN32_WCE + if (!IsValidSid(left) || !IsValidSid(right)) + return APR_EINVAL; + if (!EqualSid(left, right)) + return APR_EMISMATCH; +#endif + return APR_SUCCESS; +} diff --git a/user/win32/userinfo.c b/user/win32/userinfo.c new file mode 100644 index 00000000000..c6b5084a536 --- /dev/null +++ b/user/win32/userinfo.c @@ -0,0 +1,280 @@ +/* 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_strings.h" +#include "apr_portable.h" +#include "apr_user.h" +#include "apr_arch_file_io.h" +#if APR_HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif + +#ifndef _WIN32_WCE +/* Internal sid binary to string translation, see MSKB Q131320. + * Several user related operations require our SID to access + * the registry, but in a string format. All error handling + * depends on IsValidSid(), which internally we better test long + * before we get here! + */ +static void get_sid_string(char *buf, apr_size_t blen, apr_uid_t id) +{ + PSID_IDENTIFIER_AUTHORITY psia; + DWORD nsa; + DWORD sa; + int slen; + + /* Determine authority values (these is a big-endian value, + * and NT records the value as hex if the value is > 2^32.) + */ + psia = GetSidIdentifierAuthority(id); + nsa = (DWORD)(psia->Value[5]) + ((DWORD)(psia->Value[4]) << 8) + + ((DWORD)(psia->Value[3]) << 16) + ((DWORD)(psia->Value[2]) << 24); + sa = (DWORD)(psia->Value[1]) + ((DWORD)(psia->Value[0]) << 8); + if (sa) { + slen = apr_snprintf(buf, blen, "S-%d-0x%04x%08x", + SID_REVISION, (unsigned int)sa, (unsigned int)nsa); + } else { + slen = apr_snprintf(buf, blen, "S-%d-%lu", + SID_REVISION, nsa); + } + + /* Now append all the subauthority strings. + */ + nsa = *GetSidSubAuthorityCount(id); + for (sa = 0; sa < nsa; ++sa) { + slen += apr_snprintf(buf + slen, blen - slen, "-%lu", + *GetSidSubAuthority(id, sa)); + } +} +#endif +/* Query the ProfileImagePath from the version-specific branch, where the + * regkey uses the user's name on 9x, and user's sid string on NT. + */ +APR_DECLARE(apr_status_t) apr_uid_homepath_get(char **dirname, + const char *username, + apr_pool_t *p) +{ +#ifdef _WIN32_WCE + *dirname = apr_pstrdup(p, "/My Documents"); + return APR_SUCCESS; +#else + apr_status_t rv; + char regkey[MAX_PATH * 2]; + char *fixch; + DWORD keylen; + DWORD type; + HKEY key; + + if (apr_os_level >= APR_WIN_NT) { + apr_uid_t uid; + apr_gid_t gid; + + if ((rv = apr_uid_get(&uid, &gid, username, p)) != APR_SUCCESS) + return rv; + + strcpy(regkey, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\" + "ProfileList\\"); + keylen = (DWORD)strlen(regkey); + get_sid_string(regkey + keylen, sizeof(regkey) - keylen, uid); + } + else { + strcpy(regkey, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\" + "ProfileList\\"); + keylen = (DWORD)strlen(regkey); + apr_cpystrn(regkey + keylen, username, sizeof(regkey) - keylen); + } + + if ((rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, regkey, 0, + KEY_QUERY_VALUE, &key)) != ERROR_SUCCESS) + return APR_FROM_OS_ERROR(rv); + +#if APR_HAS_UNICODE_FS + IF_WIN_OS_IS_UNICODE + { + keylen = sizeof(regkey); + rv = RegQueryValueExW(key, L"ProfileImagePath", NULL, &type, + (void*)regkey, &keylen); + RegCloseKey(key); + if (rv != ERROR_SUCCESS) + return APR_FROM_OS_ERROR(rv); + if (type == REG_SZ) { + char retdir[MAX_PATH]; + if ((rv = unicode_to_utf8_path(retdir, sizeof(retdir), + (apr_wchar_t*)regkey)) != APR_SUCCESS) + return rv; + *dirname = apr_pstrdup(p, retdir); + } + else if (type == REG_EXPAND_SZ) { + apr_wchar_t path[MAX_PATH]; + char retdir[MAX_PATH]; + ExpandEnvironmentStringsW((apr_wchar_t*)regkey, path, + sizeof(path) / 2); + if ((rv = unicode_to_utf8_path(retdir, sizeof(retdir), path)) + != APR_SUCCESS) + return rv; + *dirname = apr_pstrdup(p, retdir); + } + else + return APR_ENOENT; + } +#endif +#if APR_HAS_ANSI_FS + ELSE_WIN_OS_IS_ANSI + { + keylen = sizeof(regkey); + rv = RegQueryValueEx(key, "ProfileImagePath", NULL, &type, + (void*)regkey, &keylen); + RegCloseKey(key); + if (rv != ERROR_SUCCESS) + return APR_FROM_OS_ERROR(rv); + if (type == REG_SZ) { + *dirname = apr_pstrdup(p, regkey); + } + else if (type == REG_EXPAND_SZ) { + char path[MAX_PATH]; + ExpandEnvironmentStrings(regkey, path, sizeof(path)); + *dirname = apr_pstrdup(p, path); + } + else + return APR_ENOENT; + } +#endif /* APR_HAS_ANSI_FS */ + for (fixch = *dirname; *fixch; ++fixch) + if (*fixch == '\\') + *fixch = '/'; + return APR_SUCCESS; +#endif /* _WIN32_WCE */ +} + +APR_DECLARE(apr_status_t) apr_uid_current(apr_uid_t *uid, + apr_gid_t *gid, + apr_pool_t *p) +{ +#ifdef _WIN32_WCE + return APR_ENOTIMPL; +#else + HANDLE threadtok; + DWORD needed; + TOKEN_USER *usr; + TOKEN_PRIMARY_GROUP *grp; + + if(!OpenProcessToken(GetCurrentProcess(), STANDARD_RIGHTS_READ | READ_CONTROL | TOKEN_QUERY, &threadtok)) { + return apr_get_os_error(); + } + + *uid = NULL; + if (!GetTokenInformation(threadtok, TokenUser, NULL, 0, &needed) + && (GetLastError() == ERROR_INSUFFICIENT_BUFFER) + && (usr = apr_palloc(p, needed)) + && GetTokenInformation(threadtok, TokenUser, usr, needed, &needed)) + *uid = usr->User.Sid; + else + return apr_get_os_error(); + + if (!GetTokenInformation(threadtok, TokenPrimaryGroup, NULL, 0, &needed) + && (GetLastError() == ERROR_INSUFFICIENT_BUFFER) + && (grp = apr_palloc(p, needed)) + && GetTokenInformation(threadtok, TokenPrimaryGroup, grp, needed, &needed)) + *gid = grp->PrimaryGroup; + else + return apr_get_os_error(); + + return APR_SUCCESS; +#endif +} + +APR_DECLARE(apr_status_t) apr_uid_get(apr_uid_t *uid, apr_gid_t *gid, + const char *username, apr_pool_t *p) +{ +#ifdef _WIN32_WCE + return APR_ENOTIMPL; +#else + SID_NAME_USE sidtype; + char anydomain[256]; + char *domain; + DWORD sidlen = 0; + DWORD domlen = sizeof(anydomain); + DWORD rv; + char *pos; + + if ((pos = strchr(username, '/'))) { + domain = apr_pstrmemdup(p, username, pos - username); + username = pos + 1; + } + else if ((pos = strchr(username, '\\'))) { + domain = apr_pstrmemdup(p, username, pos - username); + username = pos + 1; + } + else { + domain = NULL; + } + /* Get nothing on the first pass ... need to size the sid buffer + */ + rv = LookupAccountName(domain, username, domain, &sidlen, + anydomain, &domlen, &sidtype); + if (sidlen) { + /* Give it back on the second pass + */ + *uid = apr_palloc(p, sidlen); + domlen = sizeof(anydomain); + rv = LookupAccountName(domain, username, *uid, &sidlen, + anydomain, &domlen, &sidtype); + } + if (!sidlen || !rv) { + return apr_get_os_error(); + } + /* There doesn't seem to be a simple way to retrieve the primary group sid + */ + *gid = NULL; + return APR_SUCCESS; +#endif +} + +APR_DECLARE(apr_status_t) apr_uid_name_get(char **username, apr_uid_t userid, + apr_pool_t *p) +{ +#ifdef _WIN32_WCE + *username = apr_pstrdup(p, "Administrator"); + return APR_SUCCESS; +#else + SID_NAME_USE type; + char name[MAX_PATH], domain[MAX_PATH]; + DWORD cbname = sizeof(name), cbdomain = sizeof(domain); + if (!userid) + return APR_EINVAL; + if (!LookupAccountSid(NULL, userid, name, &cbname, domain, &cbdomain, &type)) + return apr_get_os_error(); + if (type != SidTypeUser && type != SidTypeAlias && type != SidTypeWellKnownGroup) + return APR_EINVAL; + *username = apr_pstrdup(p, name); + return APR_SUCCESS; +#endif +} + +APR_DECLARE(apr_status_t) apr_uid_compare(apr_uid_t left, apr_uid_t right) +{ + if (!left || !right) + return APR_EINVAL; +#ifndef _WIN32_WCE + if (!IsValidSid(left) || !IsValidSid(right)) + return APR_EINVAL; + if (!EqualSid(left, right)) + return APR_EMISMATCH; +#endif + return APR_SUCCESS; +} + diff --git a/util-misc/apr_date.c b/util-misc/apr_date.c new file mode 100644 index 00000000000..e28e967fb15 --- /dev/null +++ b/util-misc/apr_date.c @@ -0,0 +1,637 @@ +/* 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. + */ + +/* + * apr_date.c: date parsing utility routines + * These routines are (hopefully) platform independent. + * + * 27 Oct 1996 Roy Fielding + * Extracted (with many modifications) from mod_proxy.c and + * tested with over 50,000 randomly chosen valid date strings + * and several hundred variations of invalid date strings. + * + */ + +#include "apr.h" +#include "apr_lib.h" + +#define APR_WANT_STRFUNC +#include "apr_want.h" + +#if APR_HAVE_STDLIB_H +#include <stdlib.h> +#endif + +#if APR_HAVE_CTYPE_H +#include <ctype.h> +#endif + +#include "apr_date.h" + +/* + * Compare a string to a mask + * Mask characters (arbitrary maximum is 256 characters, just in case): + * @ - uppercase letter + * $ - lowercase letter + * & - hex digit + * # - digit + * ~ - digit or space + * * - swallow remaining characters + * <x> - exact match for any other character + */ +APR_DECLARE(int) apr_date_checkmask(const char *data, const char *mask) +{ + int i; + char d; + + for (i = 0; i < 256; i++) { + d = data[i]; + switch (mask[i]) { + case '\0': + return (d == '\0'); + + case '*': + return 1; + + case '@': + if (!apr_isupper(d)) + return 0; + break; + case '$': + if (!apr_islower(d)) + return 0; + break; + case '#': + if (!apr_isdigit(d)) + return 0; + break; + case '&': + if (!apr_isxdigit(d)) + return 0; + break; + case '~': + if ((d != ' ') && !apr_isdigit(d)) + return 0; + break; + default: + if (mask[i] != d) + return 0; + break; + } + } + return 0; /* We only get here if mask is corrupted (exceeds 256) */ +} + +/* + * Parses an HTTP date in one of three standard forms: + * + * Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123 + * Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036 + * Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() format + * + * and returns the apr_time_t number of microseconds since 1 Jan 1970 GMT, + * or APR_DATE_BAD if this would be out of range or if the date is invalid. + * + * The restricted HTTP syntax is + * + * HTTP-date = rfc1123-date | rfc850-date | asctime-date + * + * rfc1123-date = wkday "," SP date1 SP time SP "GMT" + * rfc850-date = weekday "," SP date2 SP time SP "GMT" + * asctime-date = wkday SP date3 SP time SP 4DIGIT + * + * date1 = 2DIGIT SP month SP 4DIGIT + * ; day month year (e.g., 02 Jun 1982) + * date2 = 2DIGIT "-" month "-" 2DIGIT + * ; day-month-year (e.g., 02-Jun-82) + * date3 = month SP ( 2DIGIT | ( SP 1DIGIT )) + * ; month day (e.g., Jun 2) + * + * time = 2DIGIT ":" 2DIGIT ":" 2DIGIT + * ; 00:00:00 - 23:59:59 + * + * wkday = "Mon" | "Tue" | "Wed" + * | "Thu" | "Fri" | "Sat" | "Sun" + * + * weekday = "Monday" | "Tuesday" | "Wednesday" + * | "Thursday" | "Friday" | "Saturday" | "Sunday" + * + * month = "Jan" | "Feb" | "Mar" | "Apr" + * | "May" | "Jun" | "Jul" | "Aug" + * | "Sep" | "Oct" | "Nov" | "Dec" + * + * However, for the sake of robustness (and Netscapeness), we ignore the + * weekday and anything after the time field (including the timezone). + * + * This routine is intended to be very fast; 10x faster than using sscanf. + * + * Originally from Andrew Daviel <andrew@vancouver-webpages.com>, 29 Jul 96 + * but many changes since then. + * + */ +APR_DECLARE(apr_time_t) apr_date_parse_http(const char *date) +{ + apr_time_exp_t ds; + apr_time_t result; + int mint, mon; + const char *monstr, *timstr; + static const int months[12] = + { + ('J' << 16) | ('a' << 8) | 'n', ('F' << 16) | ('e' << 8) | 'b', + ('M' << 16) | ('a' << 8) | 'r', ('A' << 16) | ('p' << 8) | 'r', + ('M' << 16) | ('a' << 8) | 'y', ('J' << 16) | ('u' << 8) | 'n', + ('J' << 16) | ('u' << 8) | 'l', ('A' << 16) | ('u' << 8) | 'g', + ('S' << 16) | ('e' << 8) | 'p', ('O' << 16) | ('c' << 8) | 't', + ('N' << 16) | ('o' << 8) | 'v', ('D' << 16) | ('e' << 8) | 'c'}; + + if (!date) + return APR_DATE_BAD; + + while (*date && apr_isspace(*date)) /* Find first non-whitespace char */ + ++date; + + if (*date == '\0') + return APR_DATE_BAD; + + if ((date = strchr(date, ' ')) == NULL) /* Find space after weekday */ + return APR_DATE_BAD; + + ++date; /* Now pointing to first char after space, which should be */ + + /* start of the actual date information for all 4 formats. */ + + if (apr_date_checkmask(date, "## @$$ #### ##:##:## *")) { + /* RFC 1123 format with two days */ + ds.tm_year = ((date[7] - '0') * 10 + (date[8] - '0') - 19) * 100; + if (ds.tm_year < 0) + return APR_DATE_BAD; + + ds.tm_year += ((date[9] - '0') * 10) + (date[10] - '0'); + + ds.tm_mday = ((date[0] - '0') * 10) + (date[1] - '0'); + + monstr = date + 3; + timstr = date + 12; + } + else if (apr_date_checkmask(date, "##-@$$-## ##:##:## *")) { + /* RFC 850 format */ + ds.tm_year = ((date[7] - '0') * 10) + (date[8] - '0'); + if (ds.tm_year < 70) + ds.tm_year += 100; + + ds.tm_mday = ((date[0] - '0') * 10) + (date[1] - '0'); + + monstr = date + 3; + timstr = date + 10; + } + else if (apr_date_checkmask(date, "@$$ ~# ##:##:## ####*")) { + /* asctime format */ + ds.tm_year = ((date[16] - '0') * 10 + (date[17] - '0') - 19) * 100; + if (ds.tm_year < 0) + return APR_DATE_BAD; + + ds.tm_year += ((date[18] - '0') * 10) + (date[19] - '0'); + + if (date[4] == ' ') + ds.tm_mday = 0; + else + ds.tm_mday = (date[4] - '0') * 10; + + ds.tm_mday += (date[5] - '0'); + + monstr = date; + timstr = date + 7; + } + else if (apr_date_checkmask(date, "# @$$ #### ##:##:## *")) { + /* RFC 1123 format with one day */ + ds.tm_year = ((date[6] - '0') * 10 + (date[7] - '0') - 19) * 100; + if (ds.tm_year < 0) + return APR_DATE_BAD; + + ds.tm_year += ((date[8] - '0') * 10) + (date[9] - '0'); + + ds.tm_mday = (date[0] - '0'); + + monstr = date + 2; + timstr = date + 11; + } + else + return APR_DATE_BAD; + + if (ds.tm_mday <= 0 || ds.tm_mday > 31) + return APR_DATE_BAD; + + ds.tm_hour = ((timstr[0] - '0') * 10) + (timstr[1] - '0'); + ds.tm_min = ((timstr[3] - '0') * 10) + (timstr[4] - '0'); + ds.tm_sec = ((timstr[6] - '0') * 10) + (timstr[7] - '0'); + + if ((ds.tm_hour > 23) || (ds.tm_min > 59) || (ds.tm_sec > 61)) + return APR_DATE_BAD; + + mint = (monstr[0] << 16) | (monstr[1] << 8) | monstr[2]; + for (mon = 0; mon < 12; mon++) + if (mint == months[mon]) + break; + + if (mon == 12) + return APR_DATE_BAD; + + if ((ds.tm_mday == 31) && (mon == 3 || mon == 5 || mon == 8 || mon == 10)) + return APR_DATE_BAD; + + /* February gets special check for leapyear */ + if ((mon == 1) && + ((ds.tm_mday > 29) || + ((ds.tm_mday == 29) + && ((ds.tm_year & 3) + || (((ds.tm_year % 100) == 0) + && (((ds.tm_year % 400) != 100))))))) + return APR_DATE_BAD; + + ds.tm_mon = mon; + + /* ap_mplode_time uses tm_usec and tm_gmtoff fields, but they haven't + * been set yet. + * It should be safe to just zero out these values. + * tm_usec is the number of microseconds into the second. HTTP only + * cares about second granularity. + * tm_gmtoff is the number of seconds off of GMT the time is. By + * definition all times going through this function are in GMT, so this + * is zero. + */ + ds.tm_usec = 0; + ds.tm_gmtoff = 0; + if (apr_time_exp_get(&result, &ds) != APR_SUCCESS) + return APR_DATE_BAD; + + return result; +} + +/* + * Parses a string resembling an RFC 822 date. This is meant to be + * leinent in its parsing of dates. Hence, this will parse a wider + * range of dates than apr_date_parse_http. + * + * The prominent mailer (or poster, if mailer is unknown) that has + * been seen in the wild is included for the unknown formats. + * + * Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123 + * Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036 + * Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() format + * Sun, 6 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123 + * Sun, 06 Nov 94 08:49:37 GMT ; RFC 822 + * Sun, 6 Nov 94 08:49:37 GMT ; RFC 822 + * Sun, 06 Nov 94 08:49 GMT ; Unknown [drtr@ast.cam.ac.uk] + * Sun, 6 Nov 94 08:49 GMT ; Unknown [drtr@ast.cam.ac.uk] + * Sun, 06 Nov 94 8:49:37 GMT ; Unknown [Elm 70.85] + * Sun, 6 Nov 94 8:49:37 GMT ; Unknown [Elm 70.85] + * Mon, 7 Jan 2002 07:21:22 GMT ; Unknown [Postfix] + * Sun, 06-Nov-1994 08:49:37 GMT ; RFC 850 with four digit years + * + */ + +#define TIMEPARSE(ds,hr10,hr1,min10,min1,sec10,sec1) \ + { \ + ds.tm_hour = ((hr10 - '0') * 10) + (hr1 - '0'); \ + ds.tm_min = ((min10 - '0') * 10) + (min1 - '0'); \ + ds.tm_sec = ((sec10 - '0') * 10) + (sec1 - '0'); \ + } +#define TIMEPARSE_STD(ds,timstr) \ + { \ + TIMEPARSE(ds, timstr[0],timstr[1], \ + timstr[3],timstr[4], \ + timstr[6],timstr[7]); \ + } + +APR_DECLARE(apr_time_t) apr_date_parse_rfc(const char *date) +{ + apr_time_exp_t ds; + apr_time_t result; + int mint, mon; + const char *monstr, *timstr, *gmtstr; + static const int months[12] = + { + ('J' << 16) | ('a' << 8) | 'n', ('F' << 16) | ('e' << 8) | 'b', + ('M' << 16) | ('a' << 8) | 'r', ('A' << 16) | ('p' << 8) | 'r', + ('M' << 16) | ('a' << 8) | 'y', ('J' << 16) | ('u' << 8) | 'n', + ('J' << 16) | ('u' << 8) | 'l', ('A' << 16) | ('u' << 8) | 'g', + ('S' << 16) | ('e' << 8) | 'p', ('O' << 16) | ('c' << 8) | 't', + ('N' << 16) | ('o' << 8) | 'v', ('D' << 16) | ('e' << 8) | 'c' }; + + if (!date) + return APR_DATE_BAD; + + /* Not all dates have text days at the beginning. */ + if (!apr_isdigit(date[0])) + { + while (*date && apr_isspace(*date)) /* Find first non-whitespace char */ + ++date; + + if (*date == '\0') + return APR_DATE_BAD; + + if ((date = strchr(date, ' ')) == NULL) /* Find space after weekday */ + return APR_DATE_BAD; + + ++date; /* Now pointing to first char after space, which should be */ } + + /* start of the actual date information for all 11 formats. */ + if (apr_date_checkmask(date, "## @$$ #### ##:##:## *")) { /* RFC 1123 format */ + ds.tm_year = ((date[7] - '0') * 10 + (date[8] - '0') - 19) * 100; + + if (ds.tm_year < 0) + return APR_DATE_BAD; + + ds.tm_year += ((date[9] - '0') * 10) + (date[10] - '0'); + + ds.tm_mday = ((date[0] - '0') * 10) + (date[1] - '0'); + + monstr = date + 3; + timstr = date + 12; + gmtstr = date + 21; + + TIMEPARSE_STD(ds, timstr); + } + else if (apr_date_checkmask(date, "##-@$$-## ##:##:## *")) {/* RFC 850 format */ + ds.tm_year = ((date[7] - '0') * 10) + (date[8] - '0'); + + if (ds.tm_year < 70) + ds.tm_year += 100; + + ds.tm_mday = ((date[0] - '0') * 10) + (date[1] - '0'); + + monstr = date + 3; + timstr = date + 10; + gmtstr = date + 19; + + TIMEPARSE_STD(ds, timstr); + } + else if (apr_date_checkmask(date, "@$$ ~# ##:##:## ####*")) { + /* asctime format */ + ds.tm_year = ((date[16] - '0') * 10 + (date[17] - '0') - 19) * 100; + if (ds.tm_year < 0) + return APR_DATE_BAD; + + ds.tm_year += ((date[18] - '0') * 10) + (date[19] - '0'); + + if (date[4] == ' ') + ds.tm_mday = 0; + else + ds.tm_mday = (date[4] - '0') * 10; + + ds.tm_mday += (date[5] - '0'); + + monstr = date; + timstr = date + 7; + gmtstr = NULL; + + TIMEPARSE_STD(ds, timstr); + } + else if (apr_date_checkmask(date, "# @$$ #### ##:##:## *")) { + /* RFC 1123 format*/ + ds.tm_year = ((date[6] - '0') * 10 + (date[7] - '0') - 19) * 100; + + if (ds.tm_year < 0) + return APR_DATE_BAD; + + ds.tm_year += ((date[8] - '0') * 10) + (date[9] - '0'); + ds.tm_mday = (date[0] - '0'); + + monstr = date + 2; + timstr = date + 11; + gmtstr = date + 20; + + TIMEPARSE_STD(ds, timstr); + } + else if (apr_date_checkmask(date, "## @$$ ## ##:##:## *")) { + /* This is the old RFC 1123 date format - many many years ago, people + * used two-digit years. Oh, how foolish. + * + * Two-digit day, two-digit year version. */ + ds.tm_year = ((date[7] - '0') * 10) + (date[8] - '0'); + + if (ds.tm_year < 70) + ds.tm_year += 100; + + ds.tm_mday = ((date[0] - '0') * 10) + (date[1] - '0'); + + monstr = date + 3; + timstr = date + 10; + gmtstr = date + 19; + + TIMEPARSE_STD(ds, timstr); + } + else if (apr_date_checkmask(date, " # @$$ ## ##:##:## *")) { + /* This is the old RFC 1123 date format - many many years ago, people + * used two-digit years. Oh, how foolish. + * + * Space + one-digit day, two-digit year version.*/ + ds.tm_year = ((date[7] - '0') * 10) + (date[8] - '0'); + + if (ds.tm_year < 70) + ds.tm_year += 100; + + ds.tm_mday = (date[1] - '0'); + + monstr = date + 3; + timstr = date + 10; + gmtstr = date + 19; + + TIMEPARSE_STD(ds, timstr); + } + else if (apr_date_checkmask(date, "# @$$ ## ##:##:## *")) { + /* This is the old RFC 1123 date format - many many years ago, people + * used two-digit years. Oh, how foolish. + * + * One-digit day, two-digit year version. */ + ds.tm_year = ((date[6] - '0') * 10) + (date[7] - '0'); + + if (ds.tm_year < 70) + ds.tm_year += 100; + + ds.tm_mday = (date[0] - '0'); + + monstr = date + 2; + timstr = date + 9; + gmtstr = date + 18; + + TIMEPARSE_STD(ds, timstr); + } + else if (apr_date_checkmask(date, "## @$$ ## ##:## *")) { + /* Loser format. This is quite bogus. */ + ds.tm_year = ((date[7] - '0') * 10) + (date[8] - '0'); + + if (ds.tm_year < 70) + ds.tm_year += 100; + + ds.tm_mday = ((date[0] - '0') * 10) + (date[1] - '0'); + + monstr = date + 3; + timstr = date + 10; + gmtstr = NULL; + + TIMEPARSE(ds, timstr[0],timstr[1], timstr[3],timstr[4], '0','0'); + } + else if (apr_date_checkmask(date, "# @$$ ## ##:## *")) { + /* Loser format. This is quite bogus. */ + ds.tm_year = ((date[6] - '0') * 10) + (date[7] - '0'); + + if (ds.tm_year < 70) + ds.tm_year += 100; + + ds.tm_mday = (date[0] - '0'); + + monstr = date + 2; + timstr = date + 9; + gmtstr = NULL; + + TIMEPARSE(ds, timstr[0],timstr[1], timstr[3],timstr[4], '0','0'); + } + else if (apr_date_checkmask(date, "## @$$ ## #:##:## *")) { + /* Loser format. This is quite bogus. */ + ds.tm_year = ((date[7] - '0') * 10) + (date[8] - '0'); + + if (ds.tm_year < 70) + ds.tm_year += 100; + + ds.tm_mday = ((date[0] - '0') * 10) + (date[1] - '0'); + + monstr = date + 3; + timstr = date + 9; + gmtstr = date + 18; + + TIMEPARSE(ds, '0',timstr[1], timstr[3],timstr[4], timstr[6],timstr[7]); + } + else if (apr_date_checkmask(date, "# @$$ ## #:##:## *")) { + /* Loser format. This is quite bogus. */ + ds.tm_year = ((date[6] - '0') * 10) + (date[7] - '0'); + + if (ds.tm_year < 70) + ds.tm_year += 100; + + ds.tm_mday = (date[0] - '0'); + + monstr = date + 2; + timstr = date + 8; + gmtstr = date + 17; + + TIMEPARSE(ds, '0',timstr[1], timstr[3],timstr[4], timstr[6],timstr[7]); + } + else if (apr_date_checkmask(date, " # @$$ #### ##:##:## *")) { + /* RFC 1123 format with a space instead of a leading zero. */ + ds.tm_year = ((date[7] - '0') * 10 + (date[8] - '0') - 19) * 100; + + if (ds.tm_year < 0) + return APR_DATE_BAD; + + ds.tm_year += ((date[9] - '0') * 10) + (date[10] - '0'); + + ds.tm_mday = (date[1] - '0'); + + monstr = date + 3; + timstr = date + 12; + gmtstr = date + 21; + + TIMEPARSE_STD(ds, timstr); + } + else if (apr_date_checkmask(date, "##-@$$-#### ##:##:## *")) { + /* RFC 1123 with dashes instead of spaces between date/month/year + * This also looks like RFC 850 with four digit years. + */ + ds.tm_year = ((date[7] - '0') * 10 + (date[8] - '0') - 19) * 100; + if (ds.tm_year < 0) + return APR_DATE_BAD; + + ds.tm_year += ((date[9] - '0') * 10) + (date[10] - '0'); + + ds.tm_mday = ((date[0] - '0') * 10) + (date[1] - '0'); + + monstr = date + 3; + timstr = date + 12; + gmtstr = date + 21; + + TIMEPARSE_STD(ds, timstr); + } + else + return APR_DATE_BAD; + + if (ds.tm_mday <= 0 || ds.tm_mday > 31) + return APR_DATE_BAD; + + if ((ds.tm_hour > 23) || (ds.tm_min > 59) || (ds.tm_sec > 61)) + return APR_DATE_BAD; + + mint = (monstr[0] << 16) | (monstr[1] << 8) | monstr[2]; + for (mon = 0; mon < 12; mon++) + if (mint == months[mon]) + break; + + if (mon == 12) + return APR_DATE_BAD; + + if ((ds.tm_mday == 31) && (mon == 3 || mon == 5 || mon == 8 || mon == 10)) + return APR_DATE_BAD; + + /* February gets special check for leapyear */ + + if ((mon == 1) && + ((ds.tm_mday > 29) + || ((ds.tm_mday == 29) + && ((ds.tm_year & 3) + || (((ds.tm_year % 100) == 0) + && (((ds.tm_year % 400) != 100))))))) + return APR_DATE_BAD; + + ds.tm_mon = mon; + + /* tm_gmtoff is the number of seconds off of GMT the time is. + * + * We only currently support: [+-]ZZZZ where Z is the offset in + * hours from GMT. + * + * If there is any confusion, tm_gmtoff will remain 0. + */ + ds.tm_gmtoff = 0; + + /* Do we have a timezone ? */ + if (gmtstr) { + int offset; + switch (*gmtstr) { + case '-': + offset = atoi(gmtstr+1); + ds.tm_gmtoff -= (offset / 100) * 60 * 60; + ds.tm_gmtoff -= (offset % 100) * 60; + break; + case '+': + offset = atoi(gmtstr+1); + ds.tm_gmtoff += (offset / 100) * 60 * 60; + ds.tm_gmtoff += (offset % 100) * 60; + break; + } + } + + /* apr_time_exp_get uses tm_usec field, but it hasn't been set yet. + * It should be safe to just zero out this value. + * tm_usec is the number of microseconds into the second. HTTP only + * cares about second granularity. + */ + ds.tm_usec = 0; + + if (apr_time_exp_gmt_get(&result, &ds) != APR_SUCCESS) + return APR_DATE_BAD; + + return result; +} diff --git a/util-misc/apr_queue.c b/util-misc/apr_queue.c new file mode 100644 index 00000000000..dbc879b3544 --- /dev/null +++ b/util-misc/apr_queue.c @@ -0,0 +1,378 @@ +/* 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" + +#if APR_HAVE_STDIO_H +#include <stdio.h> +#endif +#if APR_HAVE_STDLIB_H +#include <stdlib.h> +#endif +#if APR_HAVE_UNISTD_H +#include <unistd.h> +#endif + +#include "apu.h" +#include "apr_portable.h" +#include "apr_thread_mutex.h" +#include "apr_thread_cond.h" +#include "apr_errno.h" +#include "apr_queue.h" + +#if APR_HAS_THREADS +/* + * define this to get debug messages + * +#define QUEUE_DEBUG + */ + +struct apr_queue_t { + void **data; + unsigned int nelts; /**< # elements */ + unsigned int in; /**< next empty location */ + unsigned int out; /**< next filled location */ + unsigned int bounds;/**< max size of queue */ + unsigned int full_waiters; + unsigned int empty_waiters; + apr_thread_mutex_t *one_big_mutex; + apr_thread_cond_t *not_empty; + apr_thread_cond_t *not_full; + int terminated; +}; + +#ifdef QUEUE_DEBUG +static void Q_DBG(char*msg, apr_queue_t *q) { + fprintf(stderr, "%ld\t#%d in %d out %d\t%s\n", + apr_os_thread_current(), + q->nelts, q->in, q->out, + msg + ); +} +#else +#define Q_DBG(x,y) +#endif + +/** + * Detects when the apr_queue_t is full. This utility function is expected + * to be called from within critical sections, and is not threadsafe. + */ +#define apr_queue_full(queue) ((queue)->nelts == (queue)->bounds) + +/** + * Detects when the apr_queue_t is empty. This utility function is expected + * to be called from within critical sections, and is not threadsafe. + */ +#define apr_queue_empty(queue) ((queue)->nelts == 0) + +/** + * Callback routine that is called to destroy this + * apr_queue_t when its pool is destroyed. + */ +static apr_status_t queue_destroy(void *data) +{ + apr_queue_t *queue = data; + + /* Ignore errors here, we can't do anything about them anyway. */ + + apr_thread_cond_destroy(queue->not_empty); + apr_thread_cond_destroy(queue->not_full); + apr_thread_mutex_destroy(queue->one_big_mutex); + + return APR_SUCCESS; +} + +/** + * Initialize the apr_queue_t. + */ +APR_DECLARE(apr_status_t) apr_queue_create(apr_queue_t **q, + unsigned int queue_capacity, + apr_pool_t *a) +{ + apr_status_t rv; + apr_queue_t *queue; + queue = apr_palloc(a, sizeof(apr_queue_t)); + *q = queue; + + /* nested doesn't work ;( */ + rv = apr_thread_mutex_create(&queue->one_big_mutex, + APR_THREAD_MUTEX_UNNESTED, + a); + if (rv != APR_SUCCESS) { + return rv; + } + + rv = apr_thread_cond_create(&queue->not_empty, a); + if (rv != APR_SUCCESS) { + return rv; + } + + rv = apr_thread_cond_create(&queue->not_full, a); + if (rv != APR_SUCCESS) { + return rv; + } + + /* Set all the data in the queue to NULL */ + queue->data = apr_pcalloc(a, queue_capacity * sizeof(void*)); + queue->bounds = queue_capacity; + queue->nelts = 0; + queue->in = 0; + queue->out = 0; + queue->terminated = 0; + queue->full_waiters = 0; + queue->empty_waiters = 0; + + apr_pool_cleanup_register(a, queue, queue_destroy, apr_pool_cleanup_null); + + return APR_SUCCESS; +} + +/** + * Push new data onto the queue. Blocks if the queue is full. Once + * the push operation has completed, it signals other threads waiting + * in apr_queue_pop() that they may continue consuming sockets. + */ +static apr_status_t queue_push(apr_queue_t *queue, void *data, + apr_interval_time_t timeout) +{ + apr_status_t rv; + + if (queue->terminated) { + return APR_EOF; /* no more elements ever again */ + } + + rv = apr_thread_mutex_lock(queue->one_big_mutex); + if (rv != APR_SUCCESS) { + return rv; + } + + if (apr_queue_full(queue)) { + if (!timeout) { + apr_thread_mutex_unlock(queue->one_big_mutex); + return APR_EAGAIN; + } + if (!queue->terminated) { + queue->full_waiters++; + if (timeout > 0) { + rv = apr_thread_cond_timedwait(queue->not_full, + queue->one_big_mutex, + timeout); + } + else { + rv = apr_thread_cond_wait(queue->not_full, + queue->one_big_mutex); + } + queue->full_waiters--; + if (rv != APR_SUCCESS) { + apr_thread_mutex_unlock(queue->one_big_mutex); + return rv; + } + } + /* If we wake up and it's still empty, then we were interrupted */ + if (apr_queue_full(queue)) { + Q_DBG("queue full (intr)", queue); + rv = apr_thread_mutex_unlock(queue->one_big_mutex); + if (rv != APR_SUCCESS) { + return rv; + } + if (queue->terminated) { + return APR_EOF; /* no more elements ever again */ + } + else { + return APR_EINTR; + } + } + } + + queue->data[queue->in] = data; + queue->in++; + if (queue->in >= queue->bounds) + queue->in -= queue->bounds; + queue->nelts++; + + if (queue->empty_waiters) { + Q_DBG("sig !empty", queue); + rv = apr_thread_cond_signal(queue->not_empty); + if (rv != APR_SUCCESS) { + apr_thread_mutex_unlock(queue->one_big_mutex); + return rv; + } + } + + rv = apr_thread_mutex_unlock(queue->one_big_mutex); + return rv; +} + +APR_DECLARE(apr_status_t) apr_queue_push(apr_queue_t *queue, void *data) +{ + return queue_push(queue, data, -1); +} + +/** + * Push new data onto the queue. If the queue is full, return APR_EAGAIN. If + * the push operation completes successfully, it signals other threads + * waiting in apr_queue_pop() that they may continue consuming sockets. + */ +APR_DECLARE(apr_status_t) apr_queue_trypush(apr_queue_t *queue, void *data) +{ + return queue_push(queue, data, 0); +} + +APR_DECLARE(apr_status_t) apr_queue_timedpush(apr_queue_t *queue, void *data, + apr_interval_time_t timeout) +{ + return queue_push(queue, data, timeout); +} + +/** + * not thread safe + */ +APR_DECLARE(unsigned int) apr_queue_size(apr_queue_t *queue) { + return queue->nelts; +} + +/** + * Retrieves the next item from the queue. If there are no + * items available, it will either return APR_EAGAIN (timeout = 0), + * or block until one becomes available (infinitely with timeout < 0, + * otherwise until the given timeout expires). Once retrieved, the + * item is placed into the address specified by 'data'. + */ +static apr_status_t queue_pop(apr_queue_t *queue, void **data, + apr_interval_time_t timeout) +{ + apr_status_t rv; + + if (queue->terminated) { + return APR_EOF; /* no more elements ever again */ + } + + rv = apr_thread_mutex_lock(queue->one_big_mutex); + if (rv != APR_SUCCESS) { + return rv; + } + + /* Keep waiting until we wake up and find that the queue is not empty. */ + if (apr_queue_empty(queue)) { + if (!timeout) { + apr_thread_mutex_unlock(queue->one_big_mutex); + return APR_EAGAIN; + } + if (!queue->terminated) { + queue->empty_waiters++; + if (timeout > 0) { + rv = apr_thread_cond_timedwait(queue->not_empty, + queue->one_big_mutex, + timeout); + } + else { + rv = apr_thread_cond_wait(queue->not_empty, + queue->one_big_mutex); + } + queue->empty_waiters--; + if (rv != APR_SUCCESS) { + apr_thread_mutex_unlock(queue->one_big_mutex); + return rv; + } + } + /* If we wake up and it's still empty, then we were interrupted */ + if (apr_queue_empty(queue)) { + Q_DBG("queue empty (intr)", queue); + rv = apr_thread_mutex_unlock(queue->one_big_mutex); + if (rv != APR_SUCCESS) { + return rv; + } + if (queue->terminated) { + return APR_EOF; /* no more elements ever again */ + } + else { + return APR_EINTR; + } + } + } + + *data = queue->data[queue->out]; + queue->nelts--; + + queue->out++; + if (queue->out >= queue->bounds) + queue->out -= queue->bounds; + if (queue->full_waiters) { + Q_DBG("signal !full", queue); + rv = apr_thread_cond_signal(queue->not_full); + if (rv != APR_SUCCESS) { + apr_thread_mutex_unlock(queue->one_big_mutex); + return rv; + } + } + + rv = apr_thread_mutex_unlock(queue->one_big_mutex); + return rv; +} + +APR_DECLARE(apr_status_t) apr_queue_pop(apr_queue_t *queue, void **data) +{ + return queue_pop(queue, data, -1); +} + +APR_DECLARE(apr_status_t) apr_queue_trypop(apr_queue_t *queue, void **data) +{ + return queue_pop(queue, data, 0); +} + +APR_DECLARE(apr_status_t) apr_queue_timedpop(apr_queue_t *queue, void **data, + apr_interval_time_t timeout) +{ + return queue_pop(queue, data, timeout); +} + +APR_DECLARE(apr_status_t) apr_queue_interrupt_all(apr_queue_t *queue) +{ + apr_status_t rv; + Q_DBG("intr all", queue); + if ((rv = apr_thread_mutex_lock(queue->one_big_mutex)) != APR_SUCCESS) { + return rv; + } + apr_thread_cond_broadcast(queue->not_empty); + apr_thread_cond_broadcast(queue->not_full); + + if ((rv = apr_thread_mutex_unlock(queue->one_big_mutex)) != APR_SUCCESS) { + return rv; + } + + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_queue_term(apr_queue_t *queue) +{ + apr_status_t rv; + + if ((rv = apr_thread_mutex_lock(queue->one_big_mutex)) != APR_SUCCESS) { + return rv; + } + + /* we must hold one_big_mutex when setting this... otherwise, + * we could end up setting it and waking everybody up just after a + * would-be popper checks it but right before they block + */ + queue->terminated = 1; + if ((rv = apr_thread_mutex_unlock(queue->one_big_mutex)) != APR_SUCCESS) { + return rv; + } + return apr_queue_interrupt_all(queue); +} + +#endif /* APR_HAS_THREADS */ diff --git a/util-misc/apr_reslist.c b/util-misc/apr_reslist.c new file mode 100644 index 00000000000..ecc17a7d4d6 --- /dev/null +++ b/util-misc/apr_reslist.c @@ -0,0 +1,479 @@ +/* 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 <assert.h> + +#include "apu.h" +#include "apr_reslist.h" +#include "apr_errno.h" +#include "apr_strings.h" +#include "apr_thread_mutex.h" +#include "apr_thread_cond.h" +#include "apr_ring.h" + +/** + * A single resource element. + */ +struct apr_res_t { + apr_time_t freed; + void *opaque; + APR_RING_ENTRY(apr_res_t) link; +}; +typedef struct apr_res_t apr_res_t; + +/** + * A ring of resources representing the list of available resources. + */ +APR_RING_HEAD(apr_resring_t, apr_res_t); +typedef struct apr_resring_t apr_resring_t; + +struct apr_reslist_t { + apr_pool_t *pool; /* the pool used in constructor and destructor calls */ + int ntotal; /* total number of resources managed by this list */ + int nidle; /* number of available resources */ + int min; /* desired minimum number of available resources */ + int smax; /* soft maximum on the total number of resources */ + int hmax; /* hard maximum on the total number of resources */ + apr_interval_time_t ttl; /* TTL when we have too many resources */ + apr_interval_time_t timeout; /* Timeout for waiting on resource */ + apr_reslist_constructor constructor; + apr_reslist_destructor destructor; + void *params; /* opaque data passed to constructor and destructor calls */ + apr_resring_t avail_list; + apr_resring_t free_list; +#if APR_HAS_THREADS + apr_thread_mutex_t *listlock; + apr_thread_cond_t *avail; +#endif +}; + +/** + * Grab a resource from the front of the resource list. + * Assumes: that the reslist is locked. + */ +static apr_res_t *pop_resource(apr_reslist_t *reslist) +{ + apr_res_t *res; + res = APR_RING_FIRST(&reslist->avail_list); + APR_RING_REMOVE(res, link); + reslist->nidle--; + return res; +} + +/** + * Add a resource to the beginning of the list, set the time at which + * it was added to the list. + * Assumes: that the reslist is locked. + */ +static void push_resource(apr_reslist_t *reslist, apr_res_t *resource) +{ + APR_RING_INSERT_HEAD(&reslist->avail_list, resource, apr_res_t, link); + resource->freed = apr_time_now(); + reslist->nidle++; +} + +/** + * Get an resource container from the free list or create a new one. + */ +static apr_res_t *get_container(apr_reslist_t *reslist) +{ + apr_res_t *res; + + if (!APR_RING_EMPTY(&reslist->free_list, apr_res_t, link)) { + res = APR_RING_FIRST(&reslist->free_list); + APR_RING_REMOVE(res, link); + } + else + res = apr_pcalloc(reslist->pool, sizeof(*res)); + return res; +} + +/** + * Free up a resource container by placing it on the free list. + */ +static void free_container(apr_reslist_t *reslist, apr_res_t *container) +{ + APR_RING_INSERT_TAIL(&reslist->free_list, container, apr_res_t, link); +} + +/** + * Create a new resource and return it. + * Assumes: that the reslist is locked. + */ +static apr_status_t create_resource(apr_reslist_t *reslist, apr_res_t **ret_res) +{ + apr_status_t rv; + apr_res_t *res; + + res = get_container(reslist); + + rv = reslist->constructor(&res->opaque, reslist->params, reslist->pool); + + *ret_res = res; + return rv; +} + +/** + * Destroy a single idle resource. + * Assumes: that the reslist is locked. + */ +static apr_status_t destroy_resource(apr_reslist_t *reslist, apr_res_t *res) +{ + return reslist->destructor(res->opaque, reslist->params, reslist->pool); +} + +static apr_status_t reslist_cleanup(void *data_) +{ + apr_status_t rv = APR_SUCCESS; + apr_reslist_t *rl = data_; + apr_res_t *res; + +#if APR_HAS_THREADS + apr_thread_mutex_lock(rl->listlock); + apr_pool_owner_set(rl->pool, 0); +#endif + + while (rl->nidle > 0) { + apr_status_t rv1; + res = pop_resource(rl); + rl->ntotal--; + rv1 = destroy_resource(rl, res); + if (rv1 != APR_SUCCESS) { + rv = rv1; /* loses info in the unlikely event of + * multiple *different* failures */ + } + free_container(rl, res); + } + + assert(rl->nidle == 0); + assert(rl->ntotal == 0); + +#if APR_HAS_THREADS + apr_thread_mutex_unlock(rl->listlock); + apr_thread_mutex_destroy(rl->listlock); + apr_thread_cond_destroy(rl->avail); +#endif + + return rv; +} + +/** + * Perform routine maintenance on the resource list. This call + * may instantiate new resources or expire old resources. + */ +APR_DECLARE(apr_status_t) apr_reslist_maintain(apr_reslist_t *reslist) +{ + apr_time_t now; + apr_status_t rv; + apr_res_t *res; + int created_one = 0; + +#if APR_HAS_THREADS + apr_thread_mutex_lock(reslist->listlock); + apr_pool_owner_set(reslist->pool, 0); +#endif + + /* Check if we need to create more resources, and if we are allowed to. */ + while (reslist->nidle < reslist->min && reslist->ntotal < reslist->hmax) { + /* Create the resource */ + rv = create_resource(reslist, &res); + if (rv != APR_SUCCESS) { + free_container(reslist, res); +#if APR_HAS_THREADS + apr_thread_mutex_unlock(reslist->listlock); +#endif + return rv; + } + /* Add it to the list */ + push_resource(reslist, res); + /* Update our counters */ + reslist->ntotal++; + /* If someone is waiting on that guy, wake them up. */ +#if APR_HAS_THREADS + rv = apr_thread_cond_signal(reslist->avail); + if (rv != APR_SUCCESS) { + apr_thread_mutex_unlock(reslist->listlock); + return rv; + } +#endif + created_one++; + } + + /* We don't need to see if we're over the max if we were under it before */ + if (created_one) { +#if APR_HAS_THREADS + apr_thread_mutex_unlock(reslist->listlock); +#endif + return APR_SUCCESS; + } + + /* Check if we need to expire old resources */ + now = apr_time_now(); + while (reslist->nidle > reslist->smax && reslist->nidle > 0) { + /* Peak at the last resource in the list */ + res = APR_RING_LAST(&reslist->avail_list); + /* See if the oldest entry should be expired */ + if (now - res->freed < reslist->ttl) { + /* If this entry is too young, none of the others + * will be ready to be expired either, so we are done. */ + break; + } + APR_RING_REMOVE(res, link); + reslist->nidle--; + reslist->ntotal--; + rv = destroy_resource(reslist, res); + free_container(reslist, res); + if (rv != APR_SUCCESS) { +#if APR_HAS_THREADS + apr_thread_mutex_unlock(reslist->listlock); +#endif + return rv; + } + } + +#if APR_HAS_THREADS + apr_thread_mutex_unlock(reslist->listlock); +#endif + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_reslist_create(apr_reslist_t **reslist, + int min, int smax, int hmax, + apr_interval_time_t ttl, + apr_reslist_constructor con, + apr_reslist_destructor de, + void *params, + apr_pool_t *pool) +{ + apr_status_t rv; + apr_reslist_t *rl; + + /* Do some sanity checks so we don't thrash around in the + * maintenance routine later. */ + if (min < 0 || min > smax || min > hmax || smax > hmax || hmax == 0 || + ttl < 0) { + return APR_EINVAL; + } + +#if !APR_HAS_THREADS + /* There can be only one resource when we have no threads. */ + if (min > 0) { + min = 1; + } + if (smax > 0) { + smax = 1; + } + hmax = 1; +#endif + + rl = apr_pcalloc(pool, sizeof(*rl)); + rl->pool = pool; + rl->min = min; + rl->smax = smax; + rl->hmax = hmax; + rl->ttl = ttl; + rl->constructor = con; + rl->destructor = de; + rl->params = params; + + APR_RING_INIT(&rl->avail_list, apr_res_t, link); + APR_RING_INIT(&rl->free_list, apr_res_t, link); + +#if APR_HAS_THREADS + rv = apr_thread_mutex_create(&rl->listlock, APR_THREAD_MUTEX_DEFAULT, + pool); + if (rv != APR_SUCCESS) { + return rv; + } + rv = apr_thread_cond_create(&rl->avail, pool); + if (rv != APR_SUCCESS) { + return rv; + } +#endif + + rv = apr_reslist_maintain(rl); + if (rv != APR_SUCCESS) { + /* Destroy what we've created so far. + */ + reslist_cleanup(rl); + return rv; + } + + apr_pool_cleanup_register(rl->pool, rl, reslist_cleanup, + apr_pool_cleanup_null); + + *reslist = rl; + + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_reslist_destroy(apr_reslist_t *reslist) +{ + return apr_pool_cleanup_run(reslist->pool, reslist, reslist_cleanup); +} + +APR_DECLARE(apr_status_t) apr_reslist_acquire(apr_reslist_t *reslist, + void **resource) +{ + apr_status_t rv; + apr_res_t *res; + apr_time_t now; + +#if APR_HAS_THREADS + apr_thread_mutex_lock(reslist->listlock); + apr_pool_owner_set(reslist->pool, 0); +#endif + /* If there are idle resources on the available list, use + * them right away. */ + now = apr_time_now(); + while (reslist->nidle > 0) { + /* Pop off the first resource */ + res = pop_resource(reslist); + if (reslist->ttl && (now - res->freed >= reslist->ttl)) { + /* this res is expired - kill it */ + reslist->ntotal--; + rv = destroy_resource(reslist, res); + free_container(reslist, res); + if (rv != APR_SUCCESS) { +#if APR_HAS_THREADS + apr_thread_mutex_unlock(reslist->listlock); +#endif + return rv; /* FIXME: this might cause unnecessary fails */ + } + continue; + } + *resource = res->opaque; + free_container(reslist, res); +#if APR_HAS_THREADS + apr_thread_mutex_unlock(reslist->listlock); +#endif + return APR_SUCCESS; + } + /* If we've hit our max, block until we're allowed to create + * a new one, or something becomes free. */ + while (reslist->ntotal >= reslist->hmax && reslist->nidle <= 0) { +#if APR_HAS_THREADS + if (reslist->timeout) { + if ((rv = apr_thread_cond_timedwait(reslist->avail, + reslist->listlock, reslist->timeout)) != APR_SUCCESS) { + apr_thread_mutex_unlock(reslist->listlock); + return rv; + } + } + else { + apr_thread_cond_wait(reslist->avail, reslist->listlock); + } +#else + return APR_EAGAIN; +#endif + } + /* If we popped out of the loop, first try to see if there + * are new resources available for immediate use. */ + if (reslist->nidle > 0) { + res = pop_resource(reslist); + *resource = res->opaque; + free_container(reslist, res); +#if APR_HAS_THREADS + apr_thread_mutex_unlock(reslist->listlock); +#endif + return APR_SUCCESS; + } + /* Otherwise the reason we dropped out of the loop + * was because there is a new slot available, so create + * a resource to fill the slot and use it. */ + else { + rv = create_resource(reslist, &res); + if (rv == APR_SUCCESS) { + reslist->ntotal++; + *resource = res->opaque; + } + free_container(reslist, res); +#if APR_HAS_THREADS + apr_thread_mutex_unlock(reslist->listlock); +#endif + return rv; + } +} + +APR_DECLARE(apr_status_t) apr_reslist_release(apr_reslist_t *reslist, + void *resource) +{ + apr_res_t *res; + +#if APR_HAS_THREADS + apr_thread_mutex_lock(reslist->listlock); + apr_pool_owner_set(reslist->pool, 0); +#endif + res = get_container(reslist); + res->opaque = resource; + push_resource(reslist, res); +#if APR_HAS_THREADS + apr_thread_cond_signal(reslist->avail); + apr_thread_mutex_unlock(reslist->listlock); +#endif + + return apr_reslist_maintain(reslist); +} + +APR_DECLARE(void) apr_reslist_timeout_set(apr_reslist_t *reslist, + apr_interval_time_t timeout) +{ + reslist->timeout = timeout; +} + +APR_DECLARE(apr_uint32_t) apr_reslist_acquired_count(apr_reslist_t *reslist) +{ + apr_uint32_t count; + +#if APR_HAS_THREADS + apr_thread_mutex_lock(reslist->listlock); + apr_pool_owner_set(reslist->pool, 0); +#endif + count = reslist->ntotal - reslist->nidle; +#if APR_HAS_THREADS + apr_thread_mutex_unlock(reslist->listlock); +#endif + + return count; +} + +APR_DECLARE(apr_status_t) apr_reslist_invalidate(apr_reslist_t *reslist, + void *resource) +{ + apr_status_t ret; +#if APR_HAS_THREADS + apr_thread_mutex_lock(reslist->listlock); + apr_pool_owner_set(reslist->pool, 0); +#endif + ret = reslist->destructor(resource, reslist->params, reslist->pool); + reslist->ntotal--; +#if APR_HAS_THREADS + apr_thread_cond_signal(reslist->avail); + apr_thread_mutex_unlock(reslist->listlock); +#endif + return ret; +} + +APR_DECLARE(void) apr_reslist_cleanup_order_set(apr_reslist_t *rl, + apr_uint32_t mode) +{ + apr_pool_cleanup_kill(rl->pool, rl, reslist_cleanup); + if (mode == APR_RESLIST_CLEANUP_FIRST) + apr_pool_pre_cleanup_register(rl->pool, rl, reslist_cleanup); + else + apr_pool_cleanup_register(rl->pool, rl, reslist_cleanup, + apr_pool_cleanup_null); +} diff --git a/util-misc/apr_rmm.c b/util-misc/apr_rmm.c new file mode 100644 index 00000000000..91e30885fc2 --- /dev/null +++ b/util-misc/apr_rmm.c @@ -0,0 +1,457 @@ +/* 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_general.h" +#include "apr_rmm.h" +#include "apr_errno.h" +#include "apr_lib.h" +#include "apr_strings.h" + +/* The RMM region is made up of two doubly-linked-list of blocks; the + * list of used blocks, and the list of free blocks (either list may + * be empty). The base pointer, rmm->base, points at the beginning of + * the shmem region in use. Each block is addressable by an + * apr_rmm_off_t value, which represents the offset from the base + * pointer. The term "address" is used here to mean such a value; an + * "offset from rmm->base". + * + * The RMM region contains exactly one "rmm_hdr_block_t" structure, + * the "header block", which is always stored at the base pointer. + * The firstused field in this structure is the address of the first + * block in the "used blocks" list; the firstfree field is the address + * of the first block in the "free blocks" list. + * + * Each block is prefixed by an "rmm_block_t" structure, followed by + * the caller-usable region represented by the block. The next and + * prev fields of the structure are zero if the block is at the end or + * beginning of the linked-list respectively, or otherwise hold the + * address of the next and previous blocks in the list. ("address 0", + * i.e. rmm->base is *not* a valid address for a block, since the + * header block is always stored at that address). + * + * At creation, the RMM region is initialized to hold a single block + * on the free list representing the entire available shm segment + * (minus header block); subsequent allocation and deallocation of + * blocks involves splitting blocks and coalescing adjacent blocks, + * and switching them between the free and used lists as + * appropriate. */ + +typedef struct rmm_block_t { + apr_size_t size; + apr_rmm_off_t prev; + apr_rmm_off_t next; +} rmm_block_t; + +/* Always at our apr_rmm_off(0): + */ +typedef struct rmm_hdr_block_t { + apr_size_t abssize; + apr_rmm_off_t /* rmm_block_t */ firstused; + apr_rmm_off_t /* rmm_block_t */ firstfree; +} rmm_hdr_block_t; + +#define RMM_HDR_BLOCK_SIZE (APR_ALIGN_DEFAULT(sizeof(rmm_hdr_block_t))) +#define RMM_BLOCK_SIZE (APR_ALIGN_DEFAULT(sizeof(rmm_block_t))) + +struct apr_rmm_t { + apr_pool_t *p; + rmm_hdr_block_t *base; + apr_size_t size; + apr_anylock_t lock; +}; + +static apr_rmm_off_t find_block_by_offset(apr_rmm_t *rmm, apr_rmm_off_t next, + apr_rmm_off_t find, int includes) +{ + apr_rmm_off_t prev = 0; + + while (next) { + struct rmm_block_t *blk = (rmm_block_t*)((char*)rmm->base + next); + + if (find == next) + return next; + + /* Overshot? */ + if (find < next) + return includes ? prev : 0; + + prev = next; + next = blk->next; + } + return includes ? prev : 0; +} + +static apr_rmm_off_t find_block_of_size(apr_rmm_t *rmm, apr_size_t size) +{ + apr_rmm_off_t next = rmm->base->firstfree; + apr_rmm_off_t best = 0; + apr_rmm_off_t bestsize = 0; + + while (next) { + struct rmm_block_t *blk = (rmm_block_t*)((char*)rmm->base + next); + + if (blk->size == size) + return next; + + if (blk->size >= size) { + /* XXX: sub optimal algorithm + * We need the most thorough best-fit logic, since we can + * never grow our rmm, we are SOL when we hit the wall. + */ + if (!bestsize || (blk->size < bestsize)) { + bestsize = blk->size; + best = next; + } + } + + next = blk->next; + } + + if (bestsize > RMM_BLOCK_SIZE + size) { + struct rmm_block_t *blk = (rmm_block_t*)((char*)rmm->base + best); + struct rmm_block_t *new = (rmm_block_t*)((char*)rmm->base + best + size); + + new->size = blk->size - size; + new->next = blk->next; + new->prev = best; + + blk->size = size; + blk->next = best + size; + + if (new->next) { + blk = (rmm_block_t*)((char*)rmm->base + new->next); + blk->prev = best + size; + } + } + + return best; +} + +static void move_block(apr_rmm_t *rmm, apr_rmm_off_t this, int free) +{ + struct rmm_block_t *blk = (rmm_block_t*)((char*)rmm->base + this); + + /* close the gap */ + if (blk->prev) { + struct rmm_block_t *prev = (rmm_block_t*)((char*)rmm->base + blk->prev); + prev->next = blk->next; + } + else { + if (free) { + rmm->base->firstused = blk->next; + } + else { + rmm->base->firstfree = blk->next; + } + } + if (blk->next) { + struct rmm_block_t *next = (rmm_block_t*)((char*)rmm->base + blk->next); + next->prev = blk->prev; + } + + /* now find it in the other list, pushing it to the head if required */ + if (free) { + blk->prev = find_block_by_offset(rmm, rmm->base->firstfree, this, 1); + if (!blk->prev) { + blk->next = rmm->base->firstfree; + rmm->base->firstfree = this; + } + } + else { + blk->prev = find_block_by_offset(rmm, rmm->base->firstused, this, 1); + if (!blk->prev) { + blk->next = rmm->base->firstused; + rmm->base->firstused = this; + } + } + + /* and open it up */ + if (blk->prev) { + struct rmm_block_t *prev = (rmm_block_t*)((char*)rmm->base + blk->prev); + if (free && (blk->prev + prev->size == this)) { + /* Collapse us into our predecessor */ + prev->size += blk->size; + this = blk->prev; + blk = prev; + } + else { + blk->next = prev->next; + prev->next = this; + } + } + + if (blk->next) { + struct rmm_block_t *next = (rmm_block_t*)((char*)rmm->base + blk->next); + if (free && (this + blk->size == blk->next)) { + /* Collapse us into our successor */ + blk->size += next->size; + blk->next = next->next; + if (blk->next) { + next = (rmm_block_t*)((char*)rmm->base + blk->next); + next->prev = this; + } + } + else { + next->prev = this; + } + } +} + +APR_DECLARE(apr_status_t) apr_rmm_init(apr_rmm_t **rmm, apr_anylock_t *lock, + void *base, apr_size_t size, + apr_pool_t *p) +{ + apr_status_t rv; + rmm_block_t *blk; + apr_anylock_t nulllock; + + if (!lock) { + nulllock.type = apr_anylock_none; + nulllock.lock.pm = NULL; + lock = &nulllock; + } + if ((rv = APR_ANYLOCK_LOCK(lock)) != APR_SUCCESS) + return rv; + + (*rmm) = (apr_rmm_t *)apr_pcalloc(p, sizeof(apr_rmm_t)); + (*rmm)->p = p; + (*rmm)->base = base; + (*rmm)->size = size; + (*rmm)->lock = *lock; + + (*rmm)->base->abssize = size; + (*rmm)->base->firstused = 0; + (*rmm)->base->firstfree = RMM_HDR_BLOCK_SIZE; + + blk = (rmm_block_t *)((char*)base + (*rmm)->base->firstfree); + + blk->size = size - (*rmm)->base->firstfree; + blk->prev = 0; + blk->next = 0; + + return APR_ANYLOCK_UNLOCK(lock); +} + +APR_DECLARE(apr_status_t) apr_rmm_destroy(apr_rmm_t *rmm) +{ + apr_status_t rv; + rmm_block_t *blk; + + if ((rv = APR_ANYLOCK_LOCK(&rmm->lock)) != APR_SUCCESS) { + return rv; + } + /* Blast it all --- no going back :) */ + if (rmm->base->firstused) { + apr_rmm_off_t this = rmm->base->firstused; + do { + blk = (rmm_block_t *)((char*)rmm->base + this); + this = blk->next; + blk->next = blk->prev = 0; + } while (this); + rmm->base->firstused = 0; + } + if (rmm->base->firstfree) { + apr_rmm_off_t this = rmm->base->firstfree; + do { + blk = (rmm_block_t *)((char*)rmm->base + this); + this = blk->next; + blk->next = blk->prev = 0; + } while (this); + rmm->base->firstfree = 0; + } + rmm->base->abssize = 0; + rmm->size = 0; + + return APR_ANYLOCK_UNLOCK(&rmm->lock); +} + +APR_DECLARE(apr_status_t) apr_rmm_attach(apr_rmm_t **rmm, apr_anylock_t *lock, + void *base, apr_pool_t *p) +{ + apr_anylock_t nulllock; + + if (!lock) { + nulllock.type = apr_anylock_none; + nulllock.lock.pm = NULL; + lock = &nulllock; + } + + /* sanity would be good here */ + (*rmm) = (apr_rmm_t *)apr_pcalloc(p, sizeof(apr_rmm_t)); + (*rmm)->p = p; + (*rmm)->base = base; + (*rmm)->size = (*rmm)->base->abssize; + (*rmm)->lock = *lock; + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_rmm_detach(apr_rmm_t *rmm) +{ + /* A noop until we introduce locked/refcounts */ + return APR_SUCCESS; +} + +APR_DECLARE(apr_rmm_off_t) apr_rmm_malloc(apr_rmm_t *rmm, apr_size_t reqsize) +{ + apr_size_t size; + apr_rmm_off_t this; + + size = APR_ALIGN_DEFAULT(reqsize) + RMM_BLOCK_SIZE; + if (size < reqsize) { + return 0; + } + + APR_ANYLOCK_LOCK(&rmm->lock); + + this = find_block_of_size(rmm, size); + + if (this) { + move_block(rmm, this, 0); + this += RMM_BLOCK_SIZE; + } + + APR_ANYLOCK_UNLOCK(&rmm->lock); + return this; +} + +APR_DECLARE(apr_rmm_off_t) apr_rmm_calloc(apr_rmm_t *rmm, apr_size_t reqsize) +{ + apr_size_t size; + apr_rmm_off_t this; + + size = APR_ALIGN_DEFAULT(reqsize) + RMM_BLOCK_SIZE; + if (size < reqsize) { + return 0; + } + + APR_ANYLOCK_LOCK(&rmm->lock); + + this = find_block_of_size(rmm, size); + + if (this) { + move_block(rmm, this, 0); + this += RMM_BLOCK_SIZE; + memset((char*)rmm->base + this, 0, size - RMM_BLOCK_SIZE); + } + + APR_ANYLOCK_UNLOCK(&rmm->lock); + return this; +} + +APR_DECLARE(apr_rmm_off_t) apr_rmm_realloc(apr_rmm_t *rmm, void *entity, + apr_size_t reqsize) +{ + apr_rmm_off_t this; + apr_rmm_off_t old; + struct rmm_block_t *blk; + apr_size_t size, oldsize; + + if (!entity) { + return apr_rmm_malloc(rmm, reqsize); + } + + size = APR_ALIGN_DEFAULT(reqsize); + if (size < reqsize) { + return 0; + } + old = apr_rmm_offset_get(rmm, entity); + + if ((this = apr_rmm_malloc(rmm, size)) == 0) { + return 0; + } + + blk = (rmm_block_t*)((char*)rmm->base + old - RMM_BLOCK_SIZE); + oldsize = blk->size; + + memcpy(apr_rmm_addr_get(rmm, this), + apr_rmm_addr_get(rmm, old), oldsize < size ? oldsize : size); + apr_rmm_free(rmm, old); + + return this; +} + +APR_DECLARE(apr_status_t) apr_rmm_free(apr_rmm_t *rmm, apr_rmm_off_t this) +{ + apr_status_t rv; + struct rmm_block_t *blk; + + /* A little sanity check is always healthy, especially here. + * If we really cared, we could make this compile-time + */ + if (this < RMM_HDR_BLOCK_SIZE + RMM_BLOCK_SIZE) { + return APR_EINVAL; + } + + this -= RMM_BLOCK_SIZE; + + blk = (rmm_block_t*)((char*)rmm->base + this); + + if ((rv = APR_ANYLOCK_LOCK(&rmm->lock)) != APR_SUCCESS) { + return rv; + } + if (blk->prev) { + struct rmm_block_t *prev = (rmm_block_t*)((char*)rmm->base + blk->prev); + if (prev->next != this) { + APR_ANYLOCK_UNLOCK(&rmm->lock); + return APR_EINVAL; + } + } + else { + if (rmm->base->firstused != this) { + APR_ANYLOCK_UNLOCK(&rmm->lock); + return APR_EINVAL; + } + } + + if (blk->next) { + struct rmm_block_t *next = (rmm_block_t*)((char*)rmm->base + blk->next); + if (next->prev != this) { + APR_ANYLOCK_UNLOCK(&rmm->lock); + return APR_EINVAL; + } + } + + /* Ok, it remained [apparently] sane, so unlink it + */ + move_block(rmm, this, 1); + + return APR_ANYLOCK_UNLOCK(&rmm->lock); +} + +APR_DECLARE(void *) apr_rmm_addr_get(apr_rmm_t *rmm, apr_rmm_off_t entity) +{ + /* debug-sanity checking here would be good + */ + return (void*)((char*)rmm->base + entity); +} + +APR_DECLARE(apr_rmm_off_t) apr_rmm_offset_get(apr_rmm_t *rmm, void* entity) +{ + /* debug, or always, sanity checking here would be good + * since the primitive is apr_rmm_off_t, I don't mind penalizing + * inverse conversions for safety, unless someone can prove that + * there is no choice in some cases. + */ + return ((char*)entity - (char*)rmm->base); +} + +APR_DECLARE(apr_size_t) apr_rmm_overhead_get(int n) +{ + /* overhead per block is at most APR_ALIGN_DEFAULT(1) wasted bytes + * for alignment overhead, plus the size of the rmm_block_t + * structure. */ + return RMM_HDR_BLOCK_SIZE + n * (RMM_BLOCK_SIZE + APR_ALIGN_DEFAULT(1)); +} diff --git a/util-misc/apr_thread_pool.c b/util-misc/apr_thread_pool.c new file mode 100644 index 00000000000..f5a7a4316f1 --- /dev/null +++ b/util-misc/apr_thread_pool.c @@ -0,0 +1,964 @@ +/* + * 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 <assert.h> +#include "apr_thread_pool.h" +#include "apr_ring.h" +#include "apr_thread_cond.h" +#include "apr_portable.h" + +#if APR_HAS_THREADS + +#define TASK_PRIORITY_SEGS 4 +#define TASK_PRIORITY_SEG(x) (((x)->dispatch.priority & 0xFF) / 64) + +typedef struct apr_thread_pool_task +{ + APR_RING_ENTRY(apr_thread_pool_task) link; + apr_thread_start_t func; + void *param; + void *owner; + union + { + apr_byte_t priority; + apr_time_t time; + } dispatch; +} apr_thread_pool_task_t; + +APR_RING_HEAD(apr_thread_pool_tasks, apr_thread_pool_task); + +struct apr_thread_list_elt +{ + APR_RING_ENTRY(apr_thread_list_elt) link; + apr_thread_t *thd; + volatile void *current_owner; + volatile enum { TH_RUN, TH_STOP, TH_PROBATION } state; +}; + +APR_RING_HEAD(apr_thread_list, apr_thread_list_elt); + +struct apr_thread_pool +{ + apr_pool_t *pool; + volatile apr_size_t thd_max; + volatile apr_size_t idle_max; + volatile apr_interval_time_t idle_wait; + volatile apr_size_t thd_cnt; + volatile apr_size_t idle_cnt; + volatile apr_size_t task_cnt; + volatile apr_size_t scheduled_task_cnt; + volatile apr_size_t threshold; + volatile apr_size_t tasks_run; + volatile apr_size_t tasks_high; + volatile apr_size_t thd_high; + volatile apr_size_t thd_timed_out; + struct apr_thread_pool_tasks *tasks; + struct apr_thread_pool_tasks *scheduled_tasks; + struct apr_thread_list *busy_thds; + struct apr_thread_list *idle_thds; + apr_thread_mutex_t *lock; + apr_thread_cond_t *cond; + volatile int terminated; + struct apr_thread_pool_tasks *recycled_tasks; + struct apr_thread_list *recycled_thds; + apr_thread_pool_task_t *task_idx[TASK_PRIORITY_SEGS]; +}; + +static apr_status_t thread_pool_construct(apr_thread_pool_t * me, + apr_size_t init_threads, + apr_size_t max_threads) +{ + apr_status_t rv; + int i; + + me->thd_max = max_threads; + me->idle_max = init_threads; + me->threshold = init_threads / 2; + rv = apr_thread_mutex_create(&me->lock, APR_THREAD_MUTEX_NESTED, + me->pool); + if (APR_SUCCESS != rv) { + return rv; + } + rv = apr_thread_cond_create(&me->cond, me->pool); + if (APR_SUCCESS != rv) { + apr_thread_mutex_destroy(me->lock); + return rv; + } + me->tasks = apr_palloc(me->pool, sizeof(*me->tasks)); + if (!me->tasks) { + goto CATCH_ENOMEM; + } + APR_RING_INIT(me->tasks, apr_thread_pool_task, link); + me->scheduled_tasks = apr_palloc(me->pool, sizeof(*me->scheduled_tasks)); + if (!me->scheduled_tasks) { + goto CATCH_ENOMEM; + } + APR_RING_INIT(me->scheduled_tasks, apr_thread_pool_task, link); + me->recycled_tasks = apr_palloc(me->pool, sizeof(*me->recycled_tasks)); + if (!me->recycled_tasks) { + goto CATCH_ENOMEM; + } + APR_RING_INIT(me->recycled_tasks, apr_thread_pool_task, link); + me->busy_thds = apr_palloc(me->pool, sizeof(*me->busy_thds)); + if (!me->busy_thds) { + goto CATCH_ENOMEM; + } + APR_RING_INIT(me->busy_thds, apr_thread_list_elt, link); + me->idle_thds = apr_palloc(me->pool, sizeof(*me->idle_thds)); + if (!me->idle_thds) { + goto CATCH_ENOMEM; + } + APR_RING_INIT(me->idle_thds, apr_thread_list_elt, link); + me->recycled_thds = apr_palloc(me->pool, sizeof(*me->recycled_thds)); + if (!me->recycled_thds) { + goto CATCH_ENOMEM; + } + APR_RING_INIT(me->recycled_thds, apr_thread_list_elt, link); + me->thd_cnt = me->idle_cnt = me->task_cnt = me->scheduled_task_cnt = 0; + me->tasks_run = me->tasks_high = me->thd_high = me->thd_timed_out = 0; + me->idle_wait = 0; + me->terminated = 0; + for (i = 0; i < TASK_PRIORITY_SEGS; i++) { + me->task_idx[i] = NULL; + } + goto FINAL_EXIT; + CATCH_ENOMEM: + rv = APR_ENOMEM; + apr_thread_mutex_destroy(me->lock); + apr_thread_cond_destroy(me->cond); + FINAL_EXIT: + return rv; +} + +/* + * NOTE: This function is not thread safe by itself. Caller should hold the lock + */ +static apr_thread_pool_task_t *pop_task(apr_thread_pool_t * me) +{ + apr_thread_pool_task_t *task = NULL; + int seg; + + /* check for scheduled tasks */ + if (me->scheduled_task_cnt > 0) { + task = APR_RING_FIRST(me->scheduled_tasks); + assert(task != NULL); + assert(task != + APR_RING_SENTINEL(me->scheduled_tasks, apr_thread_pool_task, + link)); + /* if it's time */ + if (task->dispatch.time <= apr_time_now()) { + --me->scheduled_task_cnt; + APR_RING_REMOVE(task, link); + return task; + } + } + /* check for normal tasks if we're not returning a scheduled task */ + if (me->task_cnt == 0) { + return NULL; + } + + task = APR_RING_FIRST(me->tasks); + assert(task != NULL); + assert(task != APR_RING_SENTINEL(me->tasks, apr_thread_pool_task, link)); + --me->task_cnt; + seg = TASK_PRIORITY_SEG(task); + if (task == me->task_idx[seg]) { + me->task_idx[seg] = APR_RING_NEXT(task, link); + if (me->task_idx[seg] == APR_RING_SENTINEL(me->tasks, + apr_thread_pool_task, link) + || TASK_PRIORITY_SEG(me->task_idx[seg]) != seg) { + me->task_idx[seg] = NULL; + } + } + APR_RING_REMOVE(task, link); + return task; +} + +static apr_interval_time_t waiting_time(apr_thread_pool_t * me) +{ + apr_thread_pool_task_t *task = NULL; + + task = APR_RING_FIRST(me->scheduled_tasks); + assert(task != NULL); + assert(task != + APR_RING_SENTINEL(me->scheduled_tasks, apr_thread_pool_task, + link)); + return task->dispatch.time - apr_time_now(); +} + +/* + * NOTE: This function is not thread safe by itself. Caller should hold the lock + */ +static struct apr_thread_list_elt *elt_new(apr_thread_pool_t * me, + apr_thread_t * t) +{ + struct apr_thread_list_elt *elt; + + if (APR_RING_EMPTY(me->recycled_thds, apr_thread_list_elt, link)) { + elt = apr_pcalloc(me->pool, sizeof(*elt)); + if (NULL == elt) { + return NULL; + } + } + else { + elt = APR_RING_FIRST(me->recycled_thds); + APR_RING_REMOVE(elt, link); + } + + APR_RING_ELEM_INIT(elt, link); + elt->thd = t; + elt->current_owner = NULL; + elt->state = TH_RUN; + return elt; +} + +/* + * The worker thread function. Take a task from the queue and perform it if + * there is any. Otherwise, put itself into the idle thread list and waiting + * for signal to wake up. + * The thread terminate directly by detach and exit when it is asked to stop + * after finishing a task. Otherwise, the thread should be in idle thread list + * and should be joined. + */ +static void *APR_THREAD_FUNC thread_pool_func(apr_thread_t * t, void *param) +{ + apr_thread_pool_t *me = param; + apr_thread_pool_task_t *task = NULL; + apr_interval_time_t wait; + struct apr_thread_list_elt *elt; + + apr_thread_mutex_lock(me->lock); + apr_pool_owner_set(me->pool, 0); + elt = elt_new(me, t); + if (!elt) { + apr_thread_mutex_unlock(me->lock); + apr_thread_exit(t, APR_ENOMEM); + } + + while (!me->terminated && elt->state != TH_STOP) { + /* Test if not new element, it is awakened from idle */ + if (APR_RING_NEXT(elt, link) != elt) { + --me->idle_cnt; + APR_RING_REMOVE(elt, link); + } + + APR_RING_INSERT_TAIL(me->busy_thds, elt, apr_thread_list_elt, link); + task = pop_task(me); + while (NULL != task && !me->terminated) { + ++me->tasks_run; + elt->current_owner = task->owner; + apr_thread_mutex_unlock(me->lock); + apr_thread_data_set(task, "apr_thread_pool_task", NULL, t); + task->func(t, task->param); + apr_thread_mutex_lock(me->lock); + apr_pool_owner_set(me->pool, 0); + APR_RING_INSERT_TAIL(me->recycled_tasks, task, + apr_thread_pool_task, link); + elt->current_owner = NULL; + if (TH_STOP == elt->state) { + break; + } + task = pop_task(me); + } + assert(NULL == elt->current_owner); + if (TH_STOP != elt->state) + APR_RING_REMOVE(elt, link); + + /* Test if a busy thread been asked to stop, which is not joinable */ + if ((me->idle_cnt >= me->idle_max + && !(me->scheduled_task_cnt && 0 >= me->idle_max) + && !me->idle_wait) + || me->terminated || elt->state != TH_RUN) { + --me->thd_cnt; + if ((TH_PROBATION == elt->state) && me->idle_wait) + ++me->thd_timed_out; + APR_RING_INSERT_TAIL(me->recycled_thds, elt, + apr_thread_list_elt, link); + apr_thread_mutex_unlock(me->lock); + apr_thread_detach(t); + apr_thread_exit(t, APR_SUCCESS); + return NULL; /* should not be here, safe net */ + } + + /* busy thread become idle */ + ++me->idle_cnt; + APR_RING_INSERT_TAIL(me->idle_thds, elt, apr_thread_list_elt, link); + + /* + * If there is a scheduled task, always scheduled to perform that task. + * Since there is no guarantee that current idle threads are scheduled + * for next scheduled task. + */ + if (me->scheduled_task_cnt) + wait = waiting_time(me); + else if (me->idle_cnt > me->idle_max) { + wait = me->idle_wait; + elt->state = TH_PROBATION; + } + else + wait = -1; + + if (wait >= 0) { + apr_thread_cond_timedwait(me->cond, me->lock, wait); + } + else { + apr_thread_cond_wait(me->cond, me->lock); + } + } + + /* idle thread been asked to stop, will be joined */ + --me->thd_cnt; + apr_thread_mutex_unlock(me->lock); + apr_thread_exit(t, APR_SUCCESS); + return NULL; /* should not be here, safe net */ +} + +static apr_status_t thread_pool_cleanup(void *me) +{ + apr_thread_pool_t *_myself = me; + + _myself->terminated = 1; + apr_thread_pool_idle_max_set(_myself, 0); + while (_myself->thd_cnt) { + apr_sleep(20 * 1000); /* spin lock with 20 ms */ + } + apr_pool_owner_set(_myself->pool, 0); + apr_thread_mutex_destroy(_myself->lock); + apr_thread_cond_destroy(_myself->cond); + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_thread_pool_create(apr_thread_pool_t ** me, + apr_size_t init_threads, + apr_size_t max_threads, + apr_pool_t * pool) +{ + apr_thread_t *t; + apr_status_t rv = APR_SUCCESS; + apr_thread_pool_t *tp; + + *me = NULL; + tp = apr_pcalloc(pool, sizeof(apr_thread_pool_t)); + + /* + * This pool will be used by different threads. As we cannot ensure that + * our caller won't use the pool without acquiring the mutex, we must + * create a new sub pool. + */ + rv = apr_pool_create(&tp->pool, pool); + if (APR_SUCCESS != rv) + return rv; + rv = thread_pool_construct(tp, init_threads, max_threads); + if (APR_SUCCESS != rv) + return rv; + apr_pool_pre_cleanup_register(tp->pool, tp, thread_pool_cleanup); + + while (init_threads) { + /* Grab the mutex as apr_thread_create() and thread_pool_func() will + * allocate from (*me)->pool. This is dangerous if there are multiple + * initial threads to create. + */ + apr_thread_mutex_lock(tp->lock); + apr_pool_owner_set(tp->pool, 0); + rv = apr_thread_create(&t, NULL, thread_pool_func, tp, tp->pool); + apr_thread_mutex_unlock(tp->lock); + if (APR_SUCCESS != rv) { + break; + } + tp->thd_cnt++; + if (tp->thd_cnt > tp->thd_high) { + tp->thd_high = tp->thd_cnt; + } + --init_threads; + } + + if (rv == APR_SUCCESS) { + *me = tp; + } + + return rv; +} + +APR_DECLARE(apr_status_t) apr_thread_pool_destroy(apr_thread_pool_t * me) +{ + apr_pool_destroy(me->pool); + return APR_SUCCESS; +} + +/* + * NOTE: This function is not thread safe by itself. Caller should hold the lock + */ +static apr_thread_pool_task_t *task_new(apr_thread_pool_t * me, + apr_thread_start_t func, + void *param, apr_byte_t priority, + void *owner, apr_time_t time) +{ + apr_thread_pool_task_t *t; + + if (APR_RING_EMPTY(me->recycled_tasks, apr_thread_pool_task, link)) { + t = apr_pcalloc(me->pool, sizeof(*t)); + if (NULL == t) { + return NULL; + } + } + else { + t = APR_RING_FIRST(me->recycled_tasks); + APR_RING_REMOVE(t, link); + } + + APR_RING_ELEM_INIT(t, link); + t->func = func; + t->param = param; + t->owner = owner; + if (time > 0) { + t->dispatch.time = apr_time_now() + time; + } + else { + t->dispatch.priority = priority; + } + return t; +} + +/* + * Test it the task is the only one within the priority segment. + * If it is not, return the first element with same or lower priority. + * Otherwise, add the task into the queue and return NULL. + * + * NOTE: This function is not thread safe by itself. Caller should hold the lock + */ +static apr_thread_pool_task_t *add_if_empty(apr_thread_pool_t * me, + apr_thread_pool_task_t * const t) +{ + int seg; + int next; + apr_thread_pool_task_t *t_next; + + seg = TASK_PRIORITY_SEG(t); + if (me->task_idx[seg]) { + assert(APR_RING_SENTINEL(me->tasks, apr_thread_pool_task, link) != + me->task_idx[seg]); + t_next = me->task_idx[seg]; + while (t_next->dispatch.priority > t->dispatch.priority) { + t_next = APR_RING_NEXT(t_next, link); + if (APR_RING_SENTINEL(me->tasks, apr_thread_pool_task, link) == + t_next) { + return t_next; + } + } + return t_next; + } + + for (next = seg - 1; next >= 0; next--) { + if (me->task_idx[next]) { + APR_RING_INSERT_BEFORE(me->task_idx[next], t, link); + break; + } + } + if (0 > next) { + APR_RING_INSERT_TAIL(me->tasks, t, apr_thread_pool_task, link); + } + me->task_idx[seg] = t; + return NULL; +} + +/* +* schedule a task to run in "time" microseconds. Find the spot in the ring where +* the time fits. Adjust the short_time so the thread wakes up when the time is reached. +*/ +static apr_status_t schedule_task(apr_thread_pool_t *me, + apr_thread_start_t func, void *param, + void *owner, apr_interval_time_t time) +{ + apr_thread_pool_task_t *t; + apr_thread_pool_task_t *t_loc; + apr_thread_t *thd; + apr_status_t rv = APR_SUCCESS; + apr_thread_mutex_lock(me->lock); + apr_pool_owner_set(me->pool, 0); + + t = task_new(me, func, param, 0, owner, time); + if (NULL == t) { + apr_thread_mutex_unlock(me->lock); + return APR_ENOMEM; + } + t_loc = APR_RING_FIRST(me->scheduled_tasks); + while (NULL != t_loc) { + /* if the time is less than the entry insert ahead of it */ + if (t->dispatch.time < t_loc->dispatch.time) { + ++me->scheduled_task_cnt; + APR_RING_INSERT_BEFORE(t_loc, t, link); + break; + } + else { + t_loc = APR_RING_NEXT(t_loc, link); + if (t_loc == + APR_RING_SENTINEL(me->scheduled_tasks, apr_thread_pool_task, + link)) { + ++me->scheduled_task_cnt; + APR_RING_INSERT_TAIL(me->scheduled_tasks, t, + apr_thread_pool_task, link); + break; + } + } + } + /* there should be at least one thread for scheduled tasks */ + if (0 == me->thd_cnt) { + rv = apr_thread_create(&thd, NULL, thread_pool_func, me, me->pool); + if (APR_SUCCESS == rv) { + ++me->thd_cnt; + if (me->thd_cnt > me->thd_high) + me->thd_high = me->thd_cnt; + } + } + apr_thread_cond_signal(me->cond); + apr_thread_mutex_unlock(me->lock); + return rv; +} + +static apr_status_t add_task(apr_thread_pool_t *me, apr_thread_start_t func, + void *param, apr_byte_t priority, int push, + void *owner) +{ + apr_thread_pool_task_t *t; + apr_thread_pool_task_t *t_loc; + apr_thread_t *thd; + apr_status_t rv = APR_SUCCESS; + + apr_thread_mutex_lock(me->lock); + apr_pool_owner_set(me->pool, 0); + + t = task_new(me, func, param, priority, owner, 0); + if (NULL == t) { + apr_thread_mutex_unlock(me->lock); + return APR_ENOMEM; + } + + t_loc = add_if_empty(me, t); + if (NULL == t_loc) { + goto FINAL_EXIT; + } + + if (push) { + while (APR_RING_SENTINEL(me->tasks, apr_thread_pool_task, link) != + t_loc && t_loc->dispatch.priority >= t->dispatch.priority) { + t_loc = APR_RING_NEXT(t_loc, link); + } + } + APR_RING_INSERT_BEFORE(t_loc, t, link); + if (!push) { + if (t_loc == me->task_idx[TASK_PRIORITY_SEG(t)]) { + me->task_idx[TASK_PRIORITY_SEG(t)] = t; + } + } + + FINAL_EXIT: + me->task_cnt++; + if (me->task_cnt > me->tasks_high) + me->tasks_high = me->task_cnt; + if (0 == me->thd_cnt || (0 == me->idle_cnt && me->thd_cnt < me->thd_max && + me->task_cnt > me->threshold)) { + rv = apr_thread_create(&thd, NULL, thread_pool_func, me, me->pool); + if (APR_SUCCESS == rv) { + ++me->thd_cnt; + if (me->thd_cnt > me->thd_high) + me->thd_high = me->thd_cnt; + } + } + + apr_thread_cond_signal(me->cond); + apr_thread_mutex_unlock(me->lock); + + return rv; +} + +APR_DECLARE(apr_status_t) apr_thread_pool_push(apr_thread_pool_t *me, + apr_thread_start_t func, + void *param, + apr_byte_t priority, + void *owner) +{ + return add_task(me, func, param, priority, 1, owner); +} + +APR_DECLARE(apr_status_t) apr_thread_pool_schedule(apr_thread_pool_t *me, + apr_thread_start_t func, + void *param, + apr_interval_time_t time, + void *owner) +{ + return schedule_task(me, func, param, owner, time); +} + +APR_DECLARE(apr_status_t) apr_thread_pool_top(apr_thread_pool_t *me, + apr_thread_start_t func, + void *param, + apr_byte_t priority, + void *owner) +{ + return add_task(me, func, param, priority, 0, owner); +} + +static apr_status_t remove_scheduled_tasks(apr_thread_pool_t *me, + void *owner) +{ + apr_thread_pool_task_t *t_loc; + apr_thread_pool_task_t *next; + + t_loc = APR_RING_FIRST(me->scheduled_tasks); + while (t_loc != + APR_RING_SENTINEL(me->scheduled_tasks, apr_thread_pool_task, + link)) { + next = APR_RING_NEXT(t_loc, link); + /* if this is the owner remove it */ + if (t_loc->owner == owner) { + --me->scheduled_task_cnt; + APR_RING_REMOVE(t_loc, link); + } + t_loc = next; + } + return APR_SUCCESS; +} + +static apr_status_t remove_tasks(apr_thread_pool_t *me, void *owner) +{ + apr_thread_pool_task_t *t_loc; + apr_thread_pool_task_t *next; + int seg; + + t_loc = APR_RING_FIRST(me->tasks); + while (t_loc != APR_RING_SENTINEL(me->tasks, apr_thread_pool_task, link)) { + next = APR_RING_NEXT(t_loc, link); + if (t_loc->owner == owner) { + --me->task_cnt; + seg = TASK_PRIORITY_SEG(t_loc); + if (t_loc == me->task_idx[seg]) { + me->task_idx[seg] = APR_RING_NEXT(t_loc, link); + if (me->task_idx[seg] == APR_RING_SENTINEL(me->tasks, + apr_thread_pool_task, + link) + || TASK_PRIORITY_SEG(me->task_idx[seg]) != seg) { + me->task_idx[seg] = NULL; + } + } + APR_RING_REMOVE(t_loc, link); + } + t_loc = next; + } + return APR_SUCCESS; +} + +static void wait_on_busy_threads(apr_thread_pool_t *me, void *owner) +{ +#ifndef NDEBUG + apr_os_thread_t *os_thread; +#endif + struct apr_thread_list_elt *elt; + apr_thread_mutex_lock(me->lock); + elt = APR_RING_FIRST(me->busy_thds); + while (elt != APR_RING_SENTINEL(me->busy_thds, apr_thread_list_elt, link)) { + if (elt->current_owner != owner) { + elt = APR_RING_NEXT(elt, link); + continue; + } +#ifndef NDEBUG + /* make sure the thread is not the one calling tasks_cancel */ + apr_os_thread_get(&os_thread, elt->thd); +#ifdef WIN32 + /* hack for apr win32 bug */ + assert(!apr_os_thread_equal(apr_os_thread_current(), os_thread)); +#else + assert(!apr_os_thread_equal(apr_os_thread_current(), *os_thread)); +#endif +#endif + while (elt->current_owner == owner) { + apr_thread_mutex_unlock(me->lock); + apr_sleep(200 * 1000); + apr_thread_mutex_lock(me->lock); + } + elt = APR_RING_FIRST(me->busy_thds); + } + apr_thread_mutex_unlock(me->lock); + return; +} + +APR_DECLARE(apr_status_t) apr_thread_pool_tasks_cancel(apr_thread_pool_t *me, + void *owner) +{ + apr_status_t rv = APR_SUCCESS; + + apr_thread_mutex_lock(me->lock); + apr_pool_owner_set(me->pool, 0); + if (me->task_cnt > 0) { + rv = remove_tasks(me, owner); + } + if (me->scheduled_task_cnt > 0) { + rv = remove_scheduled_tasks(me, owner); + } + apr_thread_mutex_unlock(me->lock); + wait_on_busy_threads(me, owner); + + return rv; +} + +APR_DECLARE(apr_size_t) apr_thread_pool_tasks_count(apr_thread_pool_t *me) +{ + return me->task_cnt; +} + +APR_DECLARE(apr_size_t) + apr_thread_pool_scheduled_tasks_count(apr_thread_pool_t *me) +{ + return me->scheduled_task_cnt; +} + +APR_DECLARE(apr_size_t) apr_thread_pool_threads_count(apr_thread_pool_t *me) +{ + return me->thd_cnt; +} + +APR_DECLARE(apr_size_t) apr_thread_pool_busy_count(apr_thread_pool_t *me) +{ + return me->thd_cnt - me->idle_cnt; +} + +APR_DECLARE(apr_size_t) apr_thread_pool_idle_count(apr_thread_pool_t *me) +{ + return me->idle_cnt; +} + +APR_DECLARE(apr_size_t) + apr_thread_pool_tasks_run_count(apr_thread_pool_t * me) +{ + return me->tasks_run; +} + +APR_DECLARE(apr_size_t) + apr_thread_pool_tasks_high_count(apr_thread_pool_t * me) +{ + return me->tasks_high; +} + +APR_DECLARE(apr_size_t) + apr_thread_pool_threads_high_count(apr_thread_pool_t * me) +{ + return me->thd_high; +} + +APR_DECLARE(apr_size_t) + apr_thread_pool_threads_idle_timeout_count(apr_thread_pool_t * me) +{ + return me->thd_timed_out; +} + + +APR_DECLARE(apr_size_t) apr_thread_pool_idle_max_get(apr_thread_pool_t *me) +{ + return me->idle_max; +} + +APR_DECLARE(apr_interval_time_t) + apr_thread_pool_idle_wait_get(apr_thread_pool_t * me) +{ + return me->idle_wait; +} + +/* + * This function stop extra idle threads to the cnt. + * @return the number of threads stopped + * NOTE: There could be busy threads become idle during this function + */ +static struct apr_thread_list_elt *trim_threads(apr_thread_pool_t *me, + apr_size_t *cnt, int idle) +{ + struct apr_thread_list *thds; + apr_size_t n, n_dbg, i; + struct apr_thread_list_elt *head, *tail, *elt; + + apr_thread_mutex_lock(me->lock); + apr_pool_owner_set(me->pool, 0); + if (idle) { + thds = me->idle_thds; + n = me->idle_cnt; + } + else { + thds = me->busy_thds; + n = me->thd_cnt - me->idle_cnt; + } + if (n <= *cnt) { + apr_thread_mutex_unlock(me->lock); + *cnt = 0; + return NULL; + } + n -= *cnt; + + head = APR_RING_FIRST(thds); + for (i = 0; i < *cnt; i++) { + head = APR_RING_NEXT(head, link); + } + tail = APR_RING_LAST(thds); + if (idle) { + APR_RING_UNSPLICE(head, tail, link); + me->idle_cnt = *cnt; + } + + n_dbg = 0; + for (elt = head; elt != tail; elt = APR_RING_NEXT(elt, link)) { + elt->state = TH_STOP; + n_dbg++; + } + elt->state = TH_STOP; + n_dbg++; + assert(n == n_dbg); + *cnt = n; + + apr_thread_mutex_unlock(me->lock); + + APR_RING_PREV(head, link) = NULL; + APR_RING_NEXT(tail, link) = NULL; + return head; +} + +static apr_size_t trim_idle_threads(apr_thread_pool_t *me, apr_size_t cnt) +{ + apr_size_t n_dbg; + struct apr_thread_list_elt *elt, *head, *tail; + apr_status_t rv; + + elt = trim_threads(me, &cnt, 1); + + apr_thread_mutex_lock(me->lock); + apr_thread_cond_broadcast(me->cond); + apr_thread_mutex_unlock(me->lock); + + n_dbg = 0; + if (NULL != (head = elt)) { + while (elt) { + tail = elt; + apr_thread_join(&rv, elt->thd); + elt = APR_RING_NEXT(elt, link); + ++n_dbg; + } + apr_thread_mutex_lock(me->lock); + APR_RING_SPLICE_TAIL(me->recycled_thds, head, tail, + apr_thread_list_elt, link); + apr_thread_mutex_unlock(me->lock); + } + assert(cnt == n_dbg); + + return cnt; +} + +/* don't join on busy threads for performance reasons, who knows how long will + * the task takes to perform + */ +static apr_size_t trim_busy_threads(apr_thread_pool_t *me, apr_size_t cnt) +{ + trim_threads(me, &cnt, 0); + return cnt; +} + +APR_DECLARE(apr_size_t) apr_thread_pool_idle_max_set(apr_thread_pool_t *me, + apr_size_t cnt) +{ + me->idle_max = cnt; + cnt = trim_idle_threads(me, cnt); + return cnt; +} + +APR_DECLARE(apr_interval_time_t) + apr_thread_pool_idle_wait_set(apr_thread_pool_t * me, + apr_interval_time_t timeout) +{ + apr_interval_time_t oldtime; + + oldtime = me->idle_wait; + me->idle_wait = timeout; + + return oldtime; +} + +APR_DECLARE(apr_size_t) apr_thread_pool_thread_max_get(apr_thread_pool_t *me) +{ + return me->thd_max; +} + +/* + * This function stop extra working threads to the new limit. + * NOTE: There could be busy threads become idle during this function + */ +APR_DECLARE(apr_size_t) apr_thread_pool_thread_max_set(apr_thread_pool_t *me, + apr_size_t cnt) +{ + unsigned int n; + + me->thd_max = cnt; + if (0 == cnt || me->thd_cnt <= cnt) { + return 0; + } + + n = me->thd_cnt - cnt; + if (n >= me->idle_cnt) { + trim_busy_threads(me, n - me->idle_cnt); + trim_idle_threads(me, 0); + } + else { + trim_idle_threads(me, me->idle_cnt - n); + } + return n; +} + +APR_DECLARE(apr_size_t) apr_thread_pool_threshold_get(apr_thread_pool_t *me) +{ + return me->threshold; +} + +APR_DECLARE(apr_size_t) apr_thread_pool_threshold_set(apr_thread_pool_t *me, + apr_size_t val) +{ + apr_size_t ov; + + ov = me->threshold; + me->threshold = val; + return ov; +} + +APR_DECLARE(apr_status_t) apr_thread_pool_task_owner_get(apr_thread_t *thd, + void **owner) +{ + apr_status_t rv; + apr_thread_pool_task_t *task; + void *data; + + rv = apr_thread_data_get(&data, "apr_thread_pool_task", thd); + if (rv != APR_SUCCESS) { + return rv; + } + + task = data; + if (!task) { + *owner = NULL; + return APR_BADARG; + } + + *owner = task->owner; + return APR_SUCCESS; +} + +#endif /* APR_HAS_THREADS */ + +/* vim: set ts=4 sw=4 et cin tw=80: */ diff --git a/util-misc/apu_dso.c b/util-misc/apu_dso.c new file mode 100644 index 00000000000..dd29076eb73 --- /dev/null +++ b/util-misc/apu_dso.c @@ -0,0 +1,208 @@ +/* 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 <ctype.h> +#include <stdio.h> + +#include "apu.h" +#include "apr_private.h" +#include "apr_pools.h" +#include "apr_tables.h" +#include "apr_dso.h" +#include "apr_strings.h" +#include "apr_hash.h" +#include "apr_file_io.h" +#include "apr_env.h" +#include "apr_atomic.h" +#include "apr_version.h" + +#include "apu_internal.h" + +#if APR_HAVE_MODULAR_DSO + +#if APR_HAS_THREADS +static apr_thread_mutex_t* mutex = NULL; +#endif +static apr_hash_t *dsos = NULL; +static apr_uint32_t initialised = 0, in_init = 1; + +#if APR_HAS_THREADS +apr_status_t apu_dso_mutex_lock() +{ + return apr_thread_mutex_lock(mutex); +} +apr_status_t apu_dso_mutex_unlock() +{ + return apr_thread_mutex_unlock(mutex); +} +#else +apr_status_t apu_dso_mutex_lock() { + return APR_SUCCESS; +} +apr_status_t apu_dso_mutex_unlock() { + return APR_SUCCESS; +} +#endif + +static apr_status_t apu_dso_term(void *ptr) +{ + /* set statics to NULL so init can work again */ + dsos = NULL; +#if APR_HAS_THREADS + mutex = NULL; +#endif + + /* Everything else we need is handled by cleanups registered + * when we created mutexes and loaded DSOs + */ + return APR_SUCCESS; +} + +apr_status_t apu_dso_init(apr_pool_t *pool) +{ + apr_status_t ret = APR_SUCCESS; + apr_pool_t *parent; + + if (apr_atomic_inc32(&initialised)) { + apr_atomic_set32(&initialised, 1); /* prevent wrap-around */ + + while (apr_atomic_read32(&in_init)) /* wait until we get fully inited */ + ; + + return APR_SUCCESS; + } + + /* Top level pool scope, need process-scope lifetime */ + for (parent = apr_pool_parent_get(pool); + parent && parent != pool; + parent = apr_pool_parent_get(pool)) + pool = parent; + + dsos = apr_hash_make(pool); + +#if APR_HAS_THREADS + ret = apr_thread_mutex_create(&mutex, APR_THREAD_MUTEX_DEFAULT, pool); + /* This already registers a pool cleanup */ +#endif + + apr_pool_cleanup_register(pool, NULL, apu_dso_term, + apr_pool_cleanup_null); + + apr_atomic_dec32(&in_init); + + return ret; +} + +apr_status_t apu_dso_load(apr_dso_handle_t **dlhandleptr, + apr_dso_handle_sym_t *dsoptr, + const char *module, + const char *modsym, + apr_pool_t *pool) +{ + apr_dso_handle_t *dlhandle = NULL; + char *pathlist; + char path[APR_PATH_MAX + 1]; + apr_array_header_t *paths; + apr_pool_t *global; + apr_status_t rv = APR_EDSOOPEN; + char *eos = NULL; + int i; + + *dsoptr = apr_hash_get(dsos, module, APR_HASH_KEY_STRING); + if (*dsoptr) { + return APR_EINIT; + } + + /* The driver DSO must have exactly the same lifetime as the + * drivers hash table; ignore the passed-in pool */ + global = apr_hash_pool_get(dsos); + + /* Retrieve our path search list or prepare for a single search */ + if ((apr_env_get(&pathlist, APR_DSOPATH, pool) != APR_SUCCESS) + || (apr_filepath_list_split(&paths, pathlist, pool) != APR_SUCCESS)) + paths = apr_array_make(pool, 1, sizeof(char*)); + +#if defined(APR_DSO_LIBDIR) + /* Always search our prefix path, but on some platforms such as + * win32 this may be left undefined + */ + (*((char **)apr_array_push(paths))) = APR_DSO_LIBDIR; +#endif + + for (i = 0; i < paths->nelts; ++i) + { +#if defined(WIN32) + /* Use win32 dso search semantics and attempt to + * load the relative lib on the first pass. + */ + if (!eos) { + eos = path; + --i; + } + else +#endif + { + eos = apr_cpystrn(path, ((char**)paths->elts)[i], sizeof(path)); + if ((eos > path) && (eos - path < sizeof(path) - 1)) + *(eos++) = '/'; + } + apr_cpystrn(eos, module, sizeof(path) - (eos - path)); + + rv = apr_dso_load(&dlhandle, path, global); + if (dlhandleptr) { + *dlhandleptr = dlhandle; + } + if (rv == APR_SUCCESS) { /* APR_EDSOOPEN */ + break; + } +#if defined(APR_DSO_LIBDIR) + else if (i < paths->nelts - 1) { +#else + else { /* No APR_DSO_LIBDIR to skip */ +#endif + /* try with apr-APR_MAJOR_VERSION appended */ + eos = apr_cpystrn(eos, + "apr-" APR_STRINGIFY(APR_MAJOR_VERSION) "/", + sizeof(path) - (eos - path)); + + apr_cpystrn(eos, module, sizeof(path) - (eos - path)); + + rv = apr_dso_load(&dlhandle, path, global); + if (dlhandleptr) { + *dlhandleptr = dlhandle; + } + if (rv == APR_SUCCESS) { /* APR_EDSOOPEN */ + break; + } + } + } + + if (rv != APR_SUCCESS) /* APR_ESYMNOTFOUND */ + return rv; + + rv = apr_dso_sym(dsoptr, dlhandle, modsym); + if (rv != APR_SUCCESS) { /* APR_ESYMNOTFOUND */ + apr_dso_unload(dlhandle); + } + else { + module = apr_pstrdup(global, module); + apr_hash_set(dsos, module, APR_HASH_KEY_STRING, *dsoptr); + } + return rv; +} + +#endif /* APR_DSO_BUILD */ + diff --git a/xlate/xlate.c b/xlate/xlate.c new file mode 100644 index 00000000000..6a84c31443e --- /dev/null +++ b/xlate/xlate.c @@ -0,0 +1,406 @@ +/* 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 "apu.h" +#include "apr_private.h" +#include "apr_lib.h" +#include "apr_strings.h" +#include "apr_portable.h" +#include "apr_xlate.h" + +/* If no implementation is available, don't generate code here since + * apr_xlate.h emitted macros which return APR_ENOTIMPL. + */ + +#if APR_HAS_XLATE + +#ifdef HAVE_STDDEF_H +#include <stddef.h> /* for NULL */ +#endif +#if APR_HAVE_STRING_H +#include <string.h> +#endif +#if APR_HAVE_STRINGS_H +#include <strings.h> +#endif +#ifdef HAVE_ICONV_H +#include <iconv.h> +#endif + +#if defined(APU_ICONV_INBUF_CONST) +#define ICONV_INBUF_TYPE const char ** +#else +#define ICONV_INBUF_TYPE char ** +#endif + +#ifndef min +#define min(x,y) ((x) <= (y) ? (x) : (y)) +#endif + +struct apr_xlate_t { + apr_pool_t *pool; + char *frompage; + char *topage; + char *sbcs_table; +#if APU_HAVE_ICONV + iconv_t ich; +#endif +}; + + +static const char *handle_special_names(const char *page, apr_pool_t *pool) +{ + if (page == APR_DEFAULT_CHARSET) { + return apr_os_default_encoding(pool); + } + else if (page == APR_LOCALE_CHARSET) { + return apr_os_locale_encoding(pool); + } +#ifdef __MVS__ + else if (!strcasecmp(page, "ISO-8859-1")) { + return "ISO8859-1"; /* z/OS ASCII name has no dash after ISO */ + } +#endif + else { + return page; + } +} + +static apr_status_t apr_xlate_cleanup(void *convset) +{ + apr_xlate_t *old = convset; + +#if APU_HAVE_ICONV + if (old->ich != (iconv_t)-1) { + if (iconv_close(old->ich)) { + int rv = errno; + + /* Sometimes, iconv is not good about setting errno. */ + return rv ? rv : APR_EINVAL; + } + } +#endif + + return APR_SUCCESS; +} + +#if APU_HAVE_ICONV +static void check_sbcs(apr_xlate_t *convset) +{ + char inbuf[256], outbuf[256]; + char *inbufptr = inbuf; + char *outbufptr = outbuf; + apr_size_t inbytes_left, outbytes_left; + int i; + apr_size_t translated; + + for (i = 0; i < sizeof(inbuf); i++) { + inbuf[i] = i; + } + + inbytes_left = outbytes_left = sizeof(inbuf); + translated = iconv(convset->ich, (ICONV_INBUF_TYPE)&inbufptr, + &inbytes_left, &outbufptr, &outbytes_left); + + if (translated != (apr_size_t)-1 + && inbytes_left == 0 + && outbytes_left == 0) { + /* hurray... this is simple translation; save the table, + * close the iconv descriptor + */ + + convset->sbcs_table = apr_pmemdup(convset->pool, outbuf, sizeof(outbuf)); + + iconv_close(convset->ich); + convset->ich = (iconv_t)-1; + + /* TODO: add the table to the cache */ + } + else { + /* reset the iconv descriptor, since it's now in an undefined + * state. */ + iconv_close(convset->ich); + convset->ich = iconv_open(convset->topage, convset->frompage); + } +} +#elif APU_HAVE_APR_ICONV +static void check_sbcs(apr_xlate_t *convset) +{ + char inbuf[256], outbuf[256]; + char *inbufptr = inbuf; + char *outbufptr = outbuf; + apr_size_t inbytes_left, outbytes_left; + int i; + apr_size_t translated; + apr_status_t rv; + + for (i = 0; i < sizeof(inbuf); i++) { + inbuf[i] = i; + } + + inbytes_left = outbytes_left = sizeof(inbuf); + rv = apr_iconv(convset->ich, (ICONV_INBUF_TYPE)&inbufptr, + &inbytes_left, &outbufptr, &outbytes_left, + &translated); + + if ((rv == APR_SUCCESS) + && (translated != (apr_size_t)-1) + && inbytes_left == 0 + && outbytes_left == 0) { + /* hurray... this is simple translation; save the table, + * close the iconv descriptor + */ + + convset->sbcs_table = apr_palloc(convset->pool, sizeof(outbuf)); + memcpy(convset->sbcs_table, outbuf, sizeof(outbuf)); + apr_iconv_close(convset->ich, convset->pool); + convset->ich = (apr_iconv_t)-1; + + /* TODO: add the table to the cache */ + } + else { + /* reset the iconv descriptor, since it's now in an undefined + * state. */ + apr_iconv_close(convset->ich, convset->pool); + rv = apr_iconv_open(convset->topage, convset->frompage, + convset->pool, &convset->ich); + } +} +#endif /* APU_HAVE_APR_ICONV */ + +static void make_identity_table(apr_xlate_t *convset) +{ + int i; + + convset->sbcs_table = apr_palloc(convset->pool, 256); + for (i = 0; i < 256; i++) + convset->sbcs_table[i] = i; +} + +APR_DECLARE(apr_status_t) apr_xlate_open(apr_xlate_t **convset, + const char *topage, + const char *frompage, + apr_pool_t *pool) +{ + apr_status_t rv; + apr_xlate_t *new; + int found = 0; + + *convset = NULL; + + topage = handle_special_names(topage, pool); + frompage = handle_special_names(frompage, pool); + + new = (apr_xlate_t *)apr_pcalloc(pool, sizeof(apr_xlate_t)); + if (!new) { + return APR_ENOMEM; + } + + new->pool = pool; + new->topage = apr_pstrdup(pool, topage); + new->frompage = apr_pstrdup(pool, frompage); + if (!new->topage || !new->frompage) { + return APR_ENOMEM; + } + +#ifdef TODO + /* search cache of codepage pairs; we may be able to avoid the + * expensive iconv_open() + */ + + set found to non-zero if found in the cache +#endif + + if ((! found) && (strcmp(topage, frompage) == 0)) { + /* to and from are the same */ + found = 1; + make_identity_table(new); + } + +#if APU_HAVE_APR_ICONV + if (!found) { + rv = apr_iconv_open(topage, frompage, pool, &new->ich); + if (rv != APR_SUCCESS) { + return rv; + } + found = 1; + check_sbcs(new); + } else + new->ich = (apr_iconv_t)-1; + +#elif APU_HAVE_ICONV + if (!found) { + new->ich = iconv_open(topage, frompage); + if (new->ich == (iconv_t)-1) { + int rv = errno; + /* Sometimes, iconv is not good about setting errno. */ + return rv ? rv : APR_EINVAL; + } + found = 1; + check_sbcs(new); + } else + new->ich = (iconv_t)-1; +#endif /* APU_HAVE_ICONV */ + + if (found) { + *convset = new; + apr_pool_cleanup_register(pool, (void *)new, apr_xlate_cleanup, + apr_pool_cleanup_null); + rv = APR_SUCCESS; + } + else { + rv = APR_EINVAL; /* iconv() would return EINVAL if it + couldn't handle the pair */ + } + + return rv; +} + +APR_DECLARE(apr_status_t) apr_xlate_sb_get(apr_xlate_t *convset, int *onoff) +{ + *onoff = convset->sbcs_table != NULL; + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_xlate_conv_buffer(apr_xlate_t *convset, + const char *inbuf, + apr_size_t *inbytes_left, + char *outbuf, + apr_size_t *outbytes_left) +{ + apr_status_t status = APR_SUCCESS; + +#if APU_HAVE_ICONV + if (convset->ich != (iconv_t)-1) { + const char *inbufptr = inbuf; + char *outbufptr = outbuf; + apr_size_t translated; + translated = iconv(convset->ich, (ICONV_INBUF_TYPE)&inbufptr, + inbytes_left, &outbufptr, outbytes_left); + + /* If everything went fine but we ran out of buffer, don't + * report it as an error. Caller needs to look at the two + * bytes-left values anyway. + * + * There are three expected cases where rc is -1. In each of + * these cases, *inbytes_left != 0. + * a) the non-error condition where we ran out of output + * buffer + * b) the non-error condition where we ran out of input (i.e., + * the last input character is incomplete) + * c) the error condition where the input is invalid + */ + if (translated == (apr_size_t)-1) { + int rv = errno; + switch (rv) { + + case E2BIG: /* out of space on output */ + status = 0; /* change table lookup code below if you + make this an error */ + break; + + case EINVAL: /* input character not complete (yet) */ + status = APR_INCOMPLETE; + break; + + case EILSEQ: /* bad input byte */ + status = APR_EINVAL; + break; + + /* Sometimes, iconv is not good about setting errno. */ + case 0: + status = APR_INCOMPLETE; + break; + + default: + status = rv; + break; + } + } + } + else +#endif + + if (inbuf) { + apr_size_t to_convert = min(*inbytes_left, *outbytes_left); + apr_size_t converted = to_convert; + char *table = convset->sbcs_table; + + while (to_convert) { + *outbuf = table[(unsigned char)*inbuf]; + ++outbuf; + ++inbuf; + --to_convert; + } + *inbytes_left -= converted; + *outbytes_left -= converted; + } + + return status; +} + +APR_DECLARE(apr_int32_t) apr_xlate_conv_byte(apr_xlate_t *convset, + unsigned char inchar) +{ + if (convset->sbcs_table) { + return convset->sbcs_table[inchar]; + } + else { + return -1; + } +} + +APR_DECLARE(apr_status_t) apr_xlate_close(apr_xlate_t *convset) +{ + return apr_pool_cleanup_run(convset->pool, convset, apr_xlate_cleanup); +} + +#else /* !APR_HAS_XLATE */ + +APR_DECLARE(apr_status_t) apr_xlate_open(apr_xlate_t **convset, + const char *topage, + const char *frompage, + apr_pool_t *pool) +{ + return APR_ENOTIMPL; +} + +APR_DECLARE(apr_status_t) apr_xlate_sb_get(apr_xlate_t *convset, int *onoff) +{ + return APR_ENOTIMPL; +} + +APR_DECLARE(apr_int32_t) apr_xlate_conv_byte(apr_xlate_t *convset, + unsigned char inchar) +{ + return (-1); +} + +APR_DECLARE(apr_status_t) apr_xlate_conv_buffer(apr_xlate_t *convset, + const char *inbuf, + apr_size_t *inbytes_left, + char *outbuf, + apr_size_t *outbytes_left) +{ + return APR_ENOTIMPL; +} + +APR_DECLARE(apr_status_t) apr_xlate_close(apr_xlate_t *convset) +{ + return APR_ENOTIMPL; +} + +#endif /* APR_HAS_XLATE */ diff --git a/xml/NWGNUmakefile b/xml/NWGNUmakefile new file mode 100644 index 00000000000..9225c6bce4d --- /dev/null +++ b/xml/NWGNUmakefile @@ -0,0 +1,303 @@ +# +# Declare the sub-directories to be built here +# + +SUBDIRS = \ + $(EOLIST) + +# +# Get the 'head' of the build environment. This includes default targets and +# paths to tools +# + +include $(APR_WORK)/build/NWGNUhead.inc + +# +# build this level's files + +# +# Make sure all needed macro's are defined +# + +ifdef EXPATSRC + +ifeq "$(wildcard $(EXPATSRC)/lib/expat.h.in)" "$(EXPATSRC)/lib/expat.h.in" +EXPAT_prebuild_headers += $(EXPATSRC)/lib/expat.h +endif +ifeq "$(wildcard $(EXPATSRC)/lib/config.hnw)" "$(EXPATSRC)/lib/config.hnw" +EXPAT_prebuild_headers += $(EXPATSRC)/lib/config.h +endif +ifeq "$(wildcard $(EXPATSRC)/expat_config.h.in)" "$(EXPATSRC)/expat_config.h.in" +EXPAT_prebuild_headers += $(EXPATSRC)/lib/expat_config.h +endif + +$(EXPATSRC)/lib/%.h: $(EXPATSRC)/lib/%.hnw + @echo Creating $@ + $(call COPY,$<,$@) + +$(EXPATSRC)/lib/%.h: $(EXPATSRC)/lib/%.h.in + @echo Creating $@ + $(call COPY,$<,$@) + +$(EXPATSRC)/lib/expat_config.h: + @echo Creating $@ + @echo $(DL)/* $(notdir $@) for NetWare platform */$(DL)>>$@ + @echo $(DL)#ifndef NETWARE$(DL)>>$@ + @echo $(DL)#error This $(notdir $@) is for NetWare platform!$(DL)>>$@ + @echo $(DL)#endif$(DL)>>$@ + @echo $(DL)#ifndef EXPAT_CONFIG_H$(DL)>>$@ + @echo $(DL)#define EXPAT_CONFIG_H$(DL)>>$@ + @echo $(DL)#define HAVE_MEMMOVE 1$(DL)>>$@ + @echo $(DL)#define XML_NS 1$(DL)>>$@ + @echo $(DL)#define XML_DTD 1$(DL)>>$@ + @echo $(DL)#define XML_BYTE_ORDER 1234$(DL)>>$@ + @echo $(DL)#define XML_CONTEXT_BYTES 1024$(DL)>>$@ + @echo $(DL)#endif /* EXPAT_CONFIG_H */$(DL)>>$@ + +vpath %.c $(EXPATSRC)/lib + +endif + +# +# These directories will be at the beginning of the include list, followed by +# INCDIRS +# +XINCDIRS += \ + $(EXPAT_INC) \ + $(APR)/include \ + $(APR)/include/private \ + $(APR)/include/arch/netware \ + $(EOLIST) + +# +# These flags will come after CFLAGS +# +XCFLAGS += \ + $(EOLIST) + +# +# These defines will come after DEFINES +# +XDEFINES += \ + -DAPU_USE_EXPAT=1 \ + -DHAVE_EXPAT_CONFIG_H \ + $(EOLIST) + +# +# These flags will be added to the link.opt file +# +XLFLAGS += \ + $(EOLIST) + +# +# These values will be appended to the correct variables based on the value of +# RELEASE +# +ifeq "$(RELEASE)" "debug" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +ifeq "$(RELEASE)" "noopt" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +ifeq "$(RELEASE)" "release" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +# +# These are used by the link target if an NLM is being generated +# This is used by the link 'name' directive to name the nlm. If left blank +# TARGET_nlm (see below) will be used. +# +NLM_NAME = + +# +# This is used by the link '-desc ' directive. +# If left blank, NLM_NAME will be used. +# +NLM_DESCRIPTION = + +# +# This is used by the '-threadname' directive. If left blank, +# NLM_NAME Thread will be used. +# +NLM_THREAD_NAME = +# +# If this is specified, it will override VERSION value in +# $(APR_WORK)/build/NWGNUenvironment.inc +# +NLM_VERSION = + +# +# If this is specified, it will override the default of 64K +# +NLM_STACK_SIZE = + +# +# If this is specified it will be used by the link '-entry' directive +# +NLM_ENTRY_SYM = + +# +# If this is specified it will be used by the link '-exit' directive +# +NLM_EXIT_SYM = + +# +# If this is specified it will be used by the link '-check' directive +# +NLM_CHECK_SYM = + +# +# If this is specified it will be used by the link '-flags' directive +# +NLM_FLAGS = + +# +# If this is specified it will be linked in with the XDCData option in the def +# file instead of the default of $(APR)/misc/netware/apache.xdc. XDCData can +# be disabled by setting APACHE_UNIPROC in the environment +# +XDCDATA = + +# +# Declare all target files (you must add your files here) +# + +# +# If there is an NLM target, put it here +# +TARGET_nlm = \ + $(EOLIST) + +# +# If there is an LIB target, put it here +# +TARGET_lib = \ + $(OBJDIR)/xml.lib \ + $(EOLIST) + +# +# These are the OBJ files needed to create the NLM target above. +# Paths must all use the '/' character +# +FILES_nlm_objs = \ + $(EOLIST) + +# +# These are the LIB files needed to create the NLM target above. +# These will be added as a library command in the link.opt file. +# +FILES_nlm_libs = \ + $(EOLIST) + +# +# These are the modules that the above NLM target depends on to load. +# These will be added as a module command in the link.opt file. +# +FILES_nlm_modules = \ + $(EOLIST) + +# +# If the nlm has a msg file, put it's path here +# +FILE_nlm_msg = + +# +# If the nlm has a hlp file put it's path here +# +FILE_nlm_hlp = + +# +# If this is specified, it will override the default copyright. +# +FILE_nlm_copyright = + +# +# Any additional imports go here +# +FILES_nlm_Ximports = \ + $(EOLIST) + +# +# Any symbols exported to here +# +FILES_nlm_exports = \ + $(EOLIST) + +# +# These are the OBJ files needed to create the LIB target above. +# Paths must all use the '/' character +# +FILES_lib_objs = \ + $(OBJDIR)/apr_xml.o \ + $(OBJDIR)/apr_xml_expat.o \ + $(EOLIST) + +ifdef EXPATSRC +FILES_lib_objs += \ + $(OBJDIR)/xmlparse.o \ + $(OBJDIR)/xmlrole.o \ + $(OBJDIR)/xmltok.o \ + $(EOLIST) +endif + +# +# implement targets and dependancies (leave this section alone) +# + +libs :: $(OBJDIR) $(EXPAT_prebuild_headers) $(TARGET_lib) + +nlms :: libs $(TARGET_nlm) + +# +# Updated this target to create necessary directories and copy files to the +# correct place. (See $(APR_WORK)/build/NWGNUhead.inc for examples) +# +install :: nlms FORCE + +clean :: + $(foreach file,$(EXPAT_prebuild_headers),$(call DEL,$(file))) + +# +# Any specialized rules here +# + +# +# Include the 'tail' makefile that has targets that depend on variables defined +# in this makefile +# + +include $(APRBUILD)/NWGNUtail.inc + diff --git a/xml/apr_xml.c b/xml/apr_xml.c new file mode 100644 index 00000000000..82791f49da9 --- /dev/null +++ b/xml/apr_xml.c @@ -0,0 +1,977 @@ +/* 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" + +#define APR_WANT_STDIO /* for sprintf() */ +#define APR_WANT_STRFUNC +#include "apr_want.h" + +#include "apr_xml.h" +typedef void* XML_Parser; +typedef int XML_Error; +typedef unsigned char XML_Char; +#include "apr_xml_internal.h" + +#define DEBUG_CR "\r\n" + +static const char APR_KW_xmlns[] = { 0x78, 0x6D, 0x6C, 0x6E, 0x73, '\0' }; +static const char APR_KW_xmlns_lang[] = { 0x78, 0x6D, 0x6C, 0x3A, 0x6C, 0x61, 0x6E, 0x67, '\0' }; + +/* errors related to namespace processing */ +#define APR_XML_NS_ERROR_UNKNOWN_PREFIX (-1000) +#define APR_XML_NS_ERROR_INVALID_DECL (-1001) + +/* test for a namespace prefix that begins with [Xx][Mm][Ll] */ +#define APR_XML_NS_IS_RESERVED(name) \ + ( (name[0] == 0x58 || name[0] == 0x78) && \ + (name[1] == 0x4D || name[1] == 0x6D) && \ + (name[2] == 0x4C || name[2] == 0x6C) ) + + +/* struct for scoping namespace declarations */ +typedef struct apr_xml_ns_scope { + const char *prefix; /* prefix used for this ns */ + int ns; /* index into namespace table */ + int emptyURI; /* the namespace URI is the empty string */ + struct apr_xml_ns_scope *next; /* next scoped namespace */ +} apr_xml_ns_scope; + + +/* return namespace table index for a given prefix */ +static int find_prefix(apr_xml_parser *parser, const char *prefix) +{ + apr_xml_elem *elem = parser->cur_elem; + + /* + ** Walk up the tree, looking for a namespace scope that defines this + ** prefix. + */ + for (; elem; elem = elem->parent) { + apr_xml_ns_scope *ns_scope; + + for (ns_scope = elem->ns_scope; ns_scope; ns_scope = ns_scope->next) { + if (strcmp(prefix, ns_scope->prefix) == 0) { + if (ns_scope->emptyURI) { + /* + ** It is possible to set the default namespace to an + ** empty URI string; this resets the default namespace + ** to mean "no namespace." We just found the prefix + ** refers to an empty URI, so return "no namespace." + */ + return APR_XML_NS_NONE; + } + + return ns_scope->ns; + } + } + } + + /* + * If the prefix is empty (""), this means that a prefix was not + * specified in the element/attribute. The search that was performed + * just above did not locate a default namespace URI (which is stored + * into ns_scope with an empty prefix). This means the element/attribute + * has "no namespace". We have a reserved value for this. + */ + if (*prefix == '\0') { + return APR_XML_NS_NONE; + } + + /* not found */ + return APR_XML_NS_ERROR_UNKNOWN_PREFIX; +} + +/* return original prefix given ns index */ +static const char * find_prefix_name(const apr_xml_elem *elem, int ns, int parent) +{ + /* + ** Walk up the tree, looking for a namespace scope that defines this + ** prefix. + */ + for (; elem; elem = parent ? elem->parent : NULL) { + apr_xml_ns_scope *ns_scope = elem->ns_scope; + + for (; ns_scope; ns_scope = ns_scope->next) { + if (ns_scope->ns == ns) + return ns_scope->prefix; + } + } + /* not found */ + return ""; +} + +static void start_handler(void *userdata, const char *name, const char **attrs) +{ + apr_xml_parser *parser = userdata; + apr_xml_elem *elem; + apr_xml_attr *attr; + apr_xml_attr *prev; + char *colon; + const char *quoted; + char *elem_name; + + /* punt once we find an error */ + if (parser->error) + return; + + elem = apr_pcalloc(parser->p, sizeof(*elem)); + + /* prep the element */ + elem->name = elem_name = apr_pstrdup(parser->p, name); + + /* fill in the attributes (note: ends up in reverse order) */ + while (attrs && *attrs) { + attr = apr_palloc(parser->p, sizeof(*attr)); + attr->name = apr_pstrdup(parser->p, *attrs++); + attr->value = apr_pstrdup(parser->p, *attrs++); + attr->next = elem->attr; + elem->attr = attr; + } + + /* hook the element into the tree */ + if (parser->cur_elem == NULL) { + /* no current element; this also becomes the root */ + parser->cur_elem = parser->doc->root = elem; + } + else { + /* this element appeared within the current elem */ + elem->parent = parser->cur_elem; + + /* set up the child/sibling links */ + if (elem->parent->last_child == NULL) { + /* no first child either */ + elem->parent->first_child = elem->parent->last_child = elem; + } + else { + /* hook onto the end of the parent's children */ + elem->parent->last_child->next = elem; + elem->parent->last_child = elem; + } + + /* this element is now the current element */ + parser->cur_elem = elem; + } + + /* scan the attributes for namespace declarations */ + for (prev = NULL, attr = elem->attr; + attr; + attr = attr->next) { + if (strncmp(attr->name, APR_KW_xmlns, 5) == 0) { + const char *prefix = &attr->name[5]; + apr_xml_ns_scope *ns_scope; + + /* test for xmlns:foo= form and xmlns= form */ + if (*prefix == 0x3A) { + /* a namespace prefix declaration must have a + non-empty value. */ + if (attr->value[0] == '\0') { + parser->error = APR_XML_NS_ERROR_INVALID_DECL; + return; + } + ++prefix; + } + else if (*prefix != '\0') { + /* advance "prev" since "attr" is still present */ + prev = attr; + continue; + } + + /* quote the URI before we ever start working with it */ + quoted = apr_xml_quote_string(parser->p, attr->value, 1); + + /* build and insert the new scope */ + ns_scope = apr_pcalloc(parser->p, sizeof(*ns_scope)); + ns_scope->prefix = prefix; + ns_scope->ns = apr_xml_insert_uri(parser->doc->namespaces, quoted); + ns_scope->emptyURI = *quoted == '\0'; + ns_scope->next = elem->ns_scope; + elem->ns_scope = ns_scope; + + /* remove this attribute from the element */ + if (prev == NULL) + elem->attr = attr->next; + else + prev->next = attr->next; + + /* Note: prev will not be advanced since we just removed "attr" */ + } + else if (strcmp(attr->name, APR_KW_xmlns_lang) == 0) { + /* save away the language (in quoted form) */ + elem->lang = apr_xml_quote_string(parser->p, attr->value, 1); + + /* remove this attribute from the element */ + if (prev == NULL) + elem->attr = attr->next; + else + prev->next = attr->next; + + /* Note: prev will not be advanced since we just removed "attr" */ + } + else { + /* advance "prev" since "attr" is still present */ + prev = attr; + } + } + + /* + ** If an xml:lang attribute didn't exist (lang==NULL), then copy the + ** language from the parent element (if present). + ** + ** NOTE: elem_size() *depends* upon this pointer equality. + */ + if (elem->lang == NULL && elem->parent != NULL) + elem->lang = elem->parent->lang; + + /* adjust the element's namespace */ + colon = strchr(elem_name, 0x3A); + if (colon == NULL) { + /* + * The element is using the default namespace, which will always + * be found. Either it will be "no namespace", or a default + * namespace URI has been specified at some point. + */ + elem->ns = find_prefix(parser, ""); + } + else if (APR_XML_NS_IS_RESERVED(elem->name)) { + elem->ns = APR_XML_NS_NONE; + } + else { + *colon = '\0'; + elem->ns = find_prefix(parser, elem->name); + elem->name = colon + 1; + + if (APR_XML_NS_IS_ERROR(elem->ns)) { + parser->error = elem->ns; + return; + } + } + + /* adjust all remaining attributes' namespaces */ + for (attr = elem->attr; attr; attr = attr->next) { + /* + * apr_xml_attr defines this as "const" but we dup'd it, so we + * know that we can change it. a bit hacky, but the existing + * structure def is best. + */ + char *attr_name = (char *)attr->name; + + colon = strchr(attr_name, 0x3A); + if (colon == NULL) { + /* + * Attributes do NOT use the default namespace. Therefore, + * we place them into the "no namespace" category. + */ + attr->ns = APR_XML_NS_NONE; + } + else if (APR_XML_NS_IS_RESERVED(attr->name)) { + attr->ns = APR_XML_NS_NONE; + } + else { + *colon = '\0'; + attr->ns = find_prefix(parser, attr->name); + attr->name = colon + 1; + + if (APR_XML_NS_IS_ERROR(attr->ns)) { + parser->error = attr->ns; + return; + } + } + } +} + +static void end_handler(void *userdata, const char *name) +{ + apr_xml_parser *parser = userdata; + + /* punt once we find an error */ + if (parser->error) + return; + + /* pop up one level */ + parser->cur_elem = parser->cur_elem->parent; +} + +static void cdata_handler(void *userdata, const char *data, int len) +{ + apr_xml_parser *parser = userdata; + apr_xml_elem *elem; + apr_text_header *hdr; + const char *s; + + /* punt once we find an error */ + if (parser->error) + return; + + elem = parser->cur_elem; + s = apr_pstrndup(parser->p, data, len); + + if (elem->last_child == NULL) { + /* no children yet. this cdata follows the start tag */ + hdr = &elem->first_cdata; + } + else { + /* child elements exist. this cdata follows the last child. */ + hdr = &elem->last_child->following_cdata; + } + + apr_text_append(parser->p, hdr, s); +} + +APR_DECLARE(apr_xml_parser *) apr_xml_parser_create(apr_pool_t *pool) +{ + return apr_xml_parser_create_internal(pool, &start_handler, &end_handler, &cdata_handler); +} + +APR_DECLARE(apr_status_t) apr_xml_parser_feed(apr_xml_parser *parser, + const char *data, + apr_size_t len) +{ + return parser->impl->Parse(parser, data, len, 0 /* is_final */); +} + +APR_DECLARE(apr_status_t) apr_xml_parser_done(apr_xml_parser *parser, + apr_xml_doc **pdoc) +{ + char end; + apr_status_t status = parser->impl->Parse(parser, &end, 0, 1 /* is_final */); + + /* get rid of the parser */ + (void) apr_pool_cleanup_run(parser->p, parser, parser->impl->cleanup); + + if (status) + return status; + + if (pdoc != NULL) + *pdoc = parser->doc; + return APR_SUCCESS; +} + +APR_DECLARE(char *) apr_xml_parser_geterror(apr_xml_parser *parser, + char *errbuf, + apr_size_t errbufsize) +{ + int error = parser->error; + const char *msg; + + /* clear our record of an error */ + parser->error = 0; + + switch (error) { + case 0: + msg = "No error."; + break; + + case APR_XML_NS_ERROR_UNKNOWN_PREFIX: + msg = "An undefined namespace prefix was used."; + break; + + case APR_XML_NS_ERROR_INVALID_DECL: + msg = "A namespace prefix was defined with an empty URI."; + break; + + case APR_XML_ERROR_EXPAT: + (void) apr_snprintf(errbuf, errbufsize, + "XML parser error code: %s (%d)", + parser->xp_msg, parser->xp_err); + return errbuf; + + case APR_XML_ERROR_PARSE_DONE: + msg = "The parser is not active."; + break; + + default: + msg = "There was an unknown error within the XML body."; + break; + } + + (void) apr_cpystrn(errbuf, msg, errbufsize); + return errbuf; +} + +APR_DECLARE(apr_status_t) apr_xml_parse_file(apr_pool_t *p, + apr_xml_parser **parser, + apr_xml_doc **ppdoc, + apr_file_t *xmlfd, + apr_size_t buffer_length) +{ + apr_status_t rv; + char *buffer; + apr_size_t length; + + *parser = apr_xml_parser_create(p); + if (*parser == NULL) { + /* FIXME: returning an error code would be nice, + * but we dont get one ;( */ + return APR_EGENERAL; + } + buffer = apr_palloc(p, buffer_length); + length = buffer_length; + + rv = apr_file_read(xmlfd, buffer, &length); + + while (rv == APR_SUCCESS) { + rv = apr_xml_parser_feed(*parser, buffer, length); + if (rv != APR_SUCCESS) { + return rv; + } + + length = buffer_length; + rv = apr_file_read(xmlfd, buffer, &length); + } + if (rv != APR_EOF) { + return rv; + } + rv = apr_xml_parser_done(*parser, ppdoc); + *parser = NULL; + return rv; +} + +APR_DECLARE(void) apr_text_append(apr_pool_t * p, apr_text_header *hdr, + const char *text) +{ + apr_text *t = apr_palloc(p, sizeof(*t)); + + t->text = text; + t->next = NULL; + + if (hdr->first == NULL) { + /* no text elements yet */ + hdr->first = hdr->last = t; + } + else { + /* append to the last text element */ + hdr->last->next = t; + hdr->last = t; + } +} + + +/* --------------------------------------------------------------- +** +** XML UTILITY FUNCTIONS +*/ + +/* +** apr_xml_quote_string: quote an XML string +** +** Replace '<', '>', and '&' with '<', '>', and '&'. +** If quotes is true, then replace '"' with '"'. +** +** quotes is typically set to true for XML strings that will occur within +** double quotes -- attribute values. +*/ +APR_DECLARE(const char *) apr_xml_quote_string(apr_pool_t *p, const char *s, + int quotes) +{ + const char *scan; + apr_size_t len = 0; + apr_size_t extra = 0; + char *qstr; + char *qscan; + char c; + + for (scan = s; (c = *scan) != '\0'; ++scan, ++len) { + if (c == '<' || c == '>') + extra += 3; /* < or > */ + else if (c == '&') + extra += 4; /* & */ + else if (quotes && c == '"') + extra += 5; /* " */ + } + + /* nothing to do? */ + if (extra == 0) + return s; + + qstr = apr_palloc(p, len + extra + 1); + for (scan = s, qscan = qstr; (c = *scan) != '\0'; ++scan) { + if (c == '<') { + *qscan++ = '&'; + *qscan++ = 'l'; + *qscan++ = 't'; + *qscan++ = ';'; + } + else if (c == '>') { + *qscan++ = '&'; + *qscan++ = 'g'; + *qscan++ = 't'; + *qscan++ = ';'; + } + else if (c == '&') { + *qscan++ = '&'; + *qscan++ = 'a'; + *qscan++ = 'm'; + *qscan++ = 'p'; + *qscan++ = ';'; + } + else if (quotes && c == '"') { + *qscan++ = '&'; + *qscan++ = 'q'; + *qscan++ = 'u'; + *qscan++ = 'o'; + *qscan++ = 't'; + *qscan++ = ';'; + } + else { + *qscan++ = c; + } + } + + *qscan = '\0'; + return qstr; +} + +/* how many characters for the given integer? */ +#define APR_XML_NS_LEN(ns) ((ns) < 10 ? 1 : (ns) < 100 ? 2 : (ns) < 1000 ? 3 : \ + (ns) < 10000 ? 4 : (ns) < 100000 ? 5 : \ + (ns) < 1000000 ? 6 : (ns) < 10000000 ? 7 : \ + (ns) < 100000000 ? 8 : (ns) < 1000000000 ? 9 : 10) + +static apr_size_t text_size(const apr_text *t) +{ + apr_size_t size = 0; + + for (; t; t = t->next) + size += strlen(t->text); + return size; +} + +static apr_size_t elem_size(const apr_xml_elem *elem, int style, + apr_array_header_t *namespaces, int *ns_map) +{ + apr_size_t size; + + if (style == APR_XML_X2T_FULL || style == APR_XML_X2T_FULL_NS_LANG || + style == APR_XML_X2T_PARSED) { + const apr_xml_attr *attr; + + size = 0; + + if (style == APR_XML_X2T_FULL_NS_LANG) { + int i; + + /* + ** The outer element will contain xmlns:ns%d="%s" attributes + ** and an xml:lang attribute, if applicable. + */ + + for (i = namespaces->nelts; i--;) { + /* compute size of: ' xmlns:ns%d="%s"' */ + size += (9 + APR_XML_NS_LEN(i) + 2 + + strlen(APR_XML_GET_URI_ITEM(namespaces, i)) + 1); + } + + if (elem->lang != NULL) { + /* compute size of: ' xml:lang="%s"' */ + size += 11 + strlen(elem->lang) + 1; + } + } + else if (style == APR_XML_X2T_PARSED) { + apr_xml_ns_scope *ns_scope = elem->ns_scope; + + /* compute size of: ' xmlns:%s="%s"' */ + for (; ns_scope; ns_scope = ns_scope->next) { + size += 10 + strlen(find_prefix_name(elem, ns_scope->ns, 0)) + + strlen(APR_XML_GET_URI_ITEM(namespaces, ns_scope->ns)); + } + + if (elem->lang != NULL) { + /* compute size of: ' xml:lang="%s"' */ + size += 11 + strlen(elem->lang) + 1; + } + } + + if (elem->ns == APR_XML_NS_NONE) { + /* compute size of: <%s> */ + size += 1 + strlen(elem->name) + 1; + } + else if (style == APR_XML_X2T_PARSED) { + /* compute size of: <%s:%s> */ + size += 3 + strlen(find_prefix_name(elem, elem->ns, 1)) + strlen(elem->name); + } + else { + int ns = ns_map ? ns_map[elem->ns] : elem->ns; + + /* compute size of: <ns%d:%s> */ + size += 3 + APR_XML_NS_LEN(ns) + 1 + strlen(elem->name) + 1; + } + + if (APR_XML_ELEM_IS_EMPTY(elem)) { + /* insert a closing "/" */ + size += 1; + } + else { + /* + * two of above plus "/": + * <ns%d:%s> ... </ns%d:%s> + * OR <%s> ... </%s> + */ + size = 2 * size + 1; + } + + for (attr = elem->attr; attr; attr = attr->next) { + if (attr->ns == APR_XML_NS_NONE) { + /* compute size of: ' %s="%s"' */ + size += 1 + strlen(attr->name) + 2 + strlen(attr->value) + 1; + } + else if (style == APR_XML_X2T_PARSED) { + /* compute size of: ' %s:%s="%s"' */ + size += 5 + strlen(find_prefix_name(elem, attr->ns, 1)) + strlen(attr->name) + strlen(attr->value); + } + else { + /* compute size of: ' ns%d:%s="%s"' */ + int ns = ns_map ? ns_map[attr->ns] : attr->ns; + size += 3 + APR_XML_NS_LEN(ns) + 1 + strlen(attr->name) + 2 + strlen(attr->value) + 1; + } + } + + /* + ** If the element has an xml:lang value that is *different* from + ** its parent, then add the thing in: ' xml:lang="%s"'. + ** + ** NOTE: we take advantage of the pointer equality established by + ** the parsing for "inheriting" the xml:lang values from parents. + */ + if (elem->lang != NULL && + (elem->parent == NULL || elem->lang != elem->parent->lang)) { + size += 11 + strlen(elem->lang) + 1; + } + } + else if (style == APR_XML_X2T_LANG_INNER) { + /* + * This style prepends the xml:lang value plus a null terminator. + * If a lang value is not present, then we insert a null term. + */ + size = elem->lang ? strlen(elem->lang) + 1 : 1; + } + else + size = 0; + + size += text_size(elem->first_cdata.first); + + for (elem = elem->first_child; elem; elem = elem->next) { + /* the size of the child element plus the CDATA that follows it */ + size += (elem_size(elem, style == APR_XML_X2T_PARSED ? APR_XML_X2T_PARSED : APR_XML_X2T_FULL, NULL, ns_map) + + text_size(elem->following_cdata.first)); + } + + return size; +} + +static char *write_text(char *s, const apr_text *t) +{ + for (; t; t = t->next) { + apr_size_t len = strlen(t->text); + memcpy(s, t->text, len); + s += len; + } + return s; +} + +static char *write_elem(char *s, const apr_xml_elem *elem, int style, + apr_array_header_t *namespaces, int *ns_map) +{ + const apr_xml_elem *child; + apr_size_t len; + int ns; + + if (style == APR_XML_X2T_FULL || style == APR_XML_X2T_FULL_NS_LANG || + style == APR_XML_X2T_PARSED) { + int empty = APR_XML_ELEM_IS_EMPTY(elem); + const apr_xml_attr *attr; + + if (elem->ns == APR_XML_NS_NONE) { + len = sprintf(s, "<%s", elem->name); + } + else if (style == APR_XML_X2T_PARSED) { + len = sprintf(s, "<%s:%s", find_prefix_name(elem, elem->ns, 1), elem->name); + } + else { + ns = ns_map ? ns_map[elem->ns] : elem->ns; + len = sprintf(s, "<ns%d:%s", ns, elem->name); + } + s += len; + + for (attr = elem->attr; attr; attr = attr->next) { + if (attr->ns == APR_XML_NS_NONE) { + len = sprintf(s, " %s=\"%s\"", attr->name, attr->value); + } + else if (style == APR_XML_X2T_PARSED) { + len = sprintf(s, " %s:%s=\"%s\"", + find_prefix_name(elem, attr->ns, 1), attr->name, attr->value); + } + else { + ns = ns_map ? ns_map[attr->ns] : attr->ns; + len = sprintf(s, " ns%d:%s=\"%s\"", ns, attr->name, attr->value); + } + s += len; + } + + /* add the xml:lang value if necessary */ + if (elem->lang != NULL && + (style == APR_XML_X2T_FULL_NS_LANG || + elem->parent == NULL || + elem->lang != elem->parent->lang)) { + len = sprintf(s, " xml:lang=\"%s\"", elem->lang); + s += len; + } + + /* add namespace definitions, if required */ + if (style == APR_XML_X2T_FULL_NS_LANG) { + int i; + + for (i = namespaces->nelts; i--;) { + len = sprintf(s, " xmlns:ns%d=\"%s\"", i, + APR_XML_GET_URI_ITEM(namespaces, i)); + s += len; + } + } + + else if (style == APR_XML_X2T_PARSED) { + apr_xml_ns_scope *ns_scope = elem->ns_scope; + + for (; ns_scope; ns_scope = ns_scope->next) { + const char *prefix = find_prefix_name(elem, ns_scope->ns, 0); + + len = sprintf(s, " xmlns%s%s=\"%s\"", + *prefix ? ":" : "", *prefix ? prefix : "", + APR_XML_GET_URI_ITEM(namespaces, ns_scope->ns)); + s += len; + } + } + + /* no more to do. close it up and go. */ + if (empty) { + *s++ = '/'; + *s++ = '>'; + return s; + } + + /* just close it */ + *s++ = '>'; + } + else if (style == APR_XML_X2T_LANG_INNER) { + /* prepend the xml:lang value */ + if (elem->lang != NULL) { + len = strlen(elem->lang); + memcpy(s, elem->lang, len); + s += len; + } + *s++ = '\0'; + } + + s = write_text(s, elem->first_cdata.first); + + for (child = elem->first_child; child; child = child->next) { + s = write_elem(s, child, + style == APR_XML_X2T_PARSED ? APR_XML_X2T_PARSED : APR_XML_X2T_FULL, + NULL, ns_map); + s = write_text(s, child->following_cdata.first); + } + + if (style == APR_XML_X2T_FULL || style == APR_XML_X2T_FULL_NS_LANG || + style == APR_XML_X2T_PARSED) { + if (elem->ns == APR_XML_NS_NONE) { + len = sprintf(s, "</%s>", elem->name); + } + else if (style == APR_XML_X2T_PARSED) { + len = sprintf(s, "</%s:%s>", find_prefix_name(elem, elem->ns, 1), elem->name); + } + else { + ns = ns_map ? ns_map[elem->ns] : elem->ns; + len = sprintf(s, "</ns%d:%s>", ns, elem->name); + } + s += len; + } + + return s; +} + +APR_DECLARE(void) apr_xml_quote_elem(apr_pool_t *p, apr_xml_elem *elem) +{ + apr_text *scan_txt; + apr_xml_attr *scan_attr; + apr_xml_elem *scan_elem; + + /* convert the element's text */ + for (scan_txt = elem->first_cdata.first; + scan_txt != NULL; + scan_txt = scan_txt->next) { + scan_txt->text = apr_xml_quote_string(p, scan_txt->text, 0); + } + for (scan_txt = elem->following_cdata.first; + scan_txt != NULL; + scan_txt = scan_txt->next) { + scan_txt->text = apr_xml_quote_string(p, scan_txt->text, 0); + } + + /* convert the attribute values */ + for (scan_attr = elem->attr; + scan_attr != NULL; + scan_attr = scan_attr->next) { + scan_attr->value = apr_xml_quote_string(p, scan_attr->value, 1); + } + + /* convert the child elements */ + for (scan_elem = elem->first_child; + scan_elem != NULL; + scan_elem = scan_elem->next) { + apr_xml_quote_elem(p, scan_elem); + } +} + +/* convert an element to a text string */ +APR_DECLARE(void) apr_xml_to_text(apr_pool_t * p, const apr_xml_elem *elem, + int style, apr_array_header_t *namespaces, + int *ns_map, const char **pbuf, + apr_size_t *psize) +{ + /* get the exact size, plus a null terminator */ + apr_size_t size = elem_size(elem, style, namespaces, ns_map) + 1; + char *s = apr_palloc(p, size); + + (void) write_elem(s, elem, style, namespaces, ns_map); + s[size - 1] = '\0'; + + *pbuf = s; + if (psize) + *psize = size; +} + +APR_DECLARE(const char *) apr_xml_empty_elem(apr_pool_t * p, + const apr_xml_elem *elem) +{ + if (elem->ns == APR_XML_NS_NONE) { + /* + * The prefix (xml...) is already within the prop name, or + * the element simply has no prefix. + */ + return apr_psprintf(p, "<%s/>" DEBUG_CR, elem->name); + } + + return apr_psprintf(p, "<ns%d:%s/>" DEBUG_CR, elem->ns, elem->name); +} + +/* return the URI's (existing) index, or insert it and return a new index */ +APR_DECLARE(int) apr_xml_insert_uri(apr_array_header_t *uri_array, + const char *uri) +{ + int i; + const char **pelt; + + /* never insert an empty URI; this index is always APR_XML_NS_NONE */ + if (*uri == '\0') + return APR_XML_NS_NONE; + + for (i = uri_array->nelts; i--;) { + if (strcmp(uri, APR_XML_GET_URI_ITEM(uri_array, i)) == 0) + return i; + } + + pelt = apr_array_push(uri_array); + *pelt = uri; /* assume uri is const or in a pool */ + return uri_array->nelts - 1; +} + +/* convert the element to EBCDIC */ +#if APR_CHARSET_EBCDIC +static apr_status_t apr_xml_parser_convert_elem(apr_xml_elem *e, + apr_xlate_t *convset) +{ + apr_xml_attr *a; + apr_xml_elem *ec; + apr_text *t; + apr_size_t inbytes_left, outbytes_left; + apr_status_t status; + + inbytes_left = outbytes_left = strlen(e->name); + status = apr_xlate_conv_buffer(convset, e->name, &inbytes_left, (char *) e->name, &outbytes_left); + if (status) { + return status; + } + + for (t = e->first_cdata.first; t != NULL; t = t->next) { + inbytes_left = outbytes_left = strlen(t->text); + status = apr_xlate_conv_buffer(convset, t->text, &inbytes_left, (char *) t->text, &outbytes_left); + if (status) { + return status; + } + } + + for (t = e->following_cdata.first; t != NULL; t = t->next) { + inbytes_left = outbytes_left = strlen(t->text); + status = apr_xlate_conv_buffer(convset, t->text, &inbytes_left, (char *) t->text, &outbytes_left); + if (status) { + return status; + } + } + + for (a = e->attr; a != NULL; a = a->next) { + inbytes_left = outbytes_left = strlen(a->name); + status = apr_xlate_conv_buffer(convset, a->name, &inbytes_left, (char *) a->name, &outbytes_left); + if (status) { + return status; + } + inbytes_left = outbytes_left = strlen(a->value); + status = apr_xlate_conv_buffer(convset, a->value, &inbytes_left, (char *) a->value, &outbytes_left); + if (status) { + return status; + } + } + + for (ec = e->first_child; ec != NULL; ec = ec->next) { + status = apr_xml_parser_convert_elem(ec, convset); + if (status) { + return status; + } + } + return APR_SUCCESS; +} + +/* convert the whole document to EBCDIC */ +APR_DECLARE(apr_status_t) apr_xml_parser_convert_doc(apr_pool_t *pool, + apr_xml_doc *pdoc, + apr_xlate_t *convset) +{ + apr_status_t status; + /* Don't convert the namespaces: they are constant! */ + if (pdoc->namespaces != NULL) { + int i; + apr_array_header_t *namespaces; + namespaces = apr_array_make(pool, pdoc->namespaces->nelts, sizeof(const char *)); + if (namespaces == NULL) + return APR_ENOMEM; + for (i = 0; i < pdoc->namespaces->nelts; i++) { + apr_size_t inbytes_left, outbytes_left; + char *ptr = (char *) APR_XML_GET_URI_ITEM(pdoc->namespaces, i); + ptr = apr_pstrdup(pool, ptr); + if ( ptr == NULL) + return APR_ENOMEM; + inbytes_left = outbytes_left = strlen(ptr); + status = apr_xlate_conv_buffer(convset, ptr, &inbytes_left, ptr, &outbytes_left); + if (status) { + return status; + } + apr_xml_insert_uri(namespaces, ptr); + } + pdoc->namespaces = namespaces; + } + return apr_xml_parser_convert_elem(pdoc->root, convset); +} +#endif diff --git a/xml/apr_xml_expat.c b/xml/apr_xml_expat.c new file mode 100644 index 00000000000..1df279988cf --- /dev/null +++ b/xml/apr_xml_expat.c @@ -0,0 +1,137 @@ +/* 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" + +#if APU_USE_EXPAT +#include "apr_xml.h" + +#if defined(HAVE_XMLPARSE_XMLPARSE_H) +#include <xmlparse/xmlparse.h> +#elif defined(HAVE_XMLTOK_XMLPARSE_H) +#include <xmltok/xmlparse.h> +#elif defined(HAVE_XML_XMLPARSE_H) +#include <xml/xmlparse.h> +#else +#include <expat.h> +#endif + +typedef enum XML_Error XML_Error; + +#include "apr_xml_internal.h" + +static apr_status_t cleanup_parser(void *ctx) +{ + apr_xml_parser *parser = ctx; + + XML_ParserFree(parser->xp); + parser->xp = NULL; + + return APR_SUCCESS; +} +static apr_status_t do_parse(apr_xml_parser *parser, + const char *data, apr_size_t len, + int is_final) +{ + if (parser->xp == NULL) { + parser->error = APR_XML_ERROR_PARSE_DONE; + } + else { + int rv = XML_Parse(parser->xp, data, (int)len, is_final); + + if (rv == 0) { + parser->error = APR_XML_ERROR_EXPAT; + parser->xp_err = XML_GetErrorCode(parser->xp); + parser->xp_msg = XML_ErrorString(parser->xp_err); + } + } + + /* ### better error code? */ + return parser->error ? APR_EGENERAL : APR_SUCCESS; +} + + +static XMLParserImpl xml_parser_expat = { + do_parse, + cleanup_parser +}; + +XMLParserImpl* apr_xml_get_parser_impl(void) { return &xml_parser_expat; } +static const char APR_KW_DAV[] = { 0x44, 0x41, 0x56, 0x3A, '\0' }; + +#if XML_MAJOR_VERSION > 1 +/* Stop the parser if an entity declaration is hit. */ +static void entity_declaration(void *userData, const XML_Char *entityName, + int is_parameter_entity, const XML_Char *value, + int value_length, const XML_Char *base, + const XML_Char *systemId, const XML_Char *publicId, + const XML_Char *notationName) +{ + apr_xml_parser *parser = userData; + + XML_StopParser(parser->xp, XML_FALSE); +} +#else +/* A noop default_handler. */ +static void default_handler(void *userData, const XML_Char *s, int len) +{ +} +#endif + +apr_xml_parser* apr_xml_parser_create_internal(apr_pool_t *pool, + void *start_func, void *end_func, void *cdata_func) +{ + apr_xml_parser *parser = apr_pcalloc(pool, sizeof(*parser)); + + parser->impl = apr_xml_get_parser_impl(); + + parser->p = pool; + parser->doc = apr_pcalloc(pool, sizeof(*parser->doc)); + + parser->doc->namespaces = apr_array_make(pool, 5, sizeof(const char *)); + + /* ### is there a way to avoid hard-coding this? */ + apr_xml_insert_uri(parser->doc->namespaces, APR_KW_DAV); + + parser->xp = XML_ParserCreate(NULL); + if (parser->xp == NULL) { + (*apr_pool_abort_get(pool))(APR_ENOMEM); + return NULL; + } + + apr_pool_cleanup_register(pool, parser, cleanup_parser, + apr_pool_cleanup_null); + + XML_SetUserData(parser->xp, parser); + XML_SetElementHandler(parser->xp, start_func, end_func); + XML_SetCharacterDataHandler(parser->xp, cdata_func); + + /* Prevent the "billion laughs" attack against expat by disabling + * internal entity expansion. With 2.x, forcibly stop the parser + * if an entity is declared - this is safer and a more obvious + * failure mode. With older versions, installing a noop + * DefaultHandler means that internal entities will be expanded as + * the empty string, which is also sufficient to prevent the + * attack. */ +#if XML_MAJOR_VERSION > 1 + XML_SetEntityDeclHandler(parser->xp, entity_declaration); +#else + XML_SetDefaultHandler(parser->xp, default_handler); +#endif + + return parser; +} +#endif diff --git a/xml/apr_xml_internal.h b/xml/apr_xml_internal.h new file mode 100644 index 00000000000..dfd191e3276 --- /dev/null +++ b/xml/apr_xml_internal.h @@ -0,0 +1,48 @@ +/* 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. + */ + +#ifndef APR_XML_INTERNAL_H +#define APR_XML_INTERNAL_H + + +struct XMLParserImpl { + apr_status_t (*Parse)(apr_xml_parser*, const char*, apr_size_t, int); + apr_status_t (*cleanup)(void*); +}; +typedef struct XMLParserImpl XMLParserImpl; +XMLParserImpl* apr_xml_get_parser_impl(void); + + +/* the real (internal) definition of the parser context */ +struct apr_xml_parser { + apr_xml_doc *doc; /* the doc we're parsing */ + apr_pool_t *p; /* the pool we allocate from */ + apr_xml_elem *cur_elem; /* current element */ + + int error; /* an error has occurred */ +#define APR_XML_ERROR_EXPAT 1 +#define APR_XML_ERROR_PARSE_DONE 2 +/* also: public APR_XML_NS_ERROR_* values (if any) */ + + XML_Parser xp; /* the actual (Expat) XML parser */ + XML_Error xp_err; /* stored Expat error code */ + const char *xp_msg; + XMLParserImpl *impl; +}; + +apr_xml_parser* apr_xml_parser_create_internal(apr_pool_t*, void*, void*, void*); + +#endif diff --git a/xml/apr_xml_libxml2.c b/xml/apr_xml_libxml2.c new file mode 100644 index 00000000000..ad72441f9a8 --- /dev/null +++ b/xml/apr_xml_libxml2.c @@ -0,0 +1,99 @@ +/* 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" + +#if APU_USE_LIBXML2 +#include "apr_xml.h" + +#include <libxml/parser.h> +#include <libxml/xmlerror.h> + +typedef xmlParserCtxtPtr XML_Parser; +typedef xmlParserErrors XML_Error; + +#include "apr_xml_internal.h" + +static apr_status_t cleanup_parser(void *ctx) +{ + apr_xml_parser *parser = ctx; + + xmlFreeParserCtxt(parser->xp); + parser->xp = NULL; + + return APR_SUCCESS; +} +static int libxml2_parse(apr_xml_parser* parser, const char* data, + apr_size_t sz, int final) +{ + parser->xp_err = xmlParseChunk(parser->xp, data, sz, final); + if (parser->xp_err != 0) { + xmlErrorPtr errptr = xmlCtxtGetLastError(parser->xp); + parser->xp_msg = errptr->message; + /* this misnomer is used as a test for (any) parser error. */ + parser->error = APR_XML_ERROR_EXPAT; + } + return parser->xp_err; +} +static XMLParserImpl xml_parser_libxml2 = { + libxml2_parse, + cleanup_parser +}; + +static const char APR_KW_DAV[] = { 0x44, 0x41, 0x56, 0x3A, '\0' }; + +XMLParserImpl* apr_xml_get_parser_impl(void) +{ + return &xml_parser_libxml2; +} + + +apr_xml_parser* apr_xml_parser_create_internal(apr_pool_t *pool, + void *start_func, void *end_func, void *cdata_func) +{ + apr_xml_parser *parser = apr_pcalloc(pool, sizeof(*parser)); + /* FIXME: This is a mismatch. We should create a single global + * sax instance and re-use it for every parser. That means we + * need an up-front initialisation function. + */ + xmlSAXHandlerPtr sax = apr_pcalloc(pool, sizeof(xmlSAXHandler)); + sax->startElement = start_func; + sax->endElement = end_func; + sax->characters = cdata_func; + sax->initialized = 1; + + parser->impl = apr_xml_get_parser_impl(); + + parser->p = pool; + parser->doc = apr_pcalloc(pool, sizeof(*parser->doc)); + + parser->doc->namespaces = apr_array_make(pool, 5, sizeof(const char *)); + + /* ### is there a way to avoid hard-coding this? */ + apr_xml_insert_uri(parser->doc->namespaces, APR_KW_DAV); + + parser->xp = xmlCreatePushParserCtxt(sax, parser, NULL, 0, NULL); + if (parser->xp == NULL) { + (*apr_pool_abort_get(pool))(APR_ENOMEM); + return NULL; + } + + apr_pool_cleanup_register(pool, parser, cleanup_parser, + apr_pool_cleanup_null); + + return parser; +} +#endif