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