summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--luni-kernel/src/main/native/java_lang_ProcessManager.c3
-rw-r--r--luni/src/main/java/org/apache/harmony/luni/platform/OSFileSystem.java164
-rw-r--r--luni/src/main/native/org_apache_harmony_luni_platform_OSFileSystem.cpp649
-rw-r--r--luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp7
-rw-r--r--luni/src/test/java/tests/api/java/io/FileTest.java3
-rw-r--r--luni/src/test/java/tests/api/java/io/RandomAccessFileTest.java30
-rw-r--r--nio/src/test/java/org/apache/harmony/nio/tests/java/nio/channels/FileChannelTest.java19
7 files changed, 304 insertions, 571 deletions
diff --git a/luni-kernel/src/main/native/java_lang_ProcessManager.c b/luni-kernel/src/main/native/java_lang_ProcessManager.c
index eaefc9f..46e78f5 100644
--- a/luni-kernel/src/main/native/java_lang_ProcessManager.c
+++ b/luni-kernel/src/main/native/java_lang_ProcessManager.c
@@ -64,8 +64,7 @@ static void java_lang_ProcessManager_close(JNIEnv* env,
jclass clazz, jobject javaDescriptor) {
int fd = (*env)->GetIntField(env, javaDescriptor, descriptorField);
if (closeNow(fd) == -1) {
- jclass ioException = (*env)->FindClass(env, "java/io/IOException");
- (*env)->ThrowNew(env, ioException, strerror(errno));
+ jniThrowIOException(env, errno);
}
}
diff --git a/luni/src/main/java/org/apache/harmony/luni/platform/OSFileSystem.java b/luni/src/main/java/org/apache/harmony/luni/platform/OSFileSystem.java
index 08bdac6..0338a52 100644
--- a/luni/src/main/java/org/apache/harmony/luni/platform/OSFileSystem.java
+++ b/luni/src/main/java/org/apache/harmony/luni/platform/OSFileSystem.java
@@ -69,7 +69,7 @@ class OSFileSystem implements IFileSystem {
* Note that this value for Windows differs from the one for the
* page size (64K and 4K respectively).
*/
- public native int getAllocGranularity() throws IOException;
+ public native int getAllocGranularity();
public boolean lock(int fileDescriptor, long start, long length, int type,
boolean waitFlag) throws IOException {
@@ -79,160 +79,71 @@ class OSFileSystem implements IFileSystem {
return result != -1;
}
- private native int unlockImpl(int fileDescriptor, long start, long length);
+ // BEGIN android-changed
+ private native void unlockImpl(int fileDescriptor, long start, long length) throws IOException;
public void unlock(int fileDescriptor, long start, long length)
throws IOException {
// Validate arguments
validateLockArgs(IFileSystem.SHARED_LOCK_TYPE, start, length);
- int result = unlockImpl(fileDescriptor, start, length);
- if (result == -1) {
- throw new IOException();
- }
+ unlockImpl(fileDescriptor, start, length);
}
- private native int fflushImpl(int fd, boolean metadata);
-
- public void fflush(int fileDescriptor, boolean metadata)
- throws IOException {
- int result = fflushImpl(fileDescriptor, metadata);
- if (result == -1) {
- throw new IOException();
- }
- }
+ public native void fflush(int fileDescriptor, boolean metadata) throws IOException;
/*
* File position seeking.
*/
-
- private native long seekImpl(int fd, long offset, int whence);
-
- public long seek(int fileDescriptor, long offset, int whence)
- throws IOException {
- long pos = seekImpl(fileDescriptor, offset, whence);
- if (pos == -1) {
- throw new IOException();
- }
- return pos;
- }
+ public native long seek(int fd, long offset, int whence) throws IOException;
/*
* Direct read/write APIs work on addresses.
*/
- private native long readDirectImpl(int fileDescriptor, int address,
- int offset, int length);
-
- public long readDirect(int fileDescriptor, int address, int offset,
- int length) throws IOException {
- long bytesRead = readDirectImpl(fileDescriptor, address, offset, length);
- if (bytesRead < -1) {
- throw new IOException();
- }
- return bytesRead;
- }
+ public native long readDirect(int fileDescriptor, int address, int offset, int length);
- private native long writeDirectImpl(int fileDescriptor, int address,
- int offset, int length);
-
- public long writeDirect(int fileDescriptor, int address, int offset,
- int length) throws IOException {
- long bytesWritten = writeDirectImpl(fileDescriptor, address, offset,
- length);
- if (bytesWritten < 0) {
- throw new IOException();
- }
- return bytesWritten;
- }
+ public native long writeDirect(int fileDescriptor, int address, int offset, int length)
+ throws IOException;
/*
* Indirect read/writes work on byte[]'s
*/
private native long readImpl(int fileDescriptor, byte[] bytes, int offset,
- int length);
+ int length) throws IOException;
public long read(int fileDescriptor, byte[] bytes, int offset, int length)
throws IOException {
if (bytes == null) {
throw new NullPointerException();
}
- long bytesRead = readImpl(fileDescriptor, bytes, offset, length);
- if (bytesRead < -1) {
- /*
- * TODO: bytesRead is never less than -1 so this code
- * does nothing?
- * The native code throws an exception in only one case
- * so perhaps this should be 'bytesRead < 0' to handle
- * any other cases. But the other cases have been
- * ignored until now so fixing this could break things
- */
- throw new IOException();
- }
- return bytesRead;
+ return readImpl(fileDescriptor, bytes, offset, length);
}
private native long writeImpl(int fileDescriptor, byte[] bytes,
- int offset, int length);
+ int offset, int length) throws IOException;
public long write(int fileDescriptor, byte[] bytes, int offset, int length)
throws IOException {
- long bytesWritten = writeImpl(fileDescriptor, bytes, offset, length);
- if (bytesWritten < 0) {
- throw new IOException();
+ if (bytes == null) {
+ throw new NullPointerException();
}
- return bytesWritten;
+ return writeImpl(fileDescriptor, bytes, offset, length);
}
+ // END android-changed
/*
* Scatter/gather calls.
*/
- public long readv(int fileDescriptor, int[] addresses, int[] offsets,
- int[] lengths, int size) throws IOException {
- long bytesRead = readvImpl(fileDescriptor, addresses, offsets, lengths,
- size);
- if (bytesRead < -1) {
- throw new IOException();
- }
- return bytesRead;
- }
-
- private native long readvImpl(int fileDescriptor, int[] addresses,
- int[] offsets, int[] lengths, int size);
+ public native long readv(int fileDescriptor, int[] addresses,
+ int[] offsets, int[] lengths, int size) throws IOException;
- public long writev(int fileDescriptor, int[] addresses, int[] offsets,
- int[] lengths, int size) throws IOException {
- long bytesWritten = writevImpl(fileDescriptor, addresses, offsets,
- lengths, size);
- if (bytesWritten < 0) {
- throw new IOException();
- }
- return bytesWritten;
- }
-
- private native long writevImpl(int fileDescriptor, int[] addresses,
- int[] offsets, int[] lengths, int size);
-
- private native int closeImpl(int fileDescriptor);
-
- /*
- * (non-Javadoc)
- *
- * @see org.apache.harmony.luni.platform.IFileSystem#close(long)
- */
- public void close(int fileDescriptor) throws IOException {
- int rc = closeImpl(fileDescriptor);
- if (rc == -1) {
- throw new IOException();
- }
- }
+ public native long writev(int fileDescriptor, int[] addresses, int[] offsets,
+ int[] lengths, int size) throws IOException;
- public void truncate(int fileDescriptor, long size) throws IOException {
- int rc = truncateImpl(fileDescriptor, size);
- if (rc < 0) {
- throw new IOException();
- }
- }
+ // BEGIN android-changed
+ public native void close(int fileDescriptor) throws IOException;
- private native int truncateImpl(int fileDescriptor, long size);
+ public native void truncate(int fileDescriptor, long size) throws IOException;
+ // END android-changed
public int open(byte[] fileName, int mode) throws FileNotFoundException {
if (fileName == null) {
@@ -254,16 +165,10 @@ class OSFileSystem implements IFileSystem {
private native int openImpl(byte[] fileName, int mode);
- public long transfer(int fileHandler, FileDescriptor socketDescriptor,
- long offset, long count) throws IOException {
- long result = transferImpl(fileHandler, socketDescriptor, offset, count);
- if (result < 0)
- throw new IOException();
- return result;
- }
-
- private native long transferImpl(int fileHandler,
- FileDescriptor socketDescriptor, long offset, long count);
+ // BEGIN android-changed
+ public native long transfer(int fd, FileDescriptor sd, long offset, long count)
+ throws IOException;
+ // END android-changed
// BEGIN android-deleted
// public long ttyAvailable() throws IOException {
@@ -277,17 +182,16 @@ class OSFileSystem implements IFileSystem {
// private native long ttyAvailableImpl();
// END android-deleted
+ // BEGIN android-changed
public long ttyRead(byte[] bytes, int offset, int length) throws IOException {
- long nChar = ttyReadImpl(bytes, offset, length);
- // BEGIN android-changed
- if (nChar < -1) {
- throw new IOException();
+ if (bytes == null) {
+ throw new NullPointerException();
}
- // END android-changed
- return nChar;
+ return ttyReadImpl(bytes, offset, length);
}
- private native long ttyReadImpl(byte[] bytes, int offset, int length);
+ private native long ttyReadImpl(byte[] bytes, int offset, int length) throws IOException;
+ // END android-changed
// BEGIN android-added
public native int ioctlAvailable(int fileDescriptor) throws IOException;
diff --git a/luni/src/main/native/org_apache_harmony_luni_platform_OSFileSystem.cpp b/luni/src/main/native/org_apache_harmony_luni_platform_OSFileSystem.cpp
index 5614214..d32767c 100644
--- a/luni/src/main/native/org_apache_harmony_luni_platform_OSFileSystem.cpp
+++ b/luni/src/main/native/org_apache_harmony_luni_platform_OSFileSystem.cpp
@@ -14,179 +14,193 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
+// BEGIN android-note
+// This file corresponds to harmony's OSFileSystem.c and OSFileSystemLinux32.c.
+// It has been greatly simplified by the assumption that the underlying
+// platform is always Linux.
+// END android-note
+
/*
* Common natives supporting the file system interface.
*/
#define HyMaxPath 1024
-#define HyOpenRead 1 /* Values for HyFileOpen */
+
+/* Values for HyFileOpen */
+#define HyOpenRead 1
#define HyOpenWrite 2
#define HyOpenCreate 4
#define HyOpenTruncate 8
#define HyOpenAppend 16
#define HyOpenText 32
-
/* Use this flag with HyOpenCreate, if this flag is specified then
- * trying to create an existing file will fail
+ * trying to create an existing file will fail
*/
#define HyOpenCreateNew 64
-#define HyOpenSync 128
+#define HyOpenSync 128
#define SHARED_LOCK_TYPE 1L
#include "JNIHelp.h"
#include "AndroidSystemNatives.h"
-#include <string.h>
-#include <stdio.h>
+#include <assert.h>
#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
#include <stdlib.h>
+#include <sys/ioctl.h>
#include <sys/sendfile.h>
#include <sys/uio.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-typedef struct socket_struct {
- int sock;
- unsigned short family;
-} socket_struct;
+// An equivalent of the glibc macro of the same name.
+// We want to hide EINTR from Java by simply retrying directly in
+// the native code. We care about all other errors, though.
+#define EINTR_RETRY(exp) ({ \
+ typeof (exp) _rc; \
+ do { \
+ _rc = (exp); \
+ } while (_rc == -1 && errno == EINTR); \
+ _rc; })
static void convertToPlatform(char *path) {
char *pathIndex;
pathIndex = path;
while (*pathIndex != '\0') {
- if(*pathIndex == '\\') {
+ if (*pathIndex == '\\') {
*pathIndex = '/';
}
pathIndex++;
}
}
-static int
-EsTranslateOpenFlags(int flags) {
+static int EsTranslateOpenFlags(int flags) {
int realFlags = 0;
- if(flags & HyOpenAppend) {
+ if (flags & HyOpenAppend) {
realFlags |= O_APPEND;
}
- if(flags & HyOpenTruncate) {
+ if (flags & HyOpenTruncate) {
realFlags |= O_TRUNC;
}
- if(flags & HyOpenCreate) {
+ if (flags & HyOpenCreate) {
realFlags |= O_CREAT;
}
- if(flags & HyOpenCreateNew) {
+ if (flags & HyOpenCreateNew) {
realFlags |= O_EXCL | O_CREAT;
}
#ifdef O_SYNC
- if(flags & HyOpenSync) {
- realFlags |= O_SYNC;
- }
-#endif
- if(flags & HyOpenRead) {
- if(flags & HyOpenWrite) {
+ if (flags & HyOpenSync) {
+ realFlags |= O_SYNC;
+ }
+#endif
+ if (flags & HyOpenRead) {
+ if (flags & HyOpenWrite) {
return (O_RDWR | realFlags);
}
return (O_RDONLY | realFlags);
}
- if(flags & HyOpenWrite) {
+ if (flags & HyOpenWrite) {
return (O_WRONLY | realFlags);
}
return -1;
}
-/**
- * Lock the file identified by the given handle.
- * The range and lock type are given.
- */
-static jint harmony_io_lockImpl(JNIEnv * env, jobject thiz, jint handle,
- jlong start, jlong length, jint typeFlag, jboolean waitFlag) {
-
- int rc;
- int waitMode = (waitFlag) ? F_SETLKW : F_SETLK;
- struct flock lock;
+// Checks whether we can safely treat the given jlong as an off_t without
+// accidental loss of precision.
+// TODO: this is bogus; we should use _FILE_OFFSET_BITS=64.
+static bool offsetTooLarge(JNIEnv* env, jlong longOffset) {
+ if (sizeof(off_t) >= sizeof(jlong)) {
+ // We're only concerned about the possibility that off_t is
+ // smaller than jlong. off_t is signed, so we don't need to
+ // worry about signed/unsigned.
+ return false;
+ }
- memset(&lock, 0, sizeof(lock));
+ // TODO: use std::numeric_limits<off_t>::max() and min() when we have them.
+ assert(sizeof(off_t) == sizeof(int));
+ static const off_t off_t_max = INT_MAX;
+ static const off_t off_t_min = INT_MIN;
- // If start or length overflow the max values we can represent, then max them out.
- if(start > 0x7fffffffL) {
- start = 0x7fffffffL;
- }
- if(length > 0x7fffffffL) {
- length = 0x7fffffffL;
+ if (longOffset > off_t_max || longOffset < off_t_min) {
+ // "Value too large for defined data type".
+ jniThrowIOException(env, EOVERFLOW);
+ return true;
}
+ return false;
+}
+
+static jlong translateLockLength(jlong length) {
+ // FileChannel.tryLock uses Long.MAX_VALUE to mean "lock the whole
+ // file", where POSIX would use 0. We can support that special case,
+ // even for files whose actual length we can't represent. For other
+ // out of range lengths, though, we want our range checking to fire.
+ return (length == 0x7fffffffffffffffLL) ? 0 : length;
+}
+
+static struct flock flockFromStartAndLength(jlong start, jlong length) {
+ struct flock lock;
+ memset(&lock, 0, sizeof(lock));
lock.l_whence = SEEK_SET;
lock.l_start = start;
lock.l_len = length;
- if((typeFlag & SHARED_LOCK_TYPE) == SHARED_LOCK_TYPE) {
+ return lock;
+}
+
+static jint harmony_io_lockImpl(JNIEnv* env, jobject, jint handle,
+ jlong start, jlong length, jint typeFlag, jboolean waitFlag) {
+
+ length = translateLockLength(length);
+ if (offsetTooLarge(env, start) || offsetTooLarge(env, length)) {
+ return -1;
+ }
+
+ struct flock lock(flockFromStartAndLength(start, length));
+
+ if ((typeFlag & SHARED_LOCK_TYPE) == SHARED_LOCK_TYPE) {
lock.l_type = F_RDLCK;
} else {
lock.l_type = F_WRLCK;
}
- do {
- rc = fcntl(handle, waitMode, &lock);
- } while ((rc < 0) && (errno == EINTR));
-
- return (rc == -1) ? -1 : 0;
+ int waitMode = (waitFlag) ? F_SETLKW : F_SETLK;
+ return EINTR_RETRY(fcntl(handle, waitMode, &lock));
}
-/**
- * Unlocks the specified region of the file.
- */
-static jint harmony_io_unlockImpl(JNIEnv * env, jobject thiz, jint handle,
+static void harmony_io_unlockImpl(JNIEnv* env, jobject, jint handle,
jlong start, jlong length) {
- int rc;
- struct flock lock;
-
- memset(&lock, 0, sizeof(lock));
-
- // If start or length overflow the max values we can represent, then max them out.
- if(start > 0x7fffffffL) {
- start = 0x7fffffffL;
- }
- if(length > 0x7fffffffL) {
- length = 0x7fffffffL;
+ length = translateLockLength(length);
+ if (offsetTooLarge(env, start) || offsetTooLarge(env, length)) {
+ return;
}
- lock.l_whence = SEEK_SET;
- lock.l_start = start;
- lock.l_len = length;
+ struct flock lock(flockFromStartAndLength(start, length));
lock.l_type = F_UNLCK;
- do {
- rc = fcntl(handle, F_SETLKW, &lock);
- } while ((rc < 0) && (errno == EINTR));
-
- return (rc == -1) ? -1 : 0;
+ int rc = EINTR_RETRY(fcntl(handle, F_SETLKW, &lock));
+ if (rc == -1) {
+ jniThrowIOException(env, errno);
+ }
}
/**
* Returns the granularity of the starting address for virtual memory allocation.
* (It's the same as the page size.)
- * Class: org_apache_harmony_luni_platform_OSFileSystem
- * Method: getAllocGranularity
- * Signature: ()I
*/
-static jint harmony_io_getAllocGranularity(JNIEnv * env, jobject thiz) {
- static int allocGranularity = 0;
- if(allocGranularity == 0) {
- allocGranularity = getpagesize();
- }
+static jint harmony_io_getAllocGranularity(JNIEnv* env, jobject) {
+ static int allocGranularity = getpagesize();
return allocGranularity;
}
-/*
- * Class: org_apache_harmony_luni_platform_OSFileSystem
- * Method: readvImpl
- * Signature: (I[J[I[I)J
- */
-static jlong harmony_io_readvImpl(JNIEnv *env, jobject thiz, jint fd,
+static jlong harmony_io_readv(JNIEnv* env, jobject, jint fd,
jintArray jBuffers, jintArray jOffsets, jintArray jLengths, jint size) {
iovec* vectors = new iovec[size];
if (vectors == NULL) {
+ jniThrowException(env, "java/lang/OutOfMemoryError", "native heap");
return -1;
}
jint *buffers = env->GetIntArrayElements(jBuffers, NULL);
@@ -201,18 +215,17 @@ static jlong harmony_io_readvImpl(JNIEnv *env, jobject thiz, jint fd,
env->ReleaseIntArrayElements(jOffsets, offsets, JNI_ABORT);
env->ReleaseIntArrayElements(jLengths, lengths, JNI_ABORT);
delete[] vectors;
+ if (result == -1) {
+ jniThrowIOException(env, errno);
+ }
return result;
}
-/*
- * Class: org_apache_harmony_luni_platform_OSFileSystem
- * Method: writevImpl
- * Signature: (I[J[I[I)J
- */
-static jlong harmony_io_writevImpl(JNIEnv *env, jobject thiz, jint fd,
+static jlong harmony_io_writev(JNIEnv* env, jobject, jint fd,
jintArray jBuffers, jintArray jOffsets, jintArray jLengths, jint size) {
iovec* vectors = new iovec[size];
if (vectors == NULL) {
+ jniThrowException(env, "java/lang/OutOfMemoryError", "native heap");
return -1;
}
jint *buffers = env->GetIntArrayElements(jBuffers, NULL);
@@ -227,82 +240,60 @@ static jlong harmony_io_writevImpl(JNIEnv *env, jobject thiz, jint fd,
env->ReleaseIntArrayElements(jOffsets, offsets, JNI_ABORT);
env->ReleaseIntArrayElements(jLengths, lengths, JNI_ABORT);
delete[] vectors;
+ if (result == -1) {
+ jniThrowIOException(env, errno);
+ }
return result;
}
-/*
- * Class: org_apache_harmony_luni_platform_OSFileSystem
- * Method: transferImpl
- * Signature: (IJJ)J
- */
-static jlong harmony_io_transferImpl(JNIEnv *env, jobject thiz, jint fd,
- jobject sd, jlong offset, jlong count) {
-
- int socket;
- off_t off;
+static jlong harmony_io_transfer(JNIEnv* env, jobject, jint fd, jobject sd,
+ jlong offset, jlong count) {
- socket = jniGetFDFromFileDescriptor(env, sd);
- if(socket == 0 || socket == -1) {
+ int socket = jniGetFDFromFileDescriptor(env, sd);
+ if (socket == -1) {
return -1;
}
/* Value of offset is checked in jint scope (checked in java layer)
The conversion here is to guarantee no value lost when converting offset to off_t
*/
- off = offset;
+ off_t off = offset;
- return sendfile(socket,(int)fd,(off_t *)&off,(size_t)count);
+ ssize_t rc = sendfile(socket, fd, &off, count);
+ if (rc == -1) {
+ jniThrowIOException(env, errno);
+ }
+ return rc;
}
-/*
- * Class: org_apache_harmony_io
- * Method: readDirectImpl
- * Signature: (IJI)J
- */
-static jlong harmony_io_readDirectImpl(JNIEnv * env, jobject thiz, jint fd,
+static jlong harmony_io_readDirect(JNIEnv* env, jobject, jint fd,
jint buf, jint offset, jint nbytes) {
- jint result;
- if(nbytes == 0) {
- return (jlong) 0;
+ if (nbytes == 0) {
+ return 0;
}
- result = read(fd, (void *) ((jint *)(buf+offset)), (int) nbytes);
- if(result == 0) {
- return (jlong) -1;
- } else {
- return (jlong) result;
+ jbyte* dst = reinterpret_cast<jbyte*>(buf + offset);
+ jlong rc = EINTR_RETRY(read(fd, dst, nbytes));
+ if (rc == 0) {
+ return -1;
+ }
+ if (rc == -1) {
+ jniThrowIOException(env, errno);
}
+ return rc;
}
-/*
- * Class: org_apache_harmony_io
- * Method: writeDirectImpl
- * Signature: (IJI)J
- */
-static jlong harmony_io_writeDirectImpl(JNIEnv * env, jobject thiz, jint fd,
+static jlong harmony_io_writeDirect(JNIEnv* env, jobject, jint fd,
jint buf, jint offset, jint nbytes) {
-
-
- int rc = 0;
-
- /* write will just do the right thing for HYPORT_TTY_OUT and HYPORT_TTY_ERR */
- rc = write (fd, (const void *) ((jint *)(buf+offset)), (int) nbytes);
-
- if(rc == -1) {
- jniThrowException(env, "java/io/IOException", strerror(errno));
- return -2;
+ jbyte* src = reinterpret_cast<jbyte*>(buf + offset);
+ jlong rc = EINTR_RETRY(write(fd, src, nbytes));
+ if (rc == -1) {
+ jniThrowIOException(env, errno);
}
- return (jlong) rc;
-
+ return rc;
}
-// BEGIN android-changed
-/*
- * Class: org_apache_harmony_io
- * Method: readImpl
- * Signature: (I[BII)J
- */
-static jlong harmony_io_readImpl(JNIEnv * env, jobject thiz, jint fd,
+static jlong harmony_io_readImpl(JNIEnv* env, jobject, jint fd,
jbyteArray byteArray, jint offset, jint nbytes) {
if (nbytes == 0) {
@@ -310,67 +301,28 @@ static jlong harmony_io_readImpl(JNIEnv * env, jobject thiz, jint fd,
}
jbyte* bytes = env->GetByteArrayElements(byteArray, NULL);
- jlong result;
- for (;;) {
- result = read(fd, (void *) (bytes + offset), (int) nbytes);
-
- if ((result != -1) || (errno != EINTR)) {
- break;
- }
-
- /*
- * If we didn't break above, that means that the read() call
- * returned due to EINTR. We shield Java code from this
- * possibility by trying again. Note that this is different
- * from EAGAIN, which should result in this code throwing
- * an InterruptedIOException.
- */
- }
-
+ jlong rc = EINTR_RETRY(read(fd, bytes + offset, nbytes));
env->ReleaseByteArrayElements(byteArray, bytes, 0);
- if (result == 0) {
+ if (rc == 0) {
return -1;
}
-
- if (result == -1) {
+ if (rc == -1) {
if (errno == EAGAIN) {
jniThrowException(env, "java/io/InterruptedIOException",
"Read timed out");
} else {
- jniThrowException(env, "java/io/IOException", strerror(errno));
+ jniThrowIOException(env, errno);
}
}
-
- return result;
+ return rc;
}
-/*
- * Class: org_apache_harmony_io
- * Method: writeImpl
- * Signature: (I[BII)J
- */
-static jlong harmony_io_writeImpl(JNIEnv * env, jobject thiz, jint fd,
+static jlong harmony_io_writeImpl(JNIEnv* env, jobject, jint fd,
jbyteArray byteArray, jint offset, jint nbytes) {
jbyte* bytes = env->GetByteArrayElements(byteArray, NULL);
- jlong result;
- for (;;) {
- result = write(fd, (const char *) bytes + offset, (int) nbytes);
-
- if ((result != -1) || (errno != EINTR)) {
- break;
- }
-
- /*
- * If we didn't break above, that means that the read() call
- * returned due to EINTR. We shield Java code from this
- * possibility by trying again. Note that this is different
- * from EAGAIN, which should result in this code throwing
- * an InterruptedIOException.
- */
- }
-
+ jlong result = EINTR_RETRY(write(fd, bytes + offset, nbytes));
env->ReleaseByteArrayElements(byteArray, bytes, JNI_ABORT);
if (result == -1) {
@@ -378,159 +330,77 @@ static jlong harmony_io_writeImpl(JNIEnv * env, jobject thiz, jint fd,
jniThrowException(env, "java/io/InterruptedIOException",
"Write timed out");
} else {
- jniThrowException(env, "java/io/IOException", strerror(errno));
+ jniThrowIOException(env, errno);
}
}
-
return result;
}
-// END android-changed
-
-/**
- * Seeks a file descriptor to a given file position.
- *
- * @param env pointer to Java environment
- * @param thiz pointer to object receiving the message
- * @param fd handle of file to be seeked
- * @param offset distance of movement in bytes relative to whence arg
- * @param whence enum value indicating from where the offset is relative
- * The valid values are defined in fsconstants.h.
- * @return the new file position from the beginning of the file, in bytes;
- * or -1 if a problem occurs.
- */
-static jlong harmony_io_seekImpl(JNIEnv * env, jobject thiz, jint fd,
- jlong offset, jint whence) {
-
- int mywhence = 0;
+static jlong harmony_io_seek(JNIEnv* env, jobject, jint fd, jlong offset,
+ jint javaWhence) {
/* Convert whence argument */
- switch (whence) {
- case 1:
- mywhence = 0;
- break;
- case 2:
- mywhence = 1;
- break;
- case 4:
- mywhence = 2;
- break;
- default:
- return -1;
+ int nativeWhence = 0;
+ switch (javaWhence) {
+ case 1:
+ nativeWhence = SEEK_SET;
+ break;
+ case 2:
+ nativeWhence = SEEK_CUR;
+ break;
+ case 4:
+ nativeWhence = SEEK_END;
+ break;
+ default:
+ return -1;
}
-
- off_t localOffset = (int) offset;
-
- if((mywhence < 0) || (mywhence > 2)) {
+ // If the offset is relative, lseek(2) will tell us whether it's too large.
+ // We're just worried about too large an absolute offset, which would cause
+ // us to lie to lseek(2).
+ if (offsetTooLarge(env, offset)) {
return -1;
}
- /* If file offsets are 32 bit, truncate the seek to that range */
- if(sizeof (off_t) < sizeof (jlong)) {
- if(offset > 0x7FFFFFFF) {
- localOffset = 0x7FFFFFFF;
- } else if(offset < -0x7FFFFFFF) {
- localOffset = -0x7FFFFFFF;
- }
+ jlong result = lseek(fd, offset, nativeWhence);
+ if (result == -1) {
+ jniThrowIOException(env, errno);
}
-
- return (jlong) lseek(fd, localOffset, mywhence);
+ return result;
}
-/**
- * Flushes a file state to disk.
- *
- * @param env pointer to Java environment
- * @param thiz pointer to object receiving the message
- * @param fd handle of file to be flushed
- * @param metadata if true also flush metadata,
- * otherwise just flush data is possible.
- * @return zero on success and -1 on failure
- *
- * Method: fflushImpl
- * Signature: (IZ)I
- */
-static jint harmony_io_fflushImpl(JNIEnv * env, jobject thiz, jint fd,
+// TODO: are we supposed to support the 'metadata' flag? (false => fdatasync.)
+static void harmony_io_fflush(JNIEnv* env, jobject, jint fd,
jboolean metadata) {
- return (jint) fsync(fd);
+ int rc = fsync(fd);
+ if (rc == -1) {
+ jniThrowIOException(env, errno);
+ }
}
-// BEGIN android-changed
-/**
- * Closes the given file handle
- *
- * @param env pointer to Java environment
- * @param thiz pointer to object receiving the message
- * @param fd handle of file to be closed
- * @return zero on success and -1 on failure
- *
- * Class: org_apache_harmony_io
- * Method: closeImpl
- * Signature: (I)I
- */
-static jint harmony_io_closeImpl(JNIEnv * env, jobject thiz, jint fd) {
- jint result;
-
- for (;;) {
- result = (jint) close(fd);
-
- if ((result != -1) || (errno != EINTR)) {
- break;
- }
-
- /*
- * If we didn't break above, that means that the close() call
- * returned due to EINTR. We shield Java code from this
- * possibility by trying again.
- */
+static jint harmony_io_close(JNIEnv* env, jobject, jint fd) {
+ jint rc = EINTR_RETRY(close(fd));
+ if (rc == -1) {
+ jniThrowIOException(env, errno);
}
-
- return result;
+ return rc;
}
-// END android-changed
-
-/*
- * Class: org_apache_harmony_io
- * Method: truncateImpl
- * Signature: (IJ)I
- */
-static jint harmony_io_truncateImpl(JNIEnv * env, jobject thiz, jint fd,
- jlong size) {
-
- int rc;
- off_t length = (off_t) size;
-
- // If file offsets are 32 bit, truncate the newLength to that range
- if(sizeof (off_t) < sizeof (jlong)) {
- if(length > 0x7FFFFFFF) {
- length = 0x7FFFFFFF;
- } else if(length < -0x7FFFFFFF) {
- length = -0x7FFFFFFF;
- }
+static jint harmony_io_truncate(JNIEnv* env, jobject, jint fd, jlong length) {
+ if (offsetTooLarge(env, length)) {
+ return -1;
}
- rc = ftruncate((int)fd, length);
-
- return (jint) rc;
-
+ int rc = ftruncate(fd, length);
+ if (rc == -1) {
+ jniThrowIOException(env, errno);
+ }
+ return rc;
}
-/*
- * Class: org_apache_harmony_io
- * Method: openImpl
- * Signature: ([BI)I
- */
-static jint harmony_io_openImpl(JNIEnv * env, jobject obj, jbyteArray path,
+static jint harmony_io_openImpl(JNIEnv* env, jobject, jbyteArray path,
jint jflags) {
-
- if (path == NULL) {
- jniThrowException(env, "java/lang/NullPointerException", NULL);
- return -1;
- }
-
int flags = 0;
- int mode = 0;
+ int mode = 0;
// BEGIN android-changed
// don't want default permissions to allow global access.
@@ -552,7 +422,7 @@ static jint harmony_io_openImpl(JNIEnv * env, jobject obj, jbyteArray path,
mode = 0600;
break;
case 256:
- flags = HyOpenWrite | HyOpenCreate | HyOpenAppend;
+ flags = HyOpenWrite | HyOpenCreate | HyOpenAppend;
mode = 0600;
break;
}
@@ -560,6 +430,7 @@ static jint harmony_io_openImpl(JNIEnv * env, jobject obj, jbyteArray path,
flags = EsTranslateOpenFlags(flags);
+ // TODO: clean this up when we clean up the java.io.File equivalent.
jsize length = env->GetArrayLength (path);
length = length < HyMaxPath - 1 ? length : HyMaxPath - 1;
char pathCopy[HyMaxPath];
@@ -567,104 +438,48 @@ static jint harmony_io_openImpl(JNIEnv * env, jobject obj, jbyteArray path,
pathCopy[length] = '\0';
convertToPlatform (pathCopy);
- int cc;
- do {
- cc = open(pathCopy, flags, mode);
- } while(cc < 0 && errno == EINTR);
-
- if(cc < 0 && errno > 0) {
+ jint cc = EINTR_RETRY(open(pathCopy, flags, mode));
+ // TODO: chase up the callers of this and check they wouldn't rather
+ // have us throw a meaningful IOException right here.
+ if (cc < 0 && errno > 0) {
cc = -errno;
}
-
return cc;
-
-
}
-// BEGIN android-deleted
-#if 0
-/*
- * Answers the number of remaining chars in the stdin.
- *
- * Class: org_apache_harmony_io
- * Method: ttyAvailableImpl
- * Signature: ()J
- */
-static jlong harmony_io_ttyAvailableImpl(JNIEnv *env, jobject thiz) {
-
- int rc;
- off_t curr, end;
-
- int avail = 0;
-
- // when redirected from a file
- curr = lseek(STDIN_FILENO, 0L, 2); /* don't use tell(), it doesn't exist on all platforms, i.e. linux */
- if(curr != -1) {
- end = lseek(STDIN_FILENO, 0L, 4);
- lseek(STDIN_FILENO, curr, 1);
- if(end >= curr) {
- return (jlong) (end - curr);
- }
- }
-
- /* ioctl doesn't work for files on all platforms (i.e. SOLARIS) */
-
- rc = ioctl (STDIN_FILENO, FIONREAD, &avail);
-
- /* 64 bit platforms use a 32 bit value, using IDATA fails on big endian */
- /* Pass in IDATA because ioctl() is device dependent, some devices may write 64 bits */
- if(rc != -1) {
- return (jlong) *(jint *) & avail;
- }
- return (jlong) 0;
-}
-#endif
-// END android-deleted
-
-// BEGIN android-added
-/*
- * Answers the number of remaining bytes in a file descriptor
- * using IOCTL.
- *
- * Class: org_apache_harmony_io
- * Method: ioctlAvailable
- * Signature: ()I
- */
-static jint harmony_io_ioctlAvailable(JNIEnv *env, jobject thiz, jint fd) {
- int avail = 0;
- int rc = ioctl(fd, FIONREAD, &avail);
-
+static jint harmony_io_ioctlAvailable(JNIEnv*env, jobject, jint fd) {
/*
* On underlying platforms Android cares about (read "Linux"),
* ioctl(fd, FIONREAD, &avail) is supposed to do the following:
- *
+ *
* If the fd refers to a regular file, avail is set to
* the difference between the file size and the current cursor.
* This may be negative if the cursor is past the end of the file.
- *
+ *
* If the fd refers to an open socket or the read end of a
* pipe, then avail will be set to a number of bytes that are
* available to be read without blocking.
- *
+ *
* If the fd refers to a special file/device that has some concept
* of buffering, then avail will be set in a corresponding way.
- *
+ *
* If the fd refers to a special device that does not have any
* concept of buffering, then the ioctl call will return a negative
* number, and errno will be set to ENOTTY.
- *
+ *
* If the fd refers to a special file masquerading as a regular file,
* then avail may be returned as negative, in that the special file
* may appear to have zero size and yet a previous read call may have
* actually read some amount of data and caused the cursor to be
* advanced.
*/
-
+ int avail = 0;
+ int rc = ioctl(fd, FIONREAD, &avail);
if (rc >= 0) {
/*
* Success, but make sure not to return a negative number (see
* above).
- */
+ */
if (avail < 0) {
avail = 0;
}
@@ -673,22 +488,13 @@ static jint harmony_io_ioctlAvailable(JNIEnv *env, jobject thiz, jint fd) {
avail = 0;
} else {
/* Something strange is happening. */
- jniThrowException(env, "java/io/IOException", strerror(errno));
- avail = 0;
- }
+ jniThrowIOException(env, errno);
+ }
return (jint) avail;
}
-// END android-added
-/*
- * Reads the number of bytes from stdin.
- *
- * Class: org_apache_harmony_io
- * Method: ttyReadImpl
- * Signature: ([BII)J
- */
-static jlong harmony_io_ttyReadImpl(JNIEnv *env, jobject thiz,
+static jlong harmony_io_ttyReadImpl(JNIEnv* env, jobject thiz,
jbyteArray byteArray, jint offset, jint nbytes) {
return harmony_io_readImpl(env, thiz, STDIN_FILENO, byteArray, offset, nbytes);
}
@@ -698,32 +504,27 @@ static jlong harmony_io_ttyReadImpl(JNIEnv *env, jobject thiz,
*/
static JNINativeMethod gMethods[] = {
/* name, signature, funcPtr */
+ { "close", "(I)V", (void*) harmony_io_close },
+ { "fflush", "(IZ)V", (void*) harmony_io_fflush },
+ { "getAllocGranularity","()I", (void*) harmony_io_getAllocGranularity },
+ { "ioctlAvailable", "(I)I", (void*) harmony_io_ioctlAvailable },
{ "lockImpl", "(IJJIZ)I", (void*) harmony_io_lockImpl },
- { "getAllocGranularity","()I", (void*) harmony_io_getAllocGranularity },
- { "unlockImpl", "(IJJ)I", (void*) harmony_io_unlockImpl },
- { "fflushImpl", "(IZ)I", (void*) harmony_io_fflushImpl },
- { "seekImpl", "(IJI)J", (void*) harmony_io_seekImpl },
- { "readDirectImpl", "(IIII)J", (void*) harmony_io_readDirectImpl },
- { "writeDirectImpl", "(IIII)J", (void*) harmony_io_writeDirectImpl },
+ { "openImpl", "([BI)I", (void*) harmony_io_openImpl },
+ { "readDirect", "(IIII)J", (void*) harmony_io_readDirect },
{ "readImpl", "(I[BII)J", (void*) harmony_io_readImpl },
+ { "readv", "(I[I[I[II)J",(void*) harmony_io_readv },
+ { "seek", "(IJI)J", (void*) harmony_io_seek },
+ { "transfer", "(ILjava/io/FileDescriptor;JJ)J",
+ (void*) harmony_io_transfer },
+ { "truncate", "(IJ)V", (void*) harmony_io_truncate },
+ { "ttyReadImpl", "([BII)J", (void*) harmony_io_ttyReadImpl },
+ { "unlockImpl", "(IJJ)V", (void*) harmony_io_unlockImpl },
+ { "writeDirect", "(IIII)J", (void*) harmony_io_writeDirect },
{ "writeImpl", "(I[BII)J", (void*) harmony_io_writeImpl },
- { "readvImpl", "(I[I[I[II)J",(void*) harmony_io_readvImpl },
- { "writevImpl", "(I[I[I[II)J",(void*) harmony_io_writevImpl },
- { "closeImpl", "(I)I", (void*) harmony_io_closeImpl },
- { "truncateImpl", "(IJ)I", (void*) harmony_io_truncateImpl },
- { "openImpl", "([BI)I", (void*) harmony_io_openImpl },
- { "transferImpl", "(ILjava/io/FileDescriptor;JJ)J",
- (void*) harmony_io_transferImpl },
- // BEGIN android-deleted
- //{ "ttyAvailableImpl", "()J", (void*) harmony_io_ttyAvailableImpl },
- // END android-deleted
- // BEGIN android-added
- { "ioctlAvailable", "(I)I", (void*) harmony_io_ioctlAvailable },
- // END android added
- { "ttyReadImpl", "([BII)J", (void*) harmony_io_ttyReadImpl }
+ { "writev", "(I[I[I[II)J",(void*) harmony_io_writev },
};
-int register_org_apache_harmony_luni_platform_OSFileSystem(JNIEnv *_env) {
- return jniRegisterNativeMethods(_env,
- "org/apache/harmony/luni/platform/OSFileSystem", gMethods,
- NELEM(gMethods));
+int register_org_apache_harmony_luni_platform_OSFileSystem(JNIEnv* _env) {
+ return jniRegisterNativeMethods(_env,
+ "org/apache/harmony/luni/platform/OSFileSystem", gMethods,
+ NELEM(gMethods));
}
diff --git a/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp b/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp
index dd96498..eede677 100644
--- a/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp
+++ b/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp
@@ -209,13 +209,6 @@ static void throwSocketException(JNIEnv *env, int errorCode) {
}
/**
- * Throws an IOException with the given message.
- */
-static void throwIOExceptionStr(JNIEnv *env, const char *message) {
- jniThrowException(env, "java/io/IOException", message);
-}
-
-/**
* Throws a NullPointerException.
*/
static void throwNullPointerException(JNIEnv *env) {
diff --git a/luni/src/test/java/tests/api/java/io/FileTest.java b/luni/src/test/java/tests/api/java/io/FileTest.java
index 2850826..5c0cb2a 100644
--- a/luni/src/test/java/tests/api/java/io/FileTest.java
+++ b/luni/src/test/java/tests/api/java/io/FileTest.java
@@ -688,10 +688,7 @@ public class FileTest extends junit.framework.TestCase {
method = "delete",
args = {}
)
- @KnownFailure("Non empty directories are deleted on Android.")
public void test_delete() {
- // this test passes in the emulator, but it fails on the device
-
// Test for method boolean java.io.File.delete()
try {
File dir = new File(System.getProperty("java.io.tmpdir"), platformId
diff --git a/luni/src/test/java/tests/api/java/io/RandomAccessFileTest.java b/luni/src/test/java/tests/api/java/io/RandomAccessFileTest.java
index 3b545e3..dc35610 100644
--- a/luni/src/test/java/tests/api/java/io/RandomAccessFileTest.java
+++ b/luni/src/test/java/tests/api/java/io/RandomAccessFileTest.java
@@ -1200,16 +1200,25 @@ public class RandomAccessFileTest extends junit.framework.TestCase {
} catch (IOException e) {
// Expected.
}
+ // BEGIN android-added
+ try {
+ // Android uses 32-bit off_t, so anything larger than a signed 32-bit int won't work.
+ raf.seek(((long) Integer.MAX_VALUE) + 1);
+ fail("Test 2: IOException expected.");
+ } catch (IOException e) {
+ // Expected.
+ }
+ // END android-added
raf.write(testString.getBytes(), 0, testLength);
raf.seek(12);
- assertEquals("Test 2: Seek failed to set file pointer.", 12,
+ assertEquals("Test 3: Seek failed to set file pointer.", 12,
raf.getFilePointer());
raf.close();
try {
raf.seek(1);
- fail("Test 1: IOException expected.");
+ fail("Test 4: IOException expected.");
} catch (IOException e) {
// Expected.
}
@@ -1296,10 +1305,21 @@ public class RandomAccessFileTest extends junit.framework.TestCase {
assertEquals("Test 7: Incorrect file length;",
testLength + 2, raf.length());
+ // BEGIN android-added
+ // Exception testing.
+ try {
+ // Android uses 32-bit off_t, so anything larger than a signed 32-bit int won't work.
+ raf.setLength(((long) Integer.MAX_VALUE) + 1);
+ fail("Test 8: IOException expected.");
+ } catch (IOException e) {
+ // Expected.
+ }
+ // END android-added
+
// Exception testing.
try {
raf.setLength(-1);
- fail("Test 8: IllegalArgumentException expected.");
+ fail("Test 9: IllegalArgumentException expected.");
} catch (IllegalArgumentException e) {
// Expected.
}
@@ -1307,7 +1327,7 @@ public class RandomAccessFileTest extends junit.framework.TestCase {
raf.close();
try {
raf.setLength(truncLength);
- fail("Test 9: IOException expected.");
+ fail("Test 10: IOException expected.");
} catch (IOException e) {
// Expected.
}
@@ -1501,4 +1521,4 @@ public class RandomAccessFileTest extends junit.framework.TestCase {
super.tearDown();
}
-} \ No newline at end of file
+}
diff --git a/nio/src/test/java/org/apache/harmony/nio/tests/java/nio/channels/FileChannelTest.java b/nio/src/test/java/org/apache/harmony/nio/tests/java/nio/channels/FileChannelTest.java
index 91d6d06..a846e70 100644
--- a/nio/src/test/java/org/apache/harmony/nio/tests/java/nio/channels/FileChannelTest.java
+++ b/nio/src/test/java/org/apache/harmony/nio/tests/java/nio/channels/FileChannelTest.java
@@ -1155,6 +1155,25 @@ public class FileChannelTest extends TestCase {
} catch (IllegalArgumentException e) {
// expected
}
+
+ // BEGIN android-added
+ // Android uses 32-bit off_t, so anything larger than a signed 32-bit int won't work...
+ // ...except for the special case of length == Long.MAX_VALUE, which is used to mean "the
+ // whole file". The special case is tested elsewhere.
+ long tooBig = ((long) Integer.MAX_VALUE) + 1;
+ try {
+ readWriteFileChannel.tryLock(tooBig, 1, false);
+ fail("should throw IOException");
+ } catch (IOException e) {
+ // expected
+ }
+ try {
+ readWriteFileChannel.tryLock(0, tooBig, false);
+ fail("should throw IOException");
+ } catch (IOException e) {
+ // expected
+ }
+ // END android-added
}
/**