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 dirent64 dirent 75 #define readdir64 readdir 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 res; 429 430 #if defined(_AIX) 431 /* AIX allows close to be restarted after EINTR */ 432 RESTARTABLE(close((int)fd), res); 433 #else 434 res = close((int)fd); 435 #endif 436 if (res == -1 && errno != EINTR) { 437 throwUnixException(env, errno); 438 } 439 } 440 441 JNIEXPORT jint JNICALL 442 Java_sun_nio_fs_UnixNativeDispatcher_read(JNIEnv* env, jclass this, jint fd, 443 jlong address, jint nbytes) 444 { 445 ssize_t n; 446 void* bufp = jlong_to_ptr(address); 447 RESTARTABLE(read((int)fd, bufp, (size_t)nbytes), n); 448 if (n == -1) { 449 throwUnixException(env, errno); 450 } 451 return (jint)n; 452 } 453 454 JNIEXPORT jint JNICALL 455 Java_sun_nio_fs_UnixNativeDispatcher_write(JNIEnv* env, jclass this, jint fd, 456 jlong address, jint nbytes) 457 { 458 ssize_t n; 459 void* bufp = jlong_to_ptr(address); 460 RESTARTABLE(write((int)fd, bufp, (size_t)nbytes), n); 461 if (n == -1) { 462 throwUnixException(env, errno); 463 } 464 return (jint)n; 465 } 466 467 /** 468 * Copy stat64 members into sun.nio.fs.UnixFileAttributes 469 */ 470 static void prepAttributes(JNIEnv* env, struct stat64* buf, jobject attrs) { 471 (*env)->SetIntField(env, attrs, attrs_st_mode, (jint)buf->st_mode); 472 (*env)->SetLongField(env, attrs, attrs_st_ino, (jlong)buf->st_ino); 473 (*env)->SetLongField(env, attrs, attrs_st_dev, (jlong)buf->st_dev); 474 (*env)->SetLongField(env, attrs, attrs_st_rdev, (jlong)buf->st_rdev); 475 (*env)->SetIntField(env, attrs, attrs_st_nlink, (jint)buf->st_nlink); 476 (*env)->SetIntField(env, attrs, attrs_st_uid, (jint)buf->st_uid); 477 (*env)->SetIntField(env, attrs, attrs_st_gid, (jint)buf->st_gid); 478 (*env)->SetLongField(env, attrs, attrs_st_size, (jlong)buf->st_size); 479 (*env)->SetLongField(env, attrs, attrs_st_atime_sec, (jlong)buf->st_atime); 480 (*env)->SetLongField(env, attrs, attrs_st_mtime_sec, (jlong)buf->st_mtime); 481 (*env)->SetLongField(env, attrs, attrs_st_ctime_sec, (jlong)buf->st_ctime); 482 483 #ifdef _DARWIN_FEATURE_64_BIT_INODE 484 (*env)->SetLongField(env, attrs, attrs_st_birthtime_sec, (jlong)buf->st_birthtime); 485 #endif 486 487 #ifndef MACOSX 488 (*env)->SetLongField(env, attrs, attrs_st_atime_nsec, (jlong)buf->st_atim.tv_nsec); 489 (*env)->SetLongField(env, attrs, attrs_st_mtime_nsec, (jlong)buf->st_mtim.tv_nsec); 490 (*env)->SetLongField(env, attrs, attrs_st_ctime_nsec, (jlong)buf->st_ctim.tv_nsec); 491 #else 492 (*env)->SetLongField(env, attrs, attrs_st_atime_nsec, (jlong)buf->st_atimespec.tv_nsec); 493 (*env)->SetLongField(env, attrs, attrs_st_mtime_nsec, (jlong)buf->st_mtimespec.tv_nsec); 494 (*env)->SetLongField(env, attrs, attrs_st_ctime_nsec, (jlong)buf->st_ctimespec.tv_nsec); 495 #endif 496 } 497 498 JNIEXPORT void JNICALL 499 Java_sun_nio_fs_UnixNativeDispatcher_stat0(JNIEnv* env, jclass this, 500 jlong pathAddress, jobject attrs) 501 { 502 int err; 503 struct stat64 buf; 504 const char* path = (const char*)jlong_to_ptr(pathAddress); 505 506 RESTARTABLE(stat64(path, &buf), err); 507 if (err == -1) { 508 throwUnixException(env, errno); 509 } else { 510 prepAttributes(env, &buf, attrs); 511 } 512 } 513 514 JNIEXPORT jint JNICALL 515 Java_sun_nio_fs_UnixNativeDispatcher_stat1(JNIEnv* env, jclass this, jlong pathAddress) { 516 int err; 517 struct stat64 buf; 518 const char* path = (const char*)jlong_to_ptr(pathAddress); 519 520 RESTARTABLE(stat64(path, &buf), err); 521 if (err == -1) { 522 return 0; 523 } else { 524 return (jint)buf.st_mode; 525 } 526 } 527 528 JNIEXPORT void JNICALL 529 Java_sun_nio_fs_UnixNativeDispatcher_lstat0(JNIEnv* env, jclass this, 530 jlong pathAddress, jobject attrs) 531 { 532 int err; 533 struct stat64 buf; 534 const char* path = (const char*)jlong_to_ptr(pathAddress); 535 536 RESTARTABLE(lstat64(path, &buf), 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_fstat(JNIEnv* env, jclass this, jint fd, 546 jobject attrs) 547 { 548 int err; 549 struct stat64 buf; 550 551 RESTARTABLE(fstat64((int)fd, &buf), err); 552 if (err == -1) { 553 throwUnixException(env, errno); 554 } else { 555 prepAttributes(env, &buf, attrs); 556 } 557 } 558 559 JNIEXPORT void JNICALL 560 Java_sun_nio_fs_UnixNativeDispatcher_fstatat0(JNIEnv* env, jclass this, jint dfd, 561 jlong pathAddress, jint flag, jobject attrs) 562 { 563 int err; 564 struct stat64 buf; 565 const char* path = (const char*)jlong_to_ptr(pathAddress); 566 567 if (my_fstatat64_func == NULL) { 568 JNU_ThrowInternalError(env, "should not reach here"); 569 return; 570 } 571 RESTARTABLE((*my_fstatat64_func)((int)dfd, path, &buf, (int)flag), err); 572 if (err == -1) { 573 throwUnixException(env, errno); 574 } else { 575 prepAttributes(env, &buf, attrs); 576 } 577 } 578 579 JNIEXPORT void JNICALL 580 Java_sun_nio_fs_UnixNativeDispatcher_chmod0(JNIEnv* env, jclass this, 581 jlong pathAddress, jint mode) 582 { 583 int err; 584 const char* path = (const char*)jlong_to_ptr(pathAddress); 585 586 RESTARTABLE(chmod(path, (mode_t)mode), err); 587 if (err == -1) { 588 throwUnixException(env, errno); 589 } 590 } 591 592 JNIEXPORT void JNICALL 593 Java_sun_nio_fs_UnixNativeDispatcher_fchmod(JNIEnv* env, jclass this, jint filedes, 594 jint mode) 595 { 596 int err; 597 598 RESTARTABLE(fchmod((int)filedes, (mode_t)mode), err); 599 if (err == -1) { 600 throwUnixException(env, errno); 601 } 602 } 603 604 605 JNIEXPORT void JNICALL 606 Java_sun_nio_fs_UnixNativeDispatcher_chown0(JNIEnv* env, jclass this, 607 jlong pathAddress, jint uid, jint gid) 608 { 609 int err; 610 const char* path = (const char*)jlong_to_ptr(pathAddress); 611 612 RESTARTABLE(chown(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_lchown0(JNIEnv* env, jclass this, jlong pathAddress, jint uid, jint gid) 620 { 621 int err; 622 const char* path = (const char*)jlong_to_ptr(pathAddress); 623 624 RESTARTABLE(lchown(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_fchown(JNIEnv* env, jclass this, jint filedes, jint uid, jint gid) 632 { 633 int err; 634 635 RESTARTABLE(fchown(filedes, (uid_t)uid, (gid_t)gid), err); 636 if (err == -1) { 637 throwUnixException(env, errno); 638 } 639 } 640 641 JNIEXPORT void JNICALL 642 Java_sun_nio_fs_UnixNativeDispatcher_utimes0(JNIEnv* env, jclass this, 643 jlong pathAddress, jlong accessTime, jlong modificationTime) 644 { 645 int err; 646 struct timeval times[2]; 647 const char* path = (const char*)jlong_to_ptr(pathAddress); 648 649 times[0].tv_sec = accessTime / 1000000; 650 times[0].tv_usec = accessTime % 1000000; 651 652 times[1].tv_sec = modificationTime / 1000000; 653 times[1].tv_usec = modificationTime % 1000000; 654 655 RESTARTABLE(utimes(path, ×[0]), err); 656 if (err == -1) { 657 throwUnixException(env, errno); 658 } 659 } 660 661 JNIEXPORT void JNICALL 662 Java_sun_nio_fs_UnixNativeDispatcher_futimes(JNIEnv* env, jclass this, jint filedes, 663 jlong accessTime, jlong modificationTime) 664 { 665 struct timeval times[2]; 666 int err = 0; 667 668 times[0].tv_sec = accessTime / 1000000; 669 times[0].tv_usec = accessTime % 1000000; 670 671 times[1].tv_sec = modificationTime / 1000000; 672 times[1].tv_usec = modificationTime % 1000000; 673 674 #ifdef _ALLBSD_SOURCE 675 RESTARTABLE(futimes(filedes, ×[0]), err); 676 #else 677 if (my_futimesat_func == NULL) { 678 JNU_ThrowInternalError(env, "my_ftimesat_func is NULL"); 679 return; 680 } 681 RESTARTABLE((*my_futimesat_func)(filedes, NULL, ×[0]), err); 682 #endif 683 if (err == -1) { 684 throwUnixException(env, errno); 685 } 686 } 687 688 JNIEXPORT jlong JNICALL 689 Java_sun_nio_fs_UnixNativeDispatcher_opendir0(JNIEnv* env, jclass this, 690 jlong pathAddress) 691 { 692 DIR* dir; 693 const char* path = (const char*)jlong_to_ptr(pathAddress); 694 695 /* EINTR not listed as a possible error */ 696 dir = opendir(path); 697 if (dir == NULL) { 698 throwUnixException(env, errno); 699 } 700 return ptr_to_jlong(dir); 701 } 702 703 JNIEXPORT jlong JNICALL 704 Java_sun_nio_fs_UnixNativeDispatcher_fdopendir(JNIEnv* env, jclass this, int dfd) { 705 DIR* dir; 706 707 if (my_fdopendir_func == NULL) { 708 JNU_ThrowInternalError(env, "should not reach here"); 709 return (jlong)-1; 710 } 711 712 /* EINTR not listed as a possible error */ 713 dir = (*my_fdopendir_func)((int)dfd); 714 if (dir == NULL) { 715 throwUnixException(env, errno); 716 } 717 return ptr_to_jlong(dir); 718 } 719 720 JNIEXPORT void JNICALL 721 Java_sun_nio_fs_UnixNativeDispatcher_closedir(JNIEnv* env, jclass this, jlong dir) { 722 DIR* dirp = jlong_to_ptr(dir); 723 724 if (closedir(dirp) == -1 && errno != EINTR) { 725 throwUnixException(env, errno); 726 } 727 } 728 729 JNIEXPORT jbyteArray JNICALL 730 Java_sun_nio_fs_UnixNativeDispatcher_readdir(JNIEnv* env, jclass this, jlong value) { 731 DIR* dirp = jlong_to_ptr(value); 732 struct dirent64* ptr; 733 734 errno = 0; 735 ptr = readdir64(dirp); 736 if (ptr == NULL) { 737 if (errno != 0) { 738 throwUnixException(env, errno); 739 } 740 return NULL; 741 } else { 742 jsize len = strlen(ptr->d_name); 743 jbyteArray bytes = (*env)->NewByteArray(env, len); 744 if (bytes != NULL) { 745 (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)(ptr->d_name)); 746 } 747 return bytes; 748 } 749 } 750 751 JNIEXPORT void JNICALL 752 Java_sun_nio_fs_UnixNativeDispatcher_mkdir0(JNIEnv* env, jclass this, 753 jlong pathAddress, jint mode) 754 { 755 const char* path = (const char*)jlong_to_ptr(pathAddress); 756 757 /* EINTR not listed as a possible error */ 758 if (mkdir(path, (mode_t)mode) == -1) { 759 throwUnixException(env, errno); 760 } 761 } 762 763 JNIEXPORT void JNICALL 764 Java_sun_nio_fs_UnixNativeDispatcher_rmdir0(JNIEnv* env, jclass this, 765 jlong pathAddress) 766 { 767 const char* path = (const char*)jlong_to_ptr(pathAddress); 768 769 /* EINTR not listed as a possible error */ 770 if (rmdir(path) == -1) { 771 throwUnixException(env, errno); 772 } 773 } 774 775 JNIEXPORT void JNICALL 776 Java_sun_nio_fs_UnixNativeDispatcher_link0(JNIEnv* env, jclass this, 777 jlong existingAddress, jlong newAddress) 778 { 779 int err; 780 const char* existing = (const char*)jlong_to_ptr(existingAddress); 781 const char* newname = (const char*)jlong_to_ptr(newAddress); 782 783 RESTARTABLE(link(existing, newname), err); 784 if (err == -1) { 785 throwUnixException(env, errno); 786 } 787 } 788 789 790 JNIEXPORT void JNICALL 791 Java_sun_nio_fs_UnixNativeDispatcher_unlink0(JNIEnv* env, jclass this, 792 jlong pathAddress) 793 { 794 const char* path = (const char*)jlong_to_ptr(pathAddress); 795 796 /* EINTR not listed as a possible error */ 797 if (unlink(path) == -1) { 798 throwUnixException(env, errno); 799 } 800 } 801 802 JNIEXPORT void JNICALL 803 Java_sun_nio_fs_UnixNativeDispatcher_unlinkat0(JNIEnv* env, jclass this, jint dfd, 804 jlong pathAddress, jint flags) 805 { 806 const char* path = (const char*)jlong_to_ptr(pathAddress); 807 808 if (my_unlinkat_func == NULL) { 809 JNU_ThrowInternalError(env, "should not reach here"); 810 return; 811 } 812 813 /* EINTR not listed as a possible error */ 814 if ((*my_unlinkat_func)((int)dfd, path, (int)flags) == -1) { 815 throwUnixException(env, errno); 816 } 817 } 818 819 JNIEXPORT void JNICALL 820 Java_sun_nio_fs_UnixNativeDispatcher_rename0(JNIEnv* env, jclass this, 821 jlong fromAddress, jlong toAddress) 822 { 823 const char* from = (const char*)jlong_to_ptr(fromAddress); 824 const char* to = (const char*)jlong_to_ptr(toAddress); 825 826 /* EINTR not listed as a possible error */ 827 if (rename(from, to) == -1) { 828 throwUnixException(env, errno); 829 } 830 } 831 832 JNIEXPORT void JNICALL 833 Java_sun_nio_fs_UnixNativeDispatcher_renameat0(JNIEnv* env, jclass this, 834 jint fromfd, jlong fromAddress, jint tofd, jlong toAddress) 835 { 836 const char* from = (const char*)jlong_to_ptr(fromAddress); 837 const char* to = (const char*)jlong_to_ptr(toAddress); 838 839 if (my_renameat_func == NULL) { 840 JNU_ThrowInternalError(env, "should not reach here"); 841 return; 842 } 843 844 /* EINTR not listed as a possible error */ 845 if ((*my_renameat_func)((int)fromfd, from, (int)tofd, to) == -1) { 846 throwUnixException(env, errno); 847 } 848 } 849 850 JNIEXPORT void JNICALL 851 Java_sun_nio_fs_UnixNativeDispatcher_symlink0(JNIEnv* env, jclass this, 852 jlong targetAddress, jlong linkAddress) 853 { 854 const char* target = (const char*)jlong_to_ptr(targetAddress); 855 const char* link = (const char*)jlong_to_ptr(linkAddress); 856 857 /* EINTR not listed as a possible error */ 858 if (symlink(target, link) == -1) { 859 throwUnixException(env, errno); 860 } 861 } 862 863 JNIEXPORT jbyteArray JNICALL 864 Java_sun_nio_fs_UnixNativeDispatcher_readlink0(JNIEnv* env, jclass this, 865 jlong pathAddress) 866 { 867 jbyteArray result = NULL; 868 char target[PATH_MAX+1]; 869 const char* path = (const char*)jlong_to_ptr(pathAddress); 870 871 /* EINTR not listed as a possible error */ 872 int n = readlink(path, target, sizeof(target)); 873 if (n == -1) { 874 throwUnixException(env, errno); 875 } else { 876 jsize len; 877 if (n == sizeof(target)) { 878 n--; 879 } 880 target[n] = '\0'; 881 len = (jsize)strlen(target); 882 result = (*env)->NewByteArray(env, len); 883 if (result != NULL) { 884 (*env)->SetByteArrayRegion(env, result, 0, len, (jbyte*)target); 885 } 886 } 887 return result; 888 } 889 890 JNIEXPORT jbyteArray JNICALL 891 Java_sun_nio_fs_UnixNativeDispatcher_realpath0(JNIEnv* env, jclass this, 892 jlong pathAddress) 893 { 894 jbyteArray result = NULL; 895 char resolved[PATH_MAX+1]; 896 const char* path = (const char*)jlong_to_ptr(pathAddress); 897 898 /* EINTR not listed as a possible error */ 899 if (realpath(path, resolved) == NULL) { 900 throwUnixException(env, errno); 901 } else { 902 jsize len = (jsize)strlen(resolved); 903 result = (*env)->NewByteArray(env, len); 904 if (result != NULL) { 905 (*env)->SetByteArrayRegion(env, result, 0, len, (jbyte*)resolved); 906 } 907 } 908 return result; 909 } 910 911 JNIEXPORT void JNICALL 912 Java_sun_nio_fs_UnixNativeDispatcher_access0(JNIEnv* env, jclass this, 913 jlong pathAddress, jint amode) 914 { 915 int err; 916 const char* path = (const char*)jlong_to_ptr(pathAddress); 917 918 RESTARTABLE(access(path, (int)amode), err); 919 if (err == -1) { 920 throwUnixException(env, errno); 921 } 922 } 923 924 JNIEXPORT jboolean JNICALL 925 Java_sun_nio_fs_UnixNativeDispatcher_exists0(JNIEnv* env, jclass this, jlong pathAddress) { 926 int err; 927 const char* path = (const char*)jlong_to_ptr(pathAddress); 928 RESTARTABLE(access(path, F_OK), err); 929 return (err == 0) ? JNI_TRUE : JNI_FALSE; 930 } 931 932 JNIEXPORT void JNICALL 933 Java_sun_nio_fs_UnixNativeDispatcher_statvfs0(JNIEnv* env, jclass this, 934 jlong pathAddress, jobject attrs) 935 { 936 int err; 937 #ifdef MACOSX 938 struct statfs buf; 939 #else 940 struct statvfs64 buf; 941 #endif 942 const char* path = (const char*)jlong_to_ptr(pathAddress); 943 944 #ifdef MACOSX 945 RESTARTABLE(statfs(path, &buf), err); 946 #else 947 RESTARTABLE(statvfs64(path, &buf), err); 948 #endif 949 if (err == -1) { 950 throwUnixException(env, errno); 951 } else { 952 #ifdef _AIX 953 /* AIX returns ULONG_MAX in buf.f_blocks for the /proc file system. */ 954 /* This is too big for a Java signed long and fools various tests. */ 955 if (buf.f_blocks == ULONG_MAX) { 956 buf.f_blocks = 0; 957 } 958 /* The number of free or available blocks can never exceed the total number of blocks */ 959 if (buf.f_blocks == 0) { 960 buf.f_bfree = 0; 961 buf.f_bavail = 0; 962 } 963 #endif 964 #ifdef MACOSX 965 (*env)->SetLongField(env, attrs, attrs_f_frsize, long_to_jlong(buf.f_bsize)); 966 #else 967 (*env)->SetLongField(env, attrs, attrs_f_frsize, long_to_jlong(buf.f_frsize)); 968 #endif 969 (*env)->SetLongField(env, attrs, attrs_f_blocks, long_to_jlong(buf.f_blocks)); 970 (*env)->SetLongField(env, attrs, attrs_f_bfree, long_to_jlong(buf.f_bfree)); 971 (*env)->SetLongField(env, attrs, attrs_f_bavail, long_to_jlong(buf.f_bavail)); 972 } 973 } 974 975 JNIEXPORT jlong JNICALL 976 Java_sun_nio_fs_UnixNativeDispatcher_pathconf0(JNIEnv* env, jclass this, 977 jlong pathAddress, jint name) 978 { 979 long err; 980 const char* path = (const char*)jlong_to_ptr(pathAddress); 981 982 err = pathconf(path, (int)name); 983 if (err == -1) { 984 throwUnixException(env, errno); 985 } 986 return (jlong)err; 987 } 988 989 JNIEXPORT jlong JNICALL 990 Java_sun_nio_fs_UnixNativeDispatcher_fpathconf(JNIEnv* env, jclass this, 991 jint fd, jint name) 992 { 993 long err; 994 995 err = fpathconf((int)fd, (int)name); 996 if (err == -1) { 997 throwUnixException(env, errno); 998 } 999 return (jlong)err; 1000 } 1001 1002 JNIEXPORT void JNICALL 1003 Java_sun_nio_fs_UnixNativeDispatcher_mknod0(JNIEnv* env, jclass this, 1004 jlong pathAddress, jint mode, jlong dev) 1005 { 1006 int err; 1007 const char* path = (const char*)jlong_to_ptr(pathAddress); 1008 1009 RESTARTABLE(mknod(path, (mode_t)mode, (dev_t)dev), err); 1010 if (err == -1) { 1011 throwUnixException(env, errno); 1012 } 1013 } 1014 1015 JNIEXPORT jbyteArray JNICALL 1016 Java_sun_nio_fs_UnixNativeDispatcher_getpwuid(JNIEnv* env, jclass this, jint uid) 1017 { 1018 jbyteArray result = NULL; 1019 int buflen; 1020 char* pwbuf; 1021 1022 /* allocate buffer for password record */ 1023 buflen = (int)sysconf(_SC_GETPW_R_SIZE_MAX); 1024 if (buflen == -1) 1025 buflen = ENT_BUF_SIZE; 1026 pwbuf = (char*)malloc(buflen); 1027 if (pwbuf == NULL) { 1028 JNU_ThrowOutOfMemoryError(env, "native heap"); 1029 } else { 1030 struct passwd pwent; 1031 struct passwd* p = NULL; 1032 int res = 0; 1033 1034 errno = 0; 1035 RESTARTABLE(getpwuid_r((uid_t)uid, &pwent, pwbuf, (size_t)buflen, &p), res); 1036 1037 if (res != 0 || p == NULL || p->pw_name == NULL || *(p->pw_name) == '\0') { 1038 /* not found or error */ 1039 if (errno == 0) 1040 errno = ENOENT; 1041 throwUnixException(env, errno); 1042 } else { 1043 jsize len = strlen(p->pw_name); 1044 result = (*env)->NewByteArray(env, len); 1045 if (result != NULL) { 1046 (*env)->SetByteArrayRegion(env, result, 0, len, (jbyte*)(p->pw_name)); 1047 } 1048 } 1049 free(pwbuf); 1050 } 1051 1052 return result; 1053 } 1054 1055 1056 JNIEXPORT jbyteArray JNICALL 1057 Java_sun_nio_fs_UnixNativeDispatcher_getgrgid(JNIEnv* env, jclass this, jint gid) 1058 { 1059 jbyteArray result = NULL; 1060 int buflen; 1061 int retry; 1062 1063 /* initial size of buffer for group record */ 1064 buflen = (int)sysconf(_SC_GETGR_R_SIZE_MAX); 1065 if (buflen == -1) 1066 buflen = ENT_BUF_SIZE; 1067 1068 do { 1069 struct group grent; 1070 struct group* g = NULL; 1071 int res = 0; 1072 1073 char* grbuf = (char*)malloc(buflen); 1074 if (grbuf == NULL) { 1075 JNU_ThrowOutOfMemoryError(env, "native heap"); 1076 return NULL; 1077 } 1078 1079 errno = 0; 1080 RESTARTABLE(getgrgid_r((gid_t)gid, &grent, grbuf, (size_t)buflen, &g), res); 1081 1082 retry = 0; 1083 if (res != 0 || g == NULL || g->gr_name == NULL || *(g->gr_name) == '\0') { 1084 /* not found or error */ 1085 if (errno == ERANGE) { 1086 /* insufficient buffer size so need larger buffer */ 1087 buflen += ENT_BUF_SIZE; 1088 retry = 1; 1089 } else { 1090 if (errno == 0) 1091 errno = ENOENT; 1092 throwUnixException(env, errno); 1093 } 1094 } else { 1095 jsize len = strlen(g->gr_name); 1096 result = (*env)->NewByteArray(env, len); 1097 if (result != NULL) { 1098 (*env)->SetByteArrayRegion(env, result, 0, len, (jbyte*)(g->gr_name)); 1099 } 1100 } 1101 1102 free(grbuf); 1103 1104 } while (retry); 1105 1106 return result; 1107 } 1108 1109 JNIEXPORT jint JNICALL 1110 Java_sun_nio_fs_UnixNativeDispatcher_getpwnam0(JNIEnv* env, jclass this, 1111 jlong nameAddress) 1112 { 1113 jint uid = -1; 1114 int buflen; 1115 char* pwbuf; 1116 1117 /* allocate buffer for password record */ 1118 buflen = (int)sysconf(_SC_GETPW_R_SIZE_MAX); 1119 if (buflen == -1) 1120 buflen = ENT_BUF_SIZE; 1121 pwbuf = (char*)malloc(buflen); 1122 if (pwbuf == NULL) { 1123 JNU_ThrowOutOfMemoryError(env, "native heap"); 1124 } else { 1125 struct passwd pwent; 1126 struct passwd* p = NULL; 1127 int res = 0; 1128 const char* name = (const char*)jlong_to_ptr(nameAddress); 1129 1130 errno = 0; 1131 RESTARTABLE(getpwnam_r(name, &pwent, pwbuf, (size_t)buflen, &p), res); 1132 1133 if (res != 0 || p == NULL || p->pw_name == NULL || *(p->pw_name) == '\0') { 1134 /* not found or error */ 1135 if (errno != 0 && errno != ENOENT && errno != ESRCH) 1136 throwUnixException(env, errno); 1137 } else { 1138 uid = p->pw_uid; 1139 } 1140 free(pwbuf); 1141 } 1142 1143 return uid; 1144 } 1145 1146 JNIEXPORT jint JNICALL 1147 Java_sun_nio_fs_UnixNativeDispatcher_getgrnam0(JNIEnv* env, jclass this, 1148 jlong nameAddress) 1149 { 1150 jint gid = -1; 1151 int buflen, retry; 1152 1153 /* initial size of buffer for group record */ 1154 buflen = (int)sysconf(_SC_GETGR_R_SIZE_MAX); 1155 if (buflen == -1) 1156 buflen = ENT_BUF_SIZE; 1157 1158 do { 1159 struct group grent; 1160 struct group* g = NULL; 1161 int res = 0; 1162 char *grbuf; 1163 const char* name = (const char*)jlong_to_ptr(nameAddress); 1164 1165 grbuf = (char*)malloc(buflen); 1166 if (grbuf == NULL) { 1167 JNU_ThrowOutOfMemoryError(env, "native heap"); 1168 return -1; 1169 } 1170 1171 errno = 0; 1172 RESTARTABLE(getgrnam_r(name, &grent, grbuf, (size_t)buflen, &g), res); 1173 1174 retry = 0; 1175 if (res != 0 || g == NULL || g->gr_name == NULL || *(g->gr_name) == '\0') { 1176 /* not found or error */ 1177 if (errno != 0 && errno != ENOENT && errno != ESRCH) { 1178 if (errno == ERANGE) { 1179 /* insufficient buffer size so need larger buffer */ 1180 buflen += ENT_BUF_SIZE; 1181 retry = 1; 1182 } else { 1183 throwUnixException(env, errno); 1184 } 1185 } 1186 } else { 1187 gid = g->gr_gid; 1188 } 1189 1190 free(grbuf); 1191 1192 } while (retry); 1193 1194 return gid; 1195 }