blob: a5ec8b7a8850d6bb0f69f233d5641b27ec5936f9 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 "JNIHelp.h"
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <assert.h>
#include <sys/ioctl.h>
/*
* These are JNI field IDs for the stuff we're interested in. They're
* computed when the class is loaded.
*/
static struct {
jfieldID descriptor; /* int */
jmethodID constructorInt;
jmethodID setFD;
jclass clazz;
} gCachedFields;
/*
* Internal helper function.
*
* Get the file descriptor.
*/
static inline int getFd(JNIEnv* env, jobject obj)
{
return (*env)->GetIntField(env, obj, gCachedFields.descriptor);
}
/*
* Internal helper function.
*
* Set the file descriptor.
*/
static inline void setFd(JNIEnv* env, jobject obj, jint value)
{
(*env)->SetIntField(env, obj, gCachedFields.descriptor, value);
}
/*
* native private static void nativeClassInit()
*
* Perform one-time initialization. If the class is unloaded and re-loaded,
* this will be called again.
*/
static void nativeClassInit(JNIEnv* env, jclass clazz)
{
gCachedFields.clazz = (*env)->NewGlobalRef(env, clazz);
gCachedFields.descriptor =
(*env)->GetFieldID(env, clazz, "descriptor", "I");
if(gCachedFields.descriptor == NULL) {
jniThrowException(env, "java/lang/NoSuchFieldError", "FileDescriptor");
return;
}
gCachedFields.constructorInt =
(*env)->GetMethodID(env, clazz, "<init>", "()V");
if(gCachedFields.constructorInt == NULL) {
jniThrowException(env, "java/lang/NoSuchMethodError", "<init>()V");
return;
}
}
/*
* public native void sync()
*/
static void fd_sync(JNIEnv* env, jobject obj) {
int fd = getFd(env, obj);
if (fsync(fd) != 0) {
/*
* If fd is a socket, then fsync(fd) is defined to fail with
* errno EINVAL. This isn't actually cause for concern.
* TODO: Look into not bothering to call fsync() at all if
* we know we are dealing with a socket.
*/
if (errno != EINVAL) {
jniThrowException(env, "java/io/SyncFailedException", "");
}
}
}
/*
* public native boolean valid()
*/
static jboolean fd_valid(JNIEnv* env, jobject obj) {
int fd = getFd(env, obj);
struct stat sb;
if(fstat(fd, &sb) == 0) {
return JNI_TRUE;
} else {
return JNI_FALSE;
}
}
/* checks to see if class is inited and inits if needed, returning -1
* on fail and 0 on success
*/
static int checkClassInit (JNIEnv *env) {
if(gCachedFields.clazz == NULL) {
/* this should cause the class to be inited and
* our static variables to be filled in
*
* (Note that FindClass just loads the class; it doesn't get
* initialized until we try to do something with it.)
*/
jclass clazz;
clazz = (*env)->FindClass(env, "java/io/FileDescriptor");
if(clazz == NULL) {
jniThrowException(env, "java/lang/ClassNotFoundException",
"java.io.FileDescriptor");
return -1;
}
jfieldID readWriteId;
readWriteId = (*env)->GetStaticFieldID(env, clazz, "in",
"Ljava/io/FileDescriptor;");
if(readWriteId == NULL) {
jniThrowException(env, "java/lang/NoSuchFieldException",
"FileDescriptor.readOnly(Z)");
return -1;
}
(void) (*env)->GetStaticObjectField(env, clazz, readWriteId);
}
return 0;
}
/*
* For JNIHelp.c
* Create a java.io.FileDescriptor given an integer fd
*/
jobject jniCreateFileDescriptor (JNIEnv *env, int fd) {
jobject ret;
/* the class may not have been loaded yet */
if(checkClassInit(env) < 0) {
return NULL;
}
ret = (*env)->NewObject(env, gCachedFields.clazz,
gCachedFields.constructorInt);
(*env)->SetIntField(env, ret, gCachedFields.descriptor, fd);
return ret;
}
/*
* For JNIHelp.c
* Get an int file descriptor from a java.io.FileDescriptor
*/
int jniGetFDFromFileDescriptor (JNIEnv* env, jobject fileDescriptor) {
/* should already be initialized if it's an actual FileDescriptor */
assert(fileDescriptor != NULL);
assert(gCachedFields.clazz != NULL);
return getFd(env, fileDescriptor);
}
/*
* For JNIHelp.c
* Set the descriptor of a java.io.FileDescriptor
*/
void jniSetFileDescriptorOfFD (JNIEnv* env, jobject fileDescriptor, int value) {
/* should already be initialized if it's an actual FileDescriptor */
assert(fileDescriptor != NULL);
assert(gCachedFields.clazz != NULL);
setFd(env, fileDescriptor, value);
}
/*
* JNI registration
*/
static JNINativeMethod gMethods[] = {
/* name, signature, funcPtr */
{ "oneTimeInitialization", "()V", nativeClassInit },
{ "syncImpl", "()V", fd_sync },
{ "valid", "()Z", fd_valid }
};
int register_java_io_FileDescriptor(JNIEnv* env) {
return jniRegisterNativeMethods(env, "java/io/FileDescriptor",
gMethods, NELEM(gMethods));
}