1 /* 2 * Copyright (c) 2008, 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 26 #include <stdio.h> 27 #include <stdlib.h> 28 #include <limits.h> 29 #include <fcntl.h> 30 #include <dirent.h> 31 #include <unistd.h> 32 #include <errno.h> 33 #include <dlfcn.h> 34 #include <sys/types.h> 35 #include <sys/stat.h> 36 #ifdef MACOSX 37 #include <sys/param.h> 38 #include <sys/mount.h> 39 #else 40 #include <sys/statvfs.h> 41 #endif 42 #include <sys/time.h> 43 44 /* For POSIX-compliant getpwuid_r, getgrgid_r on Solaris */ 45 #if defined(__solaris__) 46 #define _POSIX_PTHREAD_SEMANTICS 47 #endif 48 #include <pwd.h> 49 #include <grp.h> 50 51 #ifdef __solaris__ 52 #include <strings.h> 53 #endif 54 55 #ifdef __linux__ 56 #include <sys/syscall.h> 57 #endif 58 59 #if defined(__linux__) || defined(_AIX) 60 #include <string.h> 61 #endif 62 63 #ifdef _ALLBSD_SOURCE 64 #include <string.h> 65 66 #define stat64 stat 67 #ifndef MACOSX 68 #define statvfs64 statvfs 69 #endif 70 71 #define open64 open 72 #define fstat64 fstat 73 #define lstat64 lstat 74 #define readdir64 readdir 75 #endif 76 77 #include "jni.h" 78 #include "jni_util.h" 79 #include "jlong.h" 80 81 #include "jvm.h" 82 83 #include "sun_nio_fs_UnixNativeDispatcher.h" 84 85 #if defined(_AIX) 86 #define DIR DIR64 87 #define dirent dirent64 88 #define opendir opendir64 89 #define readdir readdir64 90 #define closedir closedir64 91 #endif 92 93 /** 94 * Size of password or group entry when not available via sysconf 95 */ 96 #define ENT_BUF_SIZE 1024 97 98 #define RESTARTABLE(_cmd, _result) do { \ 99 do { \ 100 _result = _cmd; \ 101 } while((_result == -1) && (errno == EINTR)); \ 102 } while(0) 103 104 #define RESTARTABLE_RETURN_PTR(_cmd, _result) do { \ 105 do { \ 106 _result = _cmd; \ 107 } while((_result == NULL) && (errno == EINTR)); \ 108 } while(0) 109 110 static jfieldID attrs_st_mode; 111 static jfieldID attrs_st_ino; 112 static jfieldID attrs_st_dev; 113 static jfieldID attrs_st_rdev; 114 static jfieldID attrs_st_nlink; 115 static jfieldID attrs_st_uid; 116 static jfieldID attrs_st_gid; 117 static jfieldID attrs_st_size; 118 static jfieldID attrs_st_atime_sec; 119 static jfieldID attrs_st_atime_nsec; 120 static jfieldID attrs_st_mtime_sec; 121 static jfieldID attrs_st_mtime_nsec; 122 static jfieldID attrs_st_ctime_sec; 123 static jfieldID attrs_st_ctime_nsec; 124 125 #ifdef _DARWIN_FEATURE_64_BIT_INODE 126 static jfieldID attrs_st_birthtime_sec; 127 #endif 128 129 static jfieldID attrs_f_frsize; 130 static jfieldID attrs_f_blocks; 131 static jfieldID attrs_f_bfree; 132 static jfieldID attrs_f_bavail; 133 134 static jfieldID entry_name; 135 static jfieldID entry_dir; 136 static jfieldID entry_fstype; 137 static jfieldID entry_options; 138 static jfieldID entry_dev; 139 140 /** 141 * System calls that may not be available at run time. 142 */ 143 typedef int openat64_func(int, const char *, int, ...); 144 typedef int fstatat64_func(int, const char *, struct stat64 *, int); 145 typedef int unlinkat_func(int, const char*, int); 146 typedef int renameat_func(int, const char*, int, const char*); 147 typedef int futimesat_func(int, const char *, const struct timeval *); 148 typedef DIR* fdopendir_func(int); 149 150 static openat64_func* my_openat64_func = NULL; 151 static fstatat64_func* my_fstatat64_func = NULL; 152 static unlinkat_func* my_unlinkat_func = NULL; 153 static renameat_func* my_renameat_func = NULL; 154 static futimesat_func* my_futimesat_func = NULL; 155 static fdopendir_func* my_fdopendir_func = NULL; 156 157 /** 158 * fstatat missing from glibc on Linux. 159 */ 160 #if defined(__linux__) && (defined(__i386) || defined(__arm__)) 161 #define FSTATAT64_SYSCALL_AVAILABLE 162 static int fstatat64_wrapper(int dfd, const char *path, 163 struct stat64 *statbuf, int flag) 164 { 165 #ifndef __NR_fstatat64 166 #define __NR_fstatat64 300 167 #endif 168 return syscall(__NR_fstatat64, dfd, path, statbuf, flag); 169 } 170 #endif 171 172 #if defined(__linux__) && defined(_LP64) && defined(__NR_newfstatat) 173 #define FSTATAT64_SYSCALL_AVAILABLE 174 static int fstatat64_wrapper(int dfd, const char *path, 175 struct stat64 *statbuf, int flag) 176 { 177 return syscall(__NR_newfstatat, dfd, path, statbuf, flag); 178 } 179 #endif 180 181 /** 182 * Call this to throw an internal UnixException when a system/library 183 * call fails 184 */ 185 static void throwUnixException(JNIEnv* env, int errnum) { 186 jobject x = JNU_NewObjectByName(env, "sun/nio/fs/UnixException", 187 "(I)V", errnum); 188 if (x != NULL) { 189 (*env)->Throw(env, x); 190 } 191 } 192 193 /** 194 * Initialization 195 */ 196 JNIEXPORT jint JNICALL 197 Java_sun_nio_fs_UnixNativeDispatcher_init(JNIEnv* env, jclass this) 198 { 199 jint capabilities = 0; 200 jclass clazz; 201 202 clazz = (*env)->FindClass(env, "sun/nio/fs/UnixFileAttributes"); 203 CHECK_NULL_RETURN(clazz, 0); 204 attrs_st_mode = (*env)->GetFieldID(env, clazz, "st_mode", "I"); 205 CHECK_NULL_RETURN(attrs_st_mode, 0); 206 attrs_st_ino = (*env)->GetFieldID(env, clazz, "st_ino", "J"); 207 CHECK_NULL_RETURN(attrs_st_ino, 0); 208 attrs_st_dev = (*env)->GetFieldID(env, clazz, "st_dev", "J"); 209 CHECK_NULL_RETURN(attrs_st_dev, 0); 210 attrs_st_rdev = (*env)->GetFieldID(env, clazz, "st_rdev", "J"); 211 CHECK_NULL_RETURN(attrs_st_rdev, 0); 212 attrs_st_nlink = (*env)->GetFieldID(env, clazz, "st_nlink", "I"); 213 CHECK_NULL_RETURN(attrs_st_nlink, 0); 214 attrs_st_uid = (*env)->GetFieldID(env, clazz, "st_uid", "I"); 215 CHECK_NULL_RETURN(attrs_st_uid, 0); 216 attrs_st_gid = (*env)->GetFieldID(env, clazz, "st_gid", "I"); 217 CHECK_NULL_RETURN(attrs_st_gid, 0); 218 attrs_st_size = (*env)->GetFieldID(env, clazz, "st_size", "J"); 219 CHECK_NULL_RETURN(attrs_st_size, 0); 220 attrs_st_atime_sec = (*env)->GetFieldID(env, clazz, "st_atime_sec", "J"); 221 CHECK_NULL_RETURN(attrs_st_atime_sec, 0); 222 attrs_st_atime_nsec = (*env)->GetFieldID(env, clazz, "st_atime_nsec", "J"); 223 CHECK_NULL_RETURN(attrs_st_atime_nsec, 0); 224 attrs_st_mtime_sec = (*env)->GetFieldID(env, clazz, "st_mtime_sec", "J"); 225 CHECK_NULL_RETURN(attrs_st_mtime_sec, 0); 226 attrs_st_mtime_nsec = (*env)->GetFieldID(env, clazz, "st_mtime_nsec", "J"); 227 CHECK_NULL_RETURN(attrs_st_mtime_nsec, 0); 228 attrs_st_ctime_sec = (*env)->GetFieldID(env, clazz, "st_ctime_sec", "J"); 229 CHECK_NULL_RETURN(attrs_st_ctime_sec, 0); 230 attrs_st_ctime_nsec = (*env)->GetFieldID(env, clazz, "st_ctime_nsec", "J"); 231 CHECK_NULL_RETURN(attrs_st_ctime_nsec, 0); 232 233 #ifdef _DARWIN_FEATURE_64_BIT_INODE 234 attrs_st_birthtime_sec = (*env)->GetFieldID(env, clazz, "st_birthtime_sec", "J"); 235 CHECK_NULL_RETURN(attrs_st_birthtime_sec, 0); 236 #endif 237 238 clazz = (*env)->FindClass(env, "sun/nio/fs/UnixFileStoreAttributes"); 239 CHECK_NULL_RETURN(clazz, 0); 240 attrs_f_frsize = (*env)->GetFieldID(env, clazz, "f_frsize", "J"); 241 CHECK_NULL_RETURN(attrs_f_frsize, 0); 242 attrs_f_blocks = (*env)->GetFieldID(env, clazz, "f_blocks", "J"); 243 CHECK_NULL_RETURN(attrs_f_blocks, 0); 244 attrs_f_bfree = (*env)->GetFieldID(env, clazz, "f_bfree", "J"); 245 CHECK_NULL_RETURN(attrs_f_bfree, 0); 246 attrs_f_bavail = (*env)->GetFieldID(env, clazz, "f_bavail", "J"); 247 CHECK_NULL_RETURN(attrs_f_bavail, 0); 248 249 clazz = (*env)->FindClass(env, "sun/nio/fs/UnixMountEntry"); 250 CHECK_NULL_RETURN(clazz, 0); 251 entry_name = (*env)->GetFieldID(env, clazz, "name", "[B"); 252 CHECK_NULL_RETURN(entry_name, 0); 253 entry_dir = (*env)->GetFieldID(env, clazz, "dir", "[B"); 254 CHECK_NULL_RETURN(entry_dir, 0); 255 entry_fstype = (*env)->GetFieldID(env, clazz, "fstype", "[B"); 256 CHECK_NULL_RETURN(entry_fstype, 0); 257 entry_options = (*env)->GetFieldID(env, clazz, "opts", "[B"); 258 CHECK_NULL_RETURN(entry_options, 0); 259 entry_dev = (*env)->GetFieldID(env, clazz, "dev", "J"); 260 CHECK_NULL_RETURN(entry_dev, 0); 261 262 /* system calls that might not be available at run time */ 263 264 #if (defined(__solaris__) && defined(_LP64)) || defined(_ALLBSD_SOURCE) 265 /* Solaris 64-bit does not have openat64/fstatat64 */ 266 my_openat64_func = (openat64_func*)dlsym(RTLD_DEFAULT, "openat"); 267 my_fstatat64_func = (fstatat64_func*)dlsym(RTLD_DEFAULT, "fstatat"); 268 #else 269 my_openat64_func = (openat64_func*) dlsym(RTLD_DEFAULT, "openat64"); 270 my_fstatat64_func = (fstatat64_func*) dlsym(RTLD_DEFAULT, "fstatat64"); 271 #endif 272 my_unlinkat_func = (unlinkat_func*) dlsym(RTLD_DEFAULT, "unlinkat"); 273 my_renameat_func = (renameat_func*) dlsym(RTLD_DEFAULT, "renameat"); 274 my_futimesat_func = (futimesat_func*) dlsym(RTLD_DEFAULT, "futimesat"); 275 #if defined(_AIX) 276 my_fdopendir_func = (fdopendir_func*) dlsym(RTLD_DEFAULT, "fdopendir64"); 277 #else 278 my_fdopendir_func = (fdopendir_func*) dlsym(RTLD_DEFAULT, "fdopendir"); 279 #endif 280 281 #if defined(FSTATAT64_SYSCALL_AVAILABLE) 282 /* fstatat64 missing from glibc */ 283 if (my_fstatat64_func == NULL) 284 my_fstatat64_func = (fstatat64_func*)&fstatat64_wrapper; 285 #endif 286 287 /* supports futimes or futimesat */ 288 289 #ifdef _ALLBSD_SOURCE 290 capabilities |= sun_nio_fs_UnixNativeDispatcher_SUPPORTS_FUTIMES; 291 #else 292 if (my_futimesat_func != NULL) 293 capabilities |= sun_nio_fs_UnixNativeDispatcher_SUPPORTS_FUTIMES; 294 #endif 295 296 /* supports openat, etc. */ 297 298 if (my_openat64_func != NULL && my_fstatat64_func != NULL && 299 my_unlinkat_func != NULL && my_renameat_func != NULL && 300 my_futimesat_func != NULL && my_fdopendir_func != NULL) 301 { 302 capabilities |= sun_nio_fs_UnixNativeDispatcher_SUPPORTS_OPENAT; 303 } 304 305 /* supports file birthtime */ 306 307 #ifdef _DARWIN_FEATURE_64_BIT_INODE 308 capabilities |= sun_nio_fs_UnixNativeDispatcher_SUPPORTS_BIRTHTIME; 309 #endif 310 311 return capabilities; 312 } 313 314 JNIEXPORT jbyteArray JNICALL 315 Java_sun_nio_fs_UnixNativeDispatcher_getcwd(JNIEnv* env, jclass this) { 316 jbyteArray result = NULL; 317 char buf[PATH_MAX+1]; 318 319 /* EINTR not listed as a possible error */ 320 char* cwd = getcwd(buf, sizeof(buf)); 321 if (cwd == NULL) { 322 throwUnixException(env, errno); 323 } else { 324 jsize len = (jsize)strlen(buf); 325 result = (*env)->NewByteArray(env, len); 326 if (result != NULL) { 327 (*env)->SetByteArrayRegion(env, result, 0, len, (jbyte*)buf); 328 } 329 } 330 return result; 331 } 332 333 JNIEXPORT jbyteArray 334 Java_sun_nio_fs_UnixNativeDispatcher_strerror(JNIEnv* env, jclass this, jint error) 335 { 336 char tmpbuf[1024]; 337 jsize len; 338 jbyteArray bytes; 339 340 getErrorString((int)errno, tmpbuf, sizeof(tmpbuf)); 341 len = strlen(tmpbuf); 342 bytes = (*env)->NewByteArray(env, len); 343 if (bytes != NULL) { 344 (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)tmpbuf); 345 } 346 return bytes; 347 } 348 349 JNIEXPORT jint 350 Java_sun_nio_fs_UnixNativeDispatcher_dup(JNIEnv* env, jclass this, jint fd) { 351 352 int res = -1; 353 354 RESTARTABLE(dup((int)fd), res); 355 if (res == -1) { 356 throwUnixException(env, errno); 357 } 358 return (jint)res; 359 } 360 361 JNIEXPORT jlong JNICALL 362 Java_sun_nio_fs_UnixNativeDispatcher_fopen0(JNIEnv* env, jclass this, 363 jlong pathAddress, jlong modeAddress) 364 { 365 FILE* fp = NULL; 366 const char* path = (const char*)jlong_to_ptr(pathAddress); 367 const char* mode = (const char*)jlong_to_ptr(modeAddress); 368 369 do { 370 fp = fopen(path, mode); 371 } while (fp == NULL && errno == EINTR); 372 373 if (fp == NULL) { 374 throwUnixException(env, errno); 375 } 376 377 return ptr_to_jlong(fp); 378 } 379 380 JNIEXPORT void JNICALL 381 Java_sun_nio_fs_UnixNativeDispatcher_fclose(JNIEnv* env, jclass this, jlong stream) 382 { 383 FILE* fp = jlong_to_ptr(stream); 384 385 /* NOTE: fclose() wrapper is only used with read-only streams. 386 * If it ever is used with write streams, it might be better to add 387 * RESTARTABLE(fflush(fp)) before closing, to make sure the stream 388 * is completely written even if fclose() failed. 389 */ 390 if (fclose(fp) == EOF && errno != EINTR) { 391 throwUnixException(env, errno); 392 } 393 } 394 395 JNIEXPORT jint JNICALL 396 Java_sun_nio_fs_UnixNativeDispatcher_open0(JNIEnv* env, jclass this, 397 jlong pathAddress, jint oflags, jint mode) 398 { 399 jint fd; 400 const char* path = (const char*)jlong_to_ptr(pathAddress); 401 402 RESTARTABLE(open64(path, (int)oflags, (mode_t)mode), fd); 403 if (fd == -1) { 404 throwUnixException(env, errno); 405 } 406 return fd; 407 } 408 409 JNIEXPORT jint JNICALL 410 Java_sun_nio_fs_UnixNativeDispatcher_openat0(JNIEnv* env, jclass this, jint dfd, 411 jlong pathAddress, jint oflags, jint mode) 412 { 413 jint fd; 414 const char* path = (const char*)jlong_to_ptr(pathAddress); 415 416 if (my_openat64_func == NULL) { 417 JNU_ThrowInternalError(env, "should not reach here"); 418 return -1; 419 } 420 421 RESTARTABLE((*my_openat64_func)(dfd, path, (int)oflags, (mode_t)mode), fd); 422 if (fd == -1) { 423 throwUnixException(env, errno); 424 } 425 return fd; 426 } 427 428 JNIEXPORT void JNICALL 429 Java_sun_nio_fs_UnixNativeDispatcher_close0(JNIEnv* env, jclass this, jint fd) { 430 int res; 431 432 #if defined(_AIX) 433 /* AIX allows close to be restarted after EINTR */ 434 RESTARTABLE(close((int)fd), res); 435 #else 436 res = close((int)fd); 437 #endif 438 if (res == -1 && errno != EINTR) { 439 throwUnixException(env, errno); 440 } 441 } 442 443 JNIEXPORT jint JNICALL 444 Java_sun_nio_fs_UnixNativeDispatcher_read(JNIEnv* env, jclass this, jint fd, 445 jlong address, jint nbytes) 446 { 447 ssize_t n; 448 void* bufp = jlong_to_ptr(address); 449 RESTARTABLE(read((int)fd, bufp, (size_t)nbytes), n); 450 if (n == -1) { 451 throwUnixException(env, errno); 452 } 453 454 if (n > 0) { 455 JVM_callFileReadBytes(env, (jint) n); 456 } 457 458 return (jint)n; 459 } 460 461 JNIEXPORT jint JNICALL 462 Java_sun_nio_fs_UnixNativeDispatcher_write(JNIEnv* env, jclass this, jint fd, 463 jlong address, jint nbytes) 464 { 465 ssize_t n; 466 void* bufp = jlong_to_ptr(address); 467 RESTARTABLE(write((int)fd, bufp, (size_t)nbytes), n); 468 if (n == -1) { 469 throwUnixException(env, errno); 470 } 471 472 if (n > 0) { 473 JVM_callFileWriteBytes(env, (jint) n); 474 } 475 476 return (jint)n; 477 } 478 479 /** 480 * Copy stat64 members into sun.nio.fs.UnixFileAttributes 481 */ 482 static void prepAttributes(JNIEnv* env, struct stat64* buf, jobject attrs) { 483 (*env)->SetIntField(env, attrs, attrs_st_mode, (jint)buf->st_mode); 484 (*env)->SetLongField(env, attrs, attrs_st_ino, (jlong)buf->st_ino); 485 (*env)->SetLongField(env, attrs, attrs_st_dev, (jlong)buf->st_dev); 486 (*env)->SetLongField(env, attrs, attrs_st_rdev, (jlong)buf->st_rdev); 487 (*env)->SetIntField(env, attrs, attrs_st_nlink, (jint)buf->st_nlink); 488 (*env)->SetIntField(env, attrs, attrs_st_uid, (jint)buf->st_uid); 489 (*env)->SetIntField(env, attrs, attrs_st_gid, (jint)buf->st_gid); 490 (*env)->SetLongField(env, attrs, attrs_st_size, (jlong)buf->st_size); 491 (*env)->SetLongField(env, attrs, attrs_st_atime_sec, (jlong)buf->st_atime); 492 (*env)->SetLongField(env, attrs, attrs_st_mtime_sec, (jlong)buf->st_mtime); 493 (*env)->SetLongField(env, attrs, attrs_st_ctime_sec, (jlong)buf->st_ctime); 494 495 #ifdef _DARWIN_FEATURE_64_BIT_INODE 496 (*env)->SetLongField(env, attrs, attrs_st_birthtime_sec, (jlong)buf->st_birthtime); 497 #endif 498 499 #ifndef MACOSX 500 (*env)->SetLongField(env, attrs, attrs_st_atime_nsec, (jlong)buf->st_atim.tv_nsec); 501 (*env)->SetLongField(env, attrs, attrs_st_mtime_nsec, (jlong)buf->st_mtim.tv_nsec); 502 (*env)->SetLongField(env, attrs, attrs_st_ctime_nsec, (jlong)buf->st_ctim.tv_nsec); 503 #else 504 (*env)->SetLongField(env, attrs, attrs_st_atime_nsec, (jlong)buf->st_atimespec.tv_nsec); 505 (*env)->SetLongField(env, attrs, attrs_st_mtime_nsec, (jlong)buf->st_mtimespec.tv_nsec); 506 (*env)->SetLongField(env, attrs, attrs_st_ctime_nsec, (jlong)buf->st_ctimespec.tv_nsec); 507 #endif 508 } 509 510 JNIEXPORT void JNICALL 511 Java_sun_nio_fs_UnixNativeDispatcher_stat0(JNIEnv* env, jclass this, 512 jlong pathAddress, jobject attrs) 513 { 514 int err; 515 struct stat64 buf; 516 const char* path = (const char*)jlong_to_ptr(pathAddress); 517 518 RESTARTABLE(stat64(path, &buf), err); 519 if (err == -1) { 520 throwUnixException(env, errno); 521 } else { 522 prepAttributes(env, &buf, attrs); 523 } 524 } 525 526 JNIEXPORT jint JNICALL 527 Java_sun_nio_fs_UnixNativeDispatcher_stat1(JNIEnv* env, jclass this, jlong pathAddress) { 528 int err; 529 struct stat64 buf; 530 const char* path = (const char*)jlong_to_ptr(pathAddress); 531 532 RESTARTABLE(stat64(path, &buf), err); 533 if (err == -1) { 534 return 0; 535 } else { 536 return (jint)buf.st_mode; 537 } 538 } 539 540 JNIEXPORT void JNICALL 541 Java_sun_nio_fs_UnixNativeDispatcher_lstat0(JNIEnv* env, jclass this, 542 jlong pathAddress, jobject attrs) 543 { 544 int err; 545 struct stat64 buf; 546 const char* path = (const char*)jlong_to_ptr(pathAddress); 547 548 RESTARTABLE(lstat64(path, &buf), err); 549 if (err == -1) { 550 throwUnixException(env, errno); 551 } else { 552 prepAttributes(env, &buf, attrs); 553 } 554 } 555 556 JNIEXPORT void JNICALL 557 Java_sun_nio_fs_UnixNativeDispatcher_fstat(JNIEnv* env, jclass this, jint fd, 558 jobject attrs) 559 { 560 int err; 561 struct stat64 buf; 562 563 RESTARTABLE(fstat64((int)fd, &buf), err); 564 if (err == -1) { 565 throwUnixException(env, errno); 566 } else { 567 prepAttributes(env, &buf, attrs); 568 } 569 } 570 571 JNIEXPORT void JNICALL 572 Java_sun_nio_fs_UnixNativeDispatcher_fstatat0(JNIEnv* env, jclass this, jint dfd, 573 jlong pathAddress, jint flag, jobject attrs) 574 { 575 int err; 576 struct stat64 buf; 577 const char* path = (const char*)jlong_to_ptr(pathAddress); 578 579 if (my_fstatat64_func == NULL) { 580 JNU_ThrowInternalError(env, "should not reach here"); 581 return; 582 } 583 RESTARTABLE((*my_fstatat64_func)((int)dfd, path, &buf, (int)flag), err); 584 if (err == -1) { 585 throwUnixException(env, errno); 586 } else { 587 prepAttributes(env, &buf, attrs); 588 } 589 } 590 591 JNIEXPORT void JNICALL 592 Java_sun_nio_fs_UnixNativeDispatcher_chmod0(JNIEnv* env, jclass this, 593 jlong pathAddress, jint mode) 594 { 595 int err; 596 const char* path = (const char*)jlong_to_ptr(pathAddress); 597 598 RESTARTABLE(chmod(path, (mode_t)mode), err); 599 if (err == -1) { 600 throwUnixException(env, errno); 601 } 602 } 603 604 JNIEXPORT void JNICALL 605 Java_sun_nio_fs_UnixNativeDispatcher_fchmod(JNIEnv* env, jclass this, jint filedes, 606 jint mode) 607 { 608 int err; 609 610 RESTARTABLE(fchmod((int)filedes, (mode_t)mode), err); 611 if (err == -1) { 612 throwUnixException(env, errno); 613 } 614 } 615 616 617 JNIEXPORT void JNICALL 618 Java_sun_nio_fs_UnixNativeDispatcher_chown0(JNIEnv* env, jclass this, 619 jlong pathAddress, jint uid, jint gid) 620 { 621 int err; 622 const char* path = (const char*)jlong_to_ptr(pathAddress); 623 624 RESTARTABLE(chown(path, (uid_t)uid, (gid_t)gid), err); 625 if (err == -1) { 626 throwUnixException(env, errno); 627 } 628 } 629 630 JNIEXPORT void JNICALL 631 Java_sun_nio_fs_UnixNativeDispatcher_lchown0(JNIEnv* env, jclass this, jlong pathAddress, jint uid, jint gid) 632 { 633 int err; 634 const char* path = (const char*)jlong_to_ptr(pathAddress); 635 636 RESTARTABLE(lchown(path, (uid_t)uid, (gid_t)gid), err); 637 if (err == -1) { 638 throwUnixException(env, errno); 639 } 640 } 641 642 JNIEXPORT void JNICALL 643 Java_sun_nio_fs_UnixNativeDispatcher_fchown(JNIEnv* env, jclass this, jint filedes, jint uid, jint gid) 644 { 645 int err; 646 647 RESTARTABLE(fchown(filedes, (uid_t)uid, (gid_t)gid), err); 648 if (err == -1) { 649 throwUnixException(env, errno); 650 } 651 } 652 653 JNIEXPORT void JNICALL 654 Java_sun_nio_fs_UnixNativeDispatcher_utimes0(JNIEnv* env, jclass this, 655 jlong pathAddress, jlong accessTime, jlong modificationTime) 656 { 657 int err; 658 struct timeval times[2]; 659 const char* path = (const char*)jlong_to_ptr(pathAddress); 660 661 times[0].tv_sec = accessTime / 1000000; 662 times[0].tv_usec = accessTime % 1000000; 663 664 times[1].tv_sec = modificationTime / 1000000; 665 times[1].tv_usec = modificationTime % 1000000; 666 667 RESTARTABLE(utimes(path, ×[0]), err); 668 if (err == -1) { 669 throwUnixException(env, errno); 670 } 671 } 672 673 JNIEXPORT void JNICALL 674 Java_sun_nio_fs_UnixNativeDispatcher_futimes(JNIEnv* env, jclass this, jint filedes, 675 jlong accessTime, jlong modificationTime) 676 { 677 struct timeval times[2]; 678 int err = 0; 679 680 times[0].tv_sec = accessTime / 1000000; 681 times[0].tv_usec = accessTime % 1000000; 682 683 times[1].tv_sec = modificationTime / 1000000; 684 times[1].tv_usec = modificationTime % 1000000; 685 686 #ifdef _ALLBSD_SOURCE 687 RESTARTABLE(futimes(filedes, ×[0]), err); 688 #else 689 if (my_futimesat_func == NULL) { 690 JNU_ThrowInternalError(env, "my_ftimesat_func is NULL"); 691 return; 692 } 693 RESTARTABLE((*my_futimesat_func)(filedes, NULL, ×[0]), err); 694 #endif 695 if (err == -1) { 696 throwUnixException(env, errno); 697 } 698 } 699 700 JNIEXPORT jlong JNICALL 701 Java_sun_nio_fs_UnixNativeDispatcher_opendir0(JNIEnv* env, jclass this, 702 jlong pathAddress) 703 { 704 DIR* dir; 705 const char* path = (const char*)jlong_to_ptr(pathAddress); 706 707 /* EINTR not listed as a possible error */ 708 dir = opendir(path); 709 if (dir == NULL) { 710 throwUnixException(env, errno); 711 } 712 return ptr_to_jlong(dir); 713 } 714 715 JNIEXPORT jlong JNICALL 716 Java_sun_nio_fs_UnixNativeDispatcher_fdopendir(JNIEnv* env, jclass this, int dfd) { 717 DIR* dir; 718 719 if (my_fdopendir_func == NULL) { 720 JNU_ThrowInternalError(env, "should not reach here"); 721 return (jlong)-1; 722 } 723 724 /* EINTR not listed as a possible error */ 725 dir = (*my_fdopendir_func)((int)dfd); 726 if (dir == NULL) { 727 throwUnixException(env, errno); 728 } 729 return ptr_to_jlong(dir); 730 } 731 732 JNIEXPORT void JNICALL 733 Java_sun_nio_fs_UnixNativeDispatcher_closedir(JNIEnv* env, jclass this, jlong dir) { 734 DIR* dirp = jlong_to_ptr(dir); 735 736 if (closedir(dirp) == -1 && errno != EINTR) { 737 throwUnixException(env, errno); 738 } 739 } 740 741 JNIEXPORT jbyteArray JNICALL 742 Java_sun_nio_fs_UnixNativeDispatcher_readdir(JNIEnv* env, jclass this, jlong value) { 743 DIR* dirp = jlong_to_ptr(value); 744 struct dirent* ptr; 745 746 errno = 0; 747 ptr = readdir(dirp); 748 if (ptr == NULL) { 749 if (errno != 0) { 750 throwUnixException(env, errno); 751 } 752 return NULL; 753 } else { 754 jsize len = strlen(ptr->d_name); 755 jbyteArray bytes = (*env)->NewByteArray(env, len); 756 if (bytes != NULL) { 757 (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)(ptr->d_name)); 758 } 759 return bytes; 760 } 761 } 762 763 JNIEXPORT void JNICALL 764 Java_sun_nio_fs_UnixNativeDispatcher_mkdir0(JNIEnv* env, jclass this, 765 jlong pathAddress, jint mode) 766 { 767 const char* path = (const char*)jlong_to_ptr(pathAddress); 768 769 /* EINTR not listed as a possible error */ 770 if (mkdir(path, (mode_t)mode) == -1) { 771 throwUnixException(env, errno); 772 } 773 } 774 775 JNIEXPORT void JNICALL 776 Java_sun_nio_fs_UnixNativeDispatcher_rmdir0(JNIEnv* env, jclass this, 777 jlong pathAddress) 778 { 779 const char* path = (const char*)jlong_to_ptr(pathAddress); 780 781 /* EINTR not listed as a possible error */ 782 if (rmdir(path) == -1) { 783 throwUnixException(env, errno); 784 } 785 } 786 787 JNIEXPORT void JNICALL 788 Java_sun_nio_fs_UnixNativeDispatcher_link0(JNIEnv* env, jclass this, 789 jlong existingAddress, jlong newAddress) 790 { 791 int err; 792 const char* existing = (const char*)jlong_to_ptr(existingAddress); 793 const char* newname = (const char*)jlong_to_ptr(newAddress); 794 795 RESTARTABLE(link(existing, newname), err); 796 if (err == -1) { 797 throwUnixException(env, errno); 798 } 799 } 800 801 802 JNIEXPORT void JNICALL 803 Java_sun_nio_fs_UnixNativeDispatcher_unlink0(JNIEnv* env, jclass this, 804 jlong pathAddress) 805 { 806 const char* path = (const char*)jlong_to_ptr(pathAddress); 807 808 /* EINTR not listed as a possible error */ 809 if (unlink(path) == -1) { 810 throwUnixException(env, errno); 811 } 812 } 813 814 JNIEXPORT void JNICALL 815 Java_sun_nio_fs_UnixNativeDispatcher_unlinkat0(JNIEnv* env, jclass this, jint dfd, 816 jlong pathAddress, jint flags) 817 { 818 const char* path = (const char*)jlong_to_ptr(pathAddress); 819 820 if (my_unlinkat_func == NULL) { 821 JNU_ThrowInternalError(env, "should not reach here"); 822 return; 823 } 824 825 /* EINTR not listed as a possible error */ 826 if ((*my_unlinkat_func)((int)dfd, path, (int)flags) == -1) { 827 throwUnixException(env, errno); 828 } 829 } 830 831 JNIEXPORT void JNICALL 832 Java_sun_nio_fs_UnixNativeDispatcher_rename0(JNIEnv* env, jclass this, 833 jlong fromAddress, jlong toAddress) 834 { 835 const char* from = (const char*)jlong_to_ptr(fromAddress); 836 const char* to = (const char*)jlong_to_ptr(toAddress); 837 838 /* EINTR not listed as a possible error */ 839 if (rename(from, to) == -1) { 840 throwUnixException(env, errno); 841 } 842 } 843 844 JNIEXPORT void JNICALL 845 Java_sun_nio_fs_UnixNativeDispatcher_renameat0(JNIEnv* env, jclass this, 846 jint fromfd, jlong fromAddress, jint tofd, jlong toAddress) 847 { 848 const char* from = (const char*)jlong_to_ptr(fromAddress); 849 const char* to = (const char*)jlong_to_ptr(toAddress); 850 851 if (my_renameat_func == NULL) { 852 JNU_ThrowInternalError(env, "should not reach here"); 853 return; 854 } 855 856 /* EINTR not listed as a possible error */ 857 if ((*my_renameat_func)((int)fromfd, from, (int)tofd, to) == -1) { 858 throwUnixException(env, errno); 859 } 860 } 861 862 JNIEXPORT void JNICALL 863 Java_sun_nio_fs_UnixNativeDispatcher_symlink0(JNIEnv* env, jclass this, 864 jlong targetAddress, jlong linkAddress) 865 { 866 const char* target = (const char*)jlong_to_ptr(targetAddress); 867 const char* link = (const char*)jlong_to_ptr(linkAddress); 868 869 /* EINTR not listed as a possible error */ 870 if (symlink(target, link) == -1) { 871 throwUnixException(env, errno); 872 } 873 } 874 875 JNIEXPORT jbyteArray JNICALL 876 Java_sun_nio_fs_UnixNativeDispatcher_readlink0(JNIEnv* env, jclass this, 877 jlong pathAddress) 878 { 879 jbyteArray result = NULL; 880 char target[PATH_MAX+1]; 881 const char* path = (const char*)jlong_to_ptr(pathAddress); 882 883 /* EINTR not listed as a possible error */ 884 int n = readlink(path, target, sizeof(target)); 885 if (n == -1) { 886 throwUnixException(env, errno); 887 } else { 888 jsize len; 889 if (n == sizeof(target)) { 890 /* Traditionally readlink(2) should not return more than */ 891 /* PATH_MAX bytes (no terminating null byte is appended). */ 892 throwUnixException(env, ENAMETOOLONG); 893 return NULL; 894 } 895 target[n] = '\0'; 896 len = (jsize)strlen(target); 897 result = (*env)->NewByteArray(env, len); 898 if (result != NULL) { 899 (*env)->SetByteArrayRegion(env, result, 0, len, (jbyte*)target); 900 } 901 } 902 return result; 903 } 904 905 JNIEXPORT jbyteArray JNICALL 906 Java_sun_nio_fs_UnixNativeDispatcher_realpath0(JNIEnv* env, jclass this, 907 jlong pathAddress) 908 { 909 jbyteArray result = NULL; 910 char resolved[PATH_MAX+1]; 911 const char* path = (const char*)jlong_to_ptr(pathAddress); 912 913 /* EINTR not listed as a possible error */ 914 if (realpath(path, resolved) == NULL) { 915 throwUnixException(env, errno); 916 } else { 917 jsize len = (jsize)strlen(resolved); 918 result = (*env)->NewByteArray(env, len); 919 if (result != NULL) { 920 (*env)->SetByteArrayRegion(env, result, 0, len, (jbyte*)resolved); 921 } 922 } 923 return result; 924 } 925 926 JNIEXPORT void JNICALL 927 Java_sun_nio_fs_UnixNativeDispatcher_access0(JNIEnv* env, jclass this, 928 jlong pathAddress, jint amode) 929 { 930 int err; 931 const char* path = (const char*)jlong_to_ptr(pathAddress); 932 933 RESTARTABLE(access(path, (int)amode), err); 934 if (err == -1) { 935 throwUnixException(env, errno); 936 } 937 } 938 939 JNIEXPORT jboolean JNICALL 940 Java_sun_nio_fs_UnixNativeDispatcher_exists0(JNIEnv* env, jclass this, jlong pathAddress) { 941 int err; 942 const char* path = (const char*)jlong_to_ptr(pathAddress); 943 RESTARTABLE(access(path, F_OK), err); 944 return (err == 0) ? JNI_TRUE : JNI_FALSE; 945 } 946 947 JNIEXPORT void JNICALL 948 Java_sun_nio_fs_UnixNativeDispatcher_statvfs0(JNIEnv* env, jclass this, 949 jlong pathAddress, jobject attrs) 950 { 951 int err; 952 #ifdef MACOSX 953 struct statfs buf; 954 #else 955 struct statvfs64 buf; 956 #endif 957 const char* path = (const char*)jlong_to_ptr(pathAddress); 958 959 #ifdef MACOSX 960 RESTARTABLE(statfs(path, &buf), err); 961 #else 962 RESTARTABLE(statvfs64(path, &buf), err); 963 #endif 964 if (err == -1) { 965 throwUnixException(env, errno); 966 } else { 967 #ifdef _AIX 968 /* AIX returns ULONG_MAX in buf.f_blocks for the /proc file system. */ 969 /* This is too big for a Java signed long and fools various tests. */ 970 if (buf.f_blocks == ULONG_MAX) { 971 buf.f_blocks = 0; 972 } 973 /* The number of free or available blocks can never exceed the total number of blocks */ 974 if (buf.f_blocks == 0) { 975 buf.f_bfree = 0; 976 buf.f_bavail = 0; 977 } 978 #endif 979 #ifdef MACOSX 980 (*env)->SetLongField(env, attrs, attrs_f_frsize, long_to_jlong(buf.f_bsize)); 981 #else 982 (*env)->SetLongField(env, attrs, attrs_f_frsize, long_to_jlong(buf.f_frsize)); 983 #endif 984 (*env)->SetLongField(env, attrs, attrs_f_blocks, long_to_jlong(buf.f_blocks)); 985 (*env)->SetLongField(env, attrs, attrs_f_bfree, long_to_jlong(buf.f_bfree)); 986 (*env)->SetLongField(env, attrs, attrs_f_bavail, long_to_jlong(buf.f_bavail)); 987 } 988 } 989 990 JNIEXPORT jlong JNICALL 991 Java_sun_nio_fs_UnixNativeDispatcher_pathconf0(JNIEnv* env, jclass this, 992 jlong pathAddress, jint name) 993 { 994 long err; 995 const char* path = (const char*)jlong_to_ptr(pathAddress); 996 997 err = pathconf(path, (int)name); 998 if (err == -1) { 999 throwUnixException(env, errno); 1000 } 1001 return (jlong)err; 1002 } 1003 1004 JNIEXPORT jlong JNICALL 1005 Java_sun_nio_fs_UnixNativeDispatcher_fpathconf(JNIEnv* env, jclass this, 1006 jint fd, jint name) 1007 { 1008 long err; 1009 1010 err = fpathconf((int)fd, (int)name); 1011 if (err == -1) { 1012 throwUnixException(env, errno); 1013 } 1014 return (jlong)err; 1015 } 1016 1017 JNIEXPORT void JNICALL 1018 Java_sun_nio_fs_UnixNativeDispatcher_mknod0(JNIEnv* env, jclass this, 1019 jlong pathAddress, jint mode, jlong dev) 1020 { 1021 int err; 1022 const char* path = (const char*)jlong_to_ptr(pathAddress); 1023 1024 RESTARTABLE(mknod(path, (mode_t)mode, (dev_t)dev), err); 1025 if (err == -1) { 1026 throwUnixException(env, errno); 1027 } 1028 } 1029 1030 JNIEXPORT jbyteArray JNICALL 1031 Java_sun_nio_fs_UnixNativeDispatcher_getpwuid(JNIEnv* env, jclass this, jint uid) 1032 { 1033 jbyteArray result = NULL; 1034 int buflen; 1035 char* pwbuf; 1036 1037 /* allocate buffer for password record */ 1038 buflen = (int)sysconf(_SC_GETPW_R_SIZE_MAX); 1039 if (buflen == -1) 1040 buflen = ENT_BUF_SIZE; 1041 pwbuf = (char*)malloc(buflen); 1042 if (pwbuf == NULL) { 1043 JNU_ThrowOutOfMemoryError(env, "native heap"); 1044 } else { 1045 struct passwd pwent; 1046 struct passwd* p = NULL; 1047 int res = 0; 1048 1049 errno = 0; 1050 RESTARTABLE(getpwuid_r((uid_t)uid, &pwent, pwbuf, (size_t)buflen, &p), res); 1051 1052 if (res != 0 || p == NULL || p->pw_name == NULL || *(p->pw_name) == '\0') { 1053 /* not found or error */ 1054 if (errno == 0) 1055 errno = ENOENT; 1056 throwUnixException(env, errno); 1057 } else { 1058 jsize len = strlen(p->pw_name); 1059 result = (*env)->NewByteArray(env, len); 1060 if (result != NULL) { 1061 (*env)->SetByteArrayRegion(env, result, 0, len, (jbyte*)(p->pw_name)); 1062 } 1063 } 1064 free(pwbuf); 1065 } 1066 1067 return result; 1068 } 1069 1070 1071 JNIEXPORT jbyteArray JNICALL 1072 Java_sun_nio_fs_UnixNativeDispatcher_getgrgid(JNIEnv* env, jclass this, jint gid) 1073 { 1074 jbyteArray result = NULL; 1075 int buflen; 1076 int retry; 1077 1078 /* initial size of buffer for group record */ 1079 buflen = (int)sysconf(_SC_GETGR_R_SIZE_MAX); 1080 if (buflen == -1) 1081 buflen = ENT_BUF_SIZE; 1082 1083 do { 1084 struct group grent; 1085 struct group* g = NULL; 1086 int res = 0; 1087 1088 char* grbuf = (char*)malloc(buflen); 1089 if (grbuf == NULL) { 1090 JNU_ThrowOutOfMemoryError(env, "native heap"); 1091 return NULL; 1092 } 1093 1094 errno = 0; 1095 RESTARTABLE(getgrgid_r((gid_t)gid, &grent, grbuf, (size_t)buflen, &g), res); 1096 1097 retry = 0; 1098 if (res != 0 || g == NULL || g->gr_name == NULL || *(g->gr_name) == '\0') { 1099 /* not found or error */ 1100 if (errno == ERANGE) { 1101 /* insufficient buffer size so need larger buffer */ 1102 buflen += ENT_BUF_SIZE; 1103 retry = 1; 1104 } else { 1105 if (errno == 0) 1106 errno = ENOENT; 1107 throwUnixException(env, errno); 1108 } 1109 } else { 1110 jsize len = strlen(g->gr_name); 1111 result = (*env)->NewByteArray(env, len); 1112 if (result != NULL) { 1113 (*env)->SetByteArrayRegion(env, result, 0, len, (jbyte*)(g->gr_name)); 1114 } 1115 } 1116 1117 free(grbuf); 1118 1119 } while (retry); 1120 1121 return result; 1122 } 1123 1124 JNIEXPORT jint JNICALL 1125 Java_sun_nio_fs_UnixNativeDispatcher_getpwnam0(JNIEnv* env, jclass this, 1126 jlong nameAddress) 1127 { 1128 jint uid = -1; 1129 int buflen; 1130 char* pwbuf; 1131 1132 /* allocate buffer for password record */ 1133 buflen = (int)sysconf(_SC_GETPW_R_SIZE_MAX); 1134 if (buflen == -1) 1135 buflen = ENT_BUF_SIZE; 1136 pwbuf = (char*)malloc(buflen); 1137 if (pwbuf == NULL) { 1138 JNU_ThrowOutOfMemoryError(env, "native heap"); 1139 } else { 1140 struct passwd pwent; 1141 struct passwd* p = NULL; 1142 int res = 0; 1143 const char* name = (const char*)jlong_to_ptr(nameAddress); 1144 1145 errno = 0; 1146 RESTARTABLE(getpwnam_r(name, &pwent, pwbuf, (size_t)buflen, &p), res); 1147 1148 if (res != 0 || p == NULL || p->pw_name == NULL || *(p->pw_name) == '\0') { 1149 /* not found or error */ 1150 if (errno != 0 && errno != ENOENT && errno != ESRCH) 1151 throwUnixException(env, errno); 1152 } else { 1153 uid = p->pw_uid; 1154 } 1155 free(pwbuf); 1156 } 1157 1158 return uid; 1159 } 1160 1161 JNIEXPORT jint JNICALL 1162 Java_sun_nio_fs_UnixNativeDispatcher_getgrnam0(JNIEnv* env, jclass this, 1163 jlong nameAddress) 1164 { 1165 jint gid = -1; 1166 int buflen, retry; 1167 1168 /* initial size of buffer for group record */ 1169 buflen = (int)sysconf(_SC_GETGR_R_SIZE_MAX); 1170 if (buflen == -1) 1171 buflen = ENT_BUF_SIZE; 1172 1173 do { 1174 struct group grent; 1175 struct group* g = NULL; 1176 int res = 0; 1177 char *grbuf; 1178 const char* name = (const char*)jlong_to_ptr(nameAddress); 1179 1180 grbuf = (char*)malloc(buflen); 1181 if (grbuf == NULL) { 1182 JNU_ThrowOutOfMemoryError(env, "native heap"); 1183 return -1; 1184 } 1185 1186 errno = 0; 1187 RESTARTABLE(getgrnam_r(name, &grent, grbuf, (size_t)buflen, &g), res); 1188 1189 retry = 0; 1190 if (res != 0 || g == NULL || g->gr_name == NULL || *(g->gr_name) == '\0') { 1191 /* not found or error */ 1192 if (errno != 0 && errno != ENOENT && errno != ESRCH) { 1193 if (errno == ERANGE) { 1194 /* insufficient buffer size so need larger buffer */ 1195 buflen += ENT_BUF_SIZE; 1196 retry = 1; 1197 } else { 1198 throwUnixException(env, errno); 1199 } 1200 } 1201 } else { 1202 gid = g->gr_gid; 1203 } 1204 1205 free(grbuf); 1206 1207 } while (retry); 1208 1209 return gid; 1210 }