You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by mt...@apache.org on 2009/09/29 07:45:13 UTC

svn commit: r819834 - in /commons/sandbox/runtime/trunk/src/main/native: include/acr_file.h os/unix/fsysio.c

Author: mturk
Date: Tue Sep 29 05:45:12 2009
New Revision: 819834

URL: http://svn.apache.org/viewvc?rev=819834&view=rev
Log:
Implement Posix file sys I/O methods

Modified:
    commons/sandbox/runtime/trunk/src/main/native/include/acr_file.h
    commons/sandbox/runtime/trunk/src/main/native/os/unix/fsysio.c

Modified: commons/sandbox/runtime/trunk/src/main/native/include/acr_file.h
URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/include/acr_file.h?rev=819834&r1=819833&r2=819834&view=diff
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/native/include/acr_file.h (original)
+++ commons/sandbox/runtime/trunk/src/main/native/include/acr_file.h Tue Sep 29 05:45:12 2009
@@ -144,6 +144,16 @@
                                            file lock */
 /** @} */
 
+/* File seek direction */
+/**
+ * @defgroup acr_seek_direction_types File Seek Direction Types
+ * @{
+ */
+
+#define ACR_FSEEK_CUR           0       /**< Seek from the current position */
+#define ACR_FSEEK_SET           1       /**< Seek from the file begin       */
+#define ACR_FSEEK_END           2       /**< Seek from the file end         */
+
 #define ACR_NO_END_SLASHA(P)                        \
     if (*(P)) {                                     \
         size_t _s = strlen((P)) - 1;                \

Modified: commons/sandbox/runtime/trunk/src/main/native/os/unix/fsysio.c
URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/os/unix/fsysio.c?rev=819834&r1=819833&r2=819834&view=diff
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/native/os/unix/fsysio.c (original)
+++ commons/sandbox/runtime/trunk/src/main/native/os/unix/fsysio.c Tue Sep 29 05:45:12 2009
@@ -257,6 +257,173 @@
         return errno;
 }
 
