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