diff options
-rw-r--r-- | CHANGES | 3 | ||||
-rw-r--r-- | configure.in | 108 | ||||
-rw-r--r-- | file_io/unix/filestat.c | 6 | ||||
-rw-r--r-- | file_io/unix/mktemp.c | 5 | ||||
-rw-r--r-- | file_io/unix/open.c | 4 | ||||
-rw-r--r-- | file_io/unix/readwrite.c | 4 | ||||
-rw-r--r-- | file_io/unix/seek.c | 13 | ||||
-rw-r--r-- | include/apr.h.in | 2 | ||||
-rw-r--r-- | include/arch/netware/apr_arch_file_io.h | 7 | ||||
-rw-r--r-- | include/arch/unix/apr_arch_file_io.h | 11 | ||||
-rw-r--r-- | mmap/unix/mmap.c | 8 | ||||
-rw-r--r-- | network_io/unix/sendrecv.c | 52 | ||||
-rw-r--r-- | test/.cvsignore | 2 | ||||
-rw-r--r-- | test/Makefile.in | 2 | ||||
-rw-r--r-- | test/test_apr.h | 1 | ||||
-rw-r--r-- | test/testall.c | 1 | ||||
-rw-r--r-- | test/testlfs.c | 278 |
17 files changed, 457 insertions, 50 deletions
@@ -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; +} + |