+ACR_IO_EXPORT_DECLARE(jint, FileSystemProvider, lock0)(ACR_JNISTDARGS,
+                                                        jint file,
+                                                        jint type)
+{
+    int rc;
+    acr_file_t *f = (acr_file_t *)ACR_IOH_FDATA(file);
+
+    if (ACR_IOH_FTYPE(file) != ACR_DT_FILE)
+        return ACR_EFTYPE;
+    if (IS_INVALID_HANDLE(f))
+        return ACR_EBADF;
+#if HAVE_FCNTL_H
+    {
+        struct flock l = { 0 };
+        int fc;
+
+        l.l_whence = SEEK_SET;  /* lock from current point */
+        l.l_start  = 0;         /* begin lock at this offset */
+        l.l_len    = 0;         /* lock to end of file */
+        if ((type & ACR_FLOCK_TYPEMASK) == ACR_FLOCK_SHARED)
+            l.l_type = F_RDLCK;
+        else
+            l.l_type = F_WRLCK;
+
+        fc = (type & ACR_FLOCK_NONBLOCK) ? F_SETLK : F_SETLKW;
+
+        /* keep trying if fcntl() gets interrupted (by a signal) */
+        while ((rc = fcntl(f->fd, 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 ACR_EAGAIN;
+            }
+            return ACR_GET_OS_ERROR();
+        }
+    }
+#elif HAVE_SYS_FILE_H
+    {
+        int ltype;
+
+        if ((type & ACR_FLOCK_TYPEMASK) == ACR_FLOCK_SHARED)
+            ltype = LOCK_SH;
+        else
+            ltype = LOCK_EX;
+        if ((type & ACR_FLOCK_NONBLOCK) != 0)
+            ltype |= LOCK_NB;
+
+        /* keep trying if flock() gets interrupted (by a signal) */
+        while ((rc = flock(f->fd, ltype)) < 0 && errno == EINTR)
+            continue;
+
+        if (rc == -1)
+            return ACR_GET_OS_ERROR();
+    }
+#else
+#error No file locking mechanism is available.
+#endif
+    return 0;
+}
+
+ACR_IO_EXPORT_DECLARE(jint, FileSystemProvider, unlock0)(ACR_JNISTDARGS,
+                                                         jint file)
+{
+    int rc;
+    acr_file_t *f = (acr_file_t *)ACR_IOH_FDATA(file);
+
+    if (ACR_IOH_FTYPE(file) != ACR_DT_FILE)
+        return ACR_EFTYPE;
+    if (IS_INVALID_HANDLE(f))
+        return ACR_EBADF;
+#if HAVE_FCNTL_H
+    {
+        struct flock l = { 0 };
+
+        l.l_whence = SEEK_SET;  /* lock from current point */
+        l.l_start  = 0;         /* begin lock at this offset */
+        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(f->fd, F_SETLKW, &l)) < 0
+               && errno == EINTR)
+            continue;
+
+        if (rc == -1)
+            return ACR_GET_OS_ERROR();
+    }
+#elif HAVE_SYS_FILE_H
+    {
+        /* keep trying if flock() gets interrupted (by a signal) */
+        while ((rc = flock(f->fd, LOCK_UN)) < 0 && errno == EINTR)
+            continue;
+
+        if (rc == -1)
+            return ACR_GET_OS_ERROR();
+    }
+#else
+#error No file locking mechanism is available.
+#endif
+
+    return 0;
+}
+
+ACR_IO_EXPORT_DECLARE(jlong, FileSystemProvider, seek0)(ACR_JNISTDARGS,
+                                                        jint file,
+                                                        jint where,
+                                                        jlong off)
+{
+    acr_off_t rc;
+    acr_off_t os = (acr_off_t)off;
+    int whence;
+    acr_file_t *f = (acr_file_t *)ACR_IOH_FDATA(file);
+
+    if (ACR_IOH_FTYPE(file) != ACR_DT_FILE) {
+        ACR_THROW_IO_IF_ERR(ACR_EFTYPE);
+        return -1;
+    }
+    if (IS_INVALID_HANDLE(f)) {
+        ACR_THROW_IO_IF_ERR(ACR_EBADF);
+        return -1;
+    }
+    switch (where) {
+        case ACR_FSEEK_CUR:
+            whence = SEEK_CUR;
+        break;
+        case ACR_FSEEK_SET:
+            whence = SEEK_SET;
+        break;
+        case ACR_FSEEK_END:
+            whence = SEEK_END;
+        break;
+        default:
+            ACR_THROW_IO_IF_ERR(ACR_EINVAL);
+            return -1;
+        break;
+    }
+    if ((rc = lseek(f->fd, os, whence)) == (off_t)-1) {
+        ACR_THROW_IO_ERRNO();
+        return -1;
+    }
+    return (jlong)rc;
+}
+
+ACR_IO_EXPORT_DECLARE(jint, FileSystemProvider, trunc0)(ACR_JNISTDARGS,
+                                                        jint file,
+                                                        jlong off)
+{
+    acr_off_t os  = (acr_off_t)off;
+    acr_file_t *f = (acr_file_t *)ACR_IOH_FDATA(file);
+
+    if (ACR_IOH_FTYPE(file) != ACR_DT_FILE)
+        return ACR_EFTYPE;
+    if (IS_INVALID_HANDLE(f))
+        return ACR_EBADF;
+    if (ftruncate(f->fd, os) == -1)
+        return ACR_GET_OS_ERROR();
+    if (lseek(f->fd, os, SEEK_SET) == (off_t)-1)
+        return ACR_GET_OS_ERROR();
+    else
+        return 0;
+}
+
 ACR_IO_EXPORT_DECLARE(jint, FileSystemProvider, read0)(ACR_JNISTDARGS,
                                                        jint file)
 {
@@ -272,6 +439,9 @@
         ACR_THROW_IO_IF_ERR(ACR_EBADF);
         return -1;
     }
+    if (f->eof) {
+        return -1;
+    }
     rd = r_read(f->fd, &c, 1);
     if (rd == -1 && (errno == EAGAIN || errno == EWOULDBLOCK) &&
         f->timeout != 0) {
@@ -284,13 +454,598 @@
             rd = r_read(f->fd, &c, 1);
         }
     }
-    if (rd == -1)
+    if (rd == -1) {
         f->err = ACR_GET_OS_ERROR();
-    else if (rd == 0)
+        if (ACR_STATUS_IS_EAGAIN(f->err))
+            return 0;
+    }
+    else if (rd == 0) {
+        f->err = 0;
         f->eof = 1;
+    }
     else if (rd == 1) {
         f->err = 0;
-        return (int)c;
+        return c;
     }
     return -1;
 }
