1/*
2 * Copyright (c) 2001, 2018, 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#include "jni.h"
26#include "jni_util.h"
27#include "jvm.h"
28#include "io_util.h"
29#include "io_util_md.h"
30#include <string.h>
31#include <unistd.h>
32
33#ifdef __solaris__
34#include <sys/filio.h>
35#endif
36
37#if defined(__linux__) || defined(_ALLBSD_SOURCE) || defined(_AIX)
38#include <sys/ioctl.h>
39#endif
40
41#ifdef MACOSX
42
43#include <CoreFoundation/CoreFoundation.h>
44
45__private_extern__
46jstring newStringPlatform(JNIEnv *env, const char* str)
47{
48 jstring rv = NULL;
49 CFMutableStringRef csref = CFStringCreateMutable(NULL, 0);
50 if (csref == NULL) {
51 JNU_ThrowOutOfMemoryError(env, "native heap");
52 } else {
53 CFStringAppendCString(csref, str, kCFStringEncodingUTF8);
54 CFStringNormalize(csref, kCFStringNormalizationFormC);
55 int clen = CFStringGetLength(csref);
56 int ulen = (clen + 1) * 2; // utf16 + zero padding
57 char* chars = malloc(ulen);
58 if (chars == NULL) {
59 CFRelease(csref);
60 JNU_ThrowOutOfMemoryError(env, "native heap");
61 } else {
62 if (CFStringGetCString(csref, chars, ulen, kCFStringEncodingUTF16)) {
63 rv = (*env)->NewString(env, (jchar*)chars, clen);
64 }
65 free(chars);
66 CFRelease(csref);
67 }
68 }
69 return rv;
70}
71#endif
72
73FD
74handleOpen(const char *path, int oflag, int mode) {
75 FD fd;
76 RESTARTABLE(open64(path, oflag, mode), fd);
77 if (fd != -1) {
78 struct stat64 buf64;
79 int result;
80 RESTARTABLE(fstat64(fd, &buf64), result);
81 if (result != -1) {
82 if (S_ISDIR(buf64.st_mode)) {
83 close(fd);
84 errno = EISDIR;
85 fd = -1;
86 }
87 } else {
88 close(fd);
89 fd = -1;
90 }
91 }
92 return fd;
93}
94
95void
96fileOpen(JNIEnv *env, jobject this, jstring path, jfieldID fid, int flags)
97{
98 WITH_PLATFORM_STRING(env, path, ps) {
99 FD fd;
100
101#if defined(__linux__) || defined(_ALLBSD_SOURCE)
102 /* Remove trailing slashes, since the kernel won't */
103 char *p = (char *)ps + strlen(ps) - 1;
104 while ((p > ps) && (*p == '/'))
105 *p-- = '\0';
106#endif
107 fd = handleOpen(ps, flags, 0666);
108 if (fd != -1) {
109 jobject fdobj;
110 jboolean append;
111 SET_FD(this, fd, fid);
112
113 fdobj = (*env)->GetObjectField(env, this, fid);
114 if (fdobj != NULL) {
115 append = (flags & O_APPEND) == 0 ? JNI_FALSE : JNI_TRUE;
116 (*env)->SetBooleanField(env, fdobj, IO_append_fdID, append);
117 }
118 } else {
119 throwFileNotFoundException(env, path);
120 }
121 } END_PLATFORM_STRING(env, ps);
122}
123
124// Function to close the fd held by this FileDescriptor and set fd to -1.
125void
126fileDescriptorClose(JNIEnv *env, jobject this)
127{
128 FD fd = (*env)->GetIntField(env, this, IO_fd_fdID);
129 if ((*env)->ExceptionOccurred(env)) {
130 return;
131 }
132
133 if (fd == -1) {
134 return; // already closed and set to -1
135 }
136
137 /* Set the fd to -1 before closing it so that the timing window
138 * of other threads using the wrong fd (closed but recycled fd,
139 * that gets re-opened with some other filename) is reduced.
140 * Practically the chance of its occurance is low, however, we are
141 * taking extra precaution over here.
142 */
143 (*env)->SetIntField(env, this, IO_fd_fdID, -1);
144 if ((*env)->ExceptionOccurred(env)) {
145 return;
146 }
147 /*
148 * Don't close file descriptors 0, 1, or 2. If we close these stream
149 * then a subsequent file open or socket will use them. Instead we
150 * just redirect these file descriptors to /dev/null.
151 */
152 if (fd >= STDIN_FILENO && fd <= STDERR_FILENO) {
153 int devnull = open("/dev/null", O_WRONLY);
154 if (devnull < 0) {
155 (*env)->SetIntField(env, this, IO_fd_fdID, fd);
156 JNU_ThrowIOExceptionWithLastError(env, "open /dev/null failed");
157 } else {
158 dup2(devnull, fd);
159 close(devnull);
160 }
161 } else if (close(fd) == -1) {
162 JNU_ThrowIOExceptionWithLastError(env, "close failed");
163 }
164}
165
166ssize_t
167handleRead(FD fd, void *buf, jint len)
168{
169 ssize_t result;
170 RESTARTABLE(read(fd, buf, len), result);
171 return result;
172}
173
174ssize_t
175handleWrite(FD fd, const void *buf, jint len)
176{
177 ssize_t result;
178 RESTARTABLE(write(fd, buf, len), result);
179 return result;
180}
181
182jint
183handleAvailable(FD fd, jlong *pbytes)
184{
185 int mode;
186 struct stat64 buf64;
187 jlong size = -1, current = -1;
188
189 int result;
190 RESTARTABLE(fstat64(fd, &buf64), result);
191 if (result != -1) {
192 mode = buf64.st_mode;
193 if (S_ISCHR(mode) || S_ISFIFO(mode) || S_ISSOCK(mode)) {
194 int n;
195 int result;
196 RESTARTABLE(ioctl(fd, FIONREAD, &n), result);
197 if (result >= 0) {
198 *pbytes = n;
199 return 1;
200 }
201 } else if (S_ISREG(mode)) {
202 size = buf64.st_size;
203 }
204 }
205
206 if ((current = lseek64(fd, 0, SEEK_CUR)) == -1) {
207 return 0;
208 }
209
210 if (size < current) {
211 if ((size = lseek64(fd, 0, SEEK_END)) == -1)
212 return 0;
213 else if (lseek64(fd, current, SEEK_SET) == -1)
214 return 0;
215 }
216
217 *pbytes = size - current;
218 return 1;
219}
220
221jint
222handleSetLength(FD fd, jlong length)
223{
224 int result;
225 RESTARTABLE(ftruncate64(fd, length), result);
226 return result;
227}
228
229jlong
230handleGetLength(FD fd)
231{
232 struct stat64 sb;
233 if (fstat64(fd, &sb) == 0) {
234 return sb.st_size;
235 } else {
236 return -1;
237 }
238}
239