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/30 20:24:39 UTC

svn commit: r820372 - /commons/sandbox/runtime/trunk/src/main/native/os/win32/fsysio.c

Author: mturk
Date: Wed Sep 30 18:24:39 2009
New Revision: 820372

URL: http://svn.apache.org/viewvc?rev=820372&view=rev
Log:
Implement win32 write methods

Modified:
    commons/sandbox/runtime/trunk/src/main/native/os/win32/fsysio.c

Modified: commons/sandbox/runtime/trunk/src/main/native/os/win32/fsysio.c
URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/os/win32/fsysio.c?rev=820372&r1=820371&r2=820372&view=diff
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/native/os/win32/fsysio.c (original)
+++ commons/sandbox/runtime/trunk/src/main/native/os/win32/fsysio.c Wed Sep 30 18:24:39 2009
@@ -286,33 +286,18 @@
     return fdo;
 }
 
-ACR_IO_EXPORT_DECLARE(jint, FileSystem, lock0)(ACR_JNISTDARGS,
-                                               jint file,
-                                               jint type)
+static int do_lock(acr_file_t *f, DWORD flags)
 {
-    OVERLAPPED  opp;
-    DWORD flags = 0;
-    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 (type & ACR_FLOCK_NONBLOCK)
-        flags = LOCKFILE_FAIL_IMMEDIATELY;
-    else if (f->blocking == BLK_OFF) {
+    if (f->blocking == BLK_OFF) {
         if (IS_INVALID_HANDLE(f->overlap.hEvent)) {
             f->overlap.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
             if (IS_INVALID_HANDLE(f->overlap.hEvent))
                 return ACR_GET_OS_ERROR();
         }
     }
-    if ((type & ACR_FLOCK_TYPEMASK) != ACR_FLOCK_SHARED)
-        flags |= LOCKFILE_EXCLUSIVE_LOCK;
     f->overlap.Offset     = 0;
     f->overlap.OffsetHigh = 0;
-    if (!LockFileEx(f->fd, flags, 0, 0xFFFFFFFF, 0xFFFFFFFF, &opp)) {
+    if (!LockFileEx(f->fd, flags, 0, 0xFFFFFFFF, 0xFFFFFFFF, &f->overlap)) {
         int rc = ACR_GET_OS_ERROR();
         if (rc == ERROR_IO_PENDING) {
             do {
@@ -347,6 +332,27 @@
     }
     else
         return 0;
+
+}
+
+ACR_IO_EXPORT_DECLARE(jint, FileSystem, lock0)(ACR_JNISTDARGS,
+                                               jint file,
+                                               jint type)
+{
+    DWORD flags = 0;
+    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 ((type & ACR_FLOCK_TYPEMASK) != ACR_FLOCK_SHARED)
+        flags |= LOCKFILE_EXCLUSIVE_LOCK;
+    if (type & ACR_FLOCK_NONBLOCK)
+        flags = LOCKFILE_FAIL_IMMEDIATELY;
+
+    return do_lock(f, flags);
 }
 
 ACR_IO_EXPORT_DECLARE(jint, FileSystem, lock1)(ACR_JNISTDARGS,
@@ -356,7 +362,6 @@
                                                jlong len)
 {
     LARGE_INTEGER lii;
-    OVERLAPPED    opp;
     DWORD flags = 0;
     acr_file_t *f = (acr_file_t *)ACR_IOH_FDATA(file);
 
@@ -367,20 +372,20 @@
 
     if (type & ACR_FLOCK_NONBLOCK)
         flags = LOCKFILE_FAIL_IMMEDIATELY;
-    else if (f->blocking == BLK_OFF) {
+    if ((type & ACR_FLOCK_TYPEMASK) != ACR_FLOCK_SHARED)
+        flags |= LOCKFILE_EXCLUSIVE_LOCK;
+    if (f->blocking == BLK_OFF) {
         if (IS_INVALID_HANDLE(f->overlap.hEvent)) {
             f->overlap.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
             if (IS_INVALID_HANDLE(f->overlap.hEvent))
                 return ACR_GET_OS_ERROR();
         }
     }
-    if ((type & ACR_FLOCK_TYPEMASK) != ACR_FLOCK_SHARED)
-        flags |= LOCKFILE_EXCLUSIVE_LOCK;
 
     f->overlap.Offset     = (DWORD)(off);
     f->overlap.OffsetHigh = (DWORD)(off >> 32);
     lii.QuadPart = len;
-    if (!LockFileEx(f->fd, flags, 0, lii.LowPart, lii.HighPart, &opp)) {
+    if (!LockFileEx(f->fd, flags, 0, lii.LowPart, lii.HighPart, &f->overlap)) {
         int rc = ACR_GET_OS_ERROR();
         if (rc == ERROR_IO_PENDING) {
             do {
@@ -953,7 +958,7 @@
         ACR_ThrowException(_E, THROW_NMARK, ACR_EX_ENULL, 0);
         return -1;
     }
-    if ((po + cs) > pl) {
+    if ((po + cs) > (DWORD)pl) {
         ACR_ThrowException(_E, THROW_NMARK, ACR_EX_EINDEX, 0);
         return -1;
     }
@@ -1137,3 +1142,663 @@
         return f->err == ACR_TIMEUP ? 0 : -1;
     return -1;
 }
+
+ACR_IO_EXPORT_DECLARE(jint, FileSystem, write0)(ACR_JNISTDARGS,
+                                                jint file,
+                                                jint b)
+{
+    unsigned char c = (unsigned char)(b & 0xFF);
+    DWORD rc;
+    DWORD wr   = 0;
+    int locked = 0;
+    LPOVERLAPPED lpo = NULL;
+    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->flags & ACR_FOPEN_APPEND) {
+        LARGE_INTEGER os;
+        LARGE_INTEGER op;
+
+        EnterCriticalSection(&f->lock);
+        /* 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.
+         */
+        rc = do_lock(f, LOCKFILE_EXCLUSIVE_LOCK);
+        if (rc) {
+            ACR_THROW_IO_IF_ERR(rc);
+            LeaveCriticalSection(&f->lock);
+            return -1;
+        }
+        /* Set the position to the file end
+         */
+        os.QuadPart = 0;
+        op.QuadPart = 0;
+        if (!SetFilePointerEx(f->fd, os, &op, FILE_END)) {
+            ACR_THROW_IO_ERRNO();
+            LeaveCriticalSection(&f->lock);
+            return -1;
+        }
+        f->pos = op.QuadPart;
+        locked = 1;
+    }
+    if (f->blocking == BLK_OFF) {
+        lpo = &f->overlap;
+        if (IS_INVALID_HANDLE(lpo->hEvent))
+            lpo->hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
+        if (IS_INVALID_HANDLE(lpo->hEvent)) {
+            ACR_THROW_IO_ERRNO();
+            if (locked)
+                LeaveCriticalSection(&f->lock);
+            return -1;
+        }
+        lpo->Offset     = (DWORD)(f->pos);
+        lpo->OffsetHigh = (DWORD)(f->pos >> 32);
+    }
+    f->err = 0;
+    if (WriteFile(f->fd, &c, 1, &wr, lpo)) {
+        /* All done. Update the position and return
+         */
+        if (wr)
+            f->pos += wr;
+        goto finally;
+    }
+    switch (f->err = GetLastError()) {
+        case ERROR_IO_PENDING:
+            if ((f->err = overlapped_wait(f, &wr)) == 0) {
+                if (wr) {
+                    f->pos += wr;
+                    goto finally;
+                }
+            }
+        break;
+        default:
+        break;
+    }
+
+finally:
+    if (locked)
+        LeaveCriticalSection(&f->lock);
+    if (wr)
+        return (jint)wr;
+    if (f->err)
+        return f->err == ACR_TIMEUP ? 0 : -1;
+    return -1;
+}
+
+ACR_IO_EXPORT_DECLARE(jint, FileSystem, write1)(ACR_JNISTDARGS,
+                                                jint file,
+                                                jbyteArray buf,
+                                                jint off,
+                                                jint len)
+{
+    jbyte  *bb;
+    DWORD   rc;
+    DWORD   po = (DWORD)off;
+    DWORD   cs = (DWORD)len;
+    DWORD   wr = 0;
+    int locked = 0;
+    LPOVERLAPPED lpo = NULL;
+    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->flags & ACR_FOPEN_APPEND) {
+        LARGE_INTEGER os;
+        LARGE_INTEGER op;
+
+        EnterCriticalSection(&f->lock);
+        /* 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.
+         */
+        rc = do_lock(f, LOCKFILE_EXCLUSIVE_LOCK);
+        if (rc) {
+            ACR_THROW_IO_IF_ERR(rc);
+            LeaveCriticalSection(&f->lock);
+            return -1;
+        }
+        /* Set the position to the file end
+         */
+        os.QuadPart = 0;
+        op.QuadPart = 0;
+        if (!SetFilePointerEx(f->fd, os, &op, FILE_END)) {
+            ACR_THROW_IO_ERRNO();
+            LeaveCriticalSection(&f->lock);
+            return -1;
+        }
+        f->pos = op.QuadPart;
+        locked = 1;
+    }
+    if (f->blocking == BLK_OFF) {
+        lpo = &f->overlap;
+        if (IS_INVALID_HANDLE(lpo->hEvent))
+            lpo->hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
+        if (IS_INVALID_HANDLE(lpo->hEvent)) {
+            ACR_THROW_IO_ERRNO();
+            if (locked)
+                LeaveCriticalSection(&f->lock);
+            return -1;
+        }
+        lpo->Offset     = (DWORD)(f->pos);
+        lpo->OffsetHigh = (DWORD)(f->pos >> 32);
+    }
+
+    bb = (*_E)->GetByteArrayElements(_E, buf, NULL);
+    if (!bb) {
+        if (locked)
+            LeaveCriticalSection(&f->lock);
+        return -1;
+    }
+    f->err = 0;
+    if (WriteFile(f->fd, bb + po, cs, &wr, lpo)) {
+        /* All done. Update the position and return
+         */
+        if (wr)
+            f->pos += wr;
+        goto finally;
+    }
+    switch (f->err = GetLastError()) {
+        case ERROR_IO_PENDING:
+            if ((f->err = overlapped_wait(f, &wr)) == 0) {
+                if (wr) {
+                    f->pos += wr;
+                    goto finally;
+                }
+            }
+        break;
+        default:
+        break;
+    }
+
+finally:
+    if (locked)
+        LeaveCriticalSection(&f->lock);
+   (*_E)->ReleaseByteArrayElements(_E, buf, bb, JNI_ABORT);
+    if (wr)
+        return (jint)wr;
+    if (f->err)
+        return f->err == ACR_TIMEUP ? 0 : -1;
+    return -1;
+}
+
+ACR_IO_EXPORT_DECLARE(jint, FileSystem, write2)(ACR_JNISTDARGS,
+                                                jint file,
+                                                jobject ptr,
+                                                jlong off,
+                                                jlong len)
+{
+    size_t  pl;
+    jbyte  *pb;
+    DWORD   rc;
+    DWORD   po = (DWORD)off;
+    DWORD   cs = (DWORD)len;
+    DWORD   wr = 0;
+    int locked = 0;
+    LPOVERLAPPED lpo = NULL;
+    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->flags & ACR_FOPEN_APPEND) {
+        LARGE_INTEGER os;
+        LARGE_INTEGER op;
+
+        EnterCriticalSection(&f->lock);
+        /* 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.
+         */
+        rc = do_lock(f, LOCKFILE_EXCLUSIVE_LOCK);
+        if (rc) {
+            ACR_THROW_IO_IF_ERR(rc);
+            LeaveCriticalSection(&f->lock);
+            return -1;
+        }
+        /* Set the position to the file end
+         */
+        os.QuadPart = 0;
+        op.QuadPart = 0;
+        if (!SetFilePointerEx(f->fd, os, &op, FILE_END)) {
+            ACR_THROW_IO_ERRNO();
+            LeaveCriticalSection(&f->lock);
+            return -1;
+        }
+        f->pos = op.QuadPart;
+        locked = 1;
+    }
+    if (f->blocking == BLK_OFF) {
+        lpo = &f->overlap;
+        if (IS_INVALID_HANDLE(lpo->hEvent))
+            lpo->hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
+        if (IS_INVALID_HANDLE(lpo->hEvent)) {
+            ACR_THROW_IO_ERRNO();
+            if (locked)
+                LeaveCriticalSection(&f->lock);
+            return -1;
+        }
+        lpo->Offset     = (DWORD)(f->pos);
+        lpo->OffsetHigh = (DWORD)(f->pos >> 32);
+    }
+    pb = (jbyte *)ACR_PointerGet(_E, ptr, &pl);
+    if (!pb) {
+        ACR_ThrowException(_E, THROW_NMARK, ACR_EX_ENULL, 0);
+        if (locked)
+            LeaveCriticalSection(&f->lock);
+        return -1;
+    }
+    if ((po + cs) > (DWORD)pl) {
+        ACR_ThrowException(_E, THROW_NMARK, ACR_EX_EINDEX, 0);
+        if (locked)
+            LeaveCriticalSection(&f->lock);
+        return -1;
+    }
+
+    f->err = 0;
+    if (WriteFile(f->fd, pb + po, cs, &wr, lpo)) {
+        /* All done. Update the position and return
+         */
+        if (wr)
+            f->pos += wr;
+        goto finally;
+    }
+    switch (f->err = GetLastError()) {
+        case ERROR_IO_PENDING:
+            if ((f->err = overlapped_wait(f, &wr)) == 0) {
+                if (wr) {
+                    f->pos += wr;
+                    goto finally;
+                }
+            }
+        break;
+        default:
+        break;
+    }
+
+finally:
+    if (locked)
+        LeaveCriticalSection(&f->lock);
+    if (wr)
+        return (jint)wr;
+    if (f->err)
+        return f->err == ACR_TIMEUP ? 0 : -1;
+    return -1;
+}
+
+ACR_IO_EXPORT_DECLARE(jint, FileSystem, write3)(ACR_JNISTDARGS,
+                                                jint file,
+                                                jobject dbb,
+                                                jlong off,
+                                                jlong len)
+{
+#if defined(_DEBUG)
+    DWORD   pl;
+#endif
+    jbyte  *pb;
+    DWORD   rc;
+    DWORD   po = (DWORD)off;
+    DWORD   cs = (DWORD)len;
+    DWORD   wr = 0;
+    int locked = 0;
+    LPOVERLAPPED lpo = NULL;
+    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->flags & ACR_FOPEN_APPEND) {
+        LARGE_INTEGER os;
+        LARGE_INTEGER op;
+
+        EnterCriticalSection(&f->lock);
+        /* 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.
+         */
+        rc = do_lock(f, LOCKFILE_EXCLUSIVE_LOCK);
+        if (rc) {
+            ACR_THROW_IO_IF_ERR(rc);
+            LeaveCriticalSection(&f->lock);
+            return -1;
+        }
+        /* Set the position to the file end
+         */
+        os.QuadPart = 0;
+        op.QuadPart = 0;
+        if (!SetFilePointerEx(f->fd, os, &op, FILE_END)) {
+            ACR_THROW_IO_ERRNO();
+            LeaveCriticalSection(&f->lock);
+            return -1;
+        }
+        f->pos = op.QuadPart;
+        locked = 1;
+    }
+    if (f->blocking == BLK_OFF) {
+        lpo = &f->overlap;
+        if (IS_INVALID_HANDLE(lpo->hEvent))
+            lpo->hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
+        if (IS_INVALID_HANDLE(lpo->hEvent)) {
+            ACR_THROW_IO_ERRNO();
+            if (locked)
+                LeaveCriticalSection(&f->lock);
+            return -1;
+        }
+        lpo->Offset     = (DWORD)(f->pos);
+        lpo->OffsetHigh = (DWORD)(f->pos >> 32);
+    }
+    pb = (jbyte *)(*_E)->GetDirectBufferAddress(_E, dbb);
+    if (!pb) {
+        ACR_ThrowException(_E, THROW_NMARK, ACR_EX_ENULL, 0);
+        if (locked)
+            LeaveCriticalSection(&f->lock);
+        return -1;
+    }
+#if defined(_DEBUG)
+    pl = (DWORD)(*_E)->GetDirectBufferCapacity(_E, dbb);
+    if ((po + cs) > pl) {
+        ACR_ThrowException(_E, THROW_NMARK, ACR_EX_EINDEX, 0);
+        if (locked)
+            LeaveCriticalSection(&f->lock);
+        return -1;
+    }
+#endif
+    f->err = 0;
+    if (WriteFile(f->fd, pb + po, cs, &wr, lpo)) {
+        /* All done. Update the position and return
+         */
+        if (wr)
+            f->pos += wr;
+        goto finally;
+    }
+    switch (f->err = GetLastError()) {
+        case ERROR_IO_PENDING:
+            if ((f->err = overlapped_wait(f, &wr)) == 0) {
+                if (wr) {
+                    f->pos += wr;
+                    goto finally;
+                }
+            }
+        break;
+        default:
+        break;
+    }
+
+finally:
+    if (locked)
+        LeaveCriticalSection(&f->lock);
+    if (wr)
+        return (jint)wr;
+    if (f->err)
+        return f->err == ACR_TIMEUP ? 0 : -1;
+    return -1;
+}
+
+ACR_IO_EXPORT_DECLARE(jint, FileSystem, write4)(ACR_JNISTDARGS,
+                                                jint file,
+                                                jobjectArray vec,
+                                                jint off,
+                                                jint len)
+{
+    DWORD   i;
+    DWORD   pl;
+    DWORD   rc;
+    DWORD   wr;
+    DWORD   po = (DWORD)off;
+    DWORD   cs = (DWORD)len;
+    jbyteArray bae;
+    jbyte     *bab;
+    DWORD      bal;
+    int   locked = 0;
+    DWORD nbytes = 0;
+    LPOVERLAPPED lpo = NULL;
+    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 = (DWORD)(*_E)->GetArrayLength(_E, vec);
+    if ((po + cs) > pl) {
+        ACR_ThrowException(_E, THROW_NMARK, ACR_EX_EINDEX, 0);
+        return -1;
+    }
+    if ((*_E)->EnsureLocalCapacity(_E, (jint)(cs * 2)))
+        return -1;
+    if (f->flags & ACR_FOPEN_APPEND) {
+        LARGE_INTEGER os;
+        LARGE_INTEGER op;
+
+        EnterCriticalSection(&f->lock);
+        /* 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.
+         */
+        rc = do_lock(f, LOCKFILE_EXCLUSIVE_LOCK);
+        if (rc) {
+            ACR_THROW_IO_IF_ERR(rc);
+            LeaveCriticalSection(&f->lock);
+            return -1;
+        }
+        /* Set the position to the file end
+         */
+        os.QuadPart = 0;
+        op.QuadPart = 0;
+        if (!SetFilePointerEx(f->fd, os, &op, FILE_END)) {
+            ACR_THROW_IO_ERRNO();
+            LeaveCriticalSection(&f->lock);
+            return -1;
+        }
+        f->pos = op.QuadPart;
+        locked = 1;
+    }
+    if (f->blocking == BLK_OFF) {
+        lpo = &f->overlap;
+        if (IS_INVALID_HANDLE(lpo->hEvent))
+            lpo->hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
+        if (IS_INVALID_HANDLE(lpo->hEvent)) {
+            ACR_THROW_IO_ERRNO();
+            if (locked)
+                LeaveCriticalSection(&f->lock);
+            return -1;
+        }
+    }
+
+    f->err = 0;
+    for (i = 0; i < cs, f->err == 0; i++) {
+        bae = (*_E)->GetObjectArrayElement(_E, vec, (jsize)(i + po));
+        bal = (DWORD)(*_E)->GetArrayLength(_E, bae);
+        bab = (*_E)->GetByteArrayElements(_E, bae, NULL);
+        if (lpo) {
+            lpo->Offset     = (DWORD)(f->pos);
+            lpo->OffsetHigh = (DWORD)(f->pos >> 32);
+        }
+        wr = 0;
+        if (WriteFile(f->fd, bab, bal, &wr, lpo)) {
+            /* All done. Update the position and return
+             */
+            if (wr) {
+                f->pos += wr;
+                nbytes += wr;
+            }
+        }
+        else {
+            switch (f->err = GetLastError()) {
+                case ERROR_IO_PENDING:
+                    if ((f->err = overlapped_wait(f, &wr)) == 0) {
+                        if (wr) {
+                            f->pos += wr;
+                            nbytes += wr;
+                        }
+                    }
+                break;
+                default:
+                break;
+            }
+        }
+        (*_E)->ReleaseByteArrayElements(_E, bae, bab, JNI_ABORT);
+    }
+
+    if (locked)
+        LeaveCriticalSection(&f->lock);
+    if (nbytes)
+        return (jint)nbytes;
+    if (f->err)
+        return f->err == ACR_TIMEUP ? 0 : -1;
+    return -1;
+}
+
+ACR_IO_EXPORT_DECLARE(jint, FileSystem, write5)(ACR_JNISTDARGS,
+                                                jint file,
+                                                jobjectArray vec,
+                                                jint off,
+                                                jint len)
+{
+    DWORD   i;
+    DWORD   pl;
+    DWORD   rc;
+    DWORD   wr;
+    DWORD   po = (DWORD)off;
+    DWORD   cs = (DWORD)len;
+    jobject bbe;
+    void   *bbb;
+    DWORD   bbl;
+    int   locked = 0;
+    DWORD nbytes = 0;
+    LPOVERLAPPED lpo = NULL;
+    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 = (DWORD)(*_E)->GetArrayLength(_E, vec);
+    if ((po + cs) > pl) {
+        ACR_ThrowException(_E, THROW_NMARK, ACR_EX_EINDEX, 0);
+        return -1;
+    }
+    if ((*_E)->EnsureLocalCapacity(_E, (jint)(cs * 2)))
+        return -1;
+    if (f->flags & ACR_FOPEN_APPEND) {
+        LARGE_INTEGER os;
+        LARGE_INTEGER op;
+
+        EnterCriticalSection(&f->lock);
+        /* 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.
+         */
+        rc = do_lock(f, LOCKFILE_EXCLUSIVE_LOCK);
+        if (rc) {
+            ACR_THROW_IO_IF_ERR(rc);
+            LeaveCriticalSection(&f->lock);
+            return -1;
+        }
+        /* Set the position to the file end
+         */
+        os.QuadPart = 0;
+        op.QuadPart = 0;
+        if (!SetFilePointerEx(f->fd, os, &op, FILE_END)) {
+            ACR_THROW_IO_ERRNO();
+            LeaveCriticalSection(&f->lock);
+            return -1;
+        }
+        f->pos = op.QuadPart;
+        locked = 1;
+    }
+    if (f->blocking == BLK_OFF) {
+        lpo = &f->overlap;
+        if (IS_INVALID_HANDLE(lpo->hEvent))
+            lpo->hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
+        if (IS_INVALID_HANDLE(lpo->hEvent)) {
+            ACR_THROW_IO_ERRNO();
+            if (locked)
+                LeaveCriticalSection(&f->lock);
+            return -1;
+        }
+    }
+
+    f->err = 0;
+    for (i = 0; i < cs, f->err == 0; i++) {
+        bbe = (*_E)->GetObjectArrayElement(_E, vec, (jsize)(i + po));
+        bbl = (DWORD)(*_E)->GetDirectBufferCapacity(_E, bbe);
+        bbb = (*_E)->GetDirectBufferAddress(_E, bbe);
+        (*_E)->DeleteLocalRef(_E, bbe);
+
+        if (lpo) {
+            lpo->Offset     = (DWORD)(f->pos);
+            lpo->OffsetHigh = (DWORD)(f->pos >> 32);
+        }
+        wr = 0;
+        if (WriteFile(f->fd, bbb, bbl, &wr, lpo)) {
+            /* All done. Update the position and return
+             */
+            if (wr) {
+                f->pos += wr;
+                nbytes += wr;
+            }
+        }
+        else {
+            switch (f->err = GetLastError()) {
+                case ERROR_IO_PENDING:
+                    if ((f->err = overlapped_wait(f, &wr)) == 0) {
+                        if (wr) {
+                            f->pos += wr;
+                            nbytes += wr;
+                        }
+                    }
+                break;
+                default:
+                break;
+            }
+        }
+    }
+
+    if (locked)
+        LeaveCriticalSection(&f->lock);
+    if (nbytes)
+        return (jint)nbytes;
+    if (f->err)
+        return f->err == ACR_TIMEUP ? 0 : -1;
+    return -1;
+}