FileInputStream.c revision 240109a2df3fb0699cdaf919b490d34668814a4e
1/*
2 * Copyright (c) 1997, 2007, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26#include <sys/ioctl.h>
27#include <sys/types.h>
28#include <sys/stat.h>
29#include <fcntl.h>
30#include <unistd.h>
31#include "jni.h"
32#include "jni_util.h"
33#include "jlong.h"
34#include "io_util.h"
35#include "io_util_md.h"
36
37#include "jvm.h"
38
39
40#include <fcntl.h>
41#include <limits.h>
42
43#include "io_util_md.h"
44#include "JNIHelp.h"
45
46#define NATIVE_METHOD(className, functionName, signature) \
47{ #functionName, signature, (void*)(className ## _ ## functionName) }
48
49/*******************************************************************/
50/*  BEGIN JNI ********* BEGIN JNI *********** BEGIN JNI ************/
51/*******************************************************************/
52
53jfieldID fis_fd; /* id for jobject 'fd' in java.io.FileInputStream */
54
55/**************************************************************
56 * static methods to store field ID's in initializers
57 */
58
59JNIEXPORT void JNICALL
60FileInputStream_initIDs(JNIEnv *env, jclass fdClass) {
61    fis_fd = (*env)->GetFieldID(env, fdClass, "fd", "Ljava/io/FileDescriptor;");
62}
63
64/**************************************************************
65 * Input stream
66 */
67
68JNIEXPORT void JNICALL
69FileInputStream_open(JNIEnv *env, jobject this, jstring path) {
70    fileOpen(env, this, path, fis_fd, O_RDONLY);
71}
72
73JNIEXPORT jint JNICALL
74FileInputStream_read0(JNIEnv *env, jobject this) {
75    return readSingle(env, this, fis_fd);
76}
77
78JNIEXPORT jint JNICALL
79FileInputStream_readBytes(JNIEnv *env, jobject this,
80        jbyteArray bytes, jint off, jint len) {
81    return readBytes(env, this, bytes, off, len, fis_fd);
82}
83
84JNIEXPORT jlong JNICALL
85FileInputStream_skip0(JNIEnv *env, jobject this, jlong toSkip) {
86    jlong cur = jlong_zero;
87    jlong end = jlong_zero;
88    FD fd = GET_FD(this, fis_fd);
89    if (fd == -1) {
90        JNU_ThrowIOException (env, "Stream Closed");
91        return 0;
92    }
93    if ((cur = IO_Lseek(fd, (jlong)0, (jint)SEEK_CUR)) == -1) {
94      if (errno == ESPIPE) {
95        JNU_ThrowByName(env, "java/io/FileInputStream$UseManualSkipException", NULL);
96      } else {
97        JNU_ThrowIOExceptionWithLastError(env, "Seek error");
98      }
99    } else if ((end = IO_Lseek(fd, toSkip, (jint)SEEK_CUR)) == -1) {
100        JNU_ThrowIOExceptionWithLastError(env, "Seek error");
101    }
102    return (end - cur);
103}
104
105static int available(int fd, jlong *bytes) {
106  int n;
107  // Unlike the original OpenJdk implementation, we use FIONREAD for all file
108  // types. For regular files, this is specified to return the difference
109  // between the current position and the file size. Note that this can be
110  // negative if we're positioned past the end of the file. We must return 0
111  // in that case.
112  if (ioctl(fd, FIONREAD, &n) != -1) {
113    if (n < 0) {
114      n = 0;
115    }
116    *bytes = n;
117    return 1;
118  }
119
120  // FIONREAD is specified to return ENOTTY when fd refers to a file
121  // type for which this ioctl isn't implemented.
122  if (errno == ENOTTY) {
123    *bytes = 0;
124    return 1;
125  }
126
127  // Raise an exception for all other error types.
128  return 0;
129}
130
131JNIEXPORT jint JNICALL
132FileInputStream_available0(JNIEnv *env, jobject this) {
133    jlong ret;
134    FD fd = GET_FD(this, fis_fd);
135    if (fd == -1) {
136        JNU_ThrowIOException (env, "Stream Closed");
137        return 0;
138    }
139    if (available(fd, &ret)) {
140        if (ret > INT_MAX) {
141            ret = (jlong) INT_MAX;
142        }
143        return jlong_to_jint(ret);
144    }
145    JNU_ThrowIOExceptionWithLastError(env, NULL);
146    return 0;
147}
148
149JNIEXPORT void JNICALL
150FileInputStream_close0(JNIEnv *env, jobject this) {
151    fileClose(env, this, fis_fd);
152}
153
154static JNINativeMethod gMethods[] = {
155  NATIVE_METHOD(FileInputStream, initIDs, "()V"),
156  NATIVE_METHOD(FileInputStream, open, "(Ljava/lang/String;)V"),
157  NATIVE_METHOD(FileInputStream, skip0, "(J)J"),
158  NATIVE_METHOD(FileInputStream, available0, "()I"),
159  //NATIVE_METHOD(FileInputStream, read0, "()I"),
160  //NATIVE_METHOD(FileInputStream, readBytes, "([BII)I"),
161  //NATIVE_METHOD(FileInputStream, close0, "()V"),
162};
163
164void register_java_io_FileInputStream(JNIEnv* env) {
165  jniRegisterNativeMethods(env, "java/io/FileInputStream", gMethods, NELEM(gMethods));
166}
167