1 /* 2 * Copyright (c) 1994, 2013, 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 <stdlib.h> 27 #include <string.h> 28 #include <stddef.h> 29 30 #include "jni.h" 31 #include "jni_util.h" 32 #include "jvm.h" 33 #include "io_util.h" 34 #include "io_util_md.h" 35 36 /* IO helper functions */ 37 38 jint 39 readSingle(JNIEnv *env, jobject this, jfieldID fid) { 40 jint nread; 41 char ret; 42 FD fd = GET_FD(this, fid); 43 if (fd == -1) { 44 JNU_ThrowIOException(env, "Stream Closed"); 45 return -1; 46 } 47 nread = IO_Read(fd, &ret, 1); 48 if (nread == 0) { /* EOF */ 49 return -1; 50 } else if (nread == -1) { /* error */ 51 JNU_ThrowIOExceptionWithLastError(env, "Read error"); 52 } 53 return ret & 0xFF; 54 } 55 56 /* The maximum size of a stack-allocated buffer. 57 */ 58 #define BUF_SIZE 8192 59 60 /* 61 * Returns true if the array slice defined by the given offset and length 62 * is out of bounds. 63 */ 64 static int 65 outOfBounds(JNIEnv *env, jint off, jint len, jbyteArray array) { 66 return ((off < 0) || 67 (len < 0) || 68 // We are very careful to avoid signed integer overflow, 69 // the result of which is undefined in C. 70 ((*env)->GetArrayLength(env, array) - off < len)); 71 } 72 73 jint 74 readBytes(JNIEnv *env, jobject this, jbyteArray bytes, 75 jint off, jint len, jfieldID fid) 76 { 77 jint nread; 78 char stackBuf[BUF_SIZE]; 79 char *buf = NULL; 80 FD fd; 81 82 if (IS_NULL(bytes)) { 83 JNU_ThrowNullPointerException(env, NULL); 84 return -1; 85 } 86 87 if (outOfBounds(env, off, len, bytes)) { 88 JNU_ThrowByName(env, "java/lang/IndexOutOfBoundsException", NULL); 89 return -1; 90 } 91 92 if (len == 0) { 93 return 0; 94 } else if (len > BUF_SIZE) { 95 buf = malloc(len); 96 if (buf == NULL) { 97 JNU_ThrowOutOfMemoryError(env, NULL); 98 return 0; 99 } 100 } else { 101 buf = stackBuf; 102 } 103 104 fd = GET_FD(this, fid); 105 if (fd == -1) { 106 JNU_ThrowIOException(env, "Stream Closed"); 107 nread = -1; 108 } else { 109 nread = IO_Read(fd, buf, len); 110 if (nread > 0) { 111 (*env)->SetByteArrayRegion(env, bytes, off, nread, (jbyte *)buf); 112 } else if (nread == -1) { 113 JNU_ThrowIOExceptionWithLastError(env, "Read error"); 114 } else { /* EOF */ 115 nread = -1; 116 } 117 } 118 119 if (buf != stackBuf) { 120 free(buf); 121 } 122 return nread; 123 } 124 125 jint 126 readBytesD(JNIEnv *env, jobject this, jbyteArray bytes, 127 jint off, jint len, jfieldID fid, jfieldID pgsz_id) 128 { 129 #ifdef _WIN32 130 JNU_ThrowIOException(env, "DirectIO is not supported on Windows platform!"); 131 #else 132 jint nread; 133 void *buf = NULL; 134 int delta = 0; 135 int gap = 0; 136 int newLen = 0; 137 long currentLocation; 138 long newStartLocation; 139 FD fd; 140 int pageSize; 141 if (IS_NULL(bytes)) { 142 JNU_ThrowNullPointerException(env, NULL); 143 return -1; 144 } 145 146 if (outOfBounds(env, off, len, bytes)) { 147 JNU_ThrowByName(env, "java/lang/IndexOutOfBoundsException", NULL); 148 return -1; 149 } 150 151 if (len == 0) { 152 return 0; 153 } 154 155 fd = GET_FD(this, fid); 156 pageSize = GET_PG_SIZE(this, pgsz_id); 157 158 if (fd == -1) { 159 JNU_ThrowIOException(env, "Stream Closed"); 160 return -1; 161 } else if (pageSize == -1) { 162 JNU_ThrowIOException(env, "Error getting kernel pageSize for DirectIO alligment"); 163 return -1; 164 } else { 165 currentLocation = IO_Lseek(fd, 0, SEEK_CUR); 166 167 if ((currentLocation % pageSize) != 0) { 168 newStartLocation = currentLocation / pageSize * pageSize; 169 gap = currentLocation - newStartLocation; 170 } else { 171 newStartLocation = currentLocation; 172 gap = 0; 173 } 174 IO_Lseek(fd, newStartLocation, SEEK_SET); 175 if ((len % pageSize) != 0) { 176 newLen = (len / pageSize + 1) * pageSize; 177 } else { 178 newLen = len; 179 } 180 if ((newLen - gap) < len) { 181 newLen = newLen + pageSize; 182 } 183 184 delta = newLen - len; 185 if (newLen == 0) { 186 return 0; 187 } else { 188 posix_memalign(&buf, pageSize, newLen); 189 if (buf == NULL) { 190 JNU_ThrowOutOfMemoryError(env, NULL); 191 return 0; 192 } 193 } 194 nread = IO_Read(fd, buf, newLen); 195 if (nread > 0) { 196 if (nread >= len) { 197 (*env)->SetByteArrayRegion(env, bytes, off, len, ((jbyte *)(buf) + gap)); //read in the middle of a file 198 } else { 199 (*env)->SetByteArrayRegion(env, bytes, off, (nread-gap), ((jbyte *)(buf) + gap)); //reached the end of the file 200 } 201 } else if (nread == -1) { 202 JNU_ThrowIOExceptionWithLastError(env, "Read error"); 203 } else { /*EOF*/ 204 nread = -1; 205 } 206 IO_Lseek(fd, (currentLocation + len), SEEK_SET); 207 208 free(buf); 209 if (nread != -1) { 210 if (nread >= len) { 211 return len; 212 } else { 213 return (nread - gap); 214 } 215 } else { 216 return -1; 217 } 218 } 219 #endif 220 } 221 222 void 223 writeSingle(JNIEnv *env, jobject this, jint byte, jboolean append, jfieldID fid) { 224 // Discard the 24 high-order bits of byte. See OutputStream#write(int) 225 char c = (char) byte; 226 jint n; 227 FD fd = GET_FD(this, fid); 228 if (fd == -1) { 229 JNU_ThrowIOException(env, "Stream Closed"); 230 return; 231 } 232 if (append == JNI_TRUE) { 233 n = IO_Append(fd, &c, 1); 234 } else { 235 n = IO_Write(fd, &c, 1); 236 } 237 if (n == -1) { 238 JNU_ThrowIOExceptionWithLastError(env, "Write error"); 239 } 240 } 241 242 void 243 writeBytes(JNIEnv *env, jobject this, jbyteArray bytes, 244 jint off, jint len, jboolean append, jfieldID fid) 245 { 246 jint n; 247 char stackBuf[BUF_SIZE]; 248 char *buf = NULL; 249 FD fd; 250 251 if (IS_NULL(bytes)) { 252 JNU_ThrowNullPointerException(env, NULL); 253 return; 254 } 255 256 if (outOfBounds(env, off, len, bytes)) { 257 JNU_ThrowByName(env, "java/lang/IndexOutOfBoundsException", NULL); 258 return; 259 } 260 261 if (len == 0) { 262 return; 263 } else if (len > BUF_SIZE) { 264 buf = malloc(len); 265 if (buf == NULL) { 266 JNU_ThrowOutOfMemoryError(env, NULL); 267 return; 268 } 269 } else { 270 buf = stackBuf; 271 } 272 273 (*env)->GetByteArrayRegion(env, bytes, off, len, (jbyte *)buf); 274 275 if (!(*env)->ExceptionOccurred(env)) { 276 off = 0; 277 while (len > 0) { 278 fd = GET_FD(this, fid); 279 if (fd == -1) { 280 JNU_ThrowIOException(env, "Stream Closed"); 281 break; 282 } 283 if (append == JNI_TRUE) { 284 n = IO_Append(fd, buf+off, len); 285 } else { 286 n = IO_Write(fd, buf+off, len); 287 } 288 if (n == -1) { 289 JNU_ThrowIOExceptionWithLastError(env, "Write error"); 290 break; 291 } 292 off += n; 293 len -= n; 294 } 295 } 296 if (buf != stackBuf) { 297 free(buf); 298 } 299 } 300 301 void 302 writeBytesD(JNIEnv *env, jobject this, jbyteArray bytes, 303 jint off, jint len, jboolean append, jfieldID fid, jfieldID pgsz_id) 304 { 305 #ifdef _WIN32 306 JNU_ThrowIOException(env, "DirectIO is not supported on Windows platform!"); 307 #else 308 jint n; 309 void *buf = NULL; 310 FD fd; 311 int pageSize; 312 long currentLocation; 313 314 fd = GET_FD(this, fid); 315 if (fd == -1) { 316 JNU_ThrowIOException(env, "Stream Closed"); 317 } 318 319 pageSize = GET_PG_SIZE(this, pgsz_id); 320 if (pageSize == -1) { 321 JNU_ThrowIOException(env, "Error getting kernel pageSize for DirectIO alligment"); 322 } 323 324 currentLocation = IO_Lseek(fd, 0, SEEK_CUR); 325 326 if ((len % pageSize != 0) || (currentLocation % pageSize != 0)) { 327 JNU_ThrowIOException(env, 328 "In DirectIO mode, the IO size and currentLocation must be aligned with kernel page size!"); 329 } 330 331 if (IS_NULL(bytes)) { 332 JNU_ThrowNullPointerException(env, NULL); 333 return; 334 } 335 336 if (outOfBounds(env, off, len, bytes)) { 337 JNU_ThrowByName(env, "java/lang/IndexOutOfBoundsException", NULL); 338 return; 339 } 340 341 if (len == 0) { 342 return; 343 } else { 344 posix_memalign(&buf, pageSize, len); 345 if (buf == NULL) { 346 JNU_ThrowOutOfMemoryError(env, NULL); 347 return; 348 } 349 } 350 351 (*env)->GetByteArrayRegion(env, bytes, off, len, (jbyte *)buf); 352 353 if (!(*env)->ExceptionOccurred(env)) { 354 off = 0; 355 while (len > 0) { 356 if (append == JNI_TRUE) { 357 n = IO_Append(fd, buf+off, len); 358 } else { 359 n = IO_Write(fd, buf+off, len); 360 } 361 if (n == -1) { 362 JNU_ThrowIOExceptionWithLastError(env, "Write error"); 363 break; 364 } 365 off += n; 366 len -= n; 367 } 368 } 369 free(buf); 370 #endif 371 } 372 373 void 374 throwFileNotFoundException(JNIEnv *env, jstring path) 375 { 376 char buf[256]; 377 size_t n; 378 jobject x; 379 jstring why = NULL; 380 381 n = getLastErrorString(buf, sizeof(buf)); 382 if (n > 0) { 383 #ifdef WIN32 384 why = (*env)->NewStringUTF(env, buf); 385 #else 386 why = JNU_NewStringPlatform(env, buf); 387 #endif 388 CHECK_NULL(why); 389 } 390 x = JNU_NewObjectByName(env, 391 "java/io/FileNotFoundException", 392 "(Ljava/lang/String;Ljava/lang/String;)V", 393 path, why); 394 if (x != NULL) { 395 (*env)->Throw(env, x); 396 } 397 }