summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES3
-rw-r--r--configure.in108
-rw-r--r--file_io/unix/filestat.c6
-rw-r--r--file_io/unix/mktemp.c5
-rw-r--r--file_io/unix/open.c4
-rw-r--r--file_io/unix/readwrite.c4
-rw-r--r--file_io/unix/seek.c13
-rw-r--r--include/apr.h.in2
-rw-r--r--include/arch/netware/apr_arch_file_io.h7
-rw-r--r--include/arch/unix/apr_arch_file_io.h11
-rw-r--r--mmap/unix/mmap.c8
-rw-r--r--network_io/unix/sendrecv.c52
-rw-r--r--test/.cvsignore2
-rw-r--r--test/Makefile.in2
-rw-r--r--test/test_apr.h1
-rw-r--r--test/testall.c1
-rw-r--r--test/testlfs.c278
17 files changed, 457 insertions, 50 deletions
diff --git a/CHANGES b/CHANGES
index 7e9ea0e20..f4c889078 100644
--- a/CHANGES
+++ b/CHANGES
@@ -7,6 +7,9 @@ Changes for APR 1.1 [Deferring these features when 1.0 is rolled out.]
Changes with APR 1.0
+ *) Support "large files" by default on 32-bit Unix platforms which
+ implement the LFS standard. [Joe Orton]
+
*) Add apr_threadattr_stacksize_set() for overriding the default
stack size for threads created by apr_thread_create().
[Jeff Trawick]
diff --git a/configure.in b/configure.in
index f7b9c99dd..37dd08e33 100644
--- a/configure.in
+++ b/configure.in
@@ -416,6 +416,55 @@ esac
AC_SUBST(OBJECTS_PLATFORM)
+# Check whether LFS has explicitly been disabled
+AC_ARG_ENABLE(lfs,[ --disable-lfs Disable large file support on 32-bit platforms],
+[apr_lfs_choice=$enableval], [apr_lfs_choice=yes])
+
+if test "$apr_lfs_choice" = "yes"; then
+ # Check whether the transitional LFS API is sufficient
+ AC_CACHE_CHECK([whether to enable -D_LARGEFILE64_SOURCE], [apr_cv_use_lfs64], [
+ apr_save_CPPFLAGS=$CPPFLAGS
+ CPPFLAGS="$CPPFLAGS -D_LARGEFILE64_SOURCE"
+ AC_TRY_RUN([
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+
+void main(void)
+{
+ int fd, ret = 0;
+ struct stat64 st;
+ off64_t off = 4242;
+
+ if (sizeof(off64_t) != 8 || sizeof(off_t) != 4)
+ exit(1);
+ if ((fd = open("conftest.lfs", O_LARGEFILE|O_CREAT|O_WRONLY)) < 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
@@ -1104,11 +1153,6 @@ else
stdint=0
fi
-if test "$ac_cv_type_off_t" = "yes"; then
- off_t_value="off_t"
-else
- off_t_value="apr_int32_t"
-fi
if test "$ac_cv_type_size_t" = "yes"; then
size_t_value="size_t"
else
@@ -1147,15 +1191,45 @@ fi
APR_CHECK_SIZEOF_EXTENDED([#include <sys/types.h>], off_t, 8)
-if test "$ac_cv_sizeof_off_t" = "$ac_cv_sizeof_int"; then
- off_t_fmt='#define APR_OFF_T_FMT "d"'
-elif test "$ac_cv_sizeof_off_t" = "$ac_cv_sizeof_long"; then
- off_t_fmt='#define APR_OFF_T_FMT "ld"'
-elif test "$ac_cv_sizeof_off_t" = "$ac_cv_sizeof_long_long"; then
+if test "${ac_cv_sizeof_off_t}${apr_cv_use_lfs64}" = "4yes"; then
+ # Enable LFS
+ aprlfs=1
+ AC_CHECK_FUNCS([mmap64 sendfile64 sendfilev64 mkstemp64])
+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'
+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
+ # with other software which may export _FILE_OFFSET_BITS,
+ # hard-code apr_off_t to long.
+ off_t_value=long
+ off_t_fmt='#define APR_OFF_T_FMT "ld"'
+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"'
+ elif 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_long"; then
+ off_t_fmt='#define APR_OFF_T_FMT APR_INT64_T_FMT'
+ else
+ AC_ERROR([could not determine the size of off_t])
+ fi
else
- off_t_fmt='#error Can not determine the proper size for off_t'
+ # Fallback on int
+ off_t_value=apr_int32_t
+ off_t_fmt=d
fi
+AC_MSG_RESULT($off_t_value)
APR_CHECK_SIZEOF_EXTENDED([#include <sys/types.h>], pid_t, 8)
@@ -1188,7 +1262,6 @@ case $host in
size_t_fmt='#define APR_SIZE_T_FMT "ld"'
;;
*-os2*)
- off_t_fmt='#define APR_OFF_T_FMT "ld"'
size_t_fmt='#define APR_SIZE_T_FMT "lu"'
;;
*-solaris*)
@@ -1208,16 +1281,6 @@ case $host in
;;
esac
-# Override format string for off_t more carefully: only use hard-coded
-# choice if using a 32-bit off_t on platforms which support LFS.
-if test "$ac_cv_sizeof_off_t" = "4"; then
- case $host in
- *linux*|*-solaris*|*aix[[45]]*)
- off_t_fmt='#define APR_OFF_T_FMT "ld"'
- ;;
- esac
-fi
-
AC_SUBST(voidp_size)
AC_SUBST(short_value)
AC_SUBST(int_value)
@@ -1238,6 +1301,7 @@ AC_SUBST(int64_literal)
AC_SUBST(uint64_literal)
AC_SUBST(stdint)
AC_SUBST(bigendian)
+AC_SUBST(aprlfs)
dnl ----------------------------- Checking for string functions
AC_CHECK_FUNCS(strnicmp, have_strnicmp="1", have_strnicmp="0")
diff --git a/file_io/unix/filestat.c b/file_io/unix/filestat.c
index 85352fa9d..4e56f9948 100644
--- a/file_io/unix/filestat.c
+++ b/file_io/unix/filestat.c
@@ -66,7 +66,7 @@ static apr_filetype_e filetype_from_mode(mode_t mode)
return type;
}
-static void fill_out_finfo(apr_finfo_t *finfo, struct stat *info,
+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
@@ -94,7 +94,7 @@ APR_DECLARE(apr_status_t) apr_file_info_get(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(thefile);
@@ -227,7 +227,7 @@ 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;
+ struct_stat info;
int srv;
if (wanted & APR_FINFO_LINK)
diff --git a/file_io/unix/mktemp.c b/file_io/unix/mktemp.c
index ff23a2f7b..6db13c69c 100644
--- a/file_io/unix/mktemp.c
+++ b/file_io/unix/mktemp.c
@@ -182,7 +182,12 @@ APR_DECLARE(apr_status_t) apr_file_mktemp(apr_file_t **fp, char *template, apr_i
return gettemp(template, fp, flags, p);
#else
+#ifdef HAVE_MKSTEMP64
+ fd = mkstemp64(template);
+#else
fd = mkstemp(template);
+#endif
+
if (fd == -1) {
return errno;
}
diff --git a/file_io/unix/open.c b/file_io/unix/open.c
index 81d622426..ee9196214 100644
--- a/file_io/unix/open.c
+++ b/file_io/unix/open.c
@@ -99,6 +99,10 @@ APR_DECLARE(apr_status_t) apr_file_open(apr_file_t **new,
}
#endif
+#if APR_HAS_LARGE_FILES && defined(_LARGEFILE64_SOURCE)
+ oflags |= O_LARGEFILE;
+#endif
+
#if APR_HAS_THREADS
if ((flag & APR_BUFFERED) && (flag & APR_XTHREAD)) {
rv = apr_thread_mutex_create(&thlock,
diff --git a/file_io/unix/readwrite.c b/file_io/unix/readwrite.c
index 3059f670f..1e6a6e665 100644
--- a/file_io/unix/readwrite.c
+++ b/file_io/unix/readwrite.c
@@ -164,11 +164,7 @@ APR_DECLARE(apr_status_t) apr_file_write(apr_file_t *thefile, const void *buf, a
*/
apr_int64_t offset = thefile->filePtr - thefile->dataRead + thefile->bufpos;
if (offset != thefile->filePtr)
-#if defined(NETWARE) && APR_HAS_LARGE_FILES
- lseek64(thefile->filedes, offset, SEEK_SET);
-#else
lseek(thefile->filedes, offset, SEEK_SET);
-#endif
thefile->bufpos = thefile->dataRead = 0;
thefile->direction = 1;
}
diff --git a/file_io/unix/seek.c b/file_io/unix/seek.c
index 2ae433f9d..cac4e9331 100644
--- a/file_io/unix/seek.c
+++ b/file_io/unix/seek.c
@@ -31,11 +31,7 @@ static apr_status_t setptr(apr_file_t *thefile, apr_off_t pos )
rc = 0;
}
else {
-#if defined(NETWARE) && APR_HAS_LARGE_FILES
- rc = lseek64(thefile->filedes, pos, SEEK_SET);
-#else
rc = lseek(thefile->filedes, pos, SEEK_SET);
-#endif
if (rc != -1 ) {
thefile->bufpos = thefile->dataRead = 0;
@@ -81,12 +77,7 @@ APR_DECLARE(apr_status_t) apr_file_seek(apr_file_t *thefile, apr_seek_where_t wh
return rc;
}
else {
-
-#if defined(NETWARE) && APR_HAS_LARGE_FILES
- rv = lseek64(thefile->filedes, *offset, where);
-#else
rv = lseek(thefile->filedes, *offset, where);
-#endif
if (rv == -1) {
*offset = -1;
return errno;
@@ -100,11 +91,7 @@ APR_DECLARE(apr_status_t) apr_file_seek(apr_file_t *thefile, apr_seek_where_t wh
apr_status_t apr_file_trunc(apr_file_t *fp, apr_off_t offset)
{
-#if defined(NETWARE) && APR_HAS_LARGE_FILES
- if (ftruncate64(fp->filedes, offset) == -1) {
-#else
if (ftruncate(fp->filedes, offset) == -1) {
-#endif
return errno;
}
return setptr(fp, offset);
diff --git a/include/apr.h.in b/include/apr.h.in
index 02ae79c1d..32e7407eb 100644
--- a/include/apr.h.in
+++ b/include/apr.h.in
@@ -218,7 +218,7 @@ extern "C" {
#define APR_HAS_UNICODE_FS 0
#define APR_HAS_PROC_INVOKED 0
#define APR_HAS_USER 1
-#define APR_HAS_LARGE_FILES 0
+#define APR_HAS_LARGE_FILES @aprlfs@
#define APR_HAS_XTHREAD_FILES 0
#define APR_HAS_OS_UUID 0
diff --git a/include/arch/netware/apr_arch_file_io.h b/include/arch/netware/apr_arch_file_io.h
index 8d8b96441..70ce289d9 100644
--- a/include/arch/netware/apr_arch_file_io.h
+++ b/include/arch/netware/apr_arch_file_io.h
@@ -70,6 +70,13 @@
#define APR_FILE_BUFSIZE 4096
+#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;
+
struct apr_file_t {
apr_pool_t *pool;
int filedes;
diff --git a/include/arch/unix/apr_arch_file_io.h b/include/arch/unix/apr_arch_file_io.h
index 0802c2639..004f59ee0 100644
--- a/include/arch/unix/apr_arch_file_io.h
+++ b/include/arch/unix/apr_arch_file_io.h
@@ -109,6 +109,17 @@ struct apr_file_t {
#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
+
struct apr_dir_t {
apr_pool_t *pool;
char *dirname;
diff --git a/mmap/unix/mmap.c b/mmap/unix/mmap.c
index 44cdbedb0..05d3f72ef 100644
--- a/mmap/unix/mmap.c
+++ b/mmap/unix/mmap.c
@@ -83,6 +83,14 @@ APR_DECLARE(apr_status_t) apr_mmap_create(apr_mmap_t **new,
apr_int32_t native_flags = 0;
#endif
+#if APR_HAS_LARGE_FILES && defined(HAVE_MMAP64)
+#define mmap mmap64
+#elif APR_HAS_LARGE_FILES && SIZEOF_OFF_T == 4
+ /* LFS but no mmap64: check for overflow */
+ if ((apr_int64_t)offset + size > INT_MAX)
+ return APR_EINVAL;
+#endif
+
if (size == 0)
return APR_EINVAL;
diff --git a/network_io/unix/sendrecv.c b/network_io/unix/sendrecv.c
index 60fae1a88..9381693ed 100644
--- a/network_io/unix/sendrecv.c
+++ b/network_io/unix/sendrecv.c
@@ -243,10 +243,28 @@ apr_status_t apr_socket_sendfile(apr_socket_t *sock, apr_file_t *file,
apr_hdtr_t *hdtr, apr_off_t *offset,
apr_size_t *len, apr_int32_t flags)
{
- off_t off = *offset;
int rv, nbytes = 0, total_hdrbytes, i;
apr_status_t arv;
+#if APR_HAS_LARGE_FILES && defined(HAVE_SENDFILE64)
+ apr_off_t off = *offset;
+#define sendfile sendfile64
+
+#elif APR_HAS_LARGE_FILES && SIZEOF_OFF_T == 4
+ /* 64-bit apr_off_t but no sendfile64(): fail if trying to send
+ * past the 2Gb limit. */
+ off_t off;
+
+ if ((apr_int64_t)*offset + *len > INT_MAX) {
+ return EINVAL;
+ }
+
+ off = *offset;
+
+#else
+ off_t off = *offset;
+#endif
+
if (!hdtr) {
hdtr = &no_hdtr;
}
@@ -562,6 +580,24 @@ apr_status_t apr_socket_sendfile(apr_socket_t *sock, apr_file_t *file,
struct iovec hdtrarray[2];
char *headerbuf, *trailerbuf;
+#if APR_HAS_LARGE_FILES && defined(HAVE_SENDFILE64)
+ /* later HP-UXes have a sendfile64() */
+#define sendfile sendfile64
+ apr_off_t off = *offset;
+
+#elif APR_HAS_LARGE_FILES && SIZEOF_OFF_T == 4
+ /* HP-UX 11.00 doesn't have a sendfile64(): fail if trying to send
+ * past the 2Gb limit */
+ off_t off;
+
+ if ((apr_int64_t)*offset + *len > INT_MAX) {
+ return EINVAL;
+ }
+ off = *offset;
+#else
+ apr_off_t off = *offset;
+#endif
+
if (!hdtr) {
hdtr = &no_hdtr;
}
@@ -627,7 +663,7 @@ apr_status_t apr_socket_sendfile(apr_socket_t *sock, apr_file_t *file,
if (nbytes) { /* any bytes to send from the file? */
rc = sendfile(sock->socketdes, /* socket */
file->filedes, /* file descriptor to send */
- *offset, /* where in the file to start */
+ off, /* where in the file to start */
nbytes, /* number of bytes to send from file */
hdtrarray, /* Headers/footers */
flags); /* undefined, set to 0 */
@@ -650,7 +686,7 @@ apr_status_t apr_socket_sendfile(apr_socket_t *sock, apr_file_t *file,
if (nbytes) {
rc = sendfile(sock->socketdes, /* socket */
file->filedes, /* file descriptor to send */
- *offset, /* where in the file to start */
+ off, /* where in the file to start */
nbytes, /* number of bytes to send from file */
hdtrarray, /* Headers/footers */
flags); /* undefined, set to 0 */
@@ -838,6 +874,12 @@ do_select:
* 111298-01, 108529-09, 109473-06, 109235-04, 108996-02, 111296-01, 109026-04,
* 108992-13
*/
+
+#if APR_HAS_LARGE_FILES && defined(HAVE_SENDFILEV64)
+#define sendfilevec_t sendfilevec64_t
+#define sendfilev sendfilev64
+#endif
+
apr_status_t apr_socket_sendfile(apr_socket_t *sock, apr_file_t *file,
apr_hdtr_t *hdtr, apr_off_t *offset,
apr_size_t *len, apr_int32_t flags)
@@ -865,7 +907,7 @@ apr_status_t apr_socket_sendfile(apr_socket_t *sock, apr_file_t *file,
for (i = 0; i < hdtr->numheaders; i++, curvec++) {
sfv[curvec].sfv_fd = SFV_FD_SELF;
sfv[curvec].sfv_flag = 0;
- sfv[curvec].sfv_off = (off_t)hdtr->headers[i].iov_base;
+ sfv[curvec].sfv_off = (apr_off_t)hdtr->headers[i].iov_base;
sfv[curvec].sfv_len = hdtr->headers[i].iov_len;
requested_len += sfv[curvec].sfv_len;
}
@@ -889,7 +931,7 @@ apr_status_t apr_socket_sendfile(apr_socket_t *sock, apr_file_t *file,
for (i = 0; i < hdtr->numtrailers; i++, curvec++) {
sfv[curvec].sfv_fd = SFV_FD_SELF;
sfv[curvec].sfv_flag = 0;
- sfv[curvec].sfv_off = (off_t)hdtr->trailers[i].iov_base;
+ sfv[curvec].sfv_off = (apr_off_t)hdtr->trailers[i].iov_base;
sfv[curvec].sfv_len = hdtr->trailers[i].iov_len;
requested_len += sfv[curvec].sfv_len;
}
diff --git a/test/.cvsignore b/test/.cvsignore
index 2bb5c1d66..d52494239 100644
--- a/test/.cvsignore
+++ b/test/.cvsignore
@@ -42,4 +42,4 @@ testlockperf
testmutexscope
testshmconsumer
testshmproducer
-
+lfstests
diff --git a/test/Makefile.in b/test/Makefile.in
index 7465cf5f0..92996fa14 100644
--- a/test/Makefile.in
+++ b/test/Makefile.in
@@ -102,7 +102,7 @@ TESTS = testall.lo testtime.lo teststr.lo testvsn.lo testipsub.lo \
testhash.lo testargs.lo testnames.lo testuser.lo testpath.lo \
testenv.lo testprocmutex.lo testrand2.lo testfnmatch.lo \
testatomic.lo testflock.lo testshm.lo testsock.lo testglobalmutex.lo \
- teststrnatcmp.lo testfilecopy.lo testtemp.lo
+ teststrnatcmp.lo testfilecopy.lo testtemp.lo testlfs.lo
testall: $(TESTS) mod_test.la libmod_test.la occhild@EXEEXT@ \
readchild@EXEEXT@ CuTest.lo proc_child@EXEEXT@ \
diff --git a/test/test_apr.h b/test/test_apr.h
index cc46f7f42..00fd9829f 100644
--- a/test/test_apr.h
+++ b/test/test_apr.h
@@ -52,6 +52,7 @@ CuSuite *testglobalmutex(void);
CuSuite *testhash(void);
CuSuite *testipsub(void);
CuSuite *testlock(void);
+CuSuite *testlfs(void);
CuSuite *testmmap(void);
CuSuite *testnames(void);
CuSuite *testoc(void);
diff --git a/test/testall.c b/test/testall.c
index 7e0a4f9f0..ad5d23b94 100644
--- a/test/testall.c
+++ b/test/testall.c
@@ -54,6 +54,7 @@ static const struct testlist {
{"testglobalmutex", testglobalmutex},
{"testhash", testhash},
{"testipsub", testipsub},
+ {"testlfs", testlfs},
{"testlock", testlock},
{"testmmap", testmmap},
{"testnames", testnames},
diff --git a/test/testlfs.c b/test/testlfs.c
new file mode 100644
index 000000000..b1297fc6a
--- /dev/null
+++ b/test/testlfs.c
@@ -0,0 +1,278 @@
+/* Copyright 2004 The Apache Software Foundation
+ *
+ * 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.
+ */
+
+#include "apr_file_io.h"
+#include "apr_file_info.h"
+#include "apr_errno.h"
+#include "apr_general.h"
+#include "apr_poll.h"
+#include "apr_strings.h"
+#include "apr_lib.h"
+#include "apr_mmap.h"
+#include "test_apr.h"
+
+/* Only enable these tests by default on platforms which support sparse
+ * files... just Unixes? */
+#if APR_HAS_LARGE_FILES && !defined(WIN32) && !defined(OS2) && !defined(NETWARE)
+#define USE_LFS_TESTS
+
+/* Tests which create an 8Gb sparse file and then check it can be used
+ * as normal. */
+
+static apr_off_t eightGb = APR_INT64_C(2) << 32;
+
+static int madefile = 0;
+
+#define PRECOND if (!madefile) CuNotImpl(tc, NULL)
+
+#define TESTDIR "lfstests"
+#define TESTFILE "large.bin"
+#define TESTFN "lfstests/large.bin"
+
+static void test_open(CuTest *tc)
+{
+ apr_file_t *f;
+ apr_status_t rv;
+
+ rv = apr_dir_make(TESTDIR, APR_OS_DEFAULT, p);
+ if (rv && !APR_STATUS_IS_EEXIST(rv)) {
+ apr_assert_success(tc, "make test directory", rv);
+ }
+
+ apr_assert_success(tc, "open file",
+ apr_file_open(&f, TESTFN,
+ APR_CREATE | APR_WRITE | APR_TRUNCATE,
+ APR_OS_DEFAULT, p));
+
+ rv = apr_file_trunc(f, eightGb);
+
+ apr_assert_success(tc, "close large file", apr_file_close(f));
+
+ /* 8Gb may pass rlimits or filesystem limits */
+
+#ifdef EFBIG
+ if (rv == EFBIG) {
+ CuNotImpl(tc, "Creation of large file (limited by rlimit or fs?)");
+ } else
+#endif
+ {
+ apr_assert_success(tc, "truncate file to 8gb", rv);
+ }
+
+ madefile = 1;
+}
+
+static void test_reopen(CuTest *tc)
+{
+ apr_file_t *fh;
+ apr_finfo_t finfo;
+
+ PRECOND;
+
+ apr_assert_success(tc, "re-open 8Gb file",
+ apr_file_open(&fh, TESTFN, APR_READ, APR_OS_DEFAULT, p));
+
+ apr_assert_success(tc, "file_info_get failed",
+ apr_file_info_get(&finfo, APR_FINFO_NORM, fh));
+
+ CuAssert(tc, "file_info_get gave incorrect size",
+ finfo.size == eightGb);
+
+ apr_assert_success(tc, "re-close large file", apr_file_close(fh));
+}
+
+static void test_stat(CuTest *tc)
+{
+ apr_finfo_t finfo;
+
+ PRECOND;
+
+ apr_assert_success(tc, "stat large file",
+ apr_stat(&finfo, TESTFN, APR_FINFO_NORM, p));
+
+ CuAssert(tc, "stat gave incorrect size", finfo.size == eightGb);
+}
+
+static void test_readdir(CuTest *tc)
+{
+ apr_dir_t *dh;
+ apr_status_t rv;
+
+ PRECOND;
+
+ apr_assert_success(tc, "open test directory",
+ apr_dir_open(&dh, TESTDIR, p));
+
+ do {
+ apr_finfo_t finfo;
+
+ rv = apr_dir_read(&finfo, APR_FINFO_NORM, dh);
+
+ if (rv == APR_SUCCESS && strcmp(finfo.name, TESTFILE) == 0) {
+ CuAssert(tc, "apr_dir_read gave incorrect size for large file",
+ finfo.size == eightGb);
+ }
+
+ } while (rv == APR_SUCCESS);
+
+ if (!APR_STATUS_IS_ENOENT(rv)) {
+ apr_assert_success(tc, "apr_dir_read failed", rv);
+ }
+
+ apr_assert_success(tc, "close test directory",
+ apr_dir_close(dh));
+}
+
+#define TESTSTR "Hello, world."
+
+static void test_append(CuTest *tc)
+{
+ apr_file_t *fh;
+ apr_finfo_t finfo;
+
+ PRECOND;
+
+ apr_assert_success(tc, "open 8Gb file for append",
+ apr_file_open(&fh, TESTFN, APR_WRITE | APR_APPEND,
+ APR_OS_DEFAULT, p));
+
+ apr_assert_success(tc, "append to 8Gb file",
+ apr_file_write_full(fh, TESTSTR, strlen(TESTSTR), NULL));
+
+ apr_assert_success(tc, "file_info_get failed",
+ apr_file_info_get(&finfo, APR_FINFO_NORM, fh));
+
+ CuAssert(tc, "file_info_get gave incorrect size",
+ finfo.size == eightGb + strlen(TESTSTR));
+
+ apr_assert_success(tc, "close 8Gb file", apr_file_close(fh));
+}
+
+static void test_seek(CuTest *tc)
+{
+ apr_file_t *fh;
+ apr_off_t pos;
+
+ PRECOND;
+
+ apr_assert_success(tc, "open 8Gb file for writing",
+ apr_file_open(&fh, TESTFN, APR_WRITE,
+ APR_OS_DEFAULT, p));
+
+ pos = eightGb;
+ apr_assert_success(tc, "seek to 8Gb", apr_file_seek(fh, APR_SET, &pos));
+ CuAssert(tc, "seek gave 8Gb offset", pos == eightGb);
+
+ pos = 0;
+ apr_assert_success(tc, "relative seek to 0", apr_file_seek(fh, APR_CUR, &pos));
+ CuAssert(tc, "relative seek gave 8Gb offset", pos == eightGb);
+
+ apr_file_close(fh);
+}
+
+static void test_write(CuTest *tc)
+{
+ apr_file_t *fh;
+ apr_off_t pos = eightGb - 4;
+
+ PRECOND;
+
+ apr_assert_success(tc, "re-open 8Gb file",
+ apr_file_open(&fh, TESTFN, APR_WRITE, APR_OS_DEFAULT, p));
+
+ apr_assert_success(tc, "seek to 8Gb - 4",
+ apr_file_seek(fh, APR_SET, &pos));
+ CuAssert(tc, "seek gave 8Gb-4 offset", pos == eightGb - 4);
+
+ apr_assert_success(tc, "write magic string to 8Gb-4",
+ apr_file_write_full(fh, "FISH", 4, NULL));
+
+ apr_assert_success(tc, "close 8Gb file", apr_file_close(fh));
+}
+
+
+#if APR_HAS_MMAP
+static void test_mmap(CuTest *tc)
+{
+ apr_mmap_t *map;
+ apr_file_t *fh;
+ apr_size_t len = 16384; /* hopefully a multiple of the page size */
+ apr_off_t off = eightGb - len;
+ void *ptr;
+
+ PRECOND;
+
+ apr_assert_success(tc, "open 8gb file for mmap",
+ apr_file_open(&fh, TESTFN, APR_READ, APR_OS_DEFAULT, p));
+
+ apr_assert_success(tc, "mmap 8Gb file",
+ apr_mmap_create(&map, fh, off, len, APR_MMAP_READ, p));
+
+ apr_assert_success(tc, "close file", apr_file_close(fh));
+
+ CuAssert(tc, "mapped a 16K block", map->size == len);
+
+ apr_assert_success(tc, "get pointer into mmaped region",
+ apr_mmap_offset(&ptr, map, len - 4));
+ CuAssert(tc, "pointer was not NULL", ptr != NULL);
+
+ CuAssert(tc, "found the magic string", memcmp(ptr, "FISH", 4) == 0);
+
+ apr_assert_success(tc, "delete mmap handle", apr_mmap_delete(map));
+}
+#endif /* APR_HAS_MMAP */
+
+static void test_format(CuTest *tc)
+{
+ apr_off_t off;
+
+ PRECOND;
+
+ off = apr_atoi64(apr_off_t_toa(p, eightGb));
+
+ CuAssert(tc, "apr_atoi64 parsed apr_off_t_toa result incorrectly",
+ off == eightGb);
+}
+
+#else
+static void test_nolfs(CuTest *tc)
+{
+ CuNotImpl(tc, "Large Files not supported");
+}
+#endif
+
+CuSuite *testlfs(void)
+{
+ CuSuite *suite = CuSuiteNew("Large File Support");
+
+#ifdef USE_LFS_TESTS
+ SUITE_ADD_TEST(suite, test_open);
+ SUITE_ADD_TEST(suite, test_reopen);
+ SUITE_ADD_TEST(suite, test_stat);
+ SUITE_ADD_TEST(suite, test_readdir);
+ SUITE_ADD_TEST(suite, test_append);
+ SUITE_ADD_TEST(suite, test_seek);
+ SUITE_ADD_TEST(suite, test_write);
+#if APR_HAS_MMAP
+ SUITE_ADD_TEST(suite, test_mmap);
+#endif
+ SUITE_ADD_TEST(suite, test_format);
+#else
+ SUITE_ADD_TEST(suite, test_nolfs)
+#endif
+
+ return suite;
+}
+