+
+ACR_IO_EXPORT_DECLARE(jint, FileSystemProvider, read1)(ACR_JNISTDARGS,
+                                                       jint file,
+                                                       jbyteArray buf,
+                                                       jint off,
+                                                       jint len)
+{
+    jbyte  *bb = NULL;
+    jbyte  *bc = NULL;
+    jbyte   onstack[ACR_PBUFF_SIZ];
+    ssize_t rd;
+    acr_file_t *f = (acr_file_t *)ACR_IOH_FDATA(file);
+
+    if (ACR_IOH_FTYPE(file) != ACR_DT_FILE) {
+        ACR_THROW_IO_IF_ERR(ACR_EFTYPE);
+        return -1;
+    }
+    if (IS_INVALID_HANDLE(f)) {
+        ACR_THROW_IO_IF_ERR(ACR_EBADF);
+        return -1;
+    }
+    if (f->eof) {
+        return -1;
+    }
+    if (len > sizeof(onstack)) {
+        if (len > (1024 * 1024)) {
+            bc = (*_E)->GetByteArrayElements(_E, buf, NULL);
+            if (bc)
+                bb = bc + (size_t)off;
+        }
+        else
+            bb = ACR_Malloc(_E, THROW_FMARK, (size_t)len);
+    }
+    else
+        bb = onstack;
+    if (!bb) {
+        /* Exception was already thrown */
+        return -1;
+    }
+    rd = r_read(f->fd, bb, (size_t)len);
+    if (rd == -1 && (errno == EAGAIN || errno == EWOULDBLOCK) &&
+        f->timeout != 0) {
+        int rc;
+        if ((rc = wait_for_io_or_timeout(f, 1))) {
+            f->err = rc;
+            if (bb != onstack) {
+                if (bc)
+                    (*_E)->ReleaseByteArrayElements(_E, buf, bc, JNI_ABORT);
+                else
+                    x_free(bb);
+            }
+            return rc == ACR_TIMEUP ? 0 : -1;
+        }
+        else {
+            rd = r_read(f->fd, bb, (size_t)len);
+        }
+    }
+    if (rd == -1) {
+        f->err = ACR_GET_OS_ERROR();
+        if (ACR_STATUS_IS_EAGAIN(f->err))
+            rd = 0;
+    }
+    else if (rd == 0) {
+        f->err = 0;
+        f->eof = 1;
+    }
+    else if (rd > 0) {
+        f->err = 0;
+        if (bc) {
+            (*_E)->ReleaseByteArrayElements(_E, buf, bc, 0);
+            return (jint)rd;
+        }
+        else {
+            (*_E)->SetByteArrayRegion(_E, buf, (jsize)off, (jsize)rd, bb);
+        }
+    }
+    if (bb != onstack) {
+        if (bc)
+            (*_E)->ReleaseByteArrayElements(_E, buf, bc, JNI_ABORT);
+        else
+            x_free(bb);
+    }
+    return (jint)rd;
+}
+
+ACR_IO_EXPORT_DECLARE(jint, FileSystemProvider, read2)(ACR_JNISTDARGS,
+                                                       jint file,
+                                                       jobject ptr,
+                                                       jint off,
+                                                       jint len)
+{
+    size_t  pl;
+    size_t  po = (size_t)off;
+    size_t  cs = (size_t)len;
+    jbyte  *pb;
+    ssize_t rd;
+    acr_file_t *f = (acr_file_t *)ACR_IOH_FDATA(file);
+
+    if (ACR_IOH_FTYPE(file) != ACR_DT_FILE) {
+        ACR_THROW_IO_IF_ERR(ACR_EFTYPE);
+        return -1;
+    }
+    if (IS_INVALID_HANDLE(f)) {
+        ACR_THROW_IO_IF_ERR(ACR_EBADF);
+        return -1;
+    }
+    if (f->eof) {
+        return -1;
+    }
+    pb = (jbyte *)ACR_PointerGet(_E, ptr, &pl);
+    if (!pb) {
+        ACR_ThrowException(_E, THROW_NMARK, ACR_EX_ENULL, 0);
+        return -1;
+    }
+    if ((po + cs) > pl) {
+        ACR_ThrowException(_E, THROW_NMARK, ACR_EX_EINDEX, 0);
+        return -1;
+    }
+    rd = r_read(f->fd, pb + po, cs);
+    if (rd == -1 && (errno == EAGAIN || errno == EWOULDBLOCK) &&
+        f->timeout != 0) {
+        int rc;
+        if ((rc = wait_for_io_or_timeout(f, 1))) {
+            f->err = rc;
+            return rc == ACR_TIMEUP ? 0 : -1;
+        }
+        else {
+            rd = r_read(f->fd, pb + po, cs);
+        }
+    }
+    if (rd == -1) {
+        f->err = ACR_GET_OS_ERROR();
+        if (ACR_STATUS_IS_EAGAIN(f->err))
+            rd = 0;
+    }
+    else if (rd == 0) {
+        f->err = 0;
+        f->eof = 1;
+    }
+    else if (rd > 0) {
+        f->err = 0;
+    }
+    return (jint)rd;
+}
+
+ACR_IO_EXPORT_DECLARE(jint, FileSystemProvider, read3)(ACR_JNISTDARGS,
+                                                       jint file,
+                                                       jobject dbb,
+                                                       jint off,
+                                                       jint len)
+{
+#if defined(_DEBUG)
+    size_t  pl;
+#endif
+    size_t  po = (size_t)off;
+    size_t  cs = (size_t)len;
+    jbyte  *pb;
+    ssize_t rd;
+    acr_file_t *f = (acr_file_t *)ACR_IOH_FDATA(file);
+
+    if (ACR_IOH_FTYPE(file) != ACR_DT_FILE) {
+        ACR_THROW_IO_IF_ERR(ACR_EFTYPE);
+        return -1;
+    }
+    if (IS_INVALID_HANDLE(f)) {
+        ACR_THROW_IO_IF_ERR(ACR_EBADF);
+        return -1;
+    }
+    if (f->eof) {
+        return -1;
+    }
+    pb = (jbyte *)(*_E)->GetDirectBufferAddress(_E, dbb);
+    if (!pb) {
+        ACR_ThrowException(_E, THROW_NMARK, ACR_EX_ENULL, 0);
+        return -1;
+    }
+#if defined(_DEBUG)
+    pl = (size_t)(*_E)->GetDirectBufferCapacity(_E, dbb);
+    if ((po + cs) > pl) {
+        ACR_ThrowException(_E, THROW_NMARK, ACR_EX_EINDEX, 0);
+        return -1;
+    }
+#endif
+    rd = r_read(f->fd, pb + po, cs);
+    if (rd == -1 && (errno == EAGAIN || errno == EWOULDBLOCK) &&
+        f->timeout != 0) {
+        int rc;
+        if ((rc = wait_for_io_or_timeout(f, 1))) {
+            f->err = rc;
+            return rc == ACR_TIMEUP ? 0 : -1;
+        }
+        else {
+            rd = r_read(f->fd, pb + po, cs);
+        }
+    }
+    if (rd == -1) {
+        f->err = ACR_GET_OS_ERROR();
+        if (ACR_STATUS_IS_EAGAIN(f->err))
+            rd = 0;
+    }
+    else if (rd == 0) {
+        f->err = 0;
+        f->eof = 1;
+    }
+    else if (rd > 0) {
+        f->err = 0;
+    }
+    return (jint)rd;
+}
+
+ACR_IO_EXPORT_DECLARE(jint, FileSystemProvider, write0)(ACR_JNISTDARGS,
+                                                        jint file,
+                                                        jint b)
+{
+    unsigned char c = (unsigned char)(b & 0xFF);
+    ssize_t wr;
+    acr_file_t *f = (acr_file_t *)ACR_IOH_FDATA(file);
+
+    if (ACR_IOH_FTYPE(file) != ACR_DT_FILE) {
+        ACR_THROW_IO_IF_ERR(ACR_EFTYPE);
+        return -1;
+    }
+    if (IS_INVALID_HANDLE(f)) {
+        ACR_THROW_IO_IF_ERR(ACR_EBADF);
+        return -1;
+    }
+    wr = r_write(f->fd, &c, 1);
+    if (wr == -1 && (errno == EAGAIN || errno == EWOULDBLOCK) &&
+        f->timeout != 0) {
+        int rc;
+        if ((rc = wait_for_io_or_timeout(f, 0))) {
+            f->err = rc;
+            return rc == ACR_TIMEUP ? 0 : -1;
+        }
+        else {
+            wr = r_write(f->fd, &c, 1);
+        }
+    }
+    if (wr == -1) {
+        f->err = ACR_GET_OS_ERROR();
+        if (ACR_STATUS_IS_EAGAIN(f->err))
+            return 0;
+    }
+    else if (wr == 1)
+        f->err = 0;
+    return wr;
+}
+
+ACR_IO_EXPORT_DECLARE(jint, FileSystemProvider, write1)(ACR_JNISTDARGS,
+                                                        jint file,
+                                                        jbyteArray buf,
+                                                        jint off,
+                                                        jint len)
+{
+    jbyte  *bb;
+    ssize_t wr;
+    acr_file_t *f = (acr_file_t *)ACR_IOH_FDATA(file);
+
+    if (ACR_IOH_FTYPE(file) != ACR_DT_FILE) {
+        ACR_THROW_IO_IF_ERR(ACR_EFTYPE);
+        return -1;
+    }
+    if (IS_INVALID_HANDLE(f)) {
+        ACR_THROW_IO_IF_ERR(ACR_EBADF);
+        return -1;
+    }
+    bb = (*_E)->GetByteArrayElements(_E, buf, NULL);
+    if (!bb) {
+        return -1;
+    }
+    wr = r_write(f->fd, bb + (size_t)off, (size_t)len);
+    if (wr == -1 && (errno == EAGAIN || errno == EWOULDBLOCK) &&
+        f->timeout != 0) {
+        int rc;
+        if ((rc = wait_for_io_or_timeout(f, 0))) {
+            f->err = rc;
+            (*_E)->ReleaseByteArrayElements(_E, buf, bb, JNI_ABORT);
+            return rc == ACR_TIMEUP ? 0 : -1;
+        }
+        else {
+            wr = r_write(f->fd, bb + (size_t)off, (size_t)len);
+        }
+    }
+    if (wr == -1) {
+        f->err = ACR_GET_OS_ERROR();
+        if (ACR_STATUS_IS_EAGAIN(f->err))
+            wr = 0;
+    }
+    else if (wr == 1)
+        f->err = 0;
+   (*_E)->ReleaseByteArrayElements(_E, buf, bb, JNI_ABORT);
+    return (jint)wr;
+}
+
+ACR_IO_EXPORT_DECLARE(jint, FileSystemProvider, write2)(ACR_JNISTDARGS,
+                                                        jint file,
+                                                        jobject ptr,
+                                                        jint off,
+                                                        jint len)
+{
+    size_t  pl;
+    size_t  po = (size_t)off;
+    size_t  cs = (size_t)len;
+    jbyte  *pb;
+    ssize_t wr;
+    acr_file_t *f = (acr_file_t *)ACR_IOH_FDATA(file);
+
+    if (ACR_IOH_FTYPE(file) != ACR_DT_FILE) {
+        ACR_THROW_IO_IF_ERR(ACR_EFTYPE);
+        return -1;
+    }
+    if (IS_INVALID_HANDLE(f)) {
+        ACR_THROW_IO_IF_ERR(ACR_EBADF);
+        return -1;
+    }
+    pb = (jbyte *)ACR_PointerGet(_E, ptr, &pl);
+    if (!pb) {
+        ACR_ThrowException(_E, THROW_NMARK, ACR_EX_ENULL, 0);
+        return -1;
+    }
+    if ((po + cs) > pl) {
+        ACR_ThrowException(_E, THROW_NMARK, ACR_EX_EINDEX, 0);
+        return -1;
+    }
+    wr = r_write(f->fd, pb + po, cs);
+    if (wr == -1 && (errno == EAGAIN || errno == EWOULDBLOCK) &&
+        f->timeout != 0) {
+        int rc;
+        if ((rc = wait_for_io_or_timeout(f, 0))) {
+            f->err = rc;
+            return rc == ACR_TIMEUP ? 0 : -1;
+        }
+        else {
+            wr = r_write(f->fd, pb + po, cs);
+        }
+    }
+    if (wr == -1) {
+        f->err = ACR_GET_OS_ERROR();
+        if (ACR_STATUS_IS_EAGAIN(f->err))
+            wr = 0;
+    }
+    else if (wr == 1)
+        f->err = 0;
+    return (jint)wr;
+}
+
+ACR_IO_EXPORT_DECLARE(jint, FileSystemProvider, write3)(ACR_JNISTDARGS,
+                                                        jint file,
+                                                        jobject dbb,
+                                                        jint off,
+                                                        jint len)
+{
+#if defined(_DEBUG)
+    size_t  pl;
+#endif
+    size_t  po = (size_t)off;
+    size_t  cs = (size_t)len;
+    jbyte  *pb;
+    ssize_t wr;
+    acr_file_t *f = (acr_file_t *)ACR_IOH_FDATA(file);
+
+    if (ACR_IOH_FTYPE(file) != ACR_DT_FILE) {
+        ACR_THROW_IO_IF_ERR(ACR_EFTYPE);
+        return -1;
+    }
+    if (IS_INVALID_HANDLE(f)) {
+        ACR_THROW_IO_IF_ERR(ACR_EBADF);
+        return -1;
+    }
+    pb = (jbyte *)(*_E)->GetDirectBufferAddress(_E, dbb);
+    if (!pb) {
+        ACR_ThrowException(_E, THROW_NMARK, ACR_EX_ENULL, 0);
+        return -1;
+    }
+#if defined(_DEBUG)
+    pl = (size_t)(*_E)->GetDirectBufferCapacity(_E, dbb);
+    if ((po + cs) > pl) {
+        ACR_ThrowException(_E, THROW_NMARK, ACR_EX_EINDEX, 0);
+        return -1;
+    }
+#endif
+    wr = r_write(f->fd, pb + po, cs);
+    if (wr == -1 && (errno == EAGAIN || errno == EWOULDBLOCK) &&
+        f->timeout != 0) {
+        int rc;
+        if ((rc = wait_for_io_or_timeout(f, 0))) {
+            f->err = rc;
+            return rc == ACR_TIMEUP ? 0 : -1;
+        }
+        else {
+            wr = r_write(f->fd, pb + po, cs);
+        }
+    }
+    if (wr == -1) {
+        f->err = ACR_GET_OS_ERROR();
+        if (ACR_STATUS_IS_EAGAIN(f->err))
+            wr = 0;
+    }
+    else if (wr == 1)
+        f->err = 0;
+    return (jint)wr;
+}
+
+#define ACR_IOVEC_ON_STACK 32
+ACR_IO_EXPORT_DECLARE(jint, FileSystemProvider, write4)(ACR_JNISTDARGS,
+                                                        jint file,
+                                                        jobjectArray vec,
+                                                        jint off,
+                                                        jint len)
+{
+    size_t   i;
+    size_t  pl;
+    size_t  po = (size_t)off;
+    size_t  cs = (size_t)len;
+    ssize_t wr;
+    struct iovec *iov;
+    struct iovec  onstack[ACR_IOVEC_ON_STACK];
+    jobject       bastack[ACR_IOVEC_ON_STACK];
+    jobject      *boa;
+    acr_file_t *f = (acr_file_t *)ACR_IOH_FDATA(file);
+
+    if (ACR_IOH_FTYPE(file) != ACR_DT_FILE) {
+        ACR_THROW_IO_IF_ERR(ACR_EFTYPE);
+        return -1;
+    }
+    if (IS_INVALID_HANDLE(f)) {
+        ACR_THROW_IO_IF_ERR(ACR_EBADF);
+        return -1;
+    }
+    pl = (size_t)(*_E)->GetArrayLength(_E, vec);
+    if ((po + cs) > pl) {
+        ACR_ThrowException(_E, THROW_NMARK, ACR_EX_EINDEX, 0);
+        return -1;
+    }
+    if ((*_E)->EnsureLocalCapacity(_E, (jint)(pl * 2)))
+        return -1;
+    if (pl > ACR_IOVEC_ON_STACK) {
+        iov = ACR_MALLOC(struct iovec, pl);
+        boa = ACR_MALLOC(jobject, pl);
+    }
+    else {
+        iov = onstack;
+        boa = bastack;
+    }
+    if (!iov || !boa) {
+        x_free(iov);
+        x_free(boa);
+        return -1;
+    }
+
+    for (i = 0; i < pl; i++) {
+        boa[i] = (*_E)->GetObjectArrayElement(_E, vec, i);
+        iov[i].iov_len  = (size_t)(*_E)->GetArrayLength(_E, boa[i]);
+        iov[i].iov_base = (*_E)->GetByteArrayElements(_E, boa[i], NULL);
+    }
+    do {
+        wr = writev(f->fd, iov, pl);
+    } while (wr == -1 && errno == EAGAIN);
+    if (wr == -1 && (errno == EAGAIN || errno == EWOULDBLOCK) &&
+        f->timeout != 0) {
+        int rc;
+        if ((rc = wait_for_io_or_timeout(f, 0))) {
+            f->err = rc;
+            for (i = 0; i < pl; i++) {
+                (*_E)->ReleaseByteArrayElements(_E, boa[i], iov[i].iov_base,
+                                                JNI_ABORT);
+            }
+            if (iov != onstack) {
+                x_free(iov);
+                x_free(boa);
+            }
+            return rc == ACR_TIMEUP ? 0 : -1;
+        }
+        else {
+            do {
+                wr = writev(f->fd, iov, pl);
+            } while (wr == -1 && errno == EAGAIN);
+        }
+    }
+    if (wr == -1) {
+        f->err = ACR_GET_OS_ERROR();
+        if (ACR_STATUS_IS_EAGAIN(f->err))
+            wr = 0;
+    }
+    else if (wr == 1)
+        f->err = 0;
+    for (i = 0; i < pl; i++) {
+        (*_E)->ReleaseByteArrayElements(_E, boa[i], iov[i].iov_base, JNI_ABORT);
+    }
+    if (iov != onstack) {
+        x_free(iov);
+        x_free(boa);
+    }
+    return (jint)wr;
+}
+
+ACR_IO_EXPORT_DECLARE(jint, FileSystemProvider, write5)(ACR_JNISTDARGS,
+                                                        jint file,
+                                                        jobjectArray vec,
+                                                        jint off,
+                                                        jint len)
+{
+    size_t   i;
+    size_t  pl;
+    size_t  po = (size_t)off;
+    size_t  cs = (size_t)len;
+    ssize_t wr;
+    struct iovec *iov;
+    struct iovec  onstack[ACR_IOVEC_ON_STACK];
+    jobject       bastack[ACR_IOVEC_ON_STACK];
+    jobject      *boa;
+    acr_file_t *f = (acr_file_t *)ACR_IOH_FDATA(file);
+
+    if (ACR_IOH_FTYPE(file) != ACR_DT_FILE) {
+        ACR_THROW_IO_IF_ERR(ACR_EFTYPE);
+        return -1;
+    }
+    if (IS_INVALID_HANDLE(f)) {
+        ACR_THROW_IO_IF_ERR(ACR_EBADF);
+        return -1;
+    }
+    pl = (size_t)(*_E)->GetArrayLength(_E, vec);
+    if ((po + cs) > pl) {
+        ACR_ThrowException(_E, THROW_NMARK, ACR_EX_EINDEX, 0);
+        return -1;
+    }
+    if ((*_E)->EnsureLocalCapacity(_E, (jint)(pl * 2)))
+        return -1;
+    if (pl > ACR_IOVEC_ON_STACK) {
+        iov = ACR_MALLOC(struct iovec, pl);
+        boa = ACR_MALLOC(jobject, pl);
+    }
+    else {
+        iov = onstack;
+        boa = bastack;
+    }
+    if (!iov || !boa) {
+        x_free(iov);
+        x_free(boa);
+        return -1;
+    }
+
+    for (i = 0; i < pl; i++) {
+        boa[i] = (*_E)->GetObjectArrayElement(_E, vec, i);
+        iov[i].iov_len  = (size_t)(*_E)->GetDirectBufferCapacity(_E, boa[i]);
+        iov[i].iov_base = (*_E)->GetDirectBufferAddress(_E, boa[i]);
+    }
+    do {
+        wr = writev(f->fd, iov, pl);
+    } while (wr == -1 && errno == EAGAIN);
+    if (wr == -1 && (errno == EAGAIN || errno == EWOULDBLOCK) &&
+        f->timeout != 0) {
+        int rc;
+        if ((rc = wait_for_io_or_timeout(f, 0))) {
+            f->err = rc;
+            if (iov != onstack) {
+                x_free(iov);
+                x_free(boa);
+            }
+            return rc == ACR_TIMEUP ? 0 : -1;
+        }
+        else {
+            do {
+                wr = writev(f->fd, iov, pl);
+            } while (wr == -1 && errno == EAGAIN);
+        }
+    }
+    if (wr == -1) {
+        f->err = ACR_GET_OS_ERROR();
+        if (ACR_STATUS_IS_EAGAIN(f->err))
+            wr = 0;
+    }
+    else if (wr == 1)
+        f->err = 0;
+    if (iov != onstack) {
+        x_free(iov);
+        x_free(boa);
+    }
+    return (jint)wr;
+}