1 /* 2 * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 #include <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* msg; 312 jsize len; 313 jbyteArray bytes; 314 315 #ifdef _AIX 316 /* strerror() is not thread-safe on AIX so we have to use strerror_r() */ 317 char buffer[256]; 318 msg = (strerror_r((int)error, buffer, 256) == 0) ? buffer : "Error while calling strerror_r"; 319 #else 320 msg = strerror((int)error); 321 #endif 322 len = strlen(msg); 323 bytes = (*env)->NewByteArray(env, len); 324 if (bytes != NULL) { 325 (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)msg); 326 } 327 return bytes; 328 } 329 330 JNIEXPORT jint 331 Java_sun_nio_fs_UnixNativeDispatcher_dup(JNIEnv* env, jclass this, jint fd) { 332 333 int res = -1; 334 335 RESTARTABLE(dup((int)fd), res); 336 if (fd == -1) { 337 throwUnixException(env, errno); 338 } 339 return (jint)res; 340 } 341 342 JNIEXPORT jlong JNICALL 343 Java_sun_nio_fs_UnixNativeDispatcher_fopen0(JNIEnv* env, jclass this, 344 jlong pathAddress, jlong modeAddress) 345 { 346 FILE* fp = NULL; 347 const char* path = (const char*)jlong_to_ptr(pathAddress); 348 const char* mode = (const char*)jlong_to_ptr(modeAddress); 349 350 do { 351 fp = fopen(path, mode); 352 } while (fp == NULL && errno == EINTR); 353 354 if (fp == NULL) { 355 throwUnixException(env, errno); 356 } 357 358 return ptr_to_jlong(fp); 359 } 360 361 JNIEXPORT void JNICALL 362 Java_sun_nio_fs_UnixNativeDispatcher_fclose(JNIEnv* env, jclass this, jlong stream) 363 { 364 int res; 365 FILE* fp = jlong_to_ptr(stream); 366 367 do { 368 res = fclose(fp); 369 } while (res == EOF && errno == EINTR); 370 if (res == EOF) { 371 throwUnixException(env, errno); 372 } 373 } 374 375 JNIEXPORT jint JNICALL 376 Java_sun_nio_fs_UnixNativeDispatcher_open0(JNIEnv* env, jclass this, 377 jlong pathAddress, jint oflags, jint mode) 378 { 379 jint fd; 380 const char* path = (const char*)jlong_to_ptr(pathAddress); 381 382 RESTARTABLE(open64(path, (int)oflags, (mode_t)mode), fd); 383 if (fd == -1) { 384 throwUnixException(env, errno); 385 } 386 return fd; 387 } 388 389 JNIEXPORT jint JNICALL 390 Java_sun_nio_fs_UnixNativeDispatcher_openat0(JNIEnv* env, jclass this, jint dfd, 391 jlong pathAddress, jint oflags, jint mode) 392 { 393 jint fd; 394 const char* path = (const char*)jlong_to_ptr(pathAddress); 395 396 if (my_openat64_func == NULL) { 397 JNU_ThrowInternalError(env, "should not reach here"); 398 return -1; 399 } 400 401 RESTARTABLE((*my_openat64_func)(dfd, path, (int)oflags, (mode_t)mode), fd); 402 if (fd == -1) { 403 throwUnixException(env, errno); 404 } 405 return fd; 406 } 407 408 JNIEXPORT void JNICALL 409 Java_sun_nio_fs_UnixNativeDispatcher_close(JNIEnv* env, jclass this, jint fd) { 410 int err; 411 /* TDB - need to decide if EIO and other errors should cause exception */ 412 RESTARTABLE(close((int)fd), err); 413 } 414 415 JNIEXPORT jint JNICALL 416 Java_sun_nio_fs_UnixNativeDispatcher_read(JNIEnv* env, jclass this, jint fd, 417 jlong address, jint nbytes) 418 { 419 ssize_t n; 420 void* bufp = jlong_to_ptr(address); 421 RESTARTABLE(read((int)fd, bufp, (size_t)nbytes), n); 422 if (n == -1) { 423 throwUnixException(env, errno); 424 } 425 return (jint)n; 426 } 427 428 JNIEXPORT jint JNICALL 429 Java_sun_nio_fs_UnixNativeDispatcher_write(JNIEnv* env, jclass this, jint fd, 430 jlong address, jint nbytes) 431 { 432 ssize_t n; 433 void* bufp = jlong_to_ptr(address); 434 RESTARTABLE(write((int)fd, bufp, (size_t)nbytes), n); 435 if (n == -1) { 436 throwUnixException(env, errno); 437 } 438 return (jint)n; 439 } 440 441 /** 442 * Copy stat64 members into sun.nio.fs.UnixFileAttributes 443 */ 444 static void prepAttributes(JNIEnv* env, struct stat64* buf, jobject attrs) { 445 (*env)->SetIntField(env, attrs, attrs_st_mode, (jint)buf->st_mode); 446 (*env)->SetLongField(env, attrs, attrs_st_ino, (jlong)buf->st_ino); 447 (*env)->SetLongField(env, attrs, attrs_st_dev, (jlong)buf->st_dev); 448 (*env)->SetLongField(env, attrs, attrs_st_rdev, (jlong)buf->st_rdev); 449 (*env)->SetIntField(env, attrs, attrs_st_nlink, (jint)buf->st_nlink); 450 (*env)->SetIntField(env, attrs, attrs_st_uid, (jint)buf->st_uid); 451 (*env)->SetIntField(env, attrs, attrs_st_gid, (jint)buf->st_gid); 452 (*env)->SetLongField(env, attrs, attrs_st_size, (jlong)buf->st_size); 453 (*env)->SetLongField(env, attrs, attrs_st_atime_sec, (jlong)buf->st_atime); 454 (*env)->SetLongField(env, attrs, attrs_st_mtime_sec, (jlong)buf->st_mtime); 455 (*env)->SetLongField(env, attrs, attrs_st_ctime_sec, (jlong)buf->st_ctime); 456 457 #ifdef _DARWIN_FEATURE_64_BIT_INODE 458 (*env)->SetLongField(env, attrs, attrs_st_birthtime_sec, (jlong)buf->st_birthtime); 459 #endif 460 461 #if (_POSIX_C_SOURCE >= 200809L) || defined(__solaris__) 462 (*env)->SetLongField(env, attrs, attrs_st_atime_nsec, (jlong)buf->st_atim.tv_nsec); 463 (*env)->SetLongField(env, attrs, attrs_st_mtime_nsec, (jlong)buf->st_mtim.tv_nsec); 464 (*env)->SetLongField(env, attrs, attrs_st_ctime_nsec, (jlong)buf->st_ctim.tv_nsec); 465 #endif 466 } 467 468 JNIEXPORT void JNICALL 469 Java_sun_nio_fs_UnixNativeDispatcher_stat0(JNIEnv* env, jclass this, 470 jlong pathAddress, jobject attrs) 471 { 472 int err; 473 struct stat64 buf; 474 const char* path = (const char*)jlong_to_ptr(pathAddress); 475 476 RESTARTABLE(stat64(path, &buf), err); 477 if (err == -1) { 478 throwUnixException(env, errno); 479 } else { 480 prepAttributes(env, &buf, attrs); 481 } 482 } 483 484 JNIEXPORT void JNICALL 485 Java_sun_nio_fs_UnixNativeDispatcher_lstat0(JNIEnv* env, jclass this, 486 jlong pathAddress, jobject attrs) 487 { 488 int err; 489 struct stat64 buf; 490 const char* path = (const char*)jlong_to_ptr(pathAddress); 491 492 RESTARTABLE(lstat64(path, &buf), err); 493 if (err == -1) { 494 throwUnixException(env, errno); 495 } else { 496 prepAttributes(env, &buf, attrs); 497 } 498 } 499 500 JNIEXPORT void JNICALL 501 Java_sun_nio_fs_UnixNativeDispatcher_fstat(JNIEnv* env, jclass this, jint fd, 502 jobject attrs) 503 { 504 int err; 505 struct stat64 buf; 506 507 RESTARTABLE(fstat64((int)fd, &buf), err); 508 if (err == -1) { 509 throwUnixException(env, errno); 510 } else { 511 prepAttributes(env, &buf, attrs); 512 } 513 } 514 515 JNIEXPORT void JNICALL 516 Java_sun_nio_fs_UnixNativeDispatcher_fstatat0(JNIEnv* env, jclass this, jint dfd, 517 jlong pathAddress, jint flag, jobject attrs) 518 { 519 int err; 520 struct stat64 buf; 521 const char* path = (const char*)jlong_to_ptr(pathAddress); 522 523 if (my_fstatat64_func == NULL) { 524 JNU_ThrowInternalError(env, "should not reach here"); 525 return; 526 } 527 RESTARTABLE((*my_fstatat64_func)((int)dfd, path, &buf, (int)flag), err); 528 if (err == -1) { 529 throwUnixException(env, errno); 530 } else { 531 prepAttributes(env, &buf, attrs); 532 } 533 } 534 535 JNIEXPORT void JNICALL 536 Java_sun_nio_fs_UnixNativeDispatcher_chmod0(JNIEnv* env, jclass this, 537 jlong pathAddress, jint mode) 538 { 539 int err; 540 const char* path = (const char*)jlong_to_ptr(pathAddress); 541 542 RESTARTABLE(chmod(path, (mode_t)mode), err); 543 if (err == -1) { 544 throwUnixException(env, errno); 545 } 546 } 547 548 JNIEXPORT void JNICALL 549 Java_sun_nio_fs_UnixNativeDispatcher_fchmod(JNIEnv* env, jclass this, jint filedes, 550 jint mode) 551 { 552 int err; 553 554 RESTARTABLE(fchmod((int)filedes, (mode_t)mode), err); 555 if (err == -1) { 556 throwUnixException(env, errno); 557 } 558 } 559 560 561 JNIEXPORT void JNICALL 562 Java_sun_nio_fs_UnixNativeDispatcher_chown0(JNIEnv* env, jclass this, 563 jlong pathAddress, jint uid, jint gid) 564 { 565 int err; 566 const char* path = (const char*)jlong_to_ptr(pathAddress); 567 568 RESTARTABLE(chown(path, (uid_t)uid, (gid_t)gid), err); 569 if (err == -1) { 570 throwUnixException(env, errno); 571 } 572 } 573 574 JNIEXPORT void JNICALL 575 Java_sun_nio_fs_UnixNativeDispatcher_lchown0(JNIEnv* env, jclass this, jlong pathAddress, jint uid, jint gid) 576 { 577 int err; 578 const char* path = (const char*)jlong_to_ptr(pathAddress); 579 580 RESTARTABLE(lchown(path, (uid_t)uid, (gid_t)gid), err); 581 if (err == -1) { 582 throwUnixException(env, errno); 583 } 584 } 585 586 JNIEXPORT void JNICALL 587 Java_sun_nio_fs_UnixNativeDispatcher_fchown(JNIEnv* env, jclass this, jint filedes, jint uid, jint gid) 588 { 589 int err; 590 591 RESTARTABLE(fchown(filedes, (uid_t)uid, (gid_t)gid), err); 592 if (err == -1) { 593 throwUnixException(env, errno); 594 } 595 } 596 597 JNIEXPORT void JNICALL 598 Java_sun_nio_fs_UnixNativeDispatcher_utimes0(JNIEnv* env, jclass this, 599 jlong pathAddress, jlong accessTime, jlong modificationTime) 600 { 601 int err; 602 struct timeval times[2]; 603 const char* path = (const char*)jlong_to_ptr(pathAddress); 604 605 times[0].tv_sec = accessTime / 1000000; 606 times[0].tv_usec = accessTime % 1000000; 607 608 times[1].tv_sec = modificationTime / 1000000; 609 times[1].tv_usec = modificationTime % 1000000; 610 611 RESTARTABLE(utimes(path, ×[0]), err); 612 if (err == -1) { 613 throwUnixException(env, errno); 614 } 615 } 616 617 JNIEXPORT void JNICALL 618 Java_sun_nio_fs_UnixNativeDispatcher_futimes(JNIEnv* env, jclass this, jint filedes, 619 jlong accessTime, jlong modificationTime) 620 { 621 struct timeval times[2]; 622 int err = 0; 623 624 times[0].tv_sec = accessTime / 1000000; 625 times[0].tv_usec = accessTime % 1000000; 626 627 times[1].tv_sec = modificationTime / 1000000; 628 times[1].tv_usec = modificationTime % 1000000; 629 630 #ifdef _ALLBSD_SOURCE 631 RESTARTABLE(futimes(filedes, ×[0]), err); 632 #else 633 if (my_futimesat_func == NULL) { 634 JNU_ThrowInternalError(env, "my_ftimesat_func is NULL"); 635 return; 636 } 637 RESTARTABLE((*my_futimesat_func)(filedes, NULL, ×[0]), err); 638 #endif 639 if (err == -1) { 640 throwUnixException(env, errno); 641 } 642 } 643 644 JNIEXPORT jlong JNICALL 645 Java_sun_nio_fs_UnixNativeDispatcher_opendir0(JNIEnv* env, jclass this, 646 jlong pathAddress) 647 { 648 DIR* dir; 649 const char* path = (const char*)jlong_to_ptr(pathAddress); 650 651 /* EINTR not listed as a possible error */ 652 dir = opendir(path); 653 if (dir == NULL) { 654 throwUnixException(env, errno); 655 } 656 return ptr_to_jlong(dir); 657 } 658 659 JNIEXPORT jlong JNICALL 660 Java_sun_nio_fs_UnixNativeDispatcher_fdopendir(JNIEnv* env, jclass this, int dfd) { 661 DIR* dir; 662 663 if (my_fdopendir_func == NULL) { 664 JNU_ThrowInternalError(env, "should not reach here"); 665 return (jlong)-1; 666 } 667 668 /* EINTR not listed as a possible error */ 669 dir = (*my_fdopendir_func)((int)dfd); 670 if (dir == NULL) { 671 throwUnixException(env, errno); 672 } 673 return ptr_to_jlong(dir); 674 } 675 676 JNIEXPORT void JNICALL 677 Java_sun_nio_fs_UnixNativeDispatcher_closedir(JNIEnv* env, jclass this, jlong dir) { 678 int err; 679 DIR* dirp = jlong_to_ptr(dir); 680 681 RESTARTABLE(closedir(dirp), err); 682 if (errno == -1) { 683 throwUnixException(env, errno); 684 } 685 } 686 687 JNIEXPORT jbyteArray JNICALL 688 Java_sun_nio_fs_UnixNativeDispatcher_readdir(JNIEnv* env, jclass this, jlong value) { 689 struct dirent64* result; 690 struct { 691 struct dirent64 buf; 692 char name_extra[PATH_MAX + 1 - sizeof result->d_name]; 693 } entry; 694 struct dirent64* ptr = &entry.buf; 695 int res; 696 DIR* dirp = jlong_to_ptr(value); 697 698 /* EINTR not listed as a possible error */ 699 /* TDB: reentrant version probably not required here */ 700 res = readdir64_r(dirp, ptr, &result); 701 702 #ifdef _AIX 703 /* On AIX, readdir_r() returns EBADF (i.e. '9') and sets 'result' to NULL for the */ 704 /* directory stream end. Otherwise, 'errno' will contain the error code. */ 705 if (res != 0) { 706 res = (result == NULL && res == EBADF) ? 0 : errno; 707 } 708 #endif 709 710 if (res != 0) { 711 throwUnixException(env, res); 712 return NULL; 713 } else { 714 if (result == NULL) { 715 return NULL; 716 } else { 717 jsize len = strlen(ptr->d_name); 718 jbyteArray bytes = (*env)->NewByteArray(env, len); 719 if (bytes != NULL) { 720 (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)(ptr->d_name)); 721 } 722 return bytes; 723 } 724 } 725 } 726 727 JNIEXPORT void JNICALL 728 Java_sun_nio_fs_UnixNativeDispatcher_mkdir0(JNIEnv* env, jclass this, 729 jlong pathAddress, jint mode) 730 { 731 const char* path = (const char*)jlong_to_ptr(pathAddress); 732 733 /* EINTR not listed as a possible error */ 734 if (mkdir(path, (mode_t)mode) == -1) { 735 throwUnixException(env, errno); 736 } 737 } 738 739 JNIEXPORT void JNICALL 740 Java_sun_nio_fs_UnixNativeDispatcher_rmdir0(JNIEnv* env, jclass this, 741 jlong pathAddress) 742 { 743 const char* path = (const char*)jlong_to_ptr(pathAddress); 744 745 /* EINTR not listed as a possible error */ 746 if (rmdir(path) == -1) { 747 throwUnixException(env, errno); 748 } 749 } 750 751 JNIEXPORT void JNICALL 752 Java_sun_nio_fs_UnixNativeDispatcher_link0(JNIEnv* env, jclass this, 753 jlong existingAddress, jlong newAddress) 754 { 755 int err; 756 const char* existing = (const char*)jlong_to_ptr(existingAddress); 757 const char* newname = (const char*)jlong_to_ptr(newAddress); 758 759 RESTARTABLE(link(existing, newname), err); 760 if (err == -1) { 761 throwUnixException(env, errno); 762 } 763 } 764 765 766 JNIEXPORT void JNICALL 767 Java_sun_nio_fs_UnixNativeDispatcher_unlink0(JNIEnv* env, jclass this, 768 jlong pathAddress) 769 { 770 const char* path = (const char*)jlong_to_ptr(pathAddress); 771 772 /* EINTR not listed as a possible error */ 773 if (unlink(path) == -1) { 774 throwUnixException(env, errno); 775 } 776 } 777 778 JNIEXPORT void JNICALL 779 Java_sun_nio_fs_UnixNativeDispatcher_unlinkat0(JNIEnv* env, jclass this, jint dfd, 780 jlong pathAddress, jint flags) 781 { 782 const char* path = (const char*)jlong_to_ptr(pathAddress); 783 784 if (my_unlinkat_func == NULL) { 785 JNU_ThrowInternalError(env, "should not reach here"); 786 return; 787 } 788 789 /* EINTR not listed as a possible error */ 790 if ((*my_unlinkat_func)((int)dfd, path, (int)flags) == -1) { 791 throwUnixException(env, errno); 792 } 793 } 794 795 JNIEXPORT void JNICALL 796 Java_sun_nio_fs_UnixNativeDispatcher_rename0(JNIEnv* env, jclass this, 797 jlong fromAddress, jlong toAddress) 798 { 799 const char* from = (const char*)jlong_to_ptr(fromAddress); 800 const char* to = (const char*)jlong_to_ptr(toAddress); 801 802 /* EINTR not listed as a possible error */ 803 if (rename(from, to) == -1) { 804 throwUnixException(env, errno); 805 } 806 } 807 808 JNIEXPORT void JNICALL 809 Java_sun_nio_fs_UnixNativeDispatcher_renameat0(JNIEnv* env, jclass this, 810 jint fromfd, jlong fromAddress, jint tofd, jlong toAddress) 811 { 812 const char* from = (const char*)jlong_to_ptr(fromAddress); 813 const char* to = (const char*)jlong_to_ptr(toAddress); 814 815 if (my_renameat_func == NULL) { 816 JNU_ThrowInternalError(env, "should not reach here"); 817 return; 818 } 819 820 /* EINTR not listed as a possible error */ 821 if ((*my_renameat_func)((int)fromfd, from, (int)tofd, to) == -1) { 822 throwUnixException(env, errno); 823 } 824 } 825 826 JNIEXPORT void JNICALL 827 Java_sun_nio_fs_UnixNativeDispatcher_symlink0(JNIEnv* env, jclass this, 828 jlong targetAddress, jlong linkAddress) 829 { 830 const char* target = (const char*)jlong_to_ptr(targetAddress); 831 const char* link = (const char*)jlong_to_ptr(linkAddress); 832 833 /* EINTR not listed as a possible error */ 834 if (symlink(target, link) == -1) { 835 throwUnixException(env, errno); 836 } 837 } 838 839 JNIEXPORT jbyteArray JNICALL 840 Java_sun_nio_fs_UnixNativeDispatcher_readlink0(JNIEnv* env, jclass this, 841 jlong pathAddress) 842 { 843 jbyteArray result = NULL; 844 char target[PATH_MAX+1]; 845 const char* path = (const char*)jlong_to_ptr(pathAddress); 846 847 /* EINTR not listed as a possible error */ 848 int n = readlink(path, target, sizeof(target)); 849 if (n == -1) { 850 throwUnixException(env, errno); 851 } else { 852 jsize len; 853 if (n == sizeof(target)) { 854 n--; 855 } 856 target[n] = '\0'; 857 len = (jsize)strlen(target); 858 result = (*env)->NewByteArray(env, len); 859 if (result != NULL) { 860 (*env)->SetByteArrayRegion(env, result, 0, len, (jbyte*)target); 861 } 862 } 863 return result; 864 } 865 866 JNIEXPORT jbyteArray JNICALL 867 Java_sun_nio_fs_UnixNativeDispatcher_realpath0(JNIEnv* env, jclass this, 868 jlong pathAddress) 869 { 870 jbyteArray result = NULL; 871 char resolved[PATH_MAX+1]; 872 const char* path = (const char*)jlong_to_ptr(pathAddress); 873 874 /* EINTR not listed as a possible error */ 875 if (realpath(path, resolved) == NULL) { 876 throwUnixException(env, errno); 877 } else { 878 jsize len = (jsize)strlen(resolved); 879 result = (*env)->NewByteArray(env, len); 880 if (result != NULL) { 881 (*env)->SetByteArrayRegion(env, result, 0, len, (jbyte*)resolved); 882 } 883 } 884 return result; 885 } 886 887 JNIEXPORT void JNICALL 888 Java_sun_nio_fs_UnixNativeDispatcher_access0(JNIEnv* env, jclass this, 889 jlong pathAddress, jint amode) 890 { 891 int err; 892 const char* path = (const char*)jlong_to_ptr(pathAddress); 893 894 RESTARTABLE(access(path, (int)amode), err); 895 if (err == -1) { 896 throwUnixException(env, errno); 897 } 898 } 899 900 JNIEXPORT void JNICALL 901 Java_sun_nio_fs_UnixNativeDispatcher_statvfs0(JNIEnv* env, jclass this, 902 jlong pathAddress, jobject attrs) 903 { 904 int err; 905 struct statvfs64 buf; 906 const char* path = (const char*)jlong_to_ptr(pathAddress); 907 908 909 RESTARTABLE(statvfs64(path, &buf), err); 910 if (err == -1) { 911 throwUnixException(env, errno); 912 } else { 913 #ifdef _AIX 914 /* AIX returns ULONG_MAX in buf.f_blocks for the /proc file system. */ 915 /* This is too big for a Java signed long and fools various tests. */ 916 if (buf.f_blocks == ULONG_MAX) { 917 buf.f_blocks = 0; 918 } 919 /* The number of free or available blocks can never exceed the total number of blocks */ 920 if (buf.f_blocks == 0) { 921 buf.f_bfree = 0; 922 buf.f_bavail = 0; 923 } 924 #endif 925 (*env)->SetLongField(env, attrs, attrs_f_frsize, long_to_jlong(buf.f_frsize)); 926 (*env)->SetLongField(env, attrs, attrs_f_blocks, long_to_jlong(buf.f_blocks)); 927 (*env)->SetLongField(env, attrs, attrs_f_bfree, long_to_jlong(buf.f_bfree)); 928 (*env)->SetLongField(env, attrs, attrs_f_bavail, long_to_jlong(buf.f_bavail)); 929 } 930 } 931 932 JNIEXPORT jlong JNICALL 933 Java_sun_nio_fs_UnixNativeDispatcher_pathconf0(JNIEnv* env, jclass this, 934 jlong pathAddress, jint name) 935 { 936 long err; 937 const char* path = (const char*)jlong_to_ptr(pathAddress); 938 939 err = pathconf(path, (int)name); 940 if (err == -1) { 941 throwUnixException(env, errno); 942 } 943 return (jlong)err; 944 } 945 946 JNIEXPORT jlong JNICALL 947 Java_sun_nio_fs_UnixNativeDispatcher_fpathconf(JNIEnv* env, jclass this, 948 jint fd, jint name) 949 { 950 long err; 951 952 err = fpathconf((int)fd, (int)name); 953 if (err == -1) { 954 throwUnixException(env, errno); 955 } 956 return (jlong)err; 957 } 958 959 JNIEXPORT void JNICALL 960 Java_sun_nio_fs_UnixNativeDispatcher_mknod0(JNIEnv* env, jclass this, 961 jlong pathAddress, jint mode, jlong dev) 962 { 963 int err; 964 const char* path = (const char*)jlong_to_ptr(pathAddress); 965 966 RESTARTABLE(mknod(path, (mode_t)mode, (dev_t)dev), err); 967 if (err == -1) { 968 throwUnixException(env, errno); 969 } 970 } 971 972 JNIEXPORT jbyteArray JNICALL 973 Java_sun_nio_fs_UnixNativeDispatcher_getpwuid(JNIEnv* env, jclass this, jint uid) 974 { 975 jbyteArray result = NULL; 976 int buflen; 977 char* pwbuf; 978 979 /* allocate buffer for password record */ 980 buflen = (int)sysconf(_SC_GETPW_R_SIZE_MAX); 981 if (buflen == -1) 982 buflen = ENT_BUF_SIZE; 983 pwbuf = (char*)malloc(buflen); 984 if (pwbuf == NULL) { 985 JNU_ThrowOutOfMemoryError(env, "native heap"); 986 } else { 987 struct passwd pwent; 988 struct passwd* p = NULL; 989 int res = 0; 990 991 errno = 0; 992 #ifdef __solaris__ 993 RESTARTABLE_RETURN_PTR(getpwuid_r((uid_t)uid, &pwent, pwbuf, (size_t)buflen), p); 994 #else 995 RESTARTABLE(getpwuid_r((uid_t)uid, &pwent, pwbuf, (size_t)buflen, &p), res); 996 #endif 997 998 if (res != 0 || p == NULL || p->pw_name == NULL || *(p->pw_name) == '\0') { 999 /* not found or error */ 1000 if (errno == 0) 1001 errno = ENOENT; 1002 throwUnixException(env, errno); 1003 } else { 1004 jsize len = strlen(p->pw_name); 1005 result = (*env)->NewByteArray(env, len); 1006 if (result != NULL) { 1007 (*env)->SetByteArrayRegion(env, result, 0, len, (jbyte*)(p->pw_name)); 1008 } 1009 } 1010 free(pwbuf); 1011 } 1012 1013 return result; 1014 } 1015 1016 1017 JNIEXPORT jbyteArray JNICALL 1018 Java_sun_nio_fs_UnixNativeDispatcher_getgrgid(JNIEnv* env, jclass this, jint gid) 1019 { 1020 jbyteArray result = NULL; 1021 int buflen; 1022 int retry; 1023 1024 /* initial size of buffer for group record */ 1025 buflen = (int)sysconf(_SC_GETGR_R_SIZE_MAX); 1026 if (buflen == -1) 1027 buflen = ENT_BUF_SIZE; 1028 1029 do { 1030 struct group grent; 1031 struct group* g = NULL; 1032 int res = 0; 1033 1034 char* grbuf = (char*)malloc(buflen); 1035 if (grbuf == NULL) { 1036 JNU_ThrowOutOfMemoryError(env, "native heap"); 1037 return NULL; 1038 } 1039 1040 errno = 0; 1041 #ifdef __solaris__ 1042 RESTARTABLE_RETURN_PTR(getgrgid_r((gid_t)gid, &grent, grbuf, (size_t)buflen), g); 1043 #else 1044 RESTARTABLE(getgrgid_r((gid_t)gid, &grent, grbuf, (size_t)buflen, &g), res); 1045 #endif 1046 1047 retry = 0; 1048 if (res != 0 || g == NULL || g->gr_name == NULL || *(g->gr_name) == '\0') { 1049 /* not found or error */ 1050 if (errno == ERANGE) { 1051 /* insufficient buffer size so need larger buffer */ 1052 buflen += ENT_BUF_SIZE; 1053 retry = 1; 1054 } else { 1055 if (errno == 0) 1056 errno = ENOENT; 1057 throwUnixException(env, errno); 1058 } 1059 } else { 1060 jsize len = strlen(g->gr_name); 1061 result = (*env)->NewByteArray(env, len); 1062 if (result != NULL) { 1063 (*env)->SetByteArrayRegion(env, result, 0, len, (jbyte*)(g->gr_name)); 1064 } 1065 } 1066 1067 free(grbuf); 1068 1069 } while (retry); 1070 1071 return result; 1072 } 1073 1074 JNIEXPORT jint JNICALL 1075 Java_sun_nio_fs_UnixNativeDispatcher_getpwnam0(JNIEnv* env, jclass this, 1076 jlong nameAddress) 1077 { 1078 jint uid = -1; 1079 int buflen; 1080 char* pwbuf; 1081 1082 /* allocate buffer for password record */ 1083 buflen = (int)sysconf(_SC_GETPW_R_SIZE_MAX); 1084 if (buflen == -1) 1085 buflen = ENT_BUF_SIZE; 1086 pwbuf = (char*)malloc(buflen); 1087 if (pwbuf == NULL) { 1088 JNU_ThrowOutOfMemoryError(env, "native heap"); 1089 } else { 1090 struct passwd pwent; 1091 struct passwd* p = NULL; 1092 int res = 0; 1093 const char* name = (const char*)jlong_to_ptr(nameAddress); 1094 1095 errno = 0; 1096 #ifdef __solaris__ 1097 RESTARTABLE_RETURN_PTR(getpwnam_r(name, &pwent, pwbuf, (size_t)buflen), p); 1098 #else 1099 RESTARTABLE(getpwnam_r(name, &pwent, pwbuf, (size_t)buflen, &p), res); 1100 #endif 1101 1102 if (res != 0 || p == NULL || p->pw_name == NULL || *(p->pw_name) == '\0') { 1103 /* not found or error */ 1104 if (errno != 0 && errno != ENOENT && errno != ESRCH) 1105 throwUnixException(env, errno); 1106 } else { 1107 uid = p->pw_uid; 1108 } 1109 free(pwbuf); 1110 } 1111 1112 return uid; 1113 } 1114 1115 JNIEXPORT jint JNICALL 1116 Java_sun_nio_fs_UnixNativeDispatcher_getgrnam0(JNIEnv* env, jclass this, 1117 jlong nameAddress) 1118 { 1119 jint gid = -1; 1120 int buflen, retry; 1121 1122 /* initial size of buffer for group record */ 1123 buflen = (int)sysconf(_SC_GETGR_R_SIZE_MAX); 1124 if (buflen == -1) 1125 buflen = ENT_BUF_SIZE; 1126 1127 do { 1128 struct group grent; 1129 struct group* g = NULL; 1130 int res = 0; 1131 char *grbuf; 1132 const char* name = (const char*)jlong_to_ptr(nameAddress); 1133 1134 grbuf = (char*)malloc(buflen); 1135 if (grbuf == NULL) { 1136 JNU_ThrowOutOfMemoryError(env, "native heap"); 1137 return -1; 1138 } 1139 1140 errno = 0; 1141 #ifdef __solaris__ 1142 RESTARTABLE_RETURN_PTR(getgrnam_r(name, &grent, grbuf, (size_t)buflen), g); 1143 #else 1144 RESTARTABLE(getgrnam_r(name, &grent, grbuf, (size_t)buflen, &g), res); 1145 #endif 1146 1147 retry = 0; 1148 if (res != 0 || g == NULL || g->gr_name == NULL || *(g->gr_name) == '\0') { 1149 /* not found or error */ 1150 if (errno != 0 && errno != ENOENT && errno != ESRCH) { 1151 if (errno == ERANGE) { 1152 /* insufficient buffer size so need larger buffer */ 1153 buflen += ENT_BUF_SIZE; 1154 retry = 1; 1155 } else { 1156 throwUnixException(env, errno); 1157 } 1158 } 1159 } else { 1160 gid = g->gr_gid; 1161 } 1162 1163 free(grbuf); 1164 1165 } while (retry); 1166 1167 return gid; 1168 }