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 - - arg 1) explanation of arg 1 - arg 2) explanation of arg 2 - arg N) explanation of arg N - -B: 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 ] + + *) Fix a deadlock when writing to locked files opened with APR_FOPEN_APPEND + on Windows. PR 50058. + [Evgeny Kotkov ] + + *) apr_file_write: Optimize large writes to buffered files on Windows. + [Evgeny Kotkov ] + + *) apr_file_trunc: Truncating a buffered file could add unexpected + data after the truncate position. PR 51017. + [Evgeny Kotkov ] + + *) apr_file_trunc: Fix an issue where reading from a buffered file + after truncate could return stale data from the buffer. + [Evgeny Kotkov ] + + *) 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 ] + + *) apr_crypto: avoid excessive iteration in bcrypt hash. + [Hanno Böck ] + + *) 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 + ] + + *) 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 ] + + *) 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 ] + + *) apr_queue: Add apr_queue_timedpush() and apr_queue_timedpop() to + support timedout operations. PR 56951. [Anthony Minessale , Travis Cross , Yann Ylavic]. + + *) apr_allocator: Be less wasteful and don't return a memnode that is + much larger than what was requested. [Stefan Fuhrmann + ] + + *) 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 , 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 ] + + *) 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 ] + +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 + + 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): + * 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 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..7b9582fe5e1 100644 --- a/Makefile.in +++ b/Makefile.in @@ -1,101 +1,176 @@ + +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 \ + 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]'` + +tools/gen_test_char@EXEEXT@: tools/gen_test_char.c + $(APR_MKDIR) tools + $(CC_FOR_BUILD) $(CFLAGS_FOR_BUILD) $< -o $@ + +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-.tar.bz2 +rpmbuild -ts apr-util-.tar.bz2 + +Run the following to create RPMs (or build from the SRPMs): + +rpmbuild -tb apr-.tar.bz2 +rpmbuild -tb apr-util-.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: + 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 ): + ============ + 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: 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 </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(<>, translit(sizeof_$2, [a-z *], [A-Z_P]))dnl -dnl The cache variable -define(<>, translit(ac_cv_sizeof_$2, [ *],[

]))dnl -changequote([, ])dnl -AC_MSG_CHECKING(size of $2) -AC_CACHE_VAL(AC_CV_NAME, -[AC_TRY_RUN([#include -$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 -#endif -#ifdef HAVE_SYS_SOCKET_H -#include -#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 + +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 + +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 + +#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 + +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 +#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 + +#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 +#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 + * . + */ + +#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 +#include +#include +#include +#include +#include + +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<> $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 +#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(<>, translit(sizeof_$2, [a-z *], [A-Z_P]))dnl +dnl The cache variable name. +define(<>, 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 +$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 +#include +#include +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 +#include +],[ +#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 +#include +],[ +#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 +#include +],[ +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 should be available everywhere! + cat > conftest.c < + 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 +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_WINSOCK2_H +#include +#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 +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#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 +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#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 +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#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 +#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 +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif +#ifdef HAVE_NETDB_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#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 +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif +#ifdef HAVE_NETDB_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#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 +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif +#ifdef HAVE_NETDB_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#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 + #endif + #ifdef HAVE_NETINET_IN_H + #include + #endif + #ifdef HAVE_ARPA_INET_H + #include + #endif + #ifdef HAVE_NETDB_H + #include + #endif + #ifdef HAVE_STDLIB_H + #include + #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 + #endif + #ifdef HAVE_NETINET_IN_H + #include + #endif + #ifdef HAVE_ARPA_INET_H + #include + #endif + #ifdef HAVE_NETDB_H + #include + #endif + #ifdef HAVE_STDLIB_H + #include + #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 +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_NETINET_TCP_H +#include +#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 +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_NETINET_TCP_H +#include +#endif +#include +#include +]], [[ + 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 +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_STDIO_H +#include +#endif +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_SYS_TIME_H +#include +#endif +#ifdef HAVE_SYS_SELECT_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_NETINET_TCP_H +#include +#endif +#ifndef HAVE_SOCKLEN_T +typedef int socklen_t; +#endif +#ifdef HAVE_FCNTL_H +#include +#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 +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#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 +#endif +#ifdef HAVE_ARPA_INET_H +#include +#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 +#endif +#ifdef HAVE_ARPA_INET_H +#include +#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 +#endif +#ifdef HAVE_NETINET_IN_H +#include +#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 +#endif +#ifdef HAVE_NETINET_IN_H +#include +#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 +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_SYS_UN_H +#include +#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 +#endif +#ifdef HAVE_NETDB_H +#include +#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 +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_NETINET_SCTP_H +#include +#endif +#ifdef HAVE_NETINET_SCTP_UIO_H +#include +#endif +#include +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 +#include +], [ + 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 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_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_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 +#include + +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 +#endif +#include +],[ + 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 +#include +#include + +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 +#include +#include + +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 +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_NETINET_TCP_H +#include +#endif +#ifndef HAVE_SOCKLEN_T +typedef int socklen_t; +#endif +#ifdef HAVE_FCNTL_H +#include +#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 +#include +#include +#include +#include +#include + +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 +#include +#include +#include + 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 +#include +#include +#include +#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 +#include +#include +#include +#include +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 +#include +#include +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 +#include +#include +#include +#include +#include +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_(?PMAJOR|MINOR|PATCH)_VERSION(\s+)(?P\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 ') + sizeof_off_t = conf.CheckTypeSize('off_t', includes='#include ') + sizeof_size_t = conf.CheckTypeSize('size_t', includes='#include ') + sizeof_ssize_t = conf.CheckTypeSize('ssize_t', includes='#include ') + 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 '): + 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 '): + subst['@size_t_value@'] = 'apr_int32_t' + + if not conf.CheckType('ssize_t', includes='#include '): + subst['@ssize_t_value@'] = 'apr_int32_t' + + if not conf.CheckType('socklen_t', includes='#include '): + 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 '): + 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 '): + 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 '): + subst['@have_corkable_tcp@'] = 1 + apr_tcp_nopush_flag="TCP_CORK" + else: + subst['@have_corkable_tcp@'] = 0 + + if conf.CheckDeclaration('TCP_NOPUSH', '#include '): + 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 '): + subst['@have_in_addr@'] = 1 + else: + subst['@have_in_addr@'] = 0 + + if conf.CheckType('struct sockaddr_storage', includes='#include '): + subst['@have_sa_storage@'] = 1 + else: + subst['@have_sa_storage@'] = 0 + + if conf.CheckType('struct rlimit', includes='#include '): + 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 ') and \ + conf.CheckFunc('getaddrinfo') and \ + conf.CheckFunc('getnameinfo'): + subst['@have_ipv6@'] = 1 + + if conf.CheckDeclaration('SO_ACCEPTFILTER', '#include '): + subst['@acceptfilter@'] = 1 + else: + subst['@acceptfilter@'] = 0 + + if conf.CheckDeclaration('IPPROTO_SCTP', '#include ') and \ + conf.Check_apr_sctp(): + subst['@have_sctp@'] = 1 + else: + subst['@have_sctp@'] = 0 + + if conf.CheckDeclaration('SO_ACCEPTFILTER', '#include '): + 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 \n#include '): + subst['@have_iovec@'] = 1 + else: + subst['@have_iovec@'] = 0 + + + if conf.CheckType('struct sockaddr_un', includes='#include '): + 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 ') 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 ], + [CRYPTD buffer; + crypt_r("passwd", "hash", &buffer);], + [apr_cv_crypt_r_style=cryptd], + [AC_TRY_COMPILE([#include ], + [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..f191a416808 --- /dev/null +++ b/build/buildcheck.sh @@ -0,0 +1,72 @@ +#! /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 +if test -z "$libtool"; then + libtool=`build/PrintPath glibtool1 glibtool libtool libtool15 libtool14` +fi +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 . +# +# 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 . + + +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 ." + +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 + #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 /* 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 + + 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 + #include + + 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 + 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' /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 + echo i586-unisys-sysv4 + exit ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # 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 <&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 . +# # 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 . +# # 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 ." + +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 ]) + + 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 ], + [ 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 ]) + 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 ]) + 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 ]) + + 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 ]) + 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 +#include +#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__ 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 +#include +], +[ + 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 + #include + ],[ + 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 +#include +#include +#include +#include +#if !defined(__MINGW32__) +#include +#endif +#include +#include +#include +#include + +#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 +#endif + +#ifdef __EMX__ +#include +#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---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 1.3.3 +- update to depend on the bzip2 binary +- build depends on python + +* Tue Jun 22 2004 Graham Leggett 1.0.0-1 +- update to support v1.0.0 of APR + +* Tue Jun 22 2004 Graham Leggett 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 + + + + + + + Test Coverage + + +

The Apache Portable Runtime Project

+ + + + + + + + +
+ ApacheCon +

Get Involved

+ +
  • CVS
  • +
  • Mailing Lists
  • +
  • Snapshots
  • +
  • Build on Win32
  • +
  • Build on Unix
  • +
    +

    Download!

    + +
  • from a mirror
  • +
    +

    Docs

    + +
  • APR
  • +
  • APR-util
  • +
  • APR-iconv
  • +
    +

    Guidelines

    + +
  • Project Guidelines
  • +
  • Contributing
  • +
  • Version Numbers
  • +
    +

    Miscellaneous

    + +
  • License
  • +
  • Projects using APR
  • +
    +
    + + + +
    + + APR Test Coverage + +
    +
    +

    This should give us some idea of how well our tests actually stress our +code. To generate this data, do the following:

    + +
  • ./buildconf
  • +
  • CFLAGS="-fprofile-arcs -ftest-coverage ./configure
  • +
  • make
  • +
  • cd test
  • +
  • make
  • +
  • ./testall
  • +
  • cd ..
  • +
  • make gcov
  • +
    +

    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.

    +
    + + +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 "" >> index.html + echo "" >> index.html + echo "
    Error generating data for $basename
    " >> 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 "
    $basename
    " >> index.html + echo "
    $percent% tested" >> index.html +done + +echo "

    Last generated `date`

    " >> index.html + +cat >> index.html << EOF +
    + +

    + + Copyright © 1999-2004, The Apache Software Foundation + +
    + + + +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 +# """ 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 +#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 ], + [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 . -# The master version of this file is at the FSF in /home/gd/gnu/lib. -# Please send patches to the Autoconf mailing list . -# -# 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 <$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 - - 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 - #include - - 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 - 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 < -#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/^ //' <$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 </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 < -#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' /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 - echo i586-unisys-sysv4 - exit 0 ;; - *:UNIX_System_V:4*:FTX*) - # From Gerald Hewes . - # 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 < -# include -#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 - 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 +## `/' suffix where is currently hardcoded to 'apr'. +## (This may become a configurable parameter at some point.) +## + +# Classical APR path layout designed for parallel installs. + + 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} + + +# Classical single-installation APR path layout. + + 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} + + +# GNU standards conforming path layout. +# See FSF's GNU project `make-stds' document for details. + + 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 + + +# Mac OS X Server (Rhapsody) + + 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 + + +# Darwin/Mac OS Layout + + 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 + + +# Red Hat Linux 7.x layout + + 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 + + +# According to the /opt filesystem conventions + + 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 + + +# BeOS layout... + + 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 + + +# SuSE 6.x layout + + 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 + + +# BSD/OS layout + + 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 + + +# Solaris 8 Layout + + 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 + + +# OpenBSD Layout + + 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 + + +# Debian layout + + 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} + diff --git a/configure.in b/configure.in index 0817ac7f37f..93574bb17ef 100644 --- a/configure.in +++ b/configure.in @@ -1,214 +1,1571 @@ -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 +]) + +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 Check build CC for gen_test_char compiling which is executed at build time. +AX_PROG_CC_FOR_BUILD + +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 -# 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" +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 -AC_CHECK_PROG(SH, sh, sh) -dnl #----------------------------- Checks for compiler flags +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 + +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 -case "$OS" in +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 + +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 -if test ".$SYS_SW" = ".AIX"; then - CFLAGS="$CFLAGS -U__STR__" - case "$SYS_KV" in - [12]*) - AC_DEFINE(USEBCOPY) - OSDIR="aix" +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 +#include +#include +#include +#include +#include + +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 ], + [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 ;; - 3*) - AC_DEFINE(NEED_RLIM_T) - OSDIR="aix" + 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 + +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 +#include ], [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 +#include + +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 +#include + +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 + +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 + +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 +#include +#include +#include +#include +#include +#include +#include +#include + +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 +#include + +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 +#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 +#include +#include +#ifdef HAVE_SYS_MMAN_H +#include +#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 ;; - 41*) - AC_DEFINE(NEED_RLIM_T) - OSDIR="aix" + *alpha*-dec-osf* ) + sendfile="0" ;; - 42*) - 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 ;; - 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) + *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 + 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' requires first +AC_CACHE_CHECK([for mswsock.h], [apr_cv_hdr_mswsock_h], +[AC_TRY_CPP( +[#include +#include +], [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 which prevents it from +# being included by itself. Check for 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 +#endif +#include +], [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 +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 +1573,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 +1599,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 +#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 ], 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 ], 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 ], 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 ], 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 ], 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 ], 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 +#include ],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 +#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 +#endif +#ifdef HAVE_STRINGS_H +#include +#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 +#include +#include +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 +#include +#include +#include +#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 #include @@ -378,167 +2213,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 +#include + 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 +#endif +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_STAT_H +#include +#endif +#ifdef HAVE_SYS_WAIT_H +#include +#endif +#if defined(HAVE_UNISTD_H) +#include +#endif +#include +#include + +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 ]) + +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 -#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 +#endif +#ifdef HAVE_SYS_STAT_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#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 -],[ -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 +#endif +#if defined(HAVE_UNISTD_H) +#include +#endif +#if defined(HAVE_UUID_H) +#include +#elif defined(HAVE_UUID_UUID_H) +#include +#elif defined(HAVE_SYS_UUID_H) +#include +#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 +#include ]) + +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 +#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 +#include + +#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 +#include +#include + +#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 + +#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 +#include + +#include "apr_strings.h" +#include "apr_time.h" +#include "apr_buckets.h" + +#include "apr_crypto_internal.h" + +#if APU_HAVE_CRYPTO + +#include + +#ifdef HAVE_NSS_NSS_H +#include +#endif +#ifdef HAVE_NSS_H +#include +#endif + +#ifdef HAVE_NSS_PK11PUB_H +#include +#endif +#ifdef HAVE_PK11PUB_H +#include +#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..76f318411da --- /dev/null +++ b/crypto/apr_crypto_openssl.c @@ -0,0 +1,950 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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 +#include +#include + +#include "apr_strings.h" +#include "apr_time.h" +#include "apr_buckets.h" + +#include "apr_crypto_internal.h" + +#if APU_HAVE_CRYPTO + +#include +#include +#include + +#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) +{ + ERR_free_strings(); + EVP_cleanup(); + ENGINE_cleanup(); + 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(); +#else + OPENSSL_malloc_init(); +#endif + ERR_load_crypto_strings(); + /* SSL_load_error_strings(); */ + OpenSSL_add_all_algorithms(); + 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 +#endif +#if APR_HAVE_UNISTD_H +#include +#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): + * 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 +#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 +#endif +#if APR_HAVE_CRYPT_H +#include +#endif +#if APR_HAVE_UNISTD_H +#include +#endif +#if APR_HAVE_PTHREAD_H +#include +#endif +#if APR_HAVE_STDLIB_H +#include +#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 , 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 + +/* 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 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 , and uses some of his + * ideas. The password hashing algorithm was designed by David Mazieres + * . 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 + +#include +#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 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 /* for getpid, gethostname */ +#endif +#if APR_HAVE_STDLIB_H +#include /* for rand, srand */ +#endif + + +#if APR_HAVE_STRING_H +#include +#endif +#if APR_HAVE_STRINGS_H +#include +#endif +#if APR_HAVE_NETDB_H +#include +#endif +#if APR_HAVE_SYS_TIME_H +#include /* 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 /* 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 +#include + +#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 +#include + +#if defined(HAVE_MYSQL_MYSQL_H) +#if defined(HAVE_MYSQL_MY_GLOBAL_H) +#include +#if defined(HAVE_MYSQL_MY_SYS_H) +#include +#endif +#endif +#include +#include +#else /* !defined(HAVE_MYSQL_MYSQL_H) */ +#if defined(HAVE_MY_GLOBAL_H) +#include +#if defined(HAVE_MY_SYS_H) +#include +#endif +#endif +#include +#include +#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 + +/* 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 +#include +#elif defined(HAVE_ODBC_SQL_H) +#include +#include +#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 +#include +#include + +#include + +#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 +#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; inout; ++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 +#include + +#ifdef HAVE_LIBPQ_FE_H +#include +#elif defined(HAVE_POSTGRESQL_LIBPQ_FE_H) +#include +#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 +#include + +#include + +#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 +#include + +#include + +#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 +#include + +#include "apr_strings.h" +#include "apr_lib.h" + +#include "apr_pools.h" +#include "apr_dbd_internal.h" + +#ifdef HAVE_FREETDS_SYBDB_H +#include +#endif +#ifdef HAVE_SYBDB_H +#include +#endif + +#include +#include +#include + +/* 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; ifmt; + 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; ifmt = 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; inargs; ++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 /* 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 +#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 /* for free() */ +#endif + +#if APU_HAVE_GDBM +#include "apr_dbm_private.h" + +#include + +#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 /* for free() */ +#endif + +#include "apu.h" +#include "apr_private.h" + +#if APU_HAVE_NDBM +#include "apr_dbm_private.h" + +#include +#include +#include +#include + +#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 /* for memset() */ +#include /* 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 /* 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 @@ + +APR Design Document + +

    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 +platform development. There may be other types that are desired and those +will be implemented in the future.

    + +

    This document will discuss the structure of APR, and how best to contribute +code to the effort.

    + +

    APR On Windows and Netware

    + +

    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.

    + +

    + 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. +

    + +

    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 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.

    + +

    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

    + +
      +
    • dso
      + Shared library routines +
    • mmap
      + Memory-mapped files +
    • poll
      + Polling I/O +
    • time
      + Time +
    • user
      + Users and groups +
    • locks
      + Process and thread locks (critical sections) +
    • shmem
      + Shared memory +
    • file_io
      + File I/O, including pipes +
    • atomic
      + Atomic integer operations +
    • strings
      + String handling routines +
    • memory
      + Pool-based memory allocation +
    • passwd
      + Reading passwords from the terminal +
    • tables
      + Tables and hashes +
    • network_io
      + Network I/O +
    • threadproc
      + Threads and processes +
    • misc
      + Any APR type which doesn't have any other place to belong. This + should be used sparingly. +
    • support
      + 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. +
    + +

    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.

    + +

    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.

    + +

    Creating an APR Type

    + +

    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:

    + +
      +
    • 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. + +
    • 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.

      +
    + +

    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 {
    +        apr_pool_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 structure. Windows does not have a filedes field, so obviously, +it is important that programs not be able to access these.

    + +

    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.

    + +

    New Function

    + +

    When creating a new function, please try to adhere to these rules.

    + +
      +
    • Result arguments should be the first arguments. +
    • If a function needs a pool, it should be the last argument. +
    • 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 header +file.

    + +

    The format for the comment block is:

    + +
    +    /**
    +     * 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
    +     */ 
    +
    + +

    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.

    + +

    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 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.

    + + + This includes functions that return TRUE/FALSE values. How that + is handled is discussed below + + +

    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.

    + + +
    +    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.
    +
    + +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. + +

    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 +apr_proc_wait, 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 apr_compare_users, which can only return +APR_SUCCESS, APR_EMISMATCH, or an error code.

    + +

    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 should be 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. 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().

    + +

    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:

    + +

    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.

    + +
    +    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 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:

    + +
    +    make syscall that fails
    +        convert to common error code
    +        return common error code
    +            decide execution based on common error code
    +
    + +

    Using option 2:

    + +
    +    make syscall that fails
    +        return error code
    +            convert to common error code (using ap_canonical_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().

    + 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 @@ + +APR Canonical Filenames + +

    APR Canonical Filename

    + +

    Requirements

    + +

    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

    . + +

    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.

    + +

    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.

    + +

    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.

    + +

    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.

    + +

    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.

    + +

    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.)

    + +

    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.

    + +
    + +

    Canonical API

    + +Functions to manipulate the apr_canon_file_t (an opaque type) include: + +
      +
    • Create canon_file_t (from char* path and canon_file_t parent path) +
    • Merged canon_file_t (from path and parent, both canon_file_t) +
    • Get char* path of all or some segments +
    • Get path flags of IsRelative, IsVirtualRoot, and IsAbsolute +
    • Compare two canon_file_t structures for file equality +
    + +

    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.

    + +

    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.

    + +

    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.

    + +
    + +

    Unix Example

    + +

    First the simplest case:

    + +
    +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        
    +
    + + + 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 @@ + + + Using APR Pools + + +

    Using APR Pools

    + +

    + From Subversion, we + have learned a lot about how to use pools in a heavily + structured/object-based environment. + Apache httpd is a + completely different beast: "allocate a request pool. use + it. destroy it." +

    + +

    + 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: +

    + +
      +
    • + Objects should not have their own pools. An object is + allocated into a pool defined by the constructor's caller. The + caller 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. +
    • + +
    • +

      + Functions should not create/destroy pools for their + operation; they should use a pool provided by the + caller. Again, the caller 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. +

      +

      + 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. +

      +
    • + +
    • +

      + Whenever an unbounded iteration occurs, a subpool should be + used. The general pattern is: +

      +
      +
      +subpool = apr_create_subpool(pool);
      +for (i = 0; i < n; ++i) {
      +  apr_pool_clear(subpool);
      +
      +  do_operation(..., subpool);
      +}
      +apr_pool_destroy(subpool);
      +
      +

      + 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 'continue' to occur within the loop, + yet still ensure the pool will be cleared. +

      +
    • + +
    • + Given all of the above, it is pretty well mandatory to pass a + pool to every 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. +
    • +
    + +
    +
    Greg Stein
    + + +Last modified: Wed Jun 25 14:50:19 PDT 2003 + + + 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 @@ + +APR Win32 Builds and Debugging + +

    APR Win32 Builds and Debugging

    + +

    Configuration and Flavors

    + +

    The Win32 APR Developer Studio projects consist of

    + +
    +
    apr/apr.dsp
    +
    Builds the static apr.lib library (-D APR_DECLARE_STATIC)
    +
    apr/libapr.dsp
    +
    Builds the dynamic libapr.dll library (no define required)
    +
    apr-util/aprutil.dsp
    +
    Builds the static aprutil.lib library (-D APR_DECLARE_STATIC)
    +
    apr-util/libaprutil.dsp
    +
    Builds the dynamic libaprutil.dll library (no define required)
    +
    apr-iconv/apriconv.dsp
    +
    Builds the static apriconv.lib library (-D API_DECLARE_STATIC)
    +
    apr-iconv/libapriconv.dsp
    +
    Builds the dynamic libapriconv.dll library (no define required)
    +
    + +

    In order to prepare to use one of the static 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.

    + +

    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.

    + +

    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.)

    + +

    The static symbols will only be fully usable if your application does not + 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.

    + +

    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.

    + + + 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 - * . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 #include #include -#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 - * . - */ - -#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 - * . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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 - * . - */ - -#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 - -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 +#include + +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 - * . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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 +#include "apr_arch_dso.h" +#include "apr_strings.h" +#include "apr_portable.h" #include #include -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 - * . - */ - -#ifndef DSO_H -#define DSO_H - -#define INCL_DOS -#include - -#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 +#include + +#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 - * . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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 +#endif +#if APR_HAVE_STDLIB_H +#include /* malloc(), free() */ +#endif +#if APR_HAVE_STRING_H +#include /* 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 - * . - */ - -#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 -#endif - -#ifdef HAVE_DL_H -#include -#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 - * . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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 - * . - */ - -#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 +;; or emacs -l +;; 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 - * . - */ - -/* 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 - * . - */ - -#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 +#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 +#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 /* 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 +#include +#include + +#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 - * . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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 -#define INCL_DOS -#include - -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 + +#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 - * . +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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 -#include -#include - -/* 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 - * . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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 +#include "apr_arch_inherit.h" -#define INCL_DOS -#include - -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 - * . - */ - -#ifndef FILE_IO_H -#define FILE_IO_H - -#define INCL_DOS -#include - -#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 - * . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 -#include +#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 + +/* 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 - * . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 #include -#include -#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. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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 -#define INCL_DOS -#include - -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 - * . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 #include -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 - * . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 #include -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 - * . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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 #include -#define INCL_DOS -#include - - -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 - * . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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 +#endif +#if APR_HAVE_LIMITS_H +#include +#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 - * . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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 - * . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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 - * . - */ - -#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 -#endif -#if HAVE_SYS_TYPES_H -#include -#endif -#if HAVE_ERRNO_H -#include -#endif -#if HAVE_STRING_H -#include -#endif -#if HAVE_DIRENT_H -#include -#endif -#if HAVE_SYS_STAT_H -#include -#endif -#if HAVE_UNISTD_H -#include -#endif -#if HAVE_STDIO_H -#include -#endif -#if HAVE_STDLIB_H -#include -#endif -#if HAVE_SYS_UIO_H -#include -#endif -#if HAVE_SYS_TIME_H -#include -#endif -#ifdef BEOS -#include -#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 +#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 +#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 - * . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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 +#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 +#endif +#ifdef HAVE_SYS_FILE_H +#include +#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 +#endif +#endif +#define arc4random() rand() +#define seedrandom(a) srand(a) +#else +#if APR_HAVE_STDINT_H +#include +#endif +#define arc4random() random() +#define seedrandom(a) srandom(a) +#endif + +#if APR_HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_STAT_H +#include +#endif +#if APR_HAVE_FCNTL_H +#include +#endif +#include +#include +#include +#include +#ifdef HAVE_TIME_H +#include +#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 /* for mkstemp() - Single Unix */ +#endif +#if APR_HAVE_UNISTD_H +#include /* 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 - * . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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 - * . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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 +#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 - * . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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 - * . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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 - * . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 #endif -#ifdef HAVE_STRING_H +#if APR_HAVE_STRING_H #include #endif -#ifdef HAVE_DIRENT_H +#if APR_HAVE_DIRENT_H #include #endif #ifdef HAVE_SYS_STAT_H #include #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 - * . - */ - -#include "fileio.h" -#include "apr_file_io.h" -#include "apr_general.h" -#include "apr_lib.h" -#include -#include -#include - -/* 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 - * . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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 +#include "apr_arch_inherit.h" +#include /* 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 - * . - */ - -#ifndef FILE_IO_H -#define FILE_IO_H - -#ifdef HAVE_SYS_STAT_H -#include -#endif -#ifdef HAVE_SYS_TYPES_H -#include -#endif -#ifdef HAVE_SYS_FCNTL_H -#include -#endif -#ifdef HAVE_TIME_H -#include -#endif -#ifdef HAVE_DIRENT_H -#include -#endif -#ifdef HAVE_MALLOC_H -#include -#endif -#ifdef HAVE_UIO_H -#include -#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 +#include + +#ifdef NETWARE +#include +#include +#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 - * . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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 #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 -#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 - * . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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 +#endif #include #include +#ifdef HAVE_SYS_STAT_H #include -#include "misc.h" +#endif +#include "apr_arch_misc.h" +#include "apr_arch_inherit.h" +#include +#include + +#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 - * . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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 +#endif #include #include +#if APR_HAVE_SYS_TYPES_H #include +#endif +#ifdef HAVE_SYS_STAT_H #include -#include "misc.h" +#endif +#if APR_HAVE_PROCESS_H +#include /* 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 - * . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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 -#include -#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; ifilehand, (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 - * . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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 #include -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 () { + 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 () { + 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 +#include +#include + +#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 - * . - */ - -#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 -#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 + * The actual values of macros and typedefs on this page
    + * are platform specific and should NOT be relied upon!
    + */ + /* 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 +#endif /* ndef _WINDOWS_ */ +#endif /* APR_HAVE_WINDOWS_H */ + +#if APR_HAVE_WINSOCK2_H +#include + +#if APR_HAVE_WS2TCPIP_H +#include +#endif + +#if APR_HAVE_MSWSOCK_H +#include +#endif + +#else /* !APR_HAVE_WINSOCK2_H */ + +#if APR_HAVE_WINSOCK_H +#include +#endif + +#endif /* !APR_HAVE_WINSOCK2_H */ + +#if APR_HAVE_SYS_TYPES_H +#include +#endif + +#if APR_HAVE_STDDEF_H +#include +#endif + +#if APR_HAVE_SYS_SOCKET_H +#include +#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 +#endif + +#if APR_HAVE_SYS_WAIT_H +#include +#endif + +#ifdef OS2 +#define INCL_DOS +#define INCL_DOSERRORS +#include +#endif + +/* header files for PATH_MAX, _POSIX_PATH_MAX */ +#if APR_HAVE_LIMITS_H +#include #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 +#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 -#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. + *
    + *
    + * void* APR_THREAD_FUNC my_thread_entry_fn(apr_thread_t *thd, void *data);
    + *
    + * 
    + */ +#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. + * + *
    + * 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. + *
    + *
    + * 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. + * + *
    + *
    + * extern APR_DECLARE_DATA type apr_variable;\n
    + * APR_DECLARE_DATA type apr_variable = value;
    + *
    + * 
    + */ +#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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef USE_WINSOCK +#include +#ifdef NW_BUILD_IPV6 +#include +#endif +#else +#include +#include +#endif +#include + +#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 - * . - */ - -/* - * 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 + * The actual values of macros and typedefs on this page
    + * are platform specific and should NOT be relied upon!
    + */ + +/* 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 +#endif +#endif + +#if APR_HAVE_WINSOCK2_H #include + +#if APR_HAVE_WS2TCPIP_H +#include +#endif + +#if APR_HAVE_MSWSOCK_H #include +#endif + +#else /* !APR_HAVE_WINSOCK2_H */ + +#if APR_HAVE_WINSOCK_H +#include +#endif + +#endif /* !APR_HAVE_WINSOCK2_H */ + +#if APR_HAVE_SYS_TYPES_H #include +#endif + +#if APR_HAVE_STDDEF_H #include -#include -#include -#include -#include -#include +#endif -#define ap_inline -#define __attribute__(__x) -#define ENUM_BITFIELD(e,n,w) signed int n : w +#if APR_HAVE_SYS_SOCKET_H +#include +#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 +#endif + +#if APR_HAVE_SYS_WAIT_H +#include +#endif -#define APR_USE_FLOCK_SERIALIZE 0 +/* header files for PATH_MAX, _POSIX_PATH_MAX */ +#if APR_HAVE_LIMITS_H +#include +#else +#if APR_HAVE_SYS_SYSLIMITS_H +#include +#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 -#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. + *
    + *
    + * void* APR_THREAD_FUNC my_thread_entry_fn(apr_thread_t *thd, void *data);
    + *
    + * 
    + */ +#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. + * + *
    + * 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. + *
    + *
    + * 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. + * + *
    + *
    + * extern APR_DECLARE_DATA type apr_variable;\n
    + * APR_DECLARE_DATA type apr_variable = value;
    + *
    + * 
    + */ +#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 + * The actual values of macros and typedefs on this page
    + * are platform specific and should NOT be relied upon!
    + */ + +/* 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 +#endif +#endif + +#if APR_HAVE_WINSOCK2_H +#include + +#if APR_HAVE_WS2TCPIP_H +#include +#endif + +#if APR_HAVE_MSWSOCK_H +#include +#endif + +#else /* !APR_HAVE_WINSOCK2_H */ + +#if APR_HAVE_WINSOCK_H +#include +#endif + +#endif /* !APR_HAVE_WINSOCK2_H */ + +#if APR_HAVE_SYS_TYPES_H +#include +#endif + +#if APR_HAVE_STDDEF_H +#include +#endif + +#if APR_HAVE_SYS_SOCKET_H +#include +#endif + +#if APR_HAVE_STDINT_H +#include +#endif + +#if APR_HAVE_SYS_WAIT_H +#include +#endif + +/* header files for PATH_MAX, _POSIX_PATH_MAX */ +#if APR_HAVE_LIMITS_H +#include +#else +#if APR_HAVE_SYS_SYSLIMITS_H +#include +#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. + *
    + *
    + * void* APR_THREAD_FUNC my_thread_entry_fn(apr_thread_t *thd, void *data);
    + *
    + * 
    + */ +#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. + * + *
    + * 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. + *
    + *
    + * 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. + * + *
    + *
    + * extern APR_DECLARE_DATA type apr_variable;\n
    + * APR_DECLARE_DATA type apr_variable = value;
    + *
    + * 
    + */ +#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 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 /* for struct iovec */ +#endif +#if APR_HAVE_STDARG_H +#include +#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: + *
    + *      while (e != APR_BRIGADE_SENTINEL(b)) {
    + *          ...
    + *          e = APR_BUCKET_NEXT(e);
    + *      }
    + * 
    + * @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: + *
    + *      APR_BUCKET_REMOVE(e);
    + *      apr_bucket_destroy(e);
    + * 
    + * @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 /* for apr_size_t */ +#include /* for apr_pool_t */ +#include /* 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): + *
    + *   '\@' - uppercase letter
    + *   '\$' - lowercase letter
    + *   '\&' - hex digit
    + *   '#' - digit
    + *   '~' - digit or space
    + *   '*' - swallow remaining characters
    + * 
    + * @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: + *
    + *     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
    + * 
    + * @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. + *
    + *     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] 
    + * 
    + * + * @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) + *
    + *  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
    + *  
    + * @param name The dbm file name to open + * @param mode The flag value + *
    + *           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
    + * 
    + * @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 + *
    + *           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
    + * 
    + * @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 - * . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 - -=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 - - 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 +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 +#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 - * . +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 +#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 + *
    + * 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
    + *
    + * 
    + */ + +/** no error. */ #define APR_SUCCESS 0 -/* APR ERROR VALUES */ +/** + * @defgroup APR_Error APR Error Values + *
    + * APR ERROR VALUES
    + * 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
    + * 
    + * + *
    + * APR STATUS VALUES
    + * 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
    + * 
    + * @{ + */ +/** @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 +#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 + *
    + *      APR_FILEPATH_NATIVE    Use native path separators (e.g. '\' on Win32)
    + *      APR_FILEPATH_TRUENAME  Tests that the root exists, and makes it proper
    + * 
    + * @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., getenv("PATH")) + * @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 - * . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 -#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 - - 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: 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 - - 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 - - arg 1) The full path to the file (using / on all systems) - arg 2) The pool to use. - -B: 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 - - arg 1) The apr file we are testing. -B: 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 - - arg 1) The apr file we are testing. - -B: 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 - - 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 +#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: 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 - - 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: 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 - - 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 - - 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 - - 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 - - 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 - - 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 - - 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 - - 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 +/** + * 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: *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 - - 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 - - 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 - - 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: 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 - - 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 - - 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 - - arg 1) the directory descriptor to read from, and fill out. - -B: 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 - - 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 - - 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 - - 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 - - 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 - - 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 - - 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 - - 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 +/** + * 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 - - 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 - - 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 - - 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 - - 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 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 +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.
    + * MATCHES: That character exactly. + * + *

    + * PATTERN: ?
    + * MATCHES: Any single character. + *

    + * + *

    + * PATTERN: *
    + * 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
    + * MATCHES: That character exactly. (Case sensitive.) + * + * PATTERN: [ followed by a class description followed by ]
    + * 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: + *

    + *              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.
    + * 
    + */ + +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 - * . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 -#endif -#if APR_HAVE_SYS_TYPES_H -#include -#endif #if APR_HAVE_SIGNAL_H #include #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 +#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 - 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 +/** 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. +/* 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: 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 - - 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 -=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 - -B: 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 - -B: 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 +/** + * @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 - * . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 +/** @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: 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: + *
    + *             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.
    + * 
    + */ +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: + *
    + *             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.
    + * 
    + * 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 + *
    + *            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
    + * 
    + * @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 - * . +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 +#endif #if APR_HAVE_STDARG_H #include #endif -#if APR_HAVE_SYS_TYPES_H -#include -#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 + *
    + * For example:
    + *                 "/foo/bar/gum"    -> "gum"
    + *                 "/foo/bar/gum/"   -> ""
    + *                 "gum"             -> "gum"
    + *                 "bs\\path\\stuff" -> "stuff"
    + * 
    */ -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 + *
    + * 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.
    + * 
    */ -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 - * . - */ - -#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 - - 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: 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 - - 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 - - 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 - - arg 1) The lock to free. - -B: 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 - - 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: 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 - - 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 - - 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 - * . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 - * . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 +#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 - - 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 +/** 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: + *
    + *          APR_MMAP_READ       MMap opened for reading
    + *          APR_MMAP_WRITE      MMap opened for writing
    + * 
    + * @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. + * @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 - * . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 -#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 #endif +#if APR_HAVE_SYS_UN_H +#include +#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 - - 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 - - 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: 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 - - 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 - - arg 1) The socket to bind - -B: 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 - - 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 - - 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 - - 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 +#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 - - 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 - - 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 - - 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 - - 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: 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 - - 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: 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 - - 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: 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 - - 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: 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 - - 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: 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 - - arg 1) The socket to enquire about. - arg 2) The local port this socket will be dealing with. - -B: 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 - - 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 - - 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 - - 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: 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 - - arg 1) The socket to use - arg 2) The IP address to attach to the socket. - -B: 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 +/** 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: + *
    + *            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 
    + * 
    + * @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: + *
    + *       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
    + * 
    + * @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 + *
    + * 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.
    + * 
    + */ +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 + *
    + * 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.
    + * 
    + */ +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 + *
    + * 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.
    + * 
    + */ +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: + *
    + *            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.
    + * 
    + * @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. + *
    + *   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
    + * 
    + */ +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: + *
    + *            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)
    + * 
    + * @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 +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 - - 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 - - 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 - - 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 - - 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: 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 - - 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 - - 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 +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 - - 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 - - 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 - - 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 - - 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 +#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 - * . - */ - -#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 -#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: + *
    + *    APR_POOL_DECLARE_ACCESSOR(file);
    + * becomes:
    + *    APR_DECLARE(apr_pool_t *) apr_file_pool_get(const apr_file_t *thefile);
    + * 
    + * @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 + * + *
    + * | 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.
    + * 
    */ +#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 - * . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 @@ -80,362 +46,494 @@ extern "C" { #if APR_HAVE_PTHREAD_H #include #endif -#if APR_HAVE_UNION_SEMUN -#include +#if APR_HAVE_SEMAPHORE_H +#include #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 -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 +#include -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 +typedef shl_t apr_os_dso_handle_t; +#elif defined(DARWIN) +#include +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 - - arg 1) The os specific file we are converting to - arg 2) The apr file to convert. - -B: 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 - - 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 - - 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 +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 - - 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 - - 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 - - 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 - - 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 - - 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 - - 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: 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 - - 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 - - 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 - - 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 - - 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 - - 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 - - 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 +/** @} */ +#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 +/** + * 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 - * . - */ - -/* - * 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 -#include -#include -#include -#include -#include -#include - -#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 + *
    + *            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
    + * 
    + * @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 + *
    + *           APR_RESLIST_CLEANUP_DEFAULT  default pool cleanup order
    + *           APR_RESLIST_CLEANUP_FIRST    use pool pre cleanup
    + * 
    + * @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 macros + * and Dean Gaudet's "splim/ring.h". + * + * + * + * 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. + *
    + *      struct my_element_t {
    + *          APR_RING_ENTRY(my_element_t) link;
    + *          int foo;
    + *          char *bar;
    + *      };
    + * 
    + * + * 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: + *
    + *      APR_RING_HEAD(my_ring_t, my_element_t);
    + *      struct my_ring_t ring, *ringp;
    + * 
    + * + * 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. + * + *
    + *     +->+------+<-+  +->+------+<-+  +->+------+<-+
    + *     |  |struct|  |  |  |struct|  |  |  |struct|  |
    + *    /   | elem |   \/   | elem |   \/   | elem |  \
    + * ...    |      |   /\   |      |   /\   |      |   ...
    + *        +------+  |  |  +------+  |  |  +------+
    + *   ...--|prev  |  |  +--|ring  |  |  +--|prev  |
    + *        |  next|--+     | entry|--+     |  next|--...
    + *        +------+        +------+        +------+
    + *        | etc. |        | etc. |        | etc. |
    + *        :      :        :      :        :      :
    + * 
    + * + * 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. + * + *
    + *        last                            first
    + *     +->+------+<-+  +->sentinel<-+  +->+------+<-+
    + *     |  |struct|  |  |            |  |  |struct|  |
    + *    /   | elem |   \/              \/   | elem |  \
    + * ...    |      |   /\              /\   |      |   ...
    + *        +------+  |  |  +------+  |  |  +------+
    + *   ...--|prev  |  |  +--|ring  |  |  +--|prev  |
    + *        |  next|--+     |  head|--+     |  next|--...
    + *        +------+        +------+        +------+
    + *        | etc. |                        | etc. |
    + *        :      :                        :      :
    + * 
    + * + * 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 +#include + +#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) + *
    + *           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
    + * 
    + * @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 + *
    + *           APR_FLOCK_SHARED
    + *           APR_FLOCK_EXCLUSIVE
    + * 
    + * @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 + *
    + *           APR_SDBM_INSERT     return an error if the record exists
    + *           APR_SDBM_REPLACE    overwrite any existing record for key
    + * 
    + */ +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 - * . - */ - -#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 - - 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 - - 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 - - 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 - - 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 - - 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 - - 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 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 - - 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 - - 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 - * . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 +#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 + + Copyright (c) 2012-2014 Daniel J. Bernstein + 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 + . + */ + +#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 + +#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 + + 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 +#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 + *
    + * 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.
    + * 
    + */ +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 - - 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 /* 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: + * + *
    + *  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);
    + *      }
    + *  }
    + * 
    + * + * 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: + *
    + *           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).
    + * 
    + * @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 - * . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 +#include +#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 - - 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 - - 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 - - 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 - - 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 - - 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 - - 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 - - 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 - - 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 - - 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 - - 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 - - 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 - - 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 - - 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 - - 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 - - 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 - - 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 - - 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 - - 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: 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 - - 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: 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 - - 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: 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 - - 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 - - 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 - - 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 - - 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 +/** 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 +/** 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 +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 +#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: + *
    + *            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
    + * 
    + */ +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: + *
    + *                 APR_LIMIT_CPU
    + *                 APR_LIMIT_MEM
    + *                 APR_LIMIT_NPROC
    + *                 APR_LIMIT_NOFILE
    + * 
    + * @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 - - 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 - - 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 - - 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: 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 - - 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: + *
    + *            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.
    + * 
    + * @param waithow 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.
    + * 
    + * @remark The child's 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.
    + * 
    + */ +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: + *
    + *            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.
    + * 
    + * @param waithow 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.
    + * 
    + * @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; + *
    + * 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 ...]
    + * 
    + */ +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: + *
    + *         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
    + * 
    + */ +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 - - 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 - - arg 1) The data to pass to the maintenance function. This is - used to find the process to unregister. - -B: 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 - - 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 - -=cut - */ -void ap_check_other_child(void); - -/* - -=head1 ap_status_t ap_kill(ap_proc_t *proc, int sig) - -B - - 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 locked 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 - * . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 - -=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 - 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 +/** @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 +/** @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 +/** @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: + *
    + *    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" 
    + * 
    + * @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 + * + *
    + * Features:
    + *
    + *   APR_WANT_STRFUNC:  strcmp, strcat, strcpy, etc
    + *   APR_WANT_MEMFUNC:  memcmp, memcpy, etc
    + *   APR_WANT_STDIO:     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)
    + * 
    + */ + +/* --------------------------------------------------------------------- */ + +#ifdef APR_WANT_STRFUNC + +#if APR_HAVE_STRING_H +#include +#endif +#if APR_HAVE_STRINGS_H +#include +#endif + +#undef APR_WANT_STRFUNC +#endif + +/* --------------------------------------------------------------------- */ + +#ifdef APR_WANT_MEMFUNC + +#if APR_HAVE_STRING_H +#include +#endif + +#undef APR_WANT_MEMFUNC +#endif + +/* --------------------------------------------------------------------- */ + +#ifdef APR_WANT_STDIO + +#if APR_HAVE_STDIO_H +#include +#endif + +#undef APR_WANT_STDIO +#endif + +/* --------------------------------------------------------------------- */ + +#ifdef APR_WANT_IOVEC + +#if APR_HAVE_IOVEC + +#if APR_HAVE_SYS_UIO_H +#include +#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 +#endif +#if APR_HAVE_ARPA_INET_H +#include +#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 - * . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 - - 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: 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 - - 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 - - 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: + *
    + *     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
    + * 
    + * @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 + 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 + *
    + * APU ERROR VALUES
    + * 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
    + * 
    + * + *
    + * APR STATUS VALUES
    + * APR_INCHILD        Program is currently executing in the child
    + * 
    + * @{ + */ +/** @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 + * + *
    + * 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)
    + * 
    + */ + +/* --------------------------------------------------------------------- */ + +#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 + * + *
    + * 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)
    + * 
    + */ + +/* --------------------------------------------------------------------- */ + +#ifdef APU_WANT_DB + +#if APU_HAVE_DB +/* win32 note.. you will need to change this for db1 */ +#include +#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 + * + *
    + * Features:
    + *
    + *   APU_WANT_DB:       
    + *
    + * 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)
    + * 
    + */ + +/* --------------------------------------------------------------------- */ + +#ifdef APU_WANT_DB + +#if APU_HAVE_DB +/* win32 note.. you will need to change this for db1 */ +#include +#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 - * . - */ - -#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 +#include + +#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 +#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 +#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 +#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 +#include +#include +#include +#include + +#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 - * . - */ - -#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 - -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 - * . - */ - -#ifndef LOCKS_H -#define LOCKS_H - -#include -#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 - * . - */ - -#ifndef NETWORK_IO_H -#define NETWORK_IO_H - -#include -#include -#include -#include -#include -#include -#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 /* 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 - * . - */ - -#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 -#include -#include -#include - -#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 + +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 +#endif +#if APR_HAVE_SYS_TYPES_H +#include +#endif +#if APR_HAVE_ERRNO_H +#include +#endif +#if APR_HAVE_STRING_H +#include +#endif +#if APR_HAVE_STRINGS_H +#include +#endif +#if APR_HAVE_DIRENT_H +#include +#endif +#ifdef HAVE_SYS_STAT_H +#include +#endif +#if APR_HAVE_UNISTD_H +#include +#endif +#if APR_HAVE_STDIO_H +#include +#endif +#if APR_HAVE_STDLIB_H +#include +#endif +#if APR_HAVE_SYS_UIO_H +#include +#endif +#if APR_HAVE_SYS_TIME_H +#include +#endif + +#include + +/* 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 + +#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 + +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 + +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 + +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 + +#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 + +/* Pick up privately consumed headers */ +#include + +/* Include alloca.h to get compiler-dependent defines */ +#include + +/* 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 +#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 +#include + +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 - * . - */ - -#ifndef DSO_H -#define DSO_H - -#define INCL_DOS -#include - -#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 - * . - */ - -#ifndef FILE_IO_H -#define FILE_IO_H - -#define INCL_DOS -#include - -#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 - * . - */ - -#ifndef LOCKS_H -#define LOCKS_H - -#include "apr_lock.h" -#include "apr_file_io.h" -#define INCL_DOS -#include - -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 - * . - */ - -#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 - * . - */ - -#include -#include - -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 - * . - */ - -#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 + +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 +#endif + +#ifdef HAVE_DLFCN_H +#include +#endif + +#ifdef HAVE_DL_H +#include +#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 +#endif +#if APR_HAVE_SYS_TYPES_H +#include +#endif +#if APR_HAVE_ERRNO_H +#include +#endif +#if APR_HAVE_STRING_H +#include +#endif +#if APR_HAVE_STRINGS_H +#include +#endif +#if APR_HAVE_DIRENT_H +#include +#endif +#ifdef HAVE_SYS_STAT_H +#include +#endif +#if APR_HAVE_UNISTD_H +#include +#endif +#if APR_HAVE_STDIO_H +#include +#endif +#if APR_HAVE_STDLIB_H +#include +#endif +#if APR_HAVE_SYS_UIO_H +#include +#endif +#if APR_HAVE_SYS_TIME_H +#include +#endif +#ifdef BEOS +#include +#endif +/* Hunting down DEV_BSIZE if not from dirent.h, sys/stat.h etc */ +#ifdef HAVE_SYS_PARAM_H +#include +#endif + +#if BEOS_BONE +# ifndef BONE7 + /* prior to BONE/7 fd_set & select were defined in sys/socket.h */ +# include +# else + /* Be moved the fd_set stuff and also the FIONBIO definition... */ +# include +# 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 +#endif +#if APR_HAVE_SIGNAL_H +#include +#endif +#if APR_HAVE_PTHREAD_H +#include +#endif + +#if APR_HAVE_STDLIB_H +#include +#endif +#if APR_HAVE_STRING_H +#include +#endif + +#ifdef BEOS +#include +#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 +#endif +#if APR_HAVE_SYS_UIO_H +#include +#endif +#ifdef HAVE_SYS_SELECT_H +#include +#endif +#if APR_HAVE_ERRNO_H +#include +#endif +#if APR_HAVE_SYS_TIME_H +#include +#endif +#if APR_HAVE_UNISTD_H +#include +#endif +#if APR_HAVE_STRING_H +#include +#endif +#if APR_HAVE_NETINET_TCP_H +#include +#endif +#if APR_HAVE_NETINET_SCTP_UIO_H +#include +#endif +#if APR_HAVE_NETINET_SCTP_H +#include +#endif +#if APR_HAVE_NETINET_IN_H +#include +#endif +#if APR_HAVE_ARPA_INET_H +#include +#endif +#if APR_HAVE_SYS_SOCKET_H +#include +#endif +#if APR_HAVE_SYS_SOCKIO_H +#include +#endif +#if APR_HAVE_NETDB_H +#include +#endif +#if APR_HAVE_FCNTL_H +#include +#endif +#if APR_HAVE_SYS_SENDFILE_H +#include +#endif +#if APR_HAVE_SYS_IOCTL_H +#include +#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 +#endif + +#if HAVE_SYS_POLL_H +#include +#endif + +#ifdef HAVE_PORT_CREATE +#include +#include +#endif + +#ifdef HAVE_KQUEUE +#include +#include +#include +#endif + +#ifdef HAVE_EPOLL +#include +#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 /* 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 +#endif +#if APR_HAVE_STDIO_H +#include +#endif +#if APR_HAVE_FCNTL_H +#include +#endif + +#ifdef HAVE_SYS_IPC_H +#include +#endif +#ifdef HAVE_SYS_SEM_H +#include +#endif +#ifdef HAVE_SYS_FILE_H +#include +#endif +#if APR_HAVE_STDLIB_H +#include +#endif +#if APR_HAVE_UNISTD_H +#include +#endif +#if APR_HAVE_STRING_H +#include +#endif +#ifdef HAVE_SYS_MMAN_H +#include +#endif +#if APR_HAVE_PTHREAD_H +#include +#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 +#endif +#ifdef HAVE_SYS_MMAN_H +#include +#endif +#ifdef HAVE_SYS_IPC_H +#include +#endif +#ifdef HAVE_SYS_MUTEX_H +#include +#endif +#ifdef HAVE_SYS_SHM_H +#include +#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 +#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 +#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 +#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 +#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 +#endif +#ifdef HAVE_SYS_RESOURCE_H +#include +#endif +#if APR_HAVE_SIGNAL_H +#include +#endif +#if APR_HAVE_STRING_H +#include +#endif +#if APR_HAVE_SYS_WAIT_H +#include +#endif +#if APR_HAVE_STRING_H +#include +#endif +#ifdef HAVE_SCHED_H +#include +#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 - * . - */ - -#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 -#endif - -#ifdef HAVE_DL_H -#include -#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 - * . - */ - -#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 -#endif -#if HAVE_SYS_TYPES_H -#include -#endif -#if HAVE_ERRNO_H -#include -#endif -#if HAVE_STRING_H -#include -#endif -#if HAVE_DIRENT_H -#include -#endif -#if HAVE_SYS_STAT_H -#include -#endif -#if HAVE_UNISTD_H -#include -#endif -#if HAVE_STDIO_H -#include -#endif -#if HAVE_STDLIB_H -#include -#endif -#if HAVE_SYS_UIO_H -#include -#endif -#if HAVE_SYS_TIME_H -#include -#endif -#ifdef BEOS -#include -#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 - * . - */ - -#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 -#endif -#if HAVE_STRING_H -#include -#endif -#if HAVE_USLOCKS_H -#include -#endif -#if HAVE_SYS_TYPES_H -#include -#endif -#if HAVE_SYS_IPC_H -#include -#endif -#if HAVE_SYS_SEM_H -#include -#endif -#if HAVE_SYS_FILE_H -#include -#endif -#if HAVE_STDIO_H -#include -#endif -#if HAVE_FCNTL_H -#include -#endif -#if HAVE_SYS_MMAN_H -#include -#endif - -#if APR_HAS_THREADS -#if HAVE_PTHREAD_H -#include -#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 - * . - */ - -#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 -#endif -#ifdef HAVE_STDIO_H -#include -#endif -#ifdef HAVE_STRING_H -#include -#endif -#ifdef HAVE_SIGNAL_H -#include -#endif -#ifdef HAVE_PTHREAD_H -#include -#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 - * . - */ - -#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 - * . - */ - -#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 -#endif -#if HAVE_SYS_UIO_H -#include -#endif -#if HAVE_POLL_H -#include -#endif -#if HAVE_ERRNO_H -#include -#endif -#if HAVE_SYS_TIME_H -#include -#endif -#if HAVE_UNISTD_H -#include -#endif -#if HAVE_STRING_H -#include -#endif -#if HAVE_NETINET_TCP_H -#include -#endif -#if HAVE_NETINET_IN_H -#include -#endif -#if HAVE_ARPA_INET_H -#include -#endif -#if HAVE_SYS_SOCKET_H -#include -#endif -#if HAVE_NETDB_H -#include -#endif -#if HAVE_FCNTL_H -#include -#endif -#if HAVE_SYS_SENDFILE_H -#include -#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 - * . - */ - -#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 -#endif -#if HAVE_SIGNAL_H -#include -#endif -#if HAVE_STRING_H -#include -#endif -#if HAVE_SYS_WAIT_H -#include -#endif -#if HAVE_STRING_H -#include -#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 +#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 +#endif +#if APR_HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_FCNTL_H +#include +#endif +#ifdef HAVE_TIME_H +#include +#endif +#if APR_HAVE_DIRENT_H +#include +#endif +#ifdef HAVE_MALLOC_H +#include +#endif + +#if APR_HAS_UNICODE_FS +#include "arch/win32/apr_arch_utf8.h" +#include + +/* 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 +#endif +#if APR_HAVE_SIGNAL_H +#include +#endif +#if APR_HAVE_PTHREAD_H +#include +#endif +#if APR_HAVE_STDLIB_H +#include +#endif +#if APR_HAVE_STRING_H +#include +#endif +#ifndef _WIN32_WCE +#include +#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 - * . + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 -#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 -#include -#include -#include -#include -#include -#include -#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 +#else +#define __wtypes_h__ +#include +#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 +#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 - * . - */ - -#ifndef ATIME_H -#define ATIME_H - -#include "apr_private.h" -#include "apr_time.h" -#include - -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 - * . - */ - -#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 - * . - */ - -#ifndef FILE_IO_H -#define FILE_IO_H - -#ifdef HAVE_SYS_STAT_H -#include -#endif -#ifdef HAVE_SYS_TYPES_H -#include -#endif -#ifdef HAVE_SYS_FCNTL_H -#include -#endif -#ifdef HAVE_TIME_H -#include -#endif -#ifdef HAVE_DIRENT_H -#include -#endif -#ifdef HAVE_MALLOC_H -#include -#endif -#ifdef HAVE_UIO_H -#include -#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 - * . - */ - -#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 - * . - */ - -#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 -#endif -#ifdef HAVE_STDIO_H -#include -#endif -#ifdef HAVE_STRING_H -#include -#endif -#ifdef HAVE_SIGNAL_H -#include -#endif -#ifdef HAVE_PTHREAD_H -#include -#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 - * . - */ - -#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 - * . - */ - -#include "apr_private.h" -#include "apr_thread_proc.h" -#include "apr_file_io.h" -#include - -#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 + +#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 + +#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 +#include + +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 - * . - */ - -#include "apr_private.h" -#include "apr_lib.h" - -#if HAVE_SYS_TYPES_H -#include -#endif -#if HAVE_STRING_H -#include -#endif -#if HAVE_CTYPE_H -#include -#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 - * . - */ - -/* - * 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 -#ifdef HAVE_CTYPE_H -# include -#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 - * . - */ - -/* 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 -#include - -#if HAVE_UNISTD_H -#include -#endif -#if HAVE_CONIO_H -#include -#endif - -#if defined(HAVE_TERMIOS_H) && !defined(HAVE_GETPASS) -#include -#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 - * . - */ - -/* - * 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): - * 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 -#endif -#ifdef HAVE_CRYPT_H -#include -#endif -#ifdef HAVE_UNISTD_H -#include -#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 - * . - */ - -/* - * 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 -#endif -#ifdef HAVE_SYS_SIGNAL_H -#include -#endif -#ifdef HAVE_SIGNAL_H -#include -#endif -#ifdef HAVE_SYS_WAIT_H -#include -#endif -#ifdef HAVE_SYS_TYPES_H -#include -#endif -#ifdef HAVE_UNISTD_H -#include -#endif -#ifdef HAVE_FCNTL_H -#include -#endif - -#ifdef HAVE_STDLIB_H -#include -#endif -#ifdef HAVE_MALLOC_H -#include -#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 - * . - */ - -#include "apr_private.h" -#include "apr_lib.h" -#ifdef HAVE_SIGNAL_H -#include -#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 - * . - */ - -#ifdef WIN32 -#include -#endif -#include "apr_private.h" - -#include "apr_lib.h" -#include -#ifdef HAVE_CTYPE_H -#include -#endif -#if HAVE_NETINET_IN_H -#include -#endif -#ifdef HAVE_SYS_SOCKET_H -#include -#endif -#ifdef HAVE_ARPA_INET_H -#include -#endif -#ifdef HAVE_LIMITS_H -#include -#endif -#ifdef HAVE_STRING_H -#include -#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 % */ - - 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 % 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 % (like syslog). - * Note that we can't point s inside fmt because the - * unknown 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 - * . - */ - -/* - * 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 -#endif -#ifdef HAVE_MALLOC_H -#include -#endif -#ifdef HAVE_STRING_H -#include -#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 - * . - */ - -#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 - * . - */ - -#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 - * . - */ - -#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 - * . - */ - -#ifndef LOCKS_H -#define LOCKS_H - -#include -#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 + */ + +#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 + */ + +#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 + */ + +#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 + +#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 - * . - */ - -#include "apr_general.h" -#include "apr_lib.h" -#include "locks.h" -#include "fileio.h" -#include -#define INCL_DOS -#include - -#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 - * . - */ - -#ifndef LOCKS_H -#define LOCKS_H - -#include "apr_lock.h" -#include "apr_file_io.h" -#define INCL_DOS -#include - -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 +#include + +#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 + +#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 +#include + +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 + +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 - * . - */ - -#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 - * . - */ - -#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 - * . - */ - -#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 - * . - */ - -#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 -#endif -#if HAVE_STRING_H -#include -#endif -#if HAVE_USLOCKS_H -#include -#endif -#if HAVE_SYS_TYPES_H -#include -#endif -#if HAVE_SYS_IPC_H -#include -#endif -#if HAVE_SYS_SEM_H -#include -#endif -#if HAVE_SYS_FILE_H -#include -#endif -#if HAVE_STDIO_H -#include -#endif -#if HAVE_FCNTL_H -#include -#endif -#if HAVE_SYS_MMAN_H -#include -#endif - -#if APR_HAS_THREADS -#if HAVE_PTHREAD_H -#include -#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 - * . - */ - -#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 - * . - */ - -#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 + +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 + +#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 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; + } + + /* \r\n\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 [ [...]]